@livekit/react-native 1.1.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -29,7 +29,7 @@ This library depends on `@livekit/react-native-webrtc`, which has additional ins
29
29
  - [iOS Installation Guide](https://github.com/livekit/react-native-webrtc/blob/master/Documentation/iOSInstallation.md)
30
30
  - [Android Installation Guide](https://github.com/livekit/react-native-webrtc/blob/master/Documentation/AndroidInstallation.md)
31
31
 
32
- ----
32
+ ---
33
33
 
34
34
  Once the `@livekit/react-native-webrtc` dependency is installed, one last step is needed to finish the installation:
35
35
 
@@ -45,7 +45,7 @@ public class MainApplication extends Application implements ReactApplication {
45
45
  @Override
46
46
  public void onCreate() {
47
47
  // Place this above any other RN related initialization
48
- LiveKitReactNative.setup();
48
+ LiveKitReactNative.setup(this);
49
49
 
50
50
  //...
51
51
  }
@@ -106,8 +106,12 @@ const [room] = useState(() => new Room());
106
106
  const { participants } = useRoom(room);
107
107
 
108
108
  useEffect(() => {
109
- AudioSession.startAudioSession();
110
- room.connect(url, token, {});
109
+ let connect = async () => {
110
+ await AudioSession.startAudioSession();
111
+ await room.connect(url, token, {});
112
+ console.log('connected to ', url, ' ', token);
113
+ };
114
+ connect();
111
115
  return () => {
112
116
  room.disconnect();
113
117
  AudioSession.stopAudioSession();
@@ -126,6 +130,40 @@ const videoView = participants.length > 0 && (
126
130
 
127
131
  Additional documentation for the LiveKit SDK can be found at https://docs.livekit.io/references/client-sdks/
128
132
 
133
+ ## Audio sessions
134
+
135
+ As seen in the above example, we've introduced a new class `AudioSession` that helps
136
+ to manage the audio session on native platforms. This class wraps either [AudioManager](https://developer.android.com/reference/android/media/AudioManager) on Android, or [AVAudioSession](https://developer.apple.com/documentation/avfaudio/avaudiosession) on iOS.
137
+
138
+ You can customize the configuration of the audio session with `configureAudio`.
139
+
140
+ ```js
141
+ useEffect(() => {
142
+ let connect = async () => {
143
+ // configure audio session prior to starting it.
144
+ await AudioSession.configureAudio({
145
+ android: {
146
+ preferredOutputList: ['earpiece'],
147
+ // See [AudioManager](https://developer.android.com/reference/android/media/AudioManager)
148
+ // for details on audio and focus modes.
149
+ audioMode: 'normal',
150
+ audioFocusMode: 'gain',
151
+ },
152
+ ios: {
153
+ defaultOutput: 'earpiece',
154
+ },
155
+ });
156
+ await AudioSession.startAudioSession();
157
+ await room.connect(url, token, {});
158
+ };
159
+ connect();
160
+ return () => {
161
+ room.disconnect();
162
+ AudioSession.stopAudioSession();
163
+ };
164
+ }, [url, token, room]);
165
+ ```
166
+
129
167
  ## Screenshare
130
168
 
131
169
  Enabling screenshare requires extra installation steps:
@@ -196,10 +234,12 @@ See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the
196
234
  Apache License 2.0
197
235
 
198
236
  <!--BEGIN_REPO_NAV-->
237
+
199
238
  <br/><table>
239
+
200
240
  <thead><tr><th colspan="2">LiveKit Ecosystem</th></tr></thead>
201
241
  <tbody>
202
- <tr><td>Client SDKs</td><td><a href="https://github.com/livekit/components-js">Components</a> · <a href="https://github.com/livekit/client-sdk-js">JavaScript</a> · <a href="https://github.com/livekit/client-sdk-rust">Rust</a> · <a href="https://github.com/livekit/client-sdk-swift">iOS/macOS</a> · <a href="https://github.com/livekit/client-sdk-android">Android</a> · <a href="https://github.com/livekit/client-sdk-flutter">Flutter</a> · <a href="https://github.com/livekit/client-sdk-unity-web">Unity (web)</a> · <b>React Native (beta)</b></td></tr><tr></tr>
242
+ <tr><td>Client SDKs</td><td><a href="https://github.com/livekit/components-js">Components</a> · <a href="https://github.com/livekit/client-sdk-js">JavaScript</a> · <a href="https://github.com/livekit/client-sdk-swift">iOS/macOS</a> · <a href="https://github.com/livekit/client-sdk-android">Android</a> · <a href="https://github.com/livekit/client-sdk-flutter">Flutter</a> · <b>React Native</b> · <a href="https://github.com/livekit/client-sdk-rust">Rust</a> · <a href="https://github.com/livekit/client-sdk-python">Python</a> · <a href="https://github.com/livekit/client-sdk-unity-web">Unity (web)</a> · <a href="https://github.com/livekit/client-sdk-unity">Unity (beta)</a></td></tr><tr></tr>
203
243
  <tr><td>Server SDKs</td><td><a href="https://github.com/livekit/server-sdk-js">Node.js</a> · <a href="https://github.com/livekit/server-sdk-go">Golang</a> · <a href="https://github.com/livekit/server-sdk-ruby">Ruby</a> · <a href="https://github.com/livekit/server-sdk-kotlin">Java/Kotlin</a> · <a href="https://github.com/agence104/livekit-server-sdk-php">PHP (community)</a> · <a href="https://github.com/tradablebits/livekit-server-sdk-python">Python (community)</a></td></tr><tr></tr>
204
244
  <tr><td>Services</td><td><a href="https://github.com/livekit/livekit">Livekit server</a> · <a href="https://github.com/livekit/egress">Egress</a> · <a href="https://github.com/livekit/ingress">Ingress</a></td></tr><tr></tr>
205
245
  <tr><td>Resources</td><td><a href="https://docs.livekit.io">Docs</a> · <a href="https://github.com/livekit-examples">Example apps</a> · <a href="https://livekit.io/cloud">Cloud</a> · <a href="https://docs.livekit.io/oss/deployment">Self-hosting</a> · <a href="https://github.com/livekit/livekit-cli">CLI</a></td></tr>
@@ -129,8 +129,8 @@ dependencies {
129
129
  // noinspection GradleDynamicVersion
130
130
  api 'com.facebook.react:react-native:+'
131
131
  implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
132
- api 'com.github.davidliu:audioswitch:c498d866c57f1d88056d5e7e7a78d622e3b0c046'
133
- api 'io.github.webrtc-sdk:android:104.5112.09'
132
+ api 'com.github.davidliu:audioswitch:d18e3e31d427c27f1593030e024b370bf24480fd'
133
+ api 'io.github.webrtc-sdk:android:104.5112.10'
134
134
  implementation project(':livekit_react-native-webrtc')
135
135
  implementation "androidx.annotation:annotation:1.4.0"
136
136
  }
@@ -1,16 +1,35 @@
1
1
  package com.livekit.reactnative
2
2
 
3
+ import android.app.Application
4
+ import android.content.Context
5
+ import android.os.Build
6
+ import com.livekit.reactnative.audio.AudioType
3
7
  import com.livekit.reactnative.video.SimulcastVideoEncoderFactoryWrapper
4
8
  import com.livekit.reactnative.video.WrappedVideoDecoderFactoryProxy
5
9
  import com.oney.WebRTCModule.WebRTCModuleOptions
6
-
10
+ import org.webrtc.audio.JavaAudioDeviceModule
7
11
 
8
12
  object LiveKitReactNative {
9
13
 
14
+ /**
15
+ * Initializes components required for LiveKit to work on Android.
16
+ *
17
+ * Must be called from your [Application.onCreate] method before any other react-native
18
+ * initialization.
19
+ */
10
20
  @JvmStatic
11
- fun setup() {
21
+ @JvmOverloads
22
+ fun setup(context: Context, audioType: AudioType = AudioType.CommunicationAudioType()) {
12
23
  val options = WebRTCModuleOptions.getInstance()
13
24
  options.videoEncoderFactory = SimulcastVideoEncoderFactoryWrapper(null, true, true)
14
25
  options.videoDecoderFactory = WrappedVideoDecoderFactoryProxy()
26
+
27
+ val useHardwareAudioProcessing = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
28
+
29
+ options.audioDeviceModule = JavaAudioDeviceModule.builder(context)
30
+ .setUseHardwareAcousticEchoCanceler(useHardwareAudioProcessing)
31
+ .setUseHardwareNoiseSuppressor(useHardwareAudioProcessing)
32
+ .setAudioAttributes(audioType.audioAttributes)
33
+ .createAudioDeviceModule()
15
34
  }
16
35
  }
@@ -1,7 +1,10 @@
1
1
  package com.livekit.reactnative
2
2
 
3
+ import android.annotation.SuppressLint
4
+ import android.content.Context
3
5
  import com.facebook.react.bridge.*
4
6
  import com.livekit.reactnative.audio.AudioDeviceKind
7
+ import com.livekit.reactnative.audio.AudioManagerUtils
5
8
  import com.livekit.reactnative.audio.AudioSwitchManager
6
9
 
7
10
 
@@ -16,12 +19,72 @@ class LivekitReactNativeModule(reactContext: ReactApplicationContext) : ReactCon
16
19
  fun configureAudio(config: ReadableMap) {
17
20
  val androidConfig = config.getMap("android") ?: return
18
21
 
19
- androidConfig.getArray("preferredOutputList")?.let { preferredOutputList ->
20
- val preferredDeviceList = preferredOutputList.toArrayList().mapNotNull { output ->
21
- val outputStr = output as? String
22
- AudioDeviceKind.fromTypeName(outputStr)?.audioDeviceClass
22
+ if (androidConfig.hasKey("preferredOutputList")) {
23
+ androidConfig.getArray("preferredOutputList")?.let { preferredOutputList ->
24
+ val preferredDeviceList = preferredOutputList.toArrayList().mapNotNull { output ->
25
+ val outputStr = output as? String
26
+ AudioDeviceKind.fromTypeName(outputStr)?.audioDeviceClass
27
+ }
28
+ audioManager.preferredDeviceList = preferredDeviceList
29
+ }
30
+ }
31
+
32
+ if (androidConfig.hasKey("audioTypeOptions")) {
33
+ val audioTypeOptions = androidConfig.getMap("audioTypeOptions") ?: return
34
+
35
+ if (audioTypeOptions.hasKey("manageAudioFocus")) {
36
+ val manageFocus = audioTypeOptions.getBoolean("manageAudioFocus")
37
+ audioManager.setManageAudioFocus(manageFocus)
38
+ }
39
+ if (audioTypeOptions.hasKey("audioMode")) {
40
+ audioTypeOptions.getString("audioMode")?.let { audioModeString ->
41
+ val audioMode = AudioManagerUtils.audioModeFromString(audioModeString)
42
+ if (audioMode != null) {
43
+ audioManager.setAudioMode(audioMode)
44
+ }
45
+ }
46
+ }
47
+
48
+ if (audioTypeOptions.hasKey("audioFocusMode")) {
49
+ audioTypeOptions.getString("audioFocusMode")?.let { focusModeString ->
50
+ val focusMode = AudioManagerUtils.focusModeFromString(focusModeString)
51
+ if (focusMode != null) {
52
+ audioManager.setFocusMode(focusMode)
53
+ }
54
+ }
55
+ }
56
+
57
+ if (audioTypeOptions.hasKey("audioStreamType")) {
58
+ audioTypeOptions.getString("audioStreamType")?.let { streamTypeString ->
59
+ val streamType = AudioManagerUtils.audioStreamTypeFromString(streamTypeString)
60
+ if (streamType != null) {
61
+ audioManager.setAudioStreamType(streamType)
62
+ }
63
+ }
64
+ }
65
+
66
+ if (audioTypeOptions.hasKey("audioAttributesUsageType")) {
67
+ audioTypeOptions.getString("audioAttributesUsageType")?.let { usageTypeString ->
68
+ val usageType = AudioManagerUtils.audioAttributesUsageTypeFromString(usageTypeString)
69
+ if (usageType != null) {
70
+ audioManager.setAudioAttributesUsageType(usageType)
71
+ }
72
+ }
73
+ }
74
+
75
+ if (audioTypeOptions.hasKey("audioAttributesContentType")) {
76
+ audioTypeOptions.getString("audioAttributesContentType")?.let { contentTypeString ->
77
+ val contentType = AudioManagerUtils.audioAttributesContentTypeFromString(contentTypeString)
78
+ if (contentType != null) {
79
+ audioManager.setAudioAttributesContentType(contentType)
80
+ }
81
+ }
82
+ }
83
+
84
+ if (audioTypeOptions.hasKey("forceHandleAudioRouting")) {
85
+ val force = audioTypeOptions.getBoolean("forceHandleAudioRouting")
86
+ audioManager.setForceHandleAudioRouting(force)
23
87
  }
24
- audioManager.preferredDeviceList = preferredDeviceList
25
88
  }
26
89
  }
27
90
 
@@ -0,0 +1,116 @@
1
+ package com.livekit.reactnative.audio
2
+
3
+ import android.media.AudioAttributes
4
+ import android.media.AudioManager
5
+ import android.util.Log
6
+
7
+
8
+ object AudioManagerUtils {
9
+ private const val TAG = "AudioManagerUtils"
10
+
11
+ fun audioModeFromString(audioModeString: String?): Int? {
12
+ if (audioModeString == null) {
13
+ return null
14
+ }
15
+
16
+ var audioMode: Int? = null
17
+ when (audioModeString) {
18
+ "normal" -> audioMode = AudioManager.MODE_NORMAL
19
+ "callScreening" -> audioMode = AudioManager.MODE_CALL_SCREENING
20
+ "inCall" -> audioMode = AudioManager.MODE_IN_CALL
21
+ "inCommunication" -> audioMode = AudioManager.MODE_IN_COMMUNICATION
22
+ "ringtone" -> audioMode = AudioManager.MODE_RINGTONE
23
+ else -> Log.w(TAG, "Unknown audio mode: $audioModeString")
24
+ }
25
+
26
+ return audioMode
27
+ }
28
+
29
+ fun focusModeFromString(focusModeString: String?): Int? {
30
+ if (focusModeString == null) {
31
+ return null
32
+ }
33
+
34
+ var focusMode: Int? = null
35
+ when (focusModeString) {
36
+ "gain" -> focusMode = AudioManager.AUDIOFOCUS_GAIN
37
+ "gainTransient" -> focusMode = AudioManager.AUDIOFOCUS_GAIN_TRANSIENT
38
+ "gainTransientExclusive" -> focusMode = AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
39
+ "gainTransientMayDuck" -> focusMode = AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
40
+ else -> Log.w(TAG, "Unknown audio focus mode: $focusModeString")
41
+ }
42
+
43
+ return focusMode
44
+ }
45
+
46
+ fun audioAttributesUsageTypeFromString(usageTypeString: String?): Int? {
47
+ if (usageTypeString == null) {
48
+ return null
49
+ }
50
+
51
+ val usageType: Int? = when (usageTypeString) {
52
+ "alarm" -> AudioAttributes.USAGE_ALARM
53
+ "assistanceAccessibility" -> AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY
54
+ "assistanceNavigationGuidance" -> AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE
55
+ "assistanceSonification" -> AudioAttributes.USAGE_ASSISTANCE_SONIFICATION
56
+ "assistant" -> AudioAttributes.USAGE_ASSISTANT
57
+ "game" -> AudioAttributes.USAGE_GAME
58
+ "media" -> AudioAttributes.USAGE_MEDIA
59
+ "notification" -> AudioAttributes.USAGE_NOTIFICATION
60
+ "notificationEvent" -> AudioAttributes.USAGE_NOTIFICATION_EVENT
61
+ "notificationRingtone" -> AudioAttributes.USAGE_NOTIFICATION_RINGTONE
62
+ "unknown" -> AudioAttributes.USAGE_UNKNOWN
63
+ "voiceCommunication" -> AudioAttributes.USAGE_VOICE_COMMUNICATION
64
+ "voiceCommunicationSignalling" -> AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING
65
+ else -> {
66
+ Log.w(TAG, "Unknown audio attributes usage type: $usageTypeString")
67
+ null
68
+ }
69
+ }
70
+
71
+ return usageType
72
+ }
73
+
74
+ fun audioAttributesContentTypeFromString(contentTypeString: String?): Int? {
75
+ if (contentTypeString == null) {
76
+ return null
77
+ }
78
+
79
+ val contentType = when (contentTypeString) {
80
+ "movie" -> AudioAttributes.CONTENT_TYPE_MOVIE
81
+ "music" -> AudioAttributes.CONTENT_TYPE_MUSIC
82
+ "sonification" -> AudioAttributes.CONTENT_TYPE_SONIFICATION
83
+ "speech" -> AudioAttributes.CONTENT_TYPE_SPEECH
84
+ "unknown" -> AudioAttributes.CONTENT_TYPE_UNKNOWN
85
+ else -> {
86
+ Log.w(TAG, "Unknown audio attributes content type: $contentTypeString")
87
+ null
88
+ }
89
+ }
90
+
91
+ return contentType
92
+ }
93
+
94
+ fun audioStreamTypeFromString(streamTypeString: String?): Int? {
95
+ if (streamTypeString == null) {
96
+ return null
97
+ }
98
+
99
+ val streamType = when (streamTypeString) {
100
+ "accessibility" -> AudioManager.STREAM_ACCESSIBILITY
101
+ "alarm" -> AudioManager.STREAM_ALARM
102
+ "dtmf" -> AudioManager.STREAM_DTMF
103
+ "music" -> AudioManager.STREAM_MUSIC
104
+ "notification" -> AudioManager.STREAM_NOTIFICATION
105
+ "ring" -> AudioManager.STREAM_RING
106
+ "system" -> AudioManager.STREAM_SYSTEM
107
+ "voiceCall" -> AudioManager.STREAM_VOICE_CALL
108
+ else -> {
109
+ Log.w(TAG, "Unknown audio stream type: $streamTypeString")
110
+ null
111
+ }
112
+ }
113
+
114
+ return streamType
115
+ }
116
+ }
@@ -1,6 +1,7 @@
1
1
  package com.livekit.reactnative.audio;
2
2
 
3
3
  import android.content.Context;
4
+ import android.media.AudioAttributes;
4
5
  import android.media.AudioManager;
5
6
  import android.os.Handler;
6
7
  import android.os.Looper;
@@ -14,6 +15,7 @@ import com.twilio.audioswitch.AudioSwitch;
14
15
  import java.util.ArrayList;
15
16
  import java.util.Collections;
16
17
  import java.util.List;
18
+ import java.util.Objects;
17
19
 
18
20
  import kotlin.Unit;
19
21
  import kotlin.jvm.functions.Function2;
@@ -32,7 +34,8 @@ public class AudioSwitchManager {
32
34
  Unit> audioDeviceChangeListener = (devices, currentDevice) -> null;
33
35
 
34
36
  @NonNull
35
- public AudioManager.OnAudioFocusChangeListener audioFocusChangeListener = (i -> {});
37
+ public AudioManager.OnAudioFocusChangeListener audioFocusChangeListener = (i -> {
38
+ });
36
39
 
37
40
  @NonNull
38
41
  public List<Class<? extends AudioDevice>> preferredDeviceList;
@@ -43,6 +46,73 @@ public class AudioSwitchManager {
43
46
  @Nullable
44
47
  private AudioSwitch audioSwitch;
45
48
 
49
+ /**
50
+ * When true, AudioSwitchHandler will request audio focus on start and abandon on stop.
51
+ *
52
+ * Defaults to true.
53
+ */
54
+ private boolean manageAudioFocus = true;
55
+
56
+ /**
57
+ * The audio focus mode to use while started.
58
+ *
59
+ * Defaults to [AudioManager.AUDIOFOCUS_GAIN].
60
+ */
61
+ private int focusMode = AudioManager.AUDIOFOCUS_GAIN;
62
+
63
+ /**
64
+ * The audio mode to use while started.
65
+ *
66
+ * Defaults to AudioManager.MODE_IN_COMMUNICATION.
67
+ */
68
+ private int audioMode = AudioManager.MODE_IN_COMMUNICATION;
69
+
70
+ /**
71
+ * The audio stream type to use when requesting audio focus on pre-O devices.
72
+ *
73
+ * Defaults to [AudioManager.STREAM_VOICE_CALL].
74
+ *
75
+ * Refer to this [compatibility table](https://source.android.com/docs/core/audio/attributes#compatibility)
76
+ * to ensure that your values match between android versions.
77
+ *
78
+ * Note: Manual audio routing may not work appropriately when using non-default values.
79
+ */
80
+ private int audioStreamType = AudioManager.STREAM_VOICE_CALL;
81
+
82
+ /**
83
+ * The audio attribute usage type to use when requesting audio focus on devices O and beyond.
84
+ *
85
+ * Defaults to [AudioAttributes.USAGE_VOICE_COMMUNICATION].
86
+ *
87
+ * Refer to this [compatibility table](https://source.android.com/docs/core/audio/attributes#compatibility)
88
+ * to ensure that your values match between android versions.
89
+ *
90
+ * Note: Manual audio routing may not work appropriately when using non-default values.
91
+ */
92
+ private int audioAttributeUsageType = AudioAttributes.USAGE_VOICE_COMMUNICATION;
93
+
94
+ /**
95
+ * The audio attribute content type to use when requesting audio focus on devices O and beyond.
96
+ *
97
+ * Defaults to [AudioAttributes.CONTENT_TYPE_SPEECH].
98
+ *
99
+ * Refer to this [compatibility table](https://source.android.com/docs/core/audio/attributes#compatibility)
100
+ * to ensure that your values match between android versions.
101
+ *
102
+ * Note: Manual audio routing may not work appropriately when using non-default values.
103
+ */
104
+ private int audioAttributeContentType = AudioAttributes.CONTENT_TYPE_SPEECH;
105
+
106
+ /**
107
+ * On certain Android devices, audio routing does not function properly and bluetooth microphones will not work
108
+ * unless audio mode is set to [AudioManager.MODE_IN_COMMUNICATION] or [AudioManager.MODE_IN_CALL].
109
+ *
110
+ * AudioSwitchManager by default will not handle audio routing in those cases to avoid audio issues.
111
+ *
112
+ * If this set to true, AudioSwitchManager will attempt to do audio routing, though behavior is undefined.
113
+ */
114
+ private boolean forceHandleAudioRouting = false;
115
+
46
116
  public AudioSwitchManager(@NonNull Context context) {
47
117
  this.context = context;
48
118
  this.audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
@@ -64,6 +134,13 @@ public class AudioSwitchManager {
64
134
  audioFocusChangeListener,
65
135
  preferredDeviceList
66
136
  );
137
+ audioSwitch.setManageAudioFocus(manageAudioFocus);
138
+ audioSwitch.setFocusMode(focusMode);
139
+ audioSwitch.setAudioMode(audioMode);
140
+ audioSwitch.setAudioStreamType(audioStreamType);
141
+ audioSwitch.setAudioAttributeContentType(audioAttributeContentType);
142
+ audioSwitch.setAudioAttributeUsageType(audioAttributeUsageType);
143
+ audioSwitch.setForceHandleAudioRouting(forceHandleAudioRouting);
67
144
  audioSwitch.start(audioDeviceChangeListener);
68
145
  audioSwitch.activate();
69
146
  });
@@ -80,7 +157,7 @@ public class AudioSwitchManager {
80
157
  });
81
158
  }
82
159
 
83
- public void setMicrophoneMute(boolean mute){
160
+ public void setMicrophoneMute(boolean mute) {
84
161
  audioManager.setMicrophoneMute(mute);
85
162
  }
86
163
 
@@ -125,16 +202,65 @@ public class AudioSwitchManager {
125
202
  }
126
203
 
127
204
  public void enableSpeakerphone(boolean enable) {
128
- if(enable) {
205
+ if (enable) {
129
206
  audioManager.setSpeakerphoneOn(true);
130
207
  } else {
131
208
  audioManager.setSpeakerphoneOn(false);
132
209
  }
133
210
  }
134
-
211
+
135
212
  public void selectAudioOutput(@Nullable AudioDeviceKind kind) {
136
213
  if (kind != null) {
137
214
  selectAudioOutput(kind.audioDeviceClass);
138
215
  }
139
216
  }
217
+
218
+ public void setManageAudioFocus(boolean manage) {
219
+ this.manageAudioFocus = manage;
220
+ if (audioSwitch != null) {
221
+ Objects.requireNonNull(audioSwitch).setManageAudioFocus(this.manageAudioFocus);
222
+ }
223
+ }
224
+
225
+ public void setFocusMode(int focusMode) {
226
+ this.focusMode = focusMode;
227
+ if (audioSwitch != null) {
228
+ Objects.requireNonNull(audioSwitch).setFocusMode(this.focusMode);
229
+ }
230
+ }
231
+
232
+ public void setAudioMode(int audioMode) {
233
+ this.audioMode = audioMode;
234
+ if (audioSwitch != null) {
235
+ Objects.requireNonNull(audioSwitch).setAudioMode(this.audioMode);
236
+ }
237
+ }
238
+
239
+ public void setAudioStreamType(int streamType) {
240
+ this.audioStreamType = streamType;
241
+ if (audioSwitch != null) {
242
+ Objects.requireNonNull(audioSwitch).setAudioStreamType(this.audioStreamType);
243
+ }
244
+ }
245
+
246
+ public void setAudioAttributesUsageType(int usageType) {
247
+ this.audioAttributeUsageType = usageType;
248
+ if (audioSwitch != null) {
249
+ Objects.requireNonNull(audioSwitch).setAudioAttributeUsageType(this.audioAttributeUsageType);
250
+ }
251
+ }
252
+
253
+ public void setAudioAttributesContentType(int contentType) {
254
+ this.audioAttributeContentType = contentType;
255
+ if (audioSwitch != null) {
256
+ Objects.requireNonNull(audioSwitch).setAudioAttributeContentType(this.audioAttributeContentType);
257
+ }
258
+ }
259
+
260
+ public void setForceHandleAudioRouting(boolean force) {
261
+ this.forceHandleAudioRouting = force;
262
+ if (audioSwitch != null) {
263
+ Objects.requireNonNull(audioSwitch).setForceHandleAudioRouting(this.forceHandleAudioRouting);
264
+ }
265
+ }
140
266
  }
@@ -0,0 +1,46 @@
1
+ package com.livekit.reactnative.audio
2
+
3
+ import android.media.AudioAttributes
4
+ import android.media.AudioManager
5
+
6
+ sealed class AudioType(
7
+ val audioMode: Int,
8
+ val audioAttributes: AudioAttributes,
9
+ val audioStreamType: Int
10
+ ) {
11
+ /**
12
+ * An audio type for general media playback usage (i.e. listener-only use cases).
13
+ *
14
+ * Audio routing is handled automatically by the system in normal media mode,
15
+ * and bluetooth microphones may not work on some devices.
16
+ */
17
+ class MediaAudioType : AudioType(
18
+ AudioManager.MODE_NORMAL,
19
+ AudioAttributes.Builder()
20
+ .setUsage(AudioAttributes.USAGE_MEDIA)
21
+ .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
22
+ .build(),
23
+ AudioManager.STREAM_MUSIC
24
+ )
25
+
26
+ /**
27
+ * An audio type for communications (i.e. participating a call or otherwise
28
+ * publishing local microphone).
29
+ *
30
+ * Audio routing can be manually controlled.
31
+ */
32
+ class CommunicationAudioType : AudioType(
33
+ AudioManager.MODE_IN_COMMUNICATION,
34
+ AudioAttributes.Builder()
35
+ .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
36
+ .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
37
+ .build(),
38
+ AudioManager.STREAM_VOICE_CALL
39
+ )
40
+
41
+ /**
42
+ * An audio type that takes in a user-defined [AudioAttributes] and audio stream type.
43
+ */
44
+ class CustomAudioType(audioMode: Int, audioAttributes: AudioAttributes, audioStreamType: Int) :
45
+ AudioType(audioMode, audioAttributes, audioStreamType)
46
+ }
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.default = void 0;
6
+ exports.default = exports.AndroidAudioTypePresets = void 0;
7
7
 
8
8
  var _reactNative = require("react-native");
9
9
 
@@ -29,10 +29,15 @@ const LivekitReactNative = _reactNative.NativeModules.LivekitReactNative ? _reac
29
29
  * This is ignored when an output is manually selected with {@link AudioSession.selectAudioOutput}.
30
30
  *
31
31
  * By default, the order is set to:
32
- * 1. `"speaker"`
33
- * 2. `"earpiece"`
34
- * 3. `"headset"`
35
- * 4. `"bluetooth"`
32
+ * 1. `"bluetooth"
33
+ * 2. `"headset"``
34
+ * 3. `"speaker"`
35
+ * 4. `"earpiece"`
36
+ *
37
+ * * audioTypeOptions - An {@link AndroidAudioTypeOptions} object which provides the
38
+ * audio options to use on Android.
39
+ *
40
+ * See {@link AndroidAudioTypePresets} for pre-configured values.
36
41
  *
37
42
  * ----
38
43
  * iOS
@@ -42,6 +47,26 @@ const LivekitReactNative = _reactNative.NativeModules.LivekitReactNative ? _reac
42
47
  * By default, this is set to `"speaker"`
43
48
  */
44
49
 
50
+ const AndroidAudioTypePresets = {
51
+ communication: {
52
+ manageAudioFocus: true,
53
+ audioMode: 'inCommunication',
54
+ audioFocusMode: 'gain',
55
+ audioStreamType: 'voiceCall',
56
+ audioAttributesUsageType: 'voiceCommunication',
57
+ audioAttributesContentType: 'speech'
58
+ },
59
+ media: {
60
+ manageAudioFocus: true,
61
+ audioMode: 'normal',
62
+ audioFocusMode: 'gain',
63
+ audioStreamType: 'music',
64
+ audioAttributesUsageType: 'media',
65
+ audioAttributesContentType: 'unknown'
66
+ }
67
+ };
68
+ exports.AndroidAudioTypePresets = AndroidAudioTypePresets;
69
+
45
70
  class AudioSession {}
46
71
 
47
72
  exports.default = AudioSession;