AudioManager is introducing delay in the setMode(MODE_IN_COMMUNICATION) - java

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

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.

how to display the "Game over" image in android for a fixed amount of time and restart the game when user taps the screen after a specified interval?

I made clone of ""Flappy bird" game by watching video tutorials.i programmed it so that when the bird falls or collides with the tubes a game over message appears on the screen and the game restarts when the player taps on the screen.
The problem is that when the user fails to tap the bird in time and it collides with the tube,the game over screen appears immediately and the user happens to tap on the game over screen which results in restarting of the game.
This makes the user unable to see the score.I have already tried using Thread.sleep().Following is the code
(gameState == 2)
{
batch.draw(gameOver,Gdx.graphics.getWidth()/2-gameOver.getWidth()/2,Gdx.graphics.getHeight()/2-gameOver.getHeight()/2);
try
{
Thread.sleep(2000);
}
catch(InterruptedException ex)
{
Thread.currentThread().interrupt();
}
if (Gdx.input.justTouched()) {
gameState = 1;
startGame();
score =0;
scoringTube = 0;
velocity = 0;
}
}
With this code the problem is that even the gameover image is being delayed and the previous problem is still occuring but now with a delay.I basically need a way so that justTouched method becomes inactive for a while when the game over screen is there.Please help.
I really wouldn't recommend using Thread.sleep; instead, you could try to use a boolean that is changed once the game ended, and prevent the method from executing in that case. Combine that with e.g a Timer that resets it after a fixed delay, and you should have the solution to your problem.
Example Usage for the timer:
new java.util.Timer().schedule(
new java.util.TimerTask() {
#Override
public void run() {
//execute code here (change boolean state)
}
},
yourDelayHere
);

Music not playing properly on touch-LibGdx

I have array of coins spread in the screen.I want to add sound when I touch a coin.
private Music coinSound;
in show():
coinSound=assetManager.get(Assets.collectCoin);
calling coinSound.play() here:
if (MyInputProcessor.isTouchDown) {
touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
game.camera.unproject(touchPos);
for (int i = 0; i < coins.length; i++) {
Rectangle textureBounds = new Rectangle(coins[i].getX(), coins[i].getY(), coins[i].getWidth(),coins[i].getHeight());
if (textureBounds.contains(touchPos.x, touchPos.y) && !coins[i].isBreakBool()) {
coinSound.play();
coins[i].setTapBool(true);
}
}
MyInputProcessor.isTouchDown = false;
}
Now sound is playing but not for all the array elements.for touch on one coin it is playing correctly every time.What do I need to change for making it play for each coins on touch?
Use Sound instead of Music.
Sound effects are small audio samples, usually no longer than a few seconds, that are played back on specific game events such as a character jumping or shooting a gun.
AssetManager manager = new AssetManager();
manager.load("data/mysound.mp3", Sound.class);
manager.finishLoading();
Get sound from AssetManager
Sound sound = manager.get("data/mysound.mp3", Sound.class);
sound.play();
Music instances are heavy, you should usually not have more than one or two at most loaded.

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.

Media Player how to recover when create fails?

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.

Categories

Resources