Using SDK audio helper instead of app's
This commit is contained in:
parent
dfb499d073
commit
f55a029192
10 changed files with 68 additions and 681 deletions
|
@ -187,6 +187,7 @@ dependencies {
|
|||
if (firebaseEnabled()) {
|
||||
implementation 'com.google.firebase:firebase-messaging:19.0.1'
|
||||
}
|
||||
implementation 'androidx.media:media:1.2.0'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.0.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'com.google.android:flexbox:1.1.0'
|
||||
|
|
|
@ -185,7 +185,6 @@ public class LinphoneManager implements SensorEventListener {
|
|||
if (mCore != null) {
|
||||
if (mCore.getCallsNb() > 0) {
|
||||
mCallManager.acceptCall(call);
|
||||
mAudioManager.routeAudioToEarPiece();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,9 +20,7 @@
|
|||
package org.linphone.assistant;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
|
@ -117,13 +115,9 @@ public class EchoCancellerCalibrationAssistantActivity extends AssistantActivity
|
|||
Core core, EcCalibratorStatus status, int delayMs) {
|
||||
if (status == EcCalibratorStatus.InProgress) return;
|
||||
core.removeListener(this);
|
||||
LinphoneManager.getAudioManager().routeAudioToEarPiece();
|
||||
goToLinphoneActivity();
|
||||
|
||||
((AudioManager) getSystemService(Context.AUDIO_SERVICE))
|
||||
.setMode(AudioManager.MODE_NORMAL);
|
||||
}
|
||||
});
|
||||
LinphoneManager.getAudioManager().startEcCalibration();
|
||||
LinphoneManager.getCore().startEchoCancellerCalibration();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,69 +19,29 @@
|
|||
*/
|
||||
package org.linphone.call;
|
||||
|
||||
import static android.media.AudioManager.MODE_RINGTONE;
|
||||
import static android.media.AudioManager.STREAM_RING;
|
||||
import static android.media.AudioManager.STREAM_VOICE_CALL;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothHeadset;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.media.AudioManager;
|
||||
import android.media.MediaPlayer;
|
||||
import android.net.Uri;
|
||||
import android.os.Vibrator;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.view.KeyEvent;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import org.linphone.LinphoneContext;
|
||||
import org.linphone.LinphoneManager;
|
||||
import org.linphone.R;
|
||||
import org.linphone.compatibility.Compatibility;
|
||||
import org.linphone.core.Address;
|
||||
import org.linphone.core.AudioDevice;
|
||||
import org.linphone.core.Call;
|
||||
import org.linphone.core.Core;
|
||||
import org.linphone.core.CoreListenerStub;
|
||||
import org.linphone.core.EcCalibratorStatus;
|
||||
import org.linphone.core.tools.Log;
|
||||
import org.linphone.receivers.BluetoothReceiver;
|
||||
import org.linphone.receivers.HeadsetReceiver;
|
||||
import org.linphone.settings.LinphonePreferences;
|
||||
|
||||
public class AndroidAudioManager {
|
||||
private Context mContext;
|
||||
private AudioManager mAudioManager;
|
||||
private Call mRingingCall;
|
||||
private MediaPlayer mRingerPlayer;
|
||||
private final Vibrator mVibrator;
|
||||
private BluetoothAdapter mBluetoothAdapter;
|
||||
private BluetoothHeadset mBluetoothHeadset;
|
||||
private BluetoothReceiver mBluetoothReceiver;
|
||||
private HeadsetReceiver mHeadsetReceiver;
|
||||
private boolean mHeadsetReceiverRegistered;
|
||||
|
||||
private boolean mIsRinging;
|
||||
private boolean mAudioFocused;
|
||||
private boolean mEchoTesterIsRunning;
|
||||
private boolean mIsBluetoothHeadsetConnected;
|
||||
private boolean mIsBluetoothHeadsetScoConnected;
|
||||
private boolean mEchoTesterIsRunning = false;
|
||||
|
||||
private CoreListenerStub mListener;
|
||||
|
||||
public AndroidAudioManager(Context context) {
|
||||
mContext = context;
|
||||
mAudioManager = ((AudioManager) context.getSystemService(Context.AUDIO_SERVICE));
|
||||
mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
|
||||
mEchoTesterIsRunning = false;
|
||||
mHeadsetReceiverRegistered = false;
|
||||
|
||||
startBluetooth();
|
||||
|
||||
mListener =
|
||||
new CoreListenerStub() {
|
||||
|
@ -91,36 +51,9 @@ public class AndroidAudioManager {
|
|||
final Call call,
|
||||
final Call.State state,
|
||||
final String message) {
|
||||
if (state == Call.State.IncomingReceived
|
||||
|| (state == Call.State.IncomingEarlyMedia
|
||||
&& mContext.getResources()
|
||||
.getBoolean(
|
||||
R.bool.allow_ringing_while_early_media))) {
|
||||
// Brighten screen for at least 10 seconds
|
||||
if (core.getCallsNb() == 1) {
|
||||
requestAudioFocus(STREAM_RING);
|
||||
|
||||
mRingingCall = call;
|
||||
startRinging(call.getRemoteAddress());
|
||||
// otherwise there is the beep
|
||||
}
|
||||
} else if (call == mRingingCall && mIsRinging) {
|
||||
// previous state was ringing, so stop ringing
|
||||
stopRinging();
|
||||
}
|
||||
|
||||
if (state == Call.State.Connected) {
|
||||
if (core.getCallsNb() == 1) {
|
||||
// It is for incoming calls, because outgoing calls enter
|
||||
// MODE_IN_COMMUNICATION immediately when they start.
|
||||
// However, incoming call first use the MODE_RINGING to play the
|
||||
// local ring.
|
||||
if (call.getDir() == Call.Dir.Incoming) {
|
||||
setAudioManagerInCallMode();
|
||||
// mAudioManager.abandonAudioFocus(null);
|
||||
requestAudioFocus(STREAM_VOICE_CALL);
|
||||
}
|
||||
if (!mIsBluetoothHeadsetConnected) {
|
||||
if (!isBluetoothHeadsetConnected()) {
|
||||
if (mContext.getResources().getBoolean(R.bool.isTablet)) {
|
||||
routeAudioToSpeaker();
|
||||
} else {
|
||||
|
@ -130,70 +63,11 @@ public class AndroidAudioManager {
|
|||
routeAudioToEarPiece();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Only register this one when a call is active
|
||||
|
||||
enableHeadsetReceiver();
|
||||
}
|
||||
} else if (state == Call.State.End || state == Call.State.Error) {
|
||||
if (core.getCallsNb() == 0) {
|
||||
if (mAudioFocused) {
|
||||
int res = mAudioManager.abandonAudioFocus(null);
|
||||
Log.d(
|
||||
"[Audio Manager] Audio focus released a bit later: "
|
||||
+ (res
|
||||
== AudioManager
|
||||
.AUDIOFOCUS_REQUEST_GRANTED
|
||||
? "Granted"
|
||||
: "Denied"));
|
||||
mAudioFocused = false;
|
||||
}
|
||||
|
||||
// Only register this one when a call is active
|
||||
if (mHeadsetReceiver != null && mHeadsetReceiverRegistered) {
|
||||
Log.i("[Audio Manager] Unregistering headset receiver");
|
||||
mContext.unregisterReceiver(mHeadsetReceiver);
|
||||
mHeadsetReceiverRegistered = false;
|
||||
}
|
||||
|
||||
TelephonyManager tm =
|
||||
(TelephonyManager)
|
||||
mContext.getSystemService(
|
||||
Context.TELEPHONY_SERVICE);
|
||||
if (tm.getCallState() == TelephonyManager.CALL_STATE_IDLE) {
|
||||
Log.d(
|
||||
"[Audio Manager] ---AndroidAudioManager: back to MODE_NORMAL");
|
||||
mAudioManager.setMode(AudioManager.MODE_NORMAL);
|
||||
Log.d(
|
||||
"[Audio Manager] All call terminated, routing back to earpiece");
|
||||
routeAudioToEarPiece();
|
||||
} else {
|
||||
routeAudioToBluetooth();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (state == Call.State.OutgoingInit) {
|
||||
// Enter the MODE_IN_COMMUNICATION mode as soon as possible, so that
|
||||
// ringback is heard normally in earpiece or bluetooth receiver.
|
||||
setAudioManagerInCallMode();
|
||||
requestAudioFocus(STREAM_VOICE_CALL);
|
||||
if (mIsBluetoothHeadsetConnected) {
|
||||
routeAudioToBluetooth();
|
||||
}
|
||||
}
|
||||
|
||||
if (state == Call.State.StreamsRunning) {
|
||||
setAudioManagerInCallMode();
|
||||
if (mIsBluetoothHeadsetConnected) {
|
||||
routeAudioToBluetooth();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEcCalibrationResult(
|
||||
Core core, EcCalibratorStatus status, int delay_ms) {
|
||||
mAudioManager.setMode(AudioManager.MODE_NORMAL);
|
||||
mAudioManager.abandonAudioFocus(null);
|
||||
Log.i("[Audio Manager] Set audio mode on 'Normal'");
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -204,16 +78,6 @@ public class AndroidAudioManager {
|
|||
}
|
||||
|
||||
public void destroy() {
|
||||
if (mBluetoothAdapter != null && mBluetoothHeadset != null) {
|
||||
Log.i("[Audio Manager] [Bluetooth] Closing HEADSET profile proxy");
|
||||
mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
|
||||
}
|
||||
|
||||
Log.i("[Audio Manager] [Bluetooth] Unegistering bluetooth receiver");
|
||||
if (mBluetoothReceiver != null) {
|
||||
mContext.unregisterReceiver(mBluetoothReceiver);
|
||||
}
|
||||
|
||||
Core core = LinphoneManager.getCore();
|
||||
if (core != null) {
|
||||
core.removeListener(mListener);
|
||||
|
@ -222,10 +86,6 @@ public class AndroidAudioManager {
|
|||
|
||||
/* Audio routing */
|
||||
|
||||
public void setAudioManagerModeNormal() {
|
||||
mAudioManager.setMode(AudioManager.MODE_NORMAL);
|
||||
}
|
||||
|
||||
public void routeAudioToEarPiece() {
|
||||
routeAudioToSpeakerHelper(false);
|
||||
}
|
||||
|
@ -244,41 +104,17 @@ public class AndroidAudioManager {
|
|||
|
||||
/* Echo cancellation */
|
||||
|
||||
public void startEcCalibration() {
|
||||
Core core = LinphoneManager.getCore();
|
||||
if (core == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
routeAudioToSpeaker();
|
||||
setAudioManagerInCallMode();
|
||||
Log.i("[Audio Manager] Set audio mode on 'Voice Communication'");
|
||||
requestAudioFocus(STREAM_VOICE_CALL);
|
||||
int oldVolume = mAudioManager.getStreamVolume(STREAM_VOICE_CALL);
|
||||
int maxVolume = mAudioManager.getStreamMaxVolume(STREAM_VOICE_CALL);
|
||||
mAudioManager.setStreamVolume(STREAM_VOICE_CALL, maxVolume, 0);
|
||||
core.startEchoCancellerCalibration();
|
||||
mAudioManager.setStreamVolume(STREAM_VOICE_CALL, oldVolume, 0);
|
||||
}
|
||||
|
||||
public void startEchoTester() {
|
||||
Core core = LinphoneManager.getCore();
|
||||
if (core == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
routeAudioToSpeaker();
|
||||
setAudioManagerInCallMode();
|
||||
Log.i("[Audio Manager] Set audio mode on 'Voice Communication'");
|
||||
requestAudioFocus(STREAM_VOICE_CALL);
|
||||
int maxVolume = mAudioManager.getStreamMaxVolume(STREAM_VOICE_CALL);
|
||||
int sampleRate;
|
||||
mAudioManager.setStreamVolume(STREAM_VOICE_CALL, maxVolume, 0);
|
||||
String sampleRateProperty =
|
||||
mAudioManager.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
|
||||
sampleRate = Integer.parseInt(sampleRateProperty);
|
||||
core.startEchoTester(sampleRate);
|
||||
mEchoTesterIsRunning = true;
|
||||
core.startEchoTester(sampleRate);
|
||||
}
|
||||
|
||||
public void stopEchoTester() {
|
||||
|
@ -287,10 +123,8 @@ public class AndroidAudioManager {
|
|||
return;
|
||||
}
|
||||
|
||||
mEchoTesterIsRunning = false;
|
||||
core.stopEchoTester();
|
||||
routeAudioToEarPiece();
|
||||
mAudioManager.setMode(AudioManager.MODE_NORMAL);
|
||||
mEchoTesterIsRunning = false;
|
||||
Log.i("[Audio Manager] Set audio mode on 'Normal'");
|
||||
}
|
||||
|
||||
|
@ -309,107 +143,23 @@ public class AndroidAudioManager {
|
|||
return false;
|
||||
}
|
||||
|
||||
private void setAudioManagerInCallMode() {
|
||||
if (mAudioManager.getMode() == AudioManager.MODE_IN_COMMUNICATION) {
|
||||
Log.w("[Audio Manager] already in MODE_IN_COMMUNICATION, skipping...");
|
||||
return;
|
||||
}
|
||||
Log.d("[Audio Manager] Mode: MODE_IN_COMMUNICATION");
|
||||
|
||||
mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
|
||||
}
|
||||
|
||||
private void requestAudioFocus(int stream) {
|
||||
if (!mAudioFocused) {
|
||||
int res =
|
||||
mAudioManager.requestAudioFocus(
|
||||
null, stream, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE);
|
||||
Log.d(
|
||||
"[Audio Manager] Audio focus requested: "
|
||||
+ (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED
|
||||
? "Granted"
|
||||
: "Denied"));
|
||||
if (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) mAudioFocused = true;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void startRinging(Address remoteAddress) {
|
||||
if (!LinphonePreferences.instance().isDeviceRingtoneEnabled()) {
|
||||
// Enable speaker audio route, linphone library will do the ringing itself automatically
|
||||
routeAudioToSpeaker();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean doNotDisturbPolicyAllowsRinging =
|
||||
Compatibility.isDoNotDisturbPolicyAllowingRinging(mContext, remoteAddress);
|
||||
if (!doNotDisturbPolicyAllowsRinging) {
|
||||
Log.e("[Audio Manager] Do not ring as Android Do Not Disturb Policy forbids it");
|
||||
return;
|
||||
}
|
||||
|
||||
routeAudioToSpeaker();
|
||||
mAudioManager.setMode(MODE_RINGTONE);
|
||||
|
||||
try {
|
||||
if ((mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE
|
||||
|| mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL)
|
||||
&& mVibrator != null
|
||||
&& LinphonePreferences.instance().isIncomingCallVibrationEnabled()) {
|
||||
Compatibility.vibrate(mVibrator);
|
||||
}
|
||||
if (mRingerPlayer == null) {
|
||||
requestAudioFocus(STREAM_RING);
|
||||
mRingerPlayer = new MediaPlayer();
|
||||
mRingerPlayer.setAudioStreamType(STREAM_RING);
|
||||
|
||||
String ringtone =
|
||||
LinphonePreferences.instance()
|
||||
.getRingtone(Settings.System.DEFAULT_RINGTONE_URI.toString());
|
||||
try {
|
||||
if (ringtone.startsWith("content://")) {
|
||||
mRingerPlayer.setDataSource(mContext, Uri.parse(ringtone));
|
||||
} else {
|
||||
FileInputStream fis = new FileInputStream(ringtone);
|
||||
mRingerPlayer.setDataSource(fis.getFD());
|
||||
fis.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(e, "[Audio Manager] Cannot set ringtone");
|
||||
}
|
||||
|
||||
mRingerPlayer.prepare();
|
||||
mRingerPlayer.setLooping(true);
|
||||
mRingerPlayer.start();
|
||||
} else {
|
||||
Log.w("[Audio Manager] Already ringing");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(e, "[Audio Manager] Cannot handle incoming call");
|
||||
}
|
||||
mIsRinging = true;
|
||||
}
|
||||
|
||||
private synchronized void stopRinging() {
|
||||
if (mRingerPlayer != null) {
|
||||
mRingerPlayer.stop();
|
||||
mRingerPlayer.release();
|
||||
mRingerPlayer = null;
|
||||
}
|
||||
if (mVibrator != null) {
|
||||
mVibrator.cancel();
|
||||
}
|
||||
|
||||
mIsRinging = false;
|
||||
}
|
||||
|
||||
private void routeAudioToSpeakerHelper(boolean speakerOn) {
|
||||
Log.w("[Audio Manager] Routing audio to " + (speakerOn ? "speaker" : "earpiece"));
|
||||
if (mIsBluetoothHeadsetScoConnected) {
|
||||
Log.w("[Audio Manager] [Bluetooth] Disabling bluetooth audio route");
|
||||
changeBluetoothSco(false);
|
||||
}
|
||||
|
||||
mAudioManager.setSpeakerphoneOn(speakerOn);
|
||||
if (LinphoneManager.getCore().getCallsNb() == 0) return;
|
||||
Call currentCall = LinphoneManager.getCore().getCurrentCall();
|
||||
if (currentCall == null) currentCall = LinphoneManager.getCore().getCalls()[0];
|
||||
if (currentCall == null) return;
|
||||
|
||||
for (AudioDevice audioDevice : LinphoneManager.getCore().getAudioDevices()) {
|
||||
if (speakerOn && audioDevice.getType() == AudioDevice.Type.Speaker) {
|
||||
currentCall.setOutputAudioDevice(audioDevice);
|
||||
return;
|
||||
} else if (!speakerOn && audioDevice.getType() == AudioDevice.Type.Earpiece) {
|
||||
currentCall.setOutputAudioDevice(audioDevice);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void adjustVolume(int i) {
|
||||
|
@ -419,7 +169,7 @@ public class AndroidAudioManager {
|
|||
}
|
||||
|
||||
int stream = STREAM_VOICE_CALL;
|
||||
if (mIsBluetoothHeadsetScoConnected) {
|
||||
if (isUsingBluetoothAudioRoute()) {
|
||||
Log.i(
|
||||
"[Audio Manager] Bluetooth is connected, try to change the volume on STREAM_BLUETOOTH_SCO");
|
||||
stream = 6; // STREAM_BLUETOOTH_SCO, it's hidden...
|
||||
|
@ -433,194 +183,45 @@ public class AndroidAudioManager {
|
|||
AudioManager.FLAG_SHOW_UI);
|
||||
}
|
||||
|
||||
// Bluetooth
|
||||
|
||||
public synchronized void bluetoothHeadetConnectionChanged(boolean connected) {
|
||||
mIsBluetoothHeadsetConnected = connected;
|
||||
mAudioManager.setBluetoothScoOn(connected);
|
||||
if (LinphoneContext.isReady()) LinphoneManager.getCallManager().refreshInCallActions();
|
||||
}
|
||||
|
||||
public synchronized void bluetoothHeadetAudioConnectionChanged(boolean connected) {
|
||||
mIsBluetoothHeadsetScoConnected = connected;
|
||||
mAudioManager.setBluetoothScoOn(connected);
|
||||
public synchronized boolean isUsingBluetoothAudioRoute() {
|
||||
if (LinphoneManager.getCore().getCallsNb() == 0) return false;
|
||||
Call currentCall = LinphoneManager.getCore().getCurrentCall();
|
||||
if (currentCall == null) currentCall = LinphoneManager.getCore().getCalls()[0];
|
||||
if (currentCall == null) return false;
|
||||
AudioDevice audioDevice = currentCall.getOutputAudioDevice();
|
||||
Log.i("[Audio Manager] Currently used audio device: ", audioDevice.getDeviceName());
|
||||
return audioDevice.getType() == AudioDevice.Type.Bluetooth;
|
||||
}
|
||||
|
||||
public synchronized boolean isBluetoothHeadsetConnected() {
|
||||
return mIsBluetoothHeadsetConnected;
|
||||
}
|
||||
|
||||
public synchronized void bluetoothHeadetScoConnectionChanged(boolean connected) {
|
||||
mIsBluetoothHeadsetScoConnected = connected;
|
||||
if (LinphoneContext.isReady()) LinphoneManager.getCallManager().refreshInCallActions();
|
||||
}
|
||||
|
||||
public synchronized boolean isUsingBluetoothAudioRoute() {
|
||||
return mIsBluetoothHeadsetScoConnected;
|
||||
for (AudioDevice audioDevice : LinphoneManager.getCore().getAudioDevices()) {
|
||||
if (audioDevice.getType() == AudioDevice.Type.Bluetooth
|
||||
&& audioDevice.hasCapability(AudioDevice.Capabilities.CapabilityPlay)) {
|
||||
Log.i("[Audio Manager] Found bluetooth device: ", audioDevice.getDeviceName());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public synchronized void routeAudioToBluetooth() {
|
||||
if (!isBluetoothHeadsetConnected()) {
|
||||
Log.w("[Audio Manager] [Bluetooth] No headset connected");
|
||||
return;
|
||||
}
|
||||
if (mAudioManager.getMode() != AudioManager.MODE_IN_COMMUNICATION) {
|
||||
Log.w(
|
||||
"[Audio Manager] [Bluetooth] Changing audio mode to MODE_IN_COMMUNICATION and requesting STREAM_VOICE_CALL focus");
|
||||
mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
|
||||
requestAudioFocus(STREAM_VOICE_CALL);
|
||||
}
|
||||
changeBluetoothSco(true);
|
||||
}
|
||||
if (LinphoneManager.getCore().getCallsNb() == 0) return;
|
||||
Call currentCall = LinphoneManager.getCore().getCurrentCall();
|
||||
if (currentCall == null) currentCall = LinphoneManager.getCore().getCalls()[0];
|
||||
if (currentCall == null) return;
|
||||
|
||||
private synchronized void changeBluetoothSco(final boolean enable) {
|
||||
// IT WILL TAKE A CERTAIN NUMBER OF CALLS TO EITHER START/STOP BLUETOOTH SCO FOR IT TO WORK
|
||||
if (enable && mIsBluetoothHeadsetScoConnected) {
|
||||
Log.i("[Audio Manager] [Bluetooth] SCO already enabled, skipping");
|
||||
return;
|
||||
} else if (!enable && !mIsBluetoothHeadsetScoConnected) {
|
||||
Log.i("[Audio Manager] [Bluetooth] SCO already disabled, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.i("[Audio Manager] [Bluetooth] SCO start/stop thread started");
|
||||
boolean resultAcknowledged;
|
||||
int retries = 0;
|
||||
|
||||
do {
|
||||
try {
|
||||
Thread.sleep(200);
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(e);
|
||||
}
|
||||
|
||||
synchronized (AndroidAudioManager.this) {
|
||||
if (enable) {
|
||||
Log.i(
|
||||
"[Audio Manager] [Bluetooth] Starting SCO: try number "
|
||||
+ retries);
|
||||
mAudioManager.startBluetoothSco();
|
||||
} else {
|
||||
Log.i(
|
||||
"[Audio Manager] [Bluetooth] Stopping SCO: try number "
|
||||
+ retries);
|
||||
mAudioManager.stopBluetoothSco();
|
||||
}
|
||||
resultAcknowledged = isUsingBluetoothAudioRoute() == enable;
|
||||
retries++;
|
||||
}
|
||||
} while (!resultAcknowledged && retries < 10);
|
||||
for (AudioDevice audioDevice : LinphoneManager.getCore().getAudioDevices()) {
|
||||
if (audioDevice.getType() == AudioDevice.Type.Bluetooth
|
||||
&& audioDevice.hasCapability(AudioDevice.Capabilities.CapabilityPlay)) {
|
||||
Log.i(
|
||||
"[Audio Manager] Found bluetooth audio device",
|
||||
audioDevice.getDeviceName(),
|
||||
", routing audio to it");
|
||||
currentCall.setOutputAudioDevice(audioDevice);
|
||||
return;
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
public void bluetoothAdapterStateChanged() {
|
||||
if (mBluetoothAdapter.isEnabled()) {
|
||||
Log.i("[Audio Manager] [Bluetooth] Adapter enabled");
|
||||
mIsBluetoothHeadsetConnected = false;
|
||||
mIsBluetoothHeadsetScoConnected = false;
|
||||
|
||||
BluetoothProfile.ServiceListener bluetoothServiceListener =
|
||||
new BluetoothProfile.ServiceListener() {
|
||||
public void onServiceConnected(int profile, BluetoothProfile proxy) {
|
||||
if (profile == BluetoothProfile.HEADSET) {
|
||||
Log.i("[Audio Manager] [Bluetooth] HEADSET profile connected");
|
||||
mBluetoothHeadset = (BluetoothHeadset) proxy;
|
||||
|
||||
List<BluetoothDevice> devices =
|
||||
mBluetoothHeadset.getConnectedDevices();
|
||||
if (devices.size() > 0) {
|
||||
Log.i(
|
||||
"[Audio Manager] [Bluetooth] A device is already connected");
|
||||
bluetoothHeadetConnectionChanged(true);
|
||||
}
|
||||
|
||||
Log.i("[Audio Manager] [Bluetooth] Registering bluetooth receiver");
|
||||
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
|
||||
filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
|
||||
filter.addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
|
||||
filter.addAction(
|
||||
BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT);
|
||||
|
||||
Intent sticky =
|
||||
mContext.registerReceiver(mBluetoothReceiver, filter);
|
||||
Log.i("[Audio Manager] [Bluetooth] Bluetooth receiver registered");
|
||||
int state =
|
||||
sticky.getIntExtra(
|
||||
AudioManager.EXTRA_SCO_AUDIO_STATE,
|
||||
AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
|
||||
if (state == AudioManager.SCO_AUDIO_STATE_CONNECTED) {
|
||||
Log.i(
|
||||
"[Audio Manager] [Bluetooth] Bluetooth headset SCO connected");
|
||||
bluetoothHeadetScoConnectionChanged(true);
|
||||
} else if (state == AudioManager.SCO_AUDIO_STATE_DISCONNECTED) {
|
||||
Log.i(
|
||||
"[Audio Manager] [Bluetooth] Bluetooth headset SCO disconnected");
|
||||
bluetoothHeadetScoConnectionChanged(false);
|
||||
} else if (state == AudioManager.SCO_AUDIO_STATE_CONNECTING) {
|
||||
Log.i(
|
||||
"[Audio Manager] [Bluetooth] Bluetooth headset SCO connecting");
|
||||
} else if (state == AudioManager.SCO_AUDIO_STATE_ERROR) {
|
||||
Log.i(
|
||||
"[Audio Manager] [Bluetooth] Bluetooth headset SCO connection error");
|
||||
} else {
|
||||
Log.w(
|
||||
"[Audio Manager] [Bluetooth] Bluetooth headset unknown SCO state changed: "
|
||||
+ state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onServiceDisconnected(int profile) {
|
||||
if (profile == BluetoothProfile.HEADSET) {
|
||||
Log.i("[Audio Manager] [Bluetooth] HEADSET profile disconnected");
|
||||
mBluetoothHeadset = null;
|
||||
mIsBluetoothHeadsetConnected = false;
|
||||
mIsBluetoothHeadsetScoConnected = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
mBluetoothAdapter.getProfileProxy(
|
||||
mContext, bluetoothServiceListener, BluetoothProfile.HEADSET);
|
||||
} else {
|
||||
Log.w("[Audio Manager] [Bluetooth] Adapter disabled");
|
||||
}
|
||||
}
|
||||
|
||||
private void startBluetooth() {
|
||||
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
if (mBluetoothAdapter != null) {
|
||||
Log.i("[Audio Manager] [Bluetooth] Adapter found");
|
||||
if (mAudioManager.isBluetoothScoAvailableOffCall()) {
|
||||
Log.i("[Audio Manager] [Bluetooth] SCO available off call, continue");
|
||||
} else {
|
||||
Log.w("[Audio Manager] [Bluetooth] SCO not available off call !");
|
||||
}
|
||||
|
||||
mBluetoothReceiver = new BluetoothReceiver();
|
||||
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
|
||||
mContext.registerReceiver(mBluetoothReceiver, filter);
|
||||
|
||||
bluetoothAdapterStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
// HEADSET
|
||||
|
||||
private void enableHeadsetReceiver() {
|
||||
mHeadsetReceiver = new HeadsetReceiver();
|
||||
|
||||
Log.i("[Audio Manager] Registering headset receiver");
|
||||
mContext.registerReceiver(
|
||||
mHeadsetReceiver, new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
|
||||
mContext.registerReceiver(
|
||||
mHeadsetReceiver, new IntentFilter(AudioManager.ACTION_HEADSET_PLUG));
|
||||
mHeadsetReceiverRegistered = true;
|
||||
Log.w(
|
||||
"[Audio Manager] Didn't find any bluetooth audio device, keeping default audio route");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -430,6 +430,14 @@ public class CallActivity extends LinphoneGenericActivity
|
|||
updateButtons();
|
||||
updateCallsList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAudioDevicesListUpdated(@NonNull Core core) {
|
||||
if (mAudioManager.isBluetoothHeadsetConnected()) {
|
||||
mAudioManager.routeAudioToBluetooth();
|
||||
}
|
||||
updateButtons();
|
||||
}
|
||||
};
|
||||
|
||||
mCore = LinphoneManager.getCore();
|
||||
|
|
|
@ -50,6 +50,7 @@ import android.widget.CheckBox;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.view.menu.MenuBuilder;
|
||||
import androidx.appcompat.view.menu.MenuPopupHelper;
|
||||
import androidx.core.view.inputmethod.InputConnectionCompat;
|
||||
|
@ -1210,6 +1211,9 @@ public class ChatMessagesFragment extends Fragment
|
|||
* Chat room callbacks
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void onNewEvent(@NonNull ChatRoom chatRoom, @NonNull EventLog eventLog) {}
|
||||
|
||||
@Override
|
||||
public void onChatMessageSent(ChatRoom cr, EventLog event) {
|
||||
((ChatMessagesGenericAdapter) mChatEventsList.getAdapter()).addToHistory(event);
|
||||
|
|
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2019 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-android
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.linphone.receivers;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothHeadset;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.AudioManager;
|
||||
import org.linphone.LinphoneManager;
|
||||
import org.linphone.core.tools.Log;
|
||||
|
||||
public class BluetoothReceiver extends BroadcastReceiver {
|
||||
public BluetoothReceiver() {
|
||||
super();
|
||||
Log.i("[Bluetooth] Bluetooth receiver created");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
Log.i("[Bluetooth] Bluetooth broadcast received");
|
||||
|
||||
if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
|
||||
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
|
||||
switch (state) {
|
||||
case BluetoothAdapter.STATE_OFF:
|
||||
Log.w("[Bluetooth] Adapter has been turned off");
|
||||
break;
|
||||
case BluetoothAdapter.STATE_TURNING_OFF:
|
||||
Log.w("[Bluetooth] Adapter is being turned off");
|
||||
break;
|
||||
case BluetoothAdapter.STATE_ON:
|
||||
Log.i("[Bluetooth] Adapter has been turned on");
|
||||
LinphoneManager.getAudioManager().bluetoothAdapterStateChanged();
|
||||
break;
|
||||
case BluetoothAdapter.STATE_TURNING_ON:
|
||||
Log.i("[Bluetooth] Adapter is being turned on");
|
||||
break;
|
||||
case BluetoothAdapter.ERROR:
|
||||
Log.e("[Bluetooth] Adapter is in error state !");
|
||||
break;
|
||||
default:
|
||||
Log.w("[Bluetooth] Unknown adapter state: ", state);
|
||||
break;
|
||||
}
|
||||
} else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
|
||||
int state =
|
||||
intent.getIntExtra(
|
||||
BluetoothHeadset.EXTRA_STATE, BluetoothHeadset.STATE_DISCONNECTED);
|
||||
if (state == BluetoothHeadset.STATE_CONNECTED) {
|
||||
Log.i("[Bluetooth] Bluetooth headset connected");
|
||||
LinphoneManager.getAudioManager().bluetoothHeadetConnectionChanged(true);
|
||||
} else if (state == BluetoothHeadset.STATE_DISCONNECTED) {
|
||||
Log.i("[Bluetooth] Bluetooth headset disconnected");
|
||||
LinphoneManager.getAudioManager().bluetoothHeadetConnectionChanged(false);
|
||||
} else {
|
||||
Log.w("[Bluetooth] Bluetooth headset unknown state changed: " + state);
|
||||
}
|
||||
} else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
|
||||
int state =
|
||||
intent.getIntExtra(
|
||||
BluetoothHeadset.EXTRA_STATE,
|
||||
BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
|
||||
if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
|
||||
Log.i("[Bluetooth] Bluetooth headset audio connected");
|
||||
LinphoneManager.getAudioManager().bluetoothHeadetAudioConnectionChanged(true);
|
||||
} else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
|
||||
Log.i("[Bluetooth] Bluetooth headset audio disconnected");
|
||||
LinphoneManager.getAudioManager().bluetoothHeadetAudioConnectionChanged(false);
|
||||
} else if (state == BluetoothHeadset.STATE_AUDIO_CONNECTING) {
|
||||
Log.i("[Bluetooth] Bluetooth headset audio connecting");
|
||||
} else {
|
||||
Log.w("[Bluetooth] Bluetooth headset unknown audio state changed: " + state);
|
||||
}
|
||||
} else if (action.equals(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED)) {
|
||||
int state =
|
||||
intent.getIntExtra(
|
||||
AudioManager.EXTRA_SCO_AUDIO_STATE,
|
||||
AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
|
||||
if (state == AudioManager.SCO_AUDIO_STATE_CONNECTED) {
|
||||
Log.i("[Bluetooth] Bluetooth headset SCO connected");
|
||||
LinphoneManager.getAudioManager().bluetoothHeadetScoConnectionChanged(true);
|
||||
} else if (state == AudioManager.SCO_AUDIO_STATE_DISCONNECTED) {
|
||||
Log.i("[Bluetooth] Bluetooth headset SCO disconnected");
|
||||
LinphoneManager.getAudioManager().bluetoothHeadetScoConnectionChanged(false);
|
||||
} else if (state == AudioManager.SCO_AUDIO_STATE_CONNECTING) {
|
||||
Log.i("[Bluetooth] Bluetooth headset SCO connecting");
|
||||
} else if (state == AudioManager.SCO_AUDIO_STATE_ERROR) {
|
||||
Log.i("[Bluetooth] Bluetooth headset SCO connection error");
|
||||
} else {
|
||||
Log.w("[Bluetooth] Bluetooth headset unknown SCO state changed: " + state);
|
||||
}
|
||||
} else if (action.equals(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT)) {
|
||||
String command =
|
||||
intent.getStringExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD);
|
||||
int type =
|
||||
intent.getIntExtra(
|
||||
BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE, -1);
|
||||
|
||||
String commandType;
|
||||
switch (type) {
|
||||
case BluetoothHeadset.AT_CMD_TYPE_ACTION:
|
||||
commandType = "AT Action";
|
||||
break;
|
||||
case BluetoothHeadset.AT_CMD_TYPE_READ:
|
||||
commandType = "AT Read";
|
||||
break;
|
||||
case BluetoothHeadset.AT_CMD_TYPE_TEST:
|
||||
commandType = "AT Test";
|
||||
break;
|
||||
case BluetoothHeadset.AT_CMD_TYPE_SET:
|
||||
commandType = "AT Set";
|
||||
break;
|
||||
case BluetoothHeadset.AT_CMD_TYPE_BASIC:
|
||||
commandType = "AT Basic";
|
||||
break;
|
||||
default:
|
||||
commandType = "AT Unknown";
|
||||
break;
|
||||
}
|
||||
Log.i("[Bluetooth] Vendor action " + commandType + " : " + command);
|
||||
} else {
|
||||
Log.w("[Bluetooth] Bluetooth unknown action: " + action);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2019 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-android
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.linphone.receivers;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.AudioManager;
|
||||
import org.linphone.LinphoneManager;
|
||||
import org.linphone.core.tools.Log;
|
||||
|
||||
public class HeadsetReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (isInitialStickyBroadcast()) {
|
||||
Log.i("[Headset] Received broadcast from sticky cache, ignoring...");
|
||||
return;
|
||||
}
|
||||
|
||||
String action = intent.getAction();
|
||||
if (action.equals(AudioManager.ACTION_HEADSET_PLUG)) {
|
||||
// This happens when the user plugs a Jack headset to the device for example
|
||||
// https://developer.android.com/reference/android/media/AudioManager.html#ACTION_HEADSET_PLUG
|
||||
int state = intent.getIntExtra("state", 0);
|
||||
String name = intent.getStringExtra("name");
|
||||
int hasMicrophone = intent.getIntExtra("microphone", 0);
|
||||
|
||||
if (state == 0) {
|
||||
Log.i("[Headset] Headset disconnected:" + name);
|
||||
} else if (state == 1) {
|
||||
Log.i("[Headset] Headset connected:" + name);
|
||||
if (hasMicrophone == 1) {
|
||||
Log.i("[Headset] Headset " + name + " has a microphone");
|
||||
}
|
||||
} else {
|
||||
Log.w("[Headset] Unknown headset plugged state: " + state);
|
||||
}
|
||||
|
||||
LinphoneManager.getAudioManager().routeAudioToEarPiece();
|
||||
LinphoneManager.getCallManager().refreshInCallActions();
|
||||
} else if (action.equals(AudioManager.ACTION_AUDIO_BECOMING_NOISY)) {
|
||||
// This happens when the user disconnect a headset, so we shouldn't play audio loudly
|
||||
Log.i("[Headset] Noisy state detected, most probably a headset has been disconnected");
|
||||
LinphoneManager.getAudioManager().routeAudioToEarPiece();
|
||||
LinphoneManager.getCallManager().refreshInCallActions();
|
||||
} else {
|
||||
Log.w("[Headset] Unknown action: " + action);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -107,7 +107,6 @@ public class RecordingsActivity extends MainActivity
|
|||
hideTopBar();
|
||||
hideTabBar();
|
||||
|
||||
LinphoneManager.getAudioManager().setAudioManagerModeNormal();
|
||||
LinphoneManager.getAudioManager().routeAudioToSpeaker();
|
||||
|
||||
removeDeletedRecordings();
|
||||
|
|
|
@ -20,9 +20,7 @@
|
|||
package org.linphone.settings;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Bundle;
|
||||
import android.text.InputType;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -274,7 +272,6 @@ public class AudioSettingsFragment extends SettingsFragment {
|
|||
Core core, EcCalibratorStatus status, int delayMs) {
|
||||
if (status == EcCalibratorStatus.InProgress) return;
|
||||
core.removeListener(this);
|
||||
LinphoneManager.getAudioManager().routeAudioToEarPiece();
|
||||
|
||||
if (status == EcCalibratorStatus.DoneNoEcho) {
|
||||
mEchoCalibration.setSubtitle(getString(R.string.no_echo));
|
||||
|
@ -287,12 +284,8 @@ public class AudioSettingsFragment extends SettingsFragment {
|
|||
mEchoCalibration.setSubtitle(getString(R.string.failed));
|
||||
}
|
||||
mEchoCanceller.setChecked(status != EcCalibratorStatus.DoneNoEcho);
|
||||
((AudioManager)
|
||||
getActivity()
|
||||
.getSystemService(Context.AUDIO_SERVICE))
|
||||
.setMode(AudioManager.MODE_NORMAL);
|
||||
}
|
||||
});
|
||||
LinphoneManager.getAudioManager().startEcCalibration();
|
||||
LinphoneManager.getCore().startEchoCancellerCalibration();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue