Media Player how to recover when create fails? - java

I have an app that plays randomly every second 1 of 20 different sounds . After almost 1000 successful times the media player create function starts to return always null. The problem remains even when I leave the app and I start it again. The only solution is when I install the app again or I switch off and on the device.
Is there any method to recover from this state? If I do release or reset, media player was already null and they produce an exception.
The sequence I do every second is the following:
if (mp != null)
{
if (mp.isPlaying())
{
mp.stop();
}
if (mp != null) mp.release();
if (mp != null) mp = null;
}
mp = MediaPlayer.create(this, R.raw.sound);
if (mp !=null)
{
mp.setOnPreparedListener(new MediaPlayer.OnPreparedListener()
{
public void onPrepared(MediaPlayer mp)
{
if (mp != null) mp.start();
}
};
}
else
{
// error, what should I do here to recover from this situation?
}

Your problem is that even when you're releasing the MediaPlayer, the OS may not have let go of the resources yet by the time you try to use it again, especially 20 times per second. I would actually recommend that you look into using a SoundPool instead for something like this.
Regardless, to do this with a MediaPlayer, you should keep only one reference, and reuse that object each time for a different sound. Since you're using raw resources for playback, a typically reuse scenario would be something like this:
AssetFileDescriptor afd = getResources().openRawResourceFd(R.raw.sound);
//Resets the MediaPlayer state but keeps the resources
mp.reset();
//Sets the data source to the requested sound (R.raw.sound)
mp.setDataSource(afd.getFileDescriptor());
//Prepare the MediaPlayer to play and then start
mp.prepare();
mp.start();

It seems I have found the solution. I have now played more than 10000 audios without reproducing the error anymore.
I want to thank to kcoppock for his help, I do not create and release now because it is much better to change the data source as he explained, but it was not the main problem.
The final solution was to convert all the mp3 files into ogg files !!!!
Media Player has definitely problems with mp3 files.

Related

How to extract or save current song from MediaPlayer after changing speed or pitch in android

I am currently developing an application to play music
I have now added the feature of adjusting the speed and pitch for music in the my app
fun MediaPlayer.setPlaybackSpeedPitch(speed: Float, pitch: Float) {
try {
if (hasMarshmallow()) {
val wasPlaying = isPlaying;
playbackParams = PlaybackParams().setSpeed(speed).setPitch(pitch)
if (!wasPlaying) pause()
}
} catch (e: Exception) {
}
}
But currently I want to extract music from MediaPlayer
How do I save music from MediaPlayer to the external storage of the phone
please any help
I tried to search a lot but didn't find any solution
any help will be deeply appreciated?
P.S. My main motive is to let user change speed or pitch to the original song and then save it.

AudioManager is introducing delay in the setMode(MODE_IN_COMMUNICATION)

I am trying to play sound on speaker even if headphones are on, BUT if there is music playing in background, I want the music to be played on headphones until the sound is played.
So I am taking the next steps:
Before I play sound, I gain audioFocus so all the background music is
stopped
After audioFocus is gained, I set MODE_COMMUNICATION to the
AudioManager, so the sound can be played on the speaker.
After the sound ends, I abandonAudioFocus and set back MODE_NORMAL to
AudioManager, so the background music can continue playing on the headphones.
The strange thing is that it depends from the device, on some device this is OK, but on Nexus 6P (Huawei) devices after setting the MODE_COMMUNICATION there is delay 3-4 seconds before the sound can be played. If I play the sound without the delay, it is not played neither to speaker nor to headphones.
THE QUESTION
How can I know how much delay to set before the sound is played? Is there any listener that I can attach, so can notify me that after setting MODE_COMMUNICATION the sound is ready to be played?
I don't want to set delay even if it is not necessary!
The solution is not setting the mode into the constructor of the class(to skip the delay), because I need the sound to be played on speaker in the specific moment!
P.S: I am playing the sound with AudioTrack, but I tried with MediaPlayer as well (setting setAudioStreamType(MODE_IN_COMMUNICATION)), but no success, the delay is still there!
So any suggestions?
In case anyone stumbles upon this post, what worked for me was calling AudioManager.setMode() and then recreating my MediaPlayer (via constructor, not create()) and using setAudioAttributes() to change the output source.
Kotlin snippet:
fun switchOutput(inCommunication: Boolean) {
//STEP 1: Change the AudioManager's audio mode
if(inCommunication) {
audioManager.mode = AudioManager.MODE_IN_CALL
audioManager.isSpeakerphoneOn = false
} else {
audioManager.mode = AudioManager.MODE_NORMAL
audioManager.isSpeakerphoneOn = true
}
//STEP 2: Recreate the MediaPlayer
if (player != null) {
try {
player?.stop()
} catch (e: RuntimeException) {
} finally {
player?.reset()
player?.release()
player = null
}
}
player = MediaPlayer()
try {
val streamType =
if (inCommunication) AudioManager.STREAM_VOICE_CALL
else AudioManager.STREAM_MUSIC
player?.setDataSource(dataSource)
player?.setAudioAttributes(AudioAttributes.Builder()
.setLegacyStreamType(streamType)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build())
player?.prepare()
player?.start()
} catch (e: java.lang.Exception) {}
}
Hope this helps :)
P.S. Notice I've used MODE_IN_CALL instead of MODE_IN_COMMUNICATION

Slow Multithreading in Java - Air Percussion project

I am creating "Air Percussion" using IMU sensors and Arduino to communicate with computer (3 separate IMUs and Arduinos). They are connected to the computer through USBs. I am gathering data on separate Threads (each thread for each sensor). When I connect only one "set" my program is working really fast. I can get even 5 plays of sound per second. Unfortunatelly when i am trying to connect 3 sensors and run them on separate Threads at the same time my program slows down horribly. Even when im moving only one of sensors, I can get like 1 "hit" per second and sometimes it's even losing some of the sounds it should play. I'll show only important parts of the code below.
In the main i've got ActionListener for button, where it should start gathering the data. I run there 3 separate Threads for each USB Port.
connectButton.addActionListener(new ActionListener(){
#Override public void actionPerformed(ActionEvent arg0) {
int dialogButton = 1;
if(!flagaKalibracjiLewa || !flagaKalibracjiPrawa){ //some unimportant flags
dialogButton = JOptionPane.showConfirmDialog(null, "Rozpoczynając program bez kalibracji będziesz miał do dyspozycji mniejszą ilość dzwięków. Czy chcesz kontynuować?","Warning",JOptionPane.YES_NO_OPTION);
}else{
dialogButton = JOptionPane.YES_OPTION;
}
if(dialogButton == JOptionPane.YES_OPTION){
if(connectButton.getText().equals("Connect")) {
if(!flagaKalibracjiLewa && !flagaKalibracjiPrawa) podlaczPorty();
Thread thread = new Thread(){
#Override public void run() {
Scanner data = new Scanner(chosenPort.getInputStream());
dataIncoming(data, "lewa");
data.close();
}
};
Thread thread2 = new Thread(){
#Override public void run() {
Scanner data = new Scanner(chosenPort2.getInputStream());
dataIncoming(data, "prawa");
data.close();
}
};
Thread thread3 = new Thread(){
#Override public void run() {
Scanner data = new Scanner(chosenPort3.getInputStream());
dataIncoming(data, "stopa");
data.close();
}
};
thread.start();
thread2.start();
thread3.start();
connectButton.setText("Disconnect");
} else {
// disconnect from the serial port
chosenPort.closePort();
chosenPort2.closePort();
chosenPort3.closePort();
portList.setEnabled(true);
portList2.setEnabled(true);
portList3.setEnabled(true);
connectButton.setText("Connect");
}
}
}
});
in "dataIncoming" method there is bunch of not important things (like picking, which sound should be played etc.). The important part is in the while loop. In the "while" im gathering next lines of data from sensor. When one of the values is higher than something it should play a sound but only if some time has passed and the sensor has moved a certain way. (when the drumstick is going down the "imuValues[4]" is increasing, when its going up its decreasing, so when its past 160 it means that the player has taken the drumstick up so its ready for the next hit)
while(data.hasNextLine()) {
try{
imuValues = data.nextLine().split(",");
if(Double.parseDouble(imuValues[4])>200 && flagaThreada) {
flagaThreada = false;
playSound(sound1);
}
if(Double.parseDouble(imuValues[4])<160 && System.currentTimeMillis()-startTime>100) {
flagaThreada = true;
startTime=System.currentTimeMillis();
}
}catch(Exception e){
System.out.println("ERROR");
}
}
and finally the method for playing the sound is :
public static synchronized void playSound(String sound) {
try {
String url = "/sounds/"+sound+".wav";
Clip clip = AudioSystem.getClip();
AudioInputStream inputStream = AudioSystem.getAudioInputStream(
Main.class.getResourceAsStream(url));
clip.open(inputStream);
clip.start();
} catch (Exception e) {
System.err.println("ERROR IN OPENING");
}
}
Is my computer to slow to compute and play sounds for 3 sensors at the same time? Or is there a way to create those Threads in a better fashion?
I wrote a version of Clip, called AudioCue, which allows multi-threading on the play commands. It is open source, BSD license (free), consists of three files which you can cut and paste into your program. There is also an API link for it. More info at AudioCue. The site has code examples as well as link to API and source code. There is also some dialogue about its use at Java-gaming.org, under the "Sound" topic thread.
The basic principle behind the code is to make the audio data available in a float array, and send multiple, independent "cursors" through it (one per play command). The setup lets us also do real time volume fading, pitch changes and panning. The audio is output via a SourceDataLine which you can configure (set thread priority, buffer size).
I'm maybe a week or two away from sharing a more advanced version that allows all AudioCues to be mixed through a single output line. This version has five classes/interfaces instead of three, and is being set up for release on github. I'm also hoping to get a donate button and the like set up for this next iteration. The next version might be more useful for Arduino in that I believe you are only allowed up to 8 audio outputs on that system.
Other than that, the steps you have taken (separating the open from the play, using setFramePosition for restarts) are correct. I can't think of anything else to add to help out besides writing your own mixer/cue player (as I have done and am willing to share).

Assigning Sound to Image

I am new to Android programming. Haven't even written a single app, so answers that are extremely detailed are appreciated. So, here it goes: I want to assign some .mp3 sound files to an area of the screen.
For eg, if I click on the picture of a cat, meow.mp3 should play. This is applicable to two different activities. Also, I am looking for a way to mute sounds from both activities from a single source, ie, the MainActivity. I tried figuring out some codes, but they weren't detailed enough for my understanding.
Any help is appreciated, thanks!
Well, this is what I did to display an image(playButtonUp) and open up another View. I need to add a .mp3 file so that the action is signified by a sound, like in the case of clicking of a button.
case MotionEvent.ACTION_DOWN:
if ((X > (screenW-playButtonUp.getWidth())/2 &&
X < ((screenW-playButtonUp.getWidth())/2) +
playButtonUp.getWidth()) &&
Y > (int)(screenH*0.7) &&
Y < (int)(screenH*0.7) +
playButtonUp.getHeight()) {
playButtonPressed = true;
break;
}
Lets assume that you have ImageView in your layout. You can get it from source code by typing:
// imageView1 is id referring to your ImageViews xml code
ImageView myImageView = (ImageView) findViewById(R.id.imageView1);
Then you can add listener to it which fires when you click the image:
myImageView.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v) {
// Add the MediaPlayer code here
// ...
}
});
Now you can add some functionality in that event. First i would add a global variable so you can start and stop the media when ever you want:
private MediaPlayer mediaPlayer;
Lets add some code to the onClick event:
// First check if mediaPlayer has been created
if( mediaPlayer != null ) {
// Then check if the mediaPlayer is playing, if it is,
// we want it to stop because if we don't stop it,
// there will be multiple sounds playing at the same time
if( mediaPlayer.isPlaying() )
mediaPlayer.stop();
}
// This creates the player and sets my slap.mp3 to be played
// => Add your mp3's in YourProject/res/raw/
mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.slap);
mediaPlayer.start();
Now you have a picture that creates a sound!
You wanted to mute sounds, I assume that you wanted to stop them playing? Use mediaPlayer.stop(); to stop playback but make sure that you have checks for mediaPlayer not null and mediaPlayer.isPlaying() before calling it, otherwise you would get an exception. I hope this will help you somehow!

Face detection not working for Front Camera

So basically, i have this code,
if(mCamera.getParameters().getMaxNumDetectedFaces()==0)
{
System.out.println("Face detection not avaliable");
}
else
{
System.out.println("Max faces: " + Integer.toString(mCamera.getParameters().getMaxNumDetectedFaces()));
}
mCamera.setFaceDetectionListener(new FaceDetectionListener() {
#Override
public void onFaceDetection(Face[] faces, Camera camera) {
// TODO Auto-generated method stub
System.out.println("Face detection callback called." + Integer.toString(faces.length));
}
});
After calling mCamera.startFaceDetection();, the callback is called, everything works as normal. However, if I change cameras, the same code results in the callback never being called. The getMaxNumDetectedFaces, returns 35 for both cameras, so I assume its supported on the front camera. I can change the camera back and forth, calling this code each time, and it will work for the back camera but not the front one.
Is there anything else I might be doing wrong?
Is it possible that the quality of the camera that's not working (the front one, right?) Isn't accurate enough for the face detection to work? The camera's image may be too noisy for the face detector to work. There are lot of other variables that could be hindering this.
Also doing a search for front camera, it looks like the front camera's points may be mirrored. This is described in: http://developer.android.com/reference/android/hardware/Camera.Face.html
I hope this helps.
Is there a way to check if the camera is being read? Java has always had some issues in registering web cams etc.... Perhaps try to make sure you can see images with the webcam.
Btw, if you want any further help, we will need to know more about the code. library etc....
This code will return the id of your Front facing camera, for others you can change camera.CameraInfo:
private int findFrontFacingCamera() {
int cameraId = -1;
// Search for the front facing camera
int numberOfCameras = Camera.getNumberOfCameras();
for (int i = 0; i < numberOfCameras; i++) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(i, info);
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
Log.d("FaceDetector", "Camera found");
cameraId = i;
break;
}
}
return cameraId;
}
I had the code which worked on my Gallaxy tablet but it wouldnt call the take foto and as a result wouldnt call face detection in other devices, so after searching for a while I found this solution which worked. I added the following code in the class where takePicture is called :
camera.startPreview();
You can use Webcame for capturing image from webcam. it automatically detects webcam so no need to extra configuration for webcam. it also support more than one webcam at a time.

Categories

Resources