Detect when sound is playing through earpiece speaker - android

Background
I'm developing an app that monitors the proximity sensor. However, I don't want to monitor the sensor while the user is listening to something through the phone ear speaker. This is because the user will probably have his/her head against the handset to listen, which in turn triggers the proximity sensor, and I'm not trying to detect head proximity.
Question
How can I detect when sound is and isn't playing through the handset ear speaker? Callbacks are preferable, of course, but I'm willing to poll if it's the only way.

You can approximate this by regularly polling and making the following checks:
Check if the audio system is not in normal mode.
Check if the audio is being routed to the earpiece.
I tested this in Android 4.3, and it seemed to work fine with the system phone app, Viber and Skype. However, it doesn't seem to detect music or non-telephony sounds played through the earpiece. I don't think this is much of a problem, because the earpiece generally seems to only be used for telephony anyway.
Example
public class EarpieceSpeakerState {
private AudioManager audioManager;
public EarpieceSpeakerState(AudioManager audioManager) {
this.audioManager = audioManager;
}
public boolean usingEarpieceSpeaker() {
return playingSound()
&& routingToEarpiece();
}
private boolean playingSound() {
return audioManager.getMode() != AudioManager.MODE_NORMAL;
}
private boolean routingToEarpiece() {
return !(
audioManager.isSpeakerphoneOn()
|| audioManager.isBluetoothScoOn()
|| audioManager.isBluetoothA2dpOn()
|| audioManager.isWiredHeadsetOn()
);
}
}

I don't know if it is the right solution but i think you should at least give it a try, check out this link.
Teorically you will not receive focus if somebody else is using the speaker of your phone.

base solution, you can extend it link
private fun initOnAudioFocusChangeListener() {
val afChangeListener: AudioManager.OnAudioFocusChangeListener =
AudioManager.OnAudioFocusChangeListener { focusChange ->
when (focusChange) {
AudioManager.AUDIOFOCUS_GAIN -> {
viewModel.isAppLostAudioFocusLiveData.value = false
}
else -> {
viewModel.isAppLostAudioFocusLiveData.value = true
}
}
}
val audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
audioManager.requestAudioFocus(
AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
.setOnAudioFocusChangeListener(afChangeListener).build()
)
} else {
audioManager.requestAudioFocus(
afChangeListener,
AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN
)
}
}

Related

Pause all the other media players and audios while Application media player starts playing

I am working on a push to talk App, where the receiver will get a live-streamed audio message from a sender if he is connected to the internet. Now everything's working all fine except one issue that is: whenever any other applications like google music or youtube are playing audios, that time if I am getting an audio notification or message through the application, both the audios are playing in a parallel manner. I am using VoiceLayer library for the app and to play a message audio, they use VoiceLayerMessagePlayer. Is there any way I can pause the other media players when I am getting a notification or voice message in my Application? I looked through the internet and found out that OnAudioFocusChangeListener might be helpful but didn't get a proper example regarding its implementation. Please do let me know if you need any more information. Thanks in advance.
You should use AudioManager service to receive notification whether you receive/lost audio focus (Managing audio focus). I've done similar thing in a project where when my app starts playing, Google Play pause and vice versa. Use the following code where you are controlling your media playback like (activity or service)
Stop MediaPlayer when an other app play music
Please check below code it's working fine.
AudioManager am = null;
// Request focus for music stream and pass
AudioManager.OnAudioFocusChangeListener
// implementation reference
int result = am.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
if(result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED)
{
// Play
}
// Implements AudioManager.OnAudioFocusChangeListener
#Override
public void onAudioFocusChange(int focusChange)
{
if(focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT)
{
// Pause
}
else if(focusChange == AudioManager.AUDIOFOCUS_GAIN)
{
// Resume
}
else if(focusChange == AudioManager.AUDIOFOCUS_LOSS)
{
// Stop or pause depending on your need
}
}
Hope this helps you and solved your problem.
please try this code. it work with me
val audioManager = requireActivity().getSystemService(Context.AUDIO_SERVICE) as AudioManager
val focusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN).run {
setAudioAttributes(AudioAttributes.Builder().run {
setUsage(AudioAttributes.USAGE_GAME)
setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
setOnAudioFocusChangeListener({ }, object : Handler() {})
build()
})
setAcceptsDelayedFocusGain(true)
build()
}
audioManager.requestAudioFocus(focusRequest)

Don' t duck audio volume if notification is inaudible?

The standard way of handling a loss of AudioFocus that can be "ducked" is as follows:
OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
// Lower the volume
}
}
};
However, if this is implemented as shown you will lower the volume even if the notification is inaudible, such as when DnD mode is turned on in Android 5.0+. There are apparently several different methods for determining if DnD is active: getAutomaticZenRule() (wtf?), getCurrentInterruptionFilter(), and getNotificationPolicy() (which requires special access). None of which are available in < API 23.
Is there a succinct way of telling if the stream requesting AudioFocus that is duck-able is actually audible without muddling through all of the above? It seems Google Play Music handles this case fine.
OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
if (!(audioManager.getStreamVolume(AudioManager.STREAM_NOTIFICATION) == 0))
// Lower the volume
}
}
};
does the job.

Cannot stop AudioTrack on Android 5

I cannot stop playback of an AudioTrack on a Nexus 4 running Android 5.0.1. Am I doing something wrong?
The code is very simple (it's actually just a test app) and it works perfectly on devices running 2.3.6 and 4.4. Here's the relevant portion:
mPlugReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(Intent.ACTION_HEADSET_PLUG.equals(intent.getAction())) {
boolean plugged = intent.getIntExtra("state", 0) == 1;
if(plugged) {
log.debug("audio device plugged");
boolean mic = intent.getIntExtra("microphone", 0) == 1;
if(mic) {
log.debug("microphone detected");
mPowerTone.play();
}
}
}
else if(AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
log.debug("stopping power tone");
mPowerTone.pause();
mPowerTone.flush();
mPowerTone.stop();
}
}
};
On 5.0.1, it logs "stopping power tone" but the track continues to play! It even continues to play after I exit the app. Sometimes it stops after a few seconds, and sometimes I have to force close the app.
I tried both with and without the calls to pause() and flush(), to no avail. It works without those calls on the older devices.
This unanswered question led me to a solution. If you call AudioTrack#stop() on Lollipop, even in conjunction with the methods that actually work, playback will not stop! You must use a condition like this:
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mPowerTone.pause();
mPowerTone.flush();
}
else {
mPowerTone.stop();
}
Keep up the good work, Google.

why is abandonAudioFocus not working in Android Music app

Im using this code to get AudioFocus and it works ok with
Android Music app ( the one preinstalled )
int result = audioManager.requestAudioFocus(meService, AudioManager.STREAM_MUSIC,AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
However when i release it with this code
audioManager.abandonAudioFocus(meService);
The Android Music app ( the one preinstalled ) does not continue playing.
if i use the AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK it works
but Android Music app is not lowering the volume enough.
Any ides why Android Music app is not resuming playback?
im using api8 and using the onAudioFocusChange
You should release it in MediaPlay.onCompleteListener(){}
After trying 4 players non of them are ducking. I might be doing something wrong and would like to see that. I answer my own question that we have to live with this.
This way works fine for me.
public class HomeActivity extends Activity implements AudioManager.OnAudioFocusChangeListener {
// Other stuff
#Override
public void onAudioFocusChange(int focusChange) {
if (focusChange == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
Log.i("HomeActivity", "Audio focus granted.");
}else if (focusChange == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
Log.i("HomeActivity", "Audio focus failed.");
}
}
}
Request AudioFocus:
private void requestAudioFocus(){
AudioManager am = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
// Request audio focus for playback
am.requestAudioFocus(this,
// Use the music stream.
AudioManager.STREAM_MUSIC,
// Request permanent focus.
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
}
Abandon AudioFocus:
private void abandonAudioFocus(){
AudioManager am = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
am.abandonAudioFocus(this);
}
Hope this would help you.

Is ToneGenerator sound smooth?

Does anyone have the same problem?
On Android's Phone app, whenever a number is pressed, the tone is always smooth.
But, when I used very similar code as the Phone app, the tone I get regularly isn't smooth...there are gaps. Is there a way to resolve this?
Some of my theories are that the emulator causes these breaks in sound as there are time lags in processing. The Phone app on the emulator is also more "compiled"/native than my code. Etc. Don't know what is the reason for these tones not being continuous.
Here's the code (literally the same as Phone app):
...
playTone(ToneGenerator.TONE_DTMF_1,150);
...
void playTone(int tone) {
// if local tone playback is disabled, just return.
if (!mDTMFToneEnabled) {
return;
}
// Also do nothing if the phone is in silent mode.
// We need to re-check the ringer mode for *every* playTone()
// call, rather than keeping a local flag that's updated in
// onResume(), since it's possible to toggle silent mode without
// leaving the current activity (via the ENDCALL-longpress menu.)
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
int ringerMode = audioManager.getRingerMode();
if ((ringerMode == AudioManager.RINGER_MODE_SILENT)
|| (ringerMode == AudioManager.RINGER_MODE_VIBRATE)) {
return;
}
synchronized (mToneGeneratorLock) {
if (mToneGenerator == null) {
Log.w("test", "playTone: mToneGenerator == null, tone: " + tone);
return;
}
// Start the new tone (will stop any playing tone)
mToneGenerator.startTone(tone, TONE_LENGTH_MS);

Categories

Resources