I'm looking to do a very simple piece of code that plays a sound effect. So far I have this code:
SoundManager snd;
int combo;
private void soundSetup() {
// Create an instance of the sound manger
snd = new SoundManager(getApplicationContext());
// Set volume rocker mode to media volume
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
// Load the samples from res/raw
combo = snd.load(R.raw.combo);
}
private void playSound() {
soundSetup();
snd.play(combo);
}
However, for some reason when I use the playSound() method, nothing happens. The audio file is in the correct location.
Is there a specific reason you are using SoundManager? I would use MediaPlayer instead, here is a link to the Android Docs
http://developer.android.com/reference/android/media/MediaPlayer.html
then it's as simple as
MediaPlayer mp = MediaPlayer.create(getApplicationContext(), R.raw.combo);
mp.start();
Make a directory called "raw/" under the "res/" directory. Drag wav or mp3 files into the raw/ directory. Play them from anywhere as above.
i have also attempted using the top answer, yet it resulted in NullPointerExceptions from the MediaPlayer when i tried playing a sound many times in a row, so I extended the code a bit.
FXPlayer is my global MediaPlayer.
public void playSound(int _id)
{
if(FXPlayer != null)
{
FXPlayer.stop();
FXPlayer.release();
}
FXPlayer = MediaPlayer.create(this, _id);
if(FXPlayer != null)
FXPlayer.start();
}
Related
The Audio interface allows to set its volume, but apps usually use the Media or Notifications volumes on Android. In a Gluon Mobile app, pressing the volume keys does nothing, while in other apps the device's volume changes.
Tested on Android 8 and 12 using Attach version 4.0.15.
Is there a way to play audio using the device's volume settings and allow the user to adjust the volume from within the device?
There seems to be no proper way to do this. Using the VideoService it's possible to change the volume of the device, but only while audio is playing, which requires the user to be ready to do so for short audio clips.
The VideoService also does not support playing a single file out of a playlist. The only solution I found was switching the playlist to a single audio clip whenever it's required to be played and isn't played already:
class MobileNotifier {
private static final String SMALL_BEEP_PATH = "/sounds/SmallBeep.wav";
private static final String BIG_BEEP_PATH = "/sounds/BigBeep.wav";
VideoService service;
private MobileNotifier(VideoService service) {
this.service = service;
service.getPlaylist().add(SHORT_BEEP_PATH);
}
public void play(Alert alert) {
switch (alert) {
case SMALL -> {
if (service.statusProperty().get() != Status.PLAYING || !SMALL_BEEP_PATH.equals(service.getPlaylist().get(0))) {
service.stop();
service.getPlaylist().set(0, SMALL_BEEP_PATH);
service.play();
}
}
case BIG -> {
if (service.statusProperty().get() != Status.PLAYING || !BIG_BEEP_PATH.equals(service.getPlaylist().get(0))) {
service.stop();
service.getPlaylist().set(0, LONG_BEEP_PATH);
service.play();
}
}
};
}
}
I am trying to stop an intro song from playing when pressing the start button. I tried doing so using this code. Note that this code does not entail all my code. The GUI looks fine, the Actionlisteners work fine too. Only the music does not stop playing when the start button is pressed.
File introPath = new File("src/BattleshipGUI/423499__soundflakes__epic-heroic-orchestral-
dramatic.wav");
File buttonPressedPath = new File("src/BattleshipGUI/sfx_patcher_button_launch.wav");
static Clip introWAV;
Menu() {
super("BattleBoard");
this.setContentPane(this.panelMain);
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
this.setLocationRelativeTo(null);
this.pack();
play(introPath); // playing when launching
// when the game starts, the sound should stop
ButtonStartGame.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
play(buttonPressedPath);
try {
if (random) {
currentCols = (Integer) spinnerColumns.getValue();
currentRows = (Integer) spinnerRows.getValue();
if (currentCols < 5 || currentRows < 5) {
throw (new IllegalArgumentException());
} else {
BoardFrame b = new BoardFrame(currentRows, currentCols);
b.SetFrame(currentRows, currentCols);
b.AddRandomShips(currentRows, currentCols);
b.ScoreMethod(adjustedScoreMethod);
introWAV.stop();
introWAV.flush();
introWAV.close();
dispose();
public static void SetIntroWAV(Clip clip){
introWAV=clip;
}
public static void play(File file) {
try {
Clip sound = AudioSystem.getClip();
sound.open(AudioSystem.getAudioInputStream(file));
SetIntroWAV(sound);
sound.start();
} catch (Exception e) {
System.out.println(e);
}
}
I tried other ways, like using while loops in the Play-class, 'if-else'-statements,... Does someone know how to fix this? Thanks in advance!
The culprit is part of your play method.
Whenever you want to play any sound you also call SetIntroWAV internally. This results in your introWAV variable being set.
Here's why that's a problem:
The first time you call play, your intro sound is played back and introWAV has the correct value.
However, once you start your game and play a different sound (namely using buttonPressedPath) your introWAV variable is set to a different value: the sound that was most recently started.
When you then try to stop your sound from playing, you're using introWAV which doesn't actually contain a reference to your intro sound anymore. Instead, this will result in your most recently played sound to be stopped since this is what introWAV is holding now.
To fix this, it's simply a case of only setting your introWAV variable once and not every time play is called. There are multiple ways of doing this, including these:
You could let your play method return the resulting Clip that will be played afterwards:
public static Clip play(File file) {
Clip sound = null;
try {
sound = AudioSystem.getClip();
sound.open(AudioSystem.getAudioInputStream(file));
sound.start();
} catch (Exception e) {
System.out.println(e);
} finally {
return sound;
}
}
You can then use this returned value to call SetIntroWAV once: SetIntroWAV(play(introPath));
You could also use this return value for other purposes like keeping local references to your sounds. However, you don't have to use it every time and can still ignore it whenever you don't need that reference.
You could rewrite your play method to also contain a parameter telling the method whether the sound you're trying to play is the intro sound:
public static void play(File file, boolean intro) {
try {
Clip sound = AudioSystem.getClip();
sound.open(AudioSystem.getAudioInputStream(file));
if(intro) {
SetIntroWAV(sound);
}
sound.start();
} catch (Exception e) {
System.out.println(e);
}
}
This will also result in SetIntroWAV only being called once.
I'd also recommend you use more of an object-oriented style of programming for this as it can make things like these much more obvious and easier to fix.
For example, you could create separate classes for audio playback and your gameplay.
IMHO the best practice with Clip variables is to load and open, and then hold them in memory. This can be done in a class that manages your sound effects. In that class, have a Clip as an instance variable and preload and open it in the constructor.
This class can also have two methods that are called from your game.
public void play() {
clip.setFramePosition(0); // ensures Clip will start from the beginning
clip.start();
}
public void stop() {
clip.stop();
}
With this sort of structure, it also become easier to manage multiple sounds. For example, you can have two instances of this sound-managing class, and set each to a different sound source. Then, you can readily stop one and start another.
I have an activity that creates an "Audio" class and tries to use android Text to Speech API to read some text. If the language is not supported, it tries to use MediaPlayer to play a custom mp3 file from the server. Finally if MediaPlayer fails, it uses Nuance SpeechKit to read the text:
My problem is when I destroy the activity, I want to destroy/stop the Nuance audio too and I'm not sure how to shutdown Nuance audio.
Activity class
private Audio audio;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_layout);
audio = new Audio(this).play("my text to read");
}
#Override
protected void onPause() {
audio.pause();
super.onPause();
}
#Override
protected void onDestroy() {
audio.destroy();
super.onDestroy();
}
Audio class
private TextToSpeech tts;
private MediaPlayer player;
private Session session;
public void play(String text) {
// check if supported
if (supported) tts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
else mediaPlayer(text);
}
private void mediaPlayer(String text) {
// make some queries on server to find the file url
if (queryFoundFile) {
player = new MediaPlayer();
player.setDataSource(myFileUrl);
player.setAudioStreamType(3);
player.prepare();
player.start();
} else nuancePlayer(text);
}
private void nuancePlayer(String text) {
Transaction.Options options = new Transaction.Options();
options.setLanguage(new Language("eng-USA"));
session = Session.Factory.session(activity, myServer, appKey);
session.speakString(text, options, new Transaction.Listener() {
#Override
public void onError(Transaction transaction, String s, TransactionException e) {
e.printStackTrace()
}
});
// it reaches here and nuance plays the audio
}
// these are the methods I call when the activity is paused or destroyed
public void pause() {
if (tts != null) tts.stop();
if (player != null) player.stop();
if (nuance != null) nuance.getAudioPlayer().stop(); // don't work
}
public void destroy() {
if (tts != null) tts.shutdown();
if (player != null) player.release();
if (nuance != null) nuance.getAudioPlayer().stop(); // don't work
}
If I'm using Text to Speech or MediaPlayer and if I destroy my Activity, the audio is immediately destroyed. But I can't seem to destroy the audio if is Nuance playing. It just keeps talking.
I did some debugging and the pause() and destroy() methods are being called. Also nuance.getAudioPlayer is not null and is the AudioPlayer playing. I can't find the reason why he is not stopping when I call the method stop() on him.
What is Nuance?
This is my first time using Nuance so I am not that experienced with this. Basically I see it like an alternative to the Android Text to Speech.
Nuance Developers
Why I have this on my project?
My project has 4 main languages, and I need to have a text to speech function to read some text. The problem is, android Text to Speech don't support some of these languages which Nuance support.
Why is Nuance my last option?
Because Nuance has costs. I try to use android TTS or MediaPlayer. Only if those two fail, I use Nuance. It is a last resort to read my text!
As per change log, this issue is known since a year ago and no fixed yet (as per changelog).
For temporary solution till they gave you fixed release you can do the following:
Break your text in small chunks and instead of playing complete text(as audio) at once, Queued these small text chunks into the audio player so that you audio will stop after finish playing the current chunk instead of complete text.
because as per known issue in the change log given below:
Please note this line:
However, if multiple Audios are queued for playback and stop() is called, then the next Audio will not begin playing and the queue will be cleared.
I hope this will help you.
A quick look on the nuance API shows that session.speakString(...) returns a Transaction, and a Transaction has 2 methods that might be of interest for you:
cancel() - Cancel the Transaction.
stopRecording() - Stop recording audio and complete the Transaction, if there is an ongoing recording.
Looks like cancel() is what you need.
Try setting session to null to see if the garbage collector solves the problem.
The app basically allows the user to play an animal sound, voice or other sound when clicking various items. I'm trying to figure out if I'm doing this in the right way because I'm seeing some issues like this error, when the user mutes>unmutes>plays a sound:
java.lang.IllegalStateException at
android.media.MediaPlayer.isPlaying(Native Method)
public class GuessActivity extends Activity implements PopupMenu.OnMenuItemClickListener {
public static int[] ssSoundsArray = {R.raw.sbuffalo, R.raw.scamel, R.raw.scat, R.raw.schicken};
public static int[] ssVoicesArray = {R.raw.buffalo, R.raw.camel, R.raw.cat, R.raw.chicken};
MediaPlayer mMediaPlayer;
Context context;
...
}
Here's an example of how I am using MediaPlayer:
if(audio_all) {
if(mMediaPlayer != null) {
if(mMediaPlayer.isPlaying()) {
mMediaPlayer.stop();
mMediaPlayer.release();
}
}
mMediaPlayer = MediaPlayer.create(this, R.raw.whatever);
mMediaPlayer.start();
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mediaPlayer) {
mMediaPlayer.release();
mMediaPlayer = null;
}
});
}
I'm doing this multiple times for different buttons etc, making sure to release() after they are done since I ran into mem issues before. So the exception is telling above is telling me isPlaying() isn't valid since MediaPlayer does not exist but for some reason it ignores if(mMediaPlayer != null)
It is necessary to stop if anything is playing since the user is free to click randomly and of course I do not want any sounds overlaying eachother.
Here's how the user mutes:
case R.id.action_toggle_sounds:
if(audio_all) {
if(mMediaPlayer != null) {
if(mMediaPlayer.isPlaying()) {
mMediaPlayer.stop();
mMediaPlayer.release();
}
}
Toast.makeText(this,"All sounds disabled",Toast.LENGTH_LONG).show();
audio_all = false;
} else {
Toast.makeText(this,"All sounds enabled",Toast.LENGTH_LONG).show();
audio_all = true;
}
return true;
I very much appreciate any help with this, thanks a lot!
If you has not so much tracks to play (not more than 32) you can try to initialize multiple MediaPlayer instances and release() them only when app onPause()/onStop() called.
Then you will have pool of ready to use MediaPlayer's. You just have to remember which one is in use right now.
Also if you use MediaPlayer in multiple threads (not only UI thread) then you MUST use mutex (thread blocking) to avoid issues.
MediaPlayer based state machine - IllegalStateException basicly means player instance is in state when calling isPlaying() not allowed. For isPlaying() documented not allowed state is only Error state, but assume state after calling release() may be also not appropriate for this.
What i want to do in my project is to play audio songs which are inside my Box account for that i am using box api . As i know we can not provide direct audio streaming for audio files in Box api for that i am trying to implement progressive download and playing audio file from sd card . i know i can play song inside on complete method of download but this is taking more time to download and than playing file . for that what i did i wrote my code for playing audio inside on progress method of downloading file but this method is getting called so many times because of that same song is playing multiple time at a time.
So is there any way to write code for progressive audio playing in Box api .if yes where should i write that ?
* Download a file and put it into the SD card. In your app, you can put the file wherever you have access to.
*/
final Box box = Box.getInstance(Constants.API_KEY);
String PATH = Environment.getExternalStorageDirectory() + "/chaseyourmusic"+folderpath;
File file = new File(PATH);
file.mkdirs();
final java.io.File destinationFile = new java.io.File(PATH + "/"
+ URLEncoder.encode(items[position].name));
/* final java.io.File destinationFile = new java.io.File(Environment.getExternalStorageDirectory() + "/"
+ URLEncoder.encode(items[position].name));*/
final ProgressDialog downloadDialog = new ProgressDialog(Browse.this);
downloadDialog.setMessage("Downloading " + items[position].name);
downloadDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
downloadDialog.setMax((int) items[position].file.getSize());
downloadDialog.setCancelable(true);
downloadDialog.show();
Toast.makeText(getApplicationContext(), "Click BACK to cancel the download.", Toast.LENGTH_SHORT).show();
final Cancelable cancelable = box.download(authToken, items[position].id, destinationFile, null, new FileDownloadListener() {
#Override
public void onComplete(final String status) {
downloadDialog.dismiss();
if (status.equals(FileDownloadListener.STATUS_DOWNLOAD_OK)) {
//Able to play audio here from sd card but this is playing after completion of download only which is taking more time .
}
else if (status.equals(FileDownloadListener.STATUS_DOWNLOAD_CANCELLED)) {
Toast.makeText(getApplicationContext(), "Download canceled.", Toast.LENGTH_LONG).show();
}
}
#Override
public void onIOException(final IOException e) {
e.printStackTrace();
downloadDialog.dismiss();
Toast.makeText(getApplicationContext(), "Download failed " + e.getMessage(), Toast.LENGTH_LONG).show();
}
#Override
public void onProgress(final long bytesDownloaded) {
downloadDialog.setProgress((int) bytesDownloaded);
//Want to write code here but this method is getting called multiple times which is creating problem in playing audio files from sd card .
}
});
downloadDialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
cancelable.cancel();
}
});
Thanks
Use something like these:
http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/StreamProxy.java?r=41487c03f461942a5747378d197320412fe99442
http://www.java2s.com/Code/Android/File/StreamProxy.htm
Basically for progressive streaming, you proceed with the download as usual (in background) and you run a stream proxy (like a server in background) and push the data to your media player (you can use external media player or write a simple one by yourself, it is only few lines of code with Android media framework)
I have use something very similar with success.
In fact I am using the answer from this post (with minor modification)
MediaPlayer stutters at start of mp3 playback