10000 feat: expose android audio modes (#1401) · InventYang/flutter-webrtc@fad3b57 · GitHub
[go: up one dir, main page]

Skip to content

Commit fad3b57

Browse files
authored
feat: expose android audio modes (flutter-webrtc#1401)
* feat: expose android audio modes * fix imports
1 parent 12ea402 commit fad3b57

File tree

6 files changed

+190
-2
lines changed

6 files changed

+190
-2
lines changed

android/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ rootProject.allprojects {
1818
repositories {
1919
google()
2020
mavenCentral()
21+
maven { url 'https://jitpack.io' }
2122
}
2223
}
2324

@@ -52,7 +53,7 @@ android {
5253

5354
dependencies {
5455
implementation 'io.github.webrtc-sdk:android:114.5735.02'
55-
implementation 'com.twilio:audioswitch:1.1.7'
56+
implementation 'com.github.davidliu:audioswitch:fb33b237aa50b3d1d2dea0e0695ecb7b38a98971'
5657
implementation 'androidx.annotation:annotation:1.1.0'
5758
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
5859
}

android/src/main/java/com/cloudwebrtc/webrtc/MethodCallHandlerImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,11 @@ public void onMethodCall(MethodCall call, @NonNull Result notSafeResult) {
552552
result.notImplemented();
553553
}
554554
break;
555+
case "setAndroidAudioConfiguration": {
556+
Map<String, Object> configuration = call.argument("configuration");
557+
AudioSwitchManager.instance.setAudioConfiguration(configuration);
558+
break;
559+
}
555560
case "enableSpeakerphone":
556561
boolean enable = call.argument("enable");
557562
AudioSwitchManager.instance.enableSpeakerphone(enable);

android/src/main/java/com/cloudwebrtc/webrtc/audio/AudioSwitchManager.java

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,15 @@
1818
import java.util.Collections;
1919
import java.util.List;
2020
import java.util.Objects;
21+
import java.util.Map;
2122

2223
import kotlin.Unit;
2324
import kotlin.jvm.functions.Function2;
2425

2526
public class AudioSwitchManager {
27+
28+
public static final String TAG = "AudioSwitchManager";
29+
2630
@SuppressLint("StaticFieldLeak")
2731
public static AudioSwitchManager instance;
2832
@NonNull
@@ -52,6 +56,20 @@ public class AudioSwitchManager {
5256

5357
private boolean _speakerphoneOn = false;
5458

59+
/**
60+
* The audio focus mode to use while started.
61+
*
62+
* Defaults to [AudioManager.AUDIOFOCUS_GAIN].
63+
*/
64+
private int focusMode = AudioManager.AUDIOFOCUS_GAIN;
65+
66+
/**
67+
* The audio mode to use while started.
68+
*
69+
* Defaults to [AudioManager.MODE_NORMAL].
70+
*/
71+
private int audioMode = AudioManager.MODE_NORMAL;
72+
5573
public AudioSwitchManager(@NonNull Context context) {
5674
this.context = context;
5775
this.audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
@@ -74,6 +92,8 @@ private void initAudioSwitch() {
7492
audioFocusChangeListener,
7593
preferredDeviceList
7694
);
95+
audioSwitch.setFocusMode(focusMode);
96+
audioSwitch.setAudioMode(audioMode);
7797
audioSwitch.start(audioDeviceChangeListener);
7898
});
7999
}
@@ -160,4 +180,92 @@ public void selectAudioOutput(@Nullable AudioDeviceKind kind) {
160180
selectAudioOutput(kind.audioDeviceClass);
161181
}
162182
}
183+
184+
public void setAudioConfiguration(Map<String, Object> configuration) {
185+
if(configuration == null) {
186+
return;
187+
}
188+
189+
String audioMode = null;
190+
if (configuration.get("androidAudioMode") instanceof String) {
191+
audioMode = (String) configuration.get("androidAudioMode");
192+
}
193+
194+
String focusMode = null;
195+
if (configuration.get("androidAudioFocusMode") instanceof String) {
196+
focusMode = (String) configuration.get("androidAudioFocusMode");
197+
}
198+
199+
setAudioMode(audioMode);
200+
setFocusMode(focusMode);
201+
}
202+
203+
public void setAudioMode(@Nullable String audioModeString) {
204+
if (audioModeString == null) {
205+
return;
206+
}
207+
208+
int audioMode = -1;
209+
switch (audioModeString) {
210+
case "normal":
211+
audioMode = AudioManager.MODE_NORMAL;
212+
break;
213+
case "callScreening":
214+
audioMode = AudioManager.MODE_CALL_SCREENING;
215+
break;
216+
case "inCall":
217+
audioMode = AudioManager.MODE_IN_CALL;
218+
break;
219+
case "inCommunication":
220+
audioMode = AudioManager.MODE_IN_COMMUNICATION;
221+
break;
222+
case "ringtone":
223+
audioMode = AudioManager.MODE_RINGTONE;
224+
break;
225+
default:
226+
Log.w(TAG, "Unknown audio mode: " + audioModeString);
227+
break;
228+
}
229+
230+
// Valid audio modes start from 0
231+
if (audioMode >= 0) {
232+
this.audioMode = audioMode;
233+
if (audioSwitch != null) {
234+
Objects.requireNonNull(audioSwitch).setAudioMode(audioMode);
235+
}
236+
}
237+
}
238+
239+
public void setFocusMode(@Nullable String focusModeString) {
240+
if (focusModeString == null) {
241+
return;
242+
}
243+
244+
int focusMode = -1;
245+
switch(focusModeString) {
246+
case "gain":
247+
focusMode = AudioManager.AUDIOFOCUS_GAIN;
248+
break;
249+
case "gainTransient":
250+
focusMode = AudioManager.AUDIOFOCUS_GAIN_TRANSIENT;
251+
break;
252+
case "gainTransientExclusive":
253+
focusMode = AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE;
254+
break;
255+
case "gainTransientMayDuck":
256+
focusMode = AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
257+
break;
258+
default:
259+
Log.w(TAG, "Unknown audio focus mode: " + focusModeString);
260+
break;
261+
}
262+
263+
// Valid focus modes start from 1
264+
if (focusMode > 0) {
265+
this.focusMode = focusMode;
266+
if (audioSwitch != null) {
267+
Objects.requireNonNull(audioSwitch).setFocusMode(focusMode);
268+
}
269+
}
270+
}
163271
}

lib/flutter_webrtc.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ export 'src/native/rtc_video_view_impl.dart'
1515
if (dart.library.html) 'src/web/rtc_video_view_impl.dart';
1616
export 'src/native/utils.dart' if (dart.library.html) 'src/web/utils.dart';
1717
export 'src/native/adapter_type.dart';
18+
export 'src/native/android/audio_configuration.dart';
19+
export 'src/native/ios/audio_configuration.dart';

lib/src/helper.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import 'package:flutter/foundation.dart';
22

33
import '../flutter_webrtc.dart';
44
import 'native/audio_management.dart';
5-
import 'native/ios/audio_configuration.dart';
65

76
class Helper {
87
static Future<List<MediaDeviceInfo>> enumerateDevices(String type) async {
@@ -122,6 +121,14 @@ class Helper {
122121
static Future<void> setMicrophoneMute(bool mute, MediaStreamTrack track) =>
123122
NativeAudioManagement.setMicrophoneMute(mute, track);
124123

124+
/// Set the audio configuration to for Android.
125+
/// Must be set before initiating a WebRTC session and cannot be changed
126+
/// mid session.
127+
static Future<void> setAndroidAudioConfiguration(
128+
AndroidAudioConfiguration androidAudioConfiguration) =>
129+
AndroidNativeAudioManagement.setAndroidAudioConfiguration(
130+
androidAudioConfiguration);
131+
125132
/// Set the audio configuration for iOS
126133
static Future<void> setAppleAudioConfiguration(
127134
AppleAudioConfiguration appleAudioConfiguration) =>
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import 'package:flutter/foundation.dart';
2+
3+
import '../utils.dart';
4+
5+
enum AndroidAudioMode {
6+
normal,
7+
callScreening,
8+
inCall,
9+
inCommunication,
10+
ringtone,
11+
}
12+
13+
extension AndroidAudioModeExt on AndroidAudioMode {
14+
String get value => describeEnum(this);
15+
}
16+
17+
extension AndroidAudioModeEnumEx on String {
18+
AndroidAudioMode toAndroidAudioMode() => AndroidAudioMode.values
19+
.firstWhere((d) => describeEnum(d) == toLowerCase());
20+
}
21+
22+
enum AndroidAudioFocusMode {
23+
gain,
24+
gainTransient,
25+
gainTransientExclusive,
26+
gainTransientMayDuck,
27+
}
28+
29+
extension AndroidAudioFocusModeExt on AndroidAudioFocusMode {
30+
String get value => describeEnum(this);
31+
}
32+
33+
extension AndroidAudioFocusModeEnumEx on String {
34+
AndroidAudioFocusMode toAndroidAudioFocusMode() =>
35 DE90 +
AndroidAudioFocusMode.values
36+
.firstWhere((d) => describeEnum(d) == toLowerCase());
37+
}
38+
39+
class AndroidAudioConfiguration {
40+
AndroidAudioConfiguration({
41+
this.androidAudioMode,
42+
this.androidAudioFocusMode,
43+
});
44+
final AndroidAudioMode? androidAudioMode;
45+
final AndroidAudioFocusMode? androidAudioFocusMode;
46+
47+
Map<String, dynamic> toMap() => <String, dynamic>{
48+
if (androidAudioMode != null)
49+
'androidAudioMode': androidAudioMode!.value,
50+
if (androidAudioFocusMode != null)
51+
'androidAudioFocusMode': androidAudioFocusMode!.value,
52+
};
53+
}
54+
55+
class AndroidNativeAudioManagement {
56+
static Future<void> setAndroidAudioConfiguration(
57+
AndroidAudioConfiguration config) async {
58+
if (WebRTC.platformIsAndroid) {
59+
await WebRTC.invokeMethod(
60+
'setAndroidAudioConfiguration',
61+
<String, dynamic>{'configuration': config.toMap()},
62+
);
63+
}
64+
}
65+
}

0 commit comments

Comments
 (0)
0