FM: update fm app to use device loopback
Update fm app to use device loopback for
playback on headset, headphone or speaker.
Change-Id: I44642858cc9a42fad0fad2ad3f8487aaa624d35e
diff --git a/fmapp2/src/com/caf/fmradio/FMRadioService.java b/fmapp2/src/com/caf/fmradio/FMRadioService.java
index 35e7e24..56d9aa6 100644
--- a/fmapp2/src/com/caf/fmradio/FMRadioService.java
+++ b/fmapp2/src/com/caf/fmradio/FMRadioService.java
@@ -207,6 +207,7 @@
private boolean mIsRecordSink = false;
private static final int AUDIO_FRAMES_COUNT_TO_IGNORE = 3;
private Object mRecordSinkLock = new Object();
+ private boolean mIsFMDeviceLoopbackActive = false;
public FMRadioService() {
}
@@ -368,7 +369,7 @@
private synchronized void stopRecordSink() {
Log.d(LOGTAG, "stopRecordSink");
- mRecordSinkLock = false;
+ mIsRecordSink = false;
synchronized (mRecordSinkLock) {
mRecordSinkLock.notify();
}
@@ -464,6 +465,57 @@
}
}
+ private boolean configureFMDeviceLoopback(boolean enable) {
+ boolean success = true;
+ int status = AudioSystem.SUCCESS;
+
+ Log.d(LOGTAG, "configureFMDeviceLoopback enable:" + enable +
+ " DeviceLoopbackActive:" + mIsFMDeviceLoopbackActive);
+ if (enable && mIsFMDeviceLoopbackActive == false) {
+ status = AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM,
+ AudioSystem.DEVICE_STATE_AVAILABLE, "", "");
+ if (status != AudioSystem.SUCCESS) {
+ success = false;
+ Log.e(LOGTAG, "configureFMDeviceLoopback failed! status:" + status);
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE, "", "");
+ } else {
+ mIsFMDeviceLoopbackActive = true;
+ }
+ } else if (!enable && mIsFMDeviceLoopbackActive == true) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE, "", "");
+ mIsFMDeviceLoopbackActive = false;
+ }
+
+ return success;
+ }
+
+ private synchronized void configureAudioDataPath(boolean enable) {
+ Log.d(LOGTAG, "configureAudioDataPath:" + enable +
+ " mA2dpConnected:" + mA2dpConnected +
+ " isRecordSinking" + isRecordSinking() +
+ " mIsFMDeviceLoopbackActive:" + mIsFMDeviceLoopbackActive);
+ if (enable) {
+ // stop existing playback path before starting new one
+ if (mA2dpConnected && mIsFMDeviceLoopbackActive) {
+ // on BT but earlier device loopback is active
+ configureFMDeviceLoopback(false);
+ } else if (!mA2dpConnected && !mIsFMDeviceLoopbackActive) {
+ // not on BT and device loop is also not active
+ exitRecordSinkThread();
+ configureFMDeviceLoopback(true);
+ }
+
+ // start app thread if none of the path started yet
+ if (!mIsFMDeviceLoopbackActive && !isRecordSinking())
+ startRecordSink();
+ } else {
+ configureFMDeviceLoopback(false);
+ exitRecordSinkThread();
+ }
+ }
+
/**
* Registers an intent to listen for ACTION_MEDIA_UNMOUNTED notifications.
* The intent will call closeExternalStorageFiles() if the external media
@@ -570,6 +622,7 @@
mA2dpDisconnected = false;
mA2dpConnected = true;
}
+ configureAudioDataPath(true);
} else if (action.equals("HDMI_CONNECTED")) {
//FM should be off when HDMI is connected.
fmOff();
@@ -592,6 +645,9 @@
}
};
+ AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+ mA2dpConnected = am.isBluetoothA2dpOn();
+ mA2dpDisconnected = !mA2dpConnected;
IntentFilter iFilter = new IntentFilter();
iFilter.addAction(Intent.ACTION_HEADSET_PLUG);
iFilter.addAction(mA2dpDeviceState.getActionSinkStateChangedString());
@@ -1058,14 +1114,13 @@
AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE);
}
}
- startRecordSink();
mPlaybackInProgress = true;
+ configureAudioDataPath(true);
}
private void stopFM(){
Log.d(LOGTAG, "In stopFM");
- stopRecordSink();
- exitRecordSinkThread();
+ configureAudioDataPath(false);
mPlaybackInProgress = false;
}