Added bluetooth audio route for Android 3.0+
This commit is contained in:
parent
d414e1f533
commit
a1f4edb281
7 changed files with 162 additions and 7 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -3,6 +3,7 @@ obj
|
|||
gen
|
||||
bin
|
||||
doc
|
||||
default.properties
|
||||
local.properties
|
||||
project.properties
|
||||
tests/*$py.class
|
||||
|
|
|
@ -31,6 +31,9 @@
|
|||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<!-- Needed to use our own Contact editor -->
|
||||
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
|
||||
<!-- Needed to route the audio to the bluetooth headset if available -->
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
|
||||
|
||||
<supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" android:anyDensity="true"/>
|
||||
|
||||
|
@ -104,6 +107,14 @@
|
|||
<intent-filter><action android:name="android.net.conn.CONNECTIVITY_CHANGE"></action></intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name="org.linphone.BluetoothManager">
|
||||
<intent-filter>
|
||||
<action android:name="android.bluetooth.device.action.ACL_CONNECTED"/>
|
||||
<action android:name="android.bluetooth.device.action.ACL_DISCONNECTED"/>
|
||||
<action android:name="android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name="org.linphone.BootReceiver">
|
||||
<intent-filter><action android:name="android.intent.action.BOOT_COMPLETED"></action></intent-filter>
|
||||
</receiver>
|
||||
|
|
|
@ -55,6 +55,8 @@
|
|||
|
||||
<bool name="hash_images_as_name_before_upload">true</bool>
|
||||
|
||||
<bool name="route_audio_to_bluetooth_if_available">true</bool>
|
||||
|
||||
<bool name="disable_every_log">false</bool>
|
||||
<bool name="disable_all_security_features_for_markets">false</bool> <!-- Disable TLS/SRTP/ZRTP -->
|
||||
<bool name="disable_all_patented_codecs_for_markets">false</bool> <!-- Disable MPEG4/H264 -->
|
||||
|
|
40
src/org/linphone/BluetoothManager.java
Normal file
40
src/org/linphone/BluetoothManager.java
Normal file
|
@ -0,0 +1,40 @@
|
|||
package org.linphone;
|
||||
|
||||
import org.linphone.mediastream.Log;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
public class BluetoothManager extends BroadcastReceiver {
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
boolean routeToBT = context.getResources().getBoolean(R.bool.route_audio_to_bluetooth_if_available);
|
||||
if (!routeToBT)
|
||||
return;
|
||||
|
||||
String action = intent.getAction();
|
||||
LinphoneManager lm = LinphoneManager.getInstance();
|
||||
|
||||
if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
|
||||
Log.e("Bluetooth Received Event" + " ACTION_ACL_DISCONNECTED" );
|
||||
|
||||
if (lm != null) {
|
||||
lm.uninitBluetooth();
|
||||
lm.routeAudioToReceiver();
|
||||
}
|
||||
} else if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
|
||||
Log.e("Bluetooth Received Event" + " ACTION_ACL_CONNECTED" );
|
||||
|
||||
if (lm != null) {
|
||||
lm.routeToBluetoothIfAvailable();
|
||||
}
|
||||
} else if (BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
|
||||
Log.e("Bluetooth state changed!");
|
||||
if (lm != null) {
|
||||
lm.startBluetooth();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -166,6 +166,10 @@ public class InCallActivity extends FragmentActivity implements
|
|||
callFragment.setArguments(getIntent().getExtras());
|
||||
getSupportFragmentManager().beginTransaction().add(R.id.fragmentContainer, callFragment).commitAllowingStateLoss();
|
||||
}
|
||||
|
||||
boolean routeToBT = getResources().getBoolean(R.bool.route_audio_to_bluetooth_if_available);
|
||||
if (routeToBT && LinphoneManager.isInstanciated() && !isSpeakerEnabled)
|
||||
LinphoneManager.getInstance().routeToBluetoothIfAvailable();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -475,11 +479,15 @@ public class InCallActivity extends FragmentActivity implements
|
|||
if (isSpeakerEnabled) {
|
||||
LinphoneManager.getInstance().routeAudioToSpeaker();
|
||||
speaker.setBackgroundResource(R.drawable.speaker_on);
|
||||
LinphoneManager.getLc().enableSpeaker(isSpeakerEnabled);
|
||||
} else {
|
||||
LinphoneManager.getInstance().routeAudioToReceiver();
|
||||
speaker.setBackgroundResource(R.drawable.speaker_off);
|
||||
|
||||
boolean routeToBT = getResources().getBoolean(R.bool.route_audio_to_bluetooth_if_available);
|
||||
if (!routeToBT)
|
||||
LinphoneManager.getLc().enableSpeaker(isSpeakerEnabled);
|
||||
}
|
||||
LinphoneManager.getLc().enableSpeaker(isSpeakerEnabled);
|
||||
}
|
||||
|
||||
private void pauseOrResumeCall() {
|
||||
|
@ -969,8 +977,13 @@ public class InCallActivity extends FragmentActivity implements
|
|||
switchVideo(isVideoEnabled, false);
|
||||
}
|
||||
|
||||
// The following should not be needed except some devices need it (e.g. Galaxy S).
|
||||
LinphoneManager.getLc().enableSpeaker(isSpeakerEnabled);
|
||||
boolean routeToBT = getResources().getBoolean(R.bool.route_audio_to_bluetooth_if_available);
|
||||
if (routeToBT && LinphoneManager.isInstanciated() && !isSpeakerEnabled) {
|
||||
LinphoneManager.getInstance().routeToBluetoothIfAvailable();
|
||||
} else {
|
||||
// The following should not be needed except some devices need it (e.g. Galaxy S).
|
||||
LinphoneManager.getLc().enableSpeaker(isSpeakerEnabled);
|
||||
}
|
||||
|
||||
isMicMuted = LinphoneManager.getLc().isMicMuted();
|
||||
enableAndRefreshInCallActions();
|
||||
|
|
|
@ -76,7 +76,12 @@ import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration.
|
|||
import org.linphone.mediastream.video.capture.hwconf.Hacks;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothHeadset;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
|
@ -141,6 +146,10 @@ public final class LinphoneManager implements LinphoneCoreListener {
|
|||
private static boolean sExited;
|
||||
|
||||
private WakeLock mIncallWakeLock;
|
||||
|
||||
private BluetoothAdapter mBluetoothAdapter;
|
||||
private BluetoothHeadset mBluetoothHeadset;
|
||||
private BluetoothProfile.ServiceListener mProfileListener;
|
||||
|
||||
private static List<LinphoneSimpleListener> simpleListeners = new ArrayList<LinphoneSimpleListener>();
|
||||
public static void addListener(LinphoneSimpleListener listener) {
|
||||
|
@ -190,9 +199,23 @@ public final class LinphoneManager implements LinphoneCoreListener {
|
|||
private BroadcastReceiver mKeepAliveReceiver = new KeepAliveReceiver();
|
||||
|
||||
private void routeAudioToSpeakerHelper(boolean speakerOn) {
|
||||
mLc.enableSpeaker(speakerOn);
|
||||
boolean routeToBluetoothEnabled = false;
|
||||
if (!speakerOn) {
|
||||
boolean routeToBT = mServiceContext.getResources().getBoolean(R.bool.route_audio_to_bluetooth_if_available);
|
||||
if (!routeToBT || (routeToBT && !routeToBluetoothIfAvailable())) {
|
||||
mLc.enableSpeaker(false);
|
||||
uninitBluetooth();
|
||||
} else {
|
||||
Log.d("Routing audio to bluetooth headset");
|
||||
routeToBluetoothEnabled = true;
|
||||
}
|
||||
} else {
|
||||
mLc.enableSpeaker(true);
|
||||
uninitBluetooth();
|
||||
}
|
||||
|
||||
for (LinphoneOnAudioChangedListener listener : getSimpleListeners(LinphoneOnAudioChangedListener.class)) {
|
||||
listener.onAudioStateChanged(speakerOn ? AudioState.SPEAKER : AudioState.EARPIECE);
|
||||
listener.onAudioStateChanged(speakerOn ? AudioState.SPEAKER : (routeToBluetoothEnabled ? AudioState.BLUETOOTH : AudioState.EARPIECE));
|
||||
}
|
||||
}
|
||||
public void routeAudioToSpeaker() {
|
||||
|
@ -216,6 +239,66 @@ public final class LinphoneManager implements LinphoneCoreListener {
|
|||
public void routeAudioToReceiver() {
|
||||
routeAudioToSpeakerHelper(false);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
public void startBluetooth() {
|
||||
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30) && mBluetoothAdapter.isEnabled()) {
|
||||
mProfileListener = new BluetoothProfile.ServiceListener() {
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
public void onServiceConnected(int profile, BluetoothProfile proxy) {
|
||||
if (profile == BluetoothProfile.HEADSET) {
|
||||
mBluetoothHeadset = (BluetoothHeadset) proxy;
|
||||
Log.d("Bluetooth headset connected");
|
||||
routeToBluetoothIfAvailable();
|
||||
}
|
||||
}
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
public void onServiceDisconnected(int profile) {
|
||||
if (profile == BluetoothProfile.HEADSET) {
|
||||
mBluetoothHeadset = null;
|
||||
Log.d("Bluetooth headset disconnected");
|
||||
routeAudioToReceiver();
|
||||
}
|
||||
}
|
||||
};
|
||||
mBluetoothAdapter.getProfileProxy(mServiceContext, mProfileListener, BluetoothProfile.HEADSET);
|
||||
} else {
|
||||
routeAudioToReceiver();
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
public boolean routeToBluetoothIfAvailable() {
|
||||
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30) && mBluetoothAdapter.isEnabled() && mAudioManager.isBluetoothScoAvailableOffCall()) {
|
||||
mAudioManager.setBluetoothScoOn(true);
|
||||
mAudioManager.startBluetoothSco();
|
||||
|
||||
boolean connected = false;
|
||||
if (mBluetoothHeadset != null) {
|
||||
List<BluetoothDevice> devices = mBluetoothHeadset.getConnectedDevices();
|
||||
for (final BluetoothDevice dev : devices) {
|
||||
connected |= mBluetoothHeadset.getConnectionState(dev) == BluetoothHeadset.STATE_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
if (!connected) {
|
||||
Log.d("No bluetooth device available");
|
||||
uninitBluetooth();
|
||||
}
|
||||
return connected;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
public void uninitBluetooth() {
|
||||
if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30) && mAudioManager != null) {
|
||||
mAudioManager.stopBluetoothSco();
|
||||
mAudioManager.setBluetoothScoOn(false);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized static final LinphoneManager createAndStart(
|
||||
Context c, LinphoneServiceListener listener) {
|
||||
|
@ -463,6 +546,11 @@ public final class LinphoneManager implements LinphoneCoreListener {
|
|||
IntentFilter lFilter = new IntentFilter(Intent.ACTION_SCREEN_ON);
|
||||
lFilter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
mServiceContext.registerReceiver(mKeepAliveReceiver, lFilter);
|
||||
|
||||
boolean routeToBT = mServiceContext.getResources().getBoolean(R.bool.route_audio_to_bluetooth_if_available);
|
||||
if (routeToBT) {
|
||||
startBluetooth();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.e(e, "Cannot start linphone");
|
||||
|
@ -474,7 +562,7 @@ public final class LinphoneManager implements LinphoneCoreListener {
|
|||
copyIfNotExist(R.raw.ringback,mRingbackSoundFile);
|
||||
copyIfNotExist(R.raw.toy_mono,mPauseSoundFile);
|
||||
copyFromPackage(R.raw.linphonerc, new File(mLinphoneInitialConfigFile).getName());
|
||||
copyIfNotExist(R.raw.lpconfig, new File(mLPConfigXsd).getName());
|
||||
// copyIfNotExist(R.raw.lpconfig, new File(mLPConfigXsd).getName());
|
||||
copyIfNotExist(R.raw.rootca, new File(mLinphoneRootCaFile).getName());
|
||||
}
|
||||
private void copyIfNotExist(int ressourceId,String target) throws IOException {
|
||||
|
|
|
@ -56,7 +56,7 @@ public interface LinphoneSimpleListener {
|
|||
}
|
||||
|
||||
public static interface LinphoneOnAudioChangedListener extends LinphoneSimpleListener {
|
||||
public enum AudioState {EARPIECE, SPEAKER}
|
||||
public enum AudioState {EARPIECE, SPEAKER, BLUETOOTH}
|
||||
void onAudioStateChanged(AudioState state);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue