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.
Related
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.
Earlier to Android lollipop detected the outgoing call is answered or not by checking the call duration if the call not answered means the call duration remains 0 Sec. But in Android Lollipop the call duration gets started before call get answered. Is there any way to detect the outgoing call is answered or not in Android lollipop?
You can override onCallStateChanged listener using Telephony Manager.
#Override
public void onCallStateChanged(int state, String number) {
switch (state) {
case TelephonyManager.CALL_STATE_OFFHOOK:
// call established.
break;
}
I have a working solution to detect when an outgoing call is answered! The solution is a little hacky but it works, at least in Samsung S6 with Android 6.0.1. I've also tested on Nexus 5x with Android 7.1.1 but it didn't work.
The way i do it is using Audio Manager to change the audiomode to MODE_IN_COMMUNICATION when i get the state of the outgoing call changes to EXTRA_STATE_OFFHOOK. After changing the audiomode to MODE_IN_COMMUNICATION, i start a thread that monitors the audiomode until the system changes it back to MODE_IN_CALL when the call is answered.
Here's the code snippet:
final AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
if (outgoingCallAnswerWatchThread != null){
outgoingCallAnswerWatchThread.interrupt();
outgoingCallAnswerWatchThread = null;
}
outgoingCallAnswerWatchThread = new Thread(new Runnable() {
#Override
public void run() {
// by changing the audio mode to MODE_IN_COMMUNICATION
// we can then detect when the call is answered
// because android changes the audio mode back to MODE_IN_CALL
// when that happens
audioManager.setMode(MODE_IN_COMMUNICATION);
while(callState == RINGING && !Thread.interrupted()){
try {
Thread.sleep(CALL_WATCHER_SLEEP_TIME_MS);
} catch (InterruptedException e) {
Log.d(TAG, "Thread interrupted!");
break;
}
int audioMode = audioManager.getMode();
Log.d(TAG, "audioMode:" + audioMode);
if (audioMode == MODE_IN_CALL){
//the call is connected
Log.i(TAG, "OUTGOING CALL answered!");
}
}
}
});
outgoingCallAnswerWatchThread.start();
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
)
}
}
I am using mediaplayer class to play .aac music files which is under raw resource. All the device performs well and start playing of each .aac file on user interaction but Nexus 5 with having Android 4.4.3 creating problem , It plays music after 1 or 2 sec delay.
Also a same code working fine with Android Kitkat 4.4.2 (MOTO G Android Device)
Below is my code
Intent i = new Intent(MusicClass.this, PlayerService.class);
i.putExtra("isplaying", "stop");
startService(i);
PlayerService class
public class PlayerService extends Service implements OnCompletionListener
private IMyRemoteService.Stub myRemoteServiceStub = new IMyRemoteService.Stub() {
#Override
public boolean isMusicPlaying() throws RemoteException {
if (mPlayer != null) {
if (mPlayer.isPlaying()) {
return true;
} else {
return false;
}
} else {
return false;
}
}
I have referred below links but not luck Link 1 & Link 2
So waht can be the solution for Android
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);