@livekit/react-native 1.2.0 → 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
@@ -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
  }
@@ -129,7 +129,7 @@ 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:fb33b237aa50b3d1d2dea0e0695ecb7b38a98971'
132
+ api 'com.github.davidliu:audioswitch:d18e3e31d427c27f1593030e024b370bf24480fd'
133
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"
@@ -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,5 +1,7 @@
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
5
7
  import com.livekit.reactnative.audio.AudioManagerUtils
@@ -17,24 +19,71 @@ class LivekitReactNativeModule(reactContext: ReactApplicationContext) : ReactCon
17
19
  fun configureAudio(config: ReadableMap) {
18
20
  val androidConfig = config.getMap("android") ?: return
19
21
 
20
- androidConfig.getArray("preferredOutputList")?.let { preferredOutputList ->
21
- val preferredDeviceList = preferredOutputList.toArrayList().mapNotNull { output ->
22
- val outputStr = output as? String
23
- 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
24
29
  }
25
- audioManager.preferredDeviceList = preferredDeviceList
26
30
  }
27
31
 
28
- androidConfig.getString("audioMode")?.let { audioModeString ->
29
- val audioMode = AudioManagerUtils.audioModeFromString(audioModeString)
30
- if (audioMode != null) {
31
- audioManager.setAudioMode(audioMode)
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)
32
38
  }
33
- }
34
- androidConfig.getString("audioFocusMode")?.let { focusModeString ->
35
- val focusMode = AudioManagerUtils.focusModeFromString(focusModeString)
36
- if (focusMode != null) {
37
- audioManager.setFocusMode(focusMode)
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)
38
87
  }
39
88
  }
40
89
  }
@@ -1,5 +1,6 @@
1
1
  package com.livekit.reactnative.audio
2
2
 
3
+ import android.media.AudioAttributes
3
4
  import android.media.AudioManager
4
5
  import android.util.Log
5
6
 
@@ -41,4 +42,75 @@ object AudioManagerUtils {
41
42
 
42
43
  return focusMode
43
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
+ }
44
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,13 @@ 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
+
46
56
  /**
47
57
  * The audio focus mode to use while started.
48
58
  *
@@ -53,9 +63,55 @@ public class AudioSwitchManager {
53
63
  /**
54
64
  * The audio mode to use while started.
55
65
  *
56
- * Defaults to [AudioManager.MODE_NORMAL].
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.
57
79
  */
58
- private int audioMode = AudioManager.MODE_NORMAL;
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;
59
115
 
60
116
  public AudioSwitchManager(@NonNull Context context) {
61
117
  this.context = context;
@@ -78,8 +134,13 @@ public class AudioSwitchManager {
78
134
  audioFocusChangeListener,
79
135
  preferredDeviceList
80
136
  );
137
+ audioSwitch.setManageAudioFocus(manageAudioFocus);
81
138
  audioSwitch.setFocusMode(focusMode);
82
139
  audioSwitch.setAudioMode(audioMode);
140
+ audioSwitch.setAudioStreamType(audioStreamType);
141
+ audioSwitch.setAudioAttributeContentType(audioAttributeContentType);
142
+ audioSwitch.setAudioAttributeUsageType(audioAttributeUsageType);
143
+ audioSwitch.setForceHandleAudioRouting(forceHandleAudioRouting);
83
144
  audioSwitch.start(audioDeviceChangeListener);
84
145
  audioSwitch.activate();
85
146
  });
@@ -96,7 +157,7 @@ public class AudioSwitchManager {
96
157
  });
97
158
  }
98
159
 
99
- public void setMicrophoneMute(boolean mute){
160
+ public void setMicrophoneMute(boolean mute) {
100
161
  audioManager.setMicrophoneMute(mute);
101
162
  }
102
163
 
@@ -141,24 +202,65 @@ public class AudioSwitchManager {
141
202
  }
142
203
 
143
204
  public void enableSpeakerphone(boolean enable) {
144
- if(enable) {
205
+ if (enable) {
145
206
  audioManager.setSpeakerphoneOn(true);
146
207
  } else {
147
208
  audioManager.setSpeakerphoneOn(false);
148
209
  }
149
210
  }
150
-
211
+
151
212
  public void selectAudioOutput(@Nullable AudioDeviceKind kind) {
152
213
  if (kind != null) {
153
214
  selectAudioOutput(kind.audioDeviceClass);
154
215
  }
155
216
  }
156
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
+
157
225
  public void setFocusMode(int focusMode) {
158
226
  this.focusMode = focusMode;
227
+ if (audioSwitch != null) {
228
+ Objects.requireNonNull(audioSwitch).setFocusMode(this.focusMode);
229
+ }
159
230
  }
160
231
 
161
232
  public void setAudioMode(int audioMode) {
162
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
+ }
163
265
  }
164
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,17 +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
36
  *
37
- * * audioMode - The audio mode to use for the audio session. Defaults to 'normal'.
37
+ * * audioTypeOptions - An {@link AndroidAudioTypeOptions} object which provides the
38
+ * audio options to use on Android.
38
39
  *
39
- * * audioFocusMode - The focus mode to use for the audio session. Defaults to 'gain'.
40
- *
41
- * See [AudioManager](https://developer.android.com/reference/android/media/AudioManager) for details
42
- * on audio and focus modes.
40
+ * See {@link AndroidAudioTypePresets} for pre-configured values.
43
41
  *
44
42
  * ----
45
43
  * iOS
@@ -49,6 +47,26 @@ const LivekitReactNative = _reactNative.NativeModules.LivekitReactNative ? _reac
49
47
  * By default, this is set to `"speaker"`
50
48
  */
51
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
+
52
70
  class AudioSession {}
53
71
 
54
72
  exports.default = AudioSession;
@@ -1 +1 @@
1
- {"version":3,"sources":["AudioSession.ts"],"names":["LINKING_ERROR","Platform","select","ios","default","LivekitReactNative","NativeModules","Proxy","get","Error","AudioSession","config","configureAudio","startAudioSession","stopAudioSession","OS","getAudioOutputs","deviceId","selectAudioOutput","showAudioRoutePicker"],"mappings":";;;;;;;AAAA;;;;AACA,MAAMA,aAAa,GAChB,gFAAD,GACAC,sBAASC,MAAT,CAAgB;AAAEC,EAAAA,GAAG,EAAE,gCAAP;AAAyCC,EAAAA,OAAO,EAAE;AAAlD,CAAhB,CADA,GAEA,sDAFA,GAGA,6CAJF;AAMA,MAAMC,kBAAkB,GAAGC,2BAAcD,kBAAd,GACvBC,2BAAcD,kBADS,GAEvB,IAAIE,KAAJ,CACE,EADF,EAEE;AACEC,EAAAA,GAAG,GAAG;AACJ,UAAM,IAAIC,KAAJ,CAAUT,aAAV,CAAN;AACD;;AAHH,CAFF,CAFJ;AAWA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAqBe,MAAMU,YAAN,CAAmB;;;;gBAAbA,Y,oBAMK,MAAOC,MAAP,IAAsC;AAC5D,QAAMN,kBAAkB,CAACO,cAAnB,CAAkCD,MAAlC,CAAN;AACD,C;;gBARkBD,Y,uBAaQ,YAAY;AACrC,QAAML,kBAAkB,CAACQ,iBAAnB,EAAN;AACD,C;;gBAfkBH,Y,sBAoBO,YAAY;AACpC,QAAML,kBAAkB,CAACS,gBAAnB,EAAN;AACD,C;;gBAtBkBJ,Y,qBAmDM,YAA+B;AACtD,MAAIT,sBAASc,EAAT,KAAgB,KAApB,EAA2B;AACzB,WAAO,CAAC,SAAD,EAAY,eAAZ,CAAP;AACD,GAFD,MAEO,IAAId,sBAASc,EAAT,KAAgB,SAApB,EAA+B;AACpC,WAAQ,MAAMV,kBAAkB,CAACW,eAAnB,EAAd;AACD,GAFM,MAEA;AACL,WAAO,EAAP;AACD;AACF,C;;gBA3DkBN,Y,uBAoEQ,MAAOO,QAAP,IAA4B;AACrD,QAAMZ,kBAAkB,CAACa,iBAAnB,CAAqCD,QAArC,CAAN;AACD,C;;gBAtEkBP,Y,0BA6EW,YAAY;AACxC,MAAIT,sBAASc,EAAT,KAAgB,KAApB,EAA2B;AACzB,UAAMV,kBAAkB,CAACc,oBAAnB,EAAN;AACD;AACF,C","sourcesContent":["import { NativeModules, Platform } from 'react-native';\nconst LINKING_ERROR =\n `The package '@livekit/react-native' doesn't seem to be linked. Make sure: \\n\\n` +\n Platform.select({ ios: \"- You have run 'pod install'\\n\", default: '' }) +\n '- You rebuilt the app after installing the package\\n' +\n '- You are not using Expo managed workflow\\n';\n\nconst LivekitReactNative = NativeModules.LivekitReactNative\n ? NativeModules.LivekitReactNative\n : new Proxy(\n {},\n {\n get() {\n throw new Error(LINKING_ERROR);\n },\n }\n );\n\n/**\n * Configuration for the underlying AudioSession.\n *\n * ----\n * Android specific options:\n *\n * * preferredOutputList - The preferred order in which to automatically select an audio output.\n * This is ignored when an output is manually selected with {@link AudioSession.selectAudioOutput}.\n *\n * By default, the order is set to:\n * 1. `\"speaker\"`\n * 2. `\"earpiece\"`\n * 3. `\"headset\"`\n * 4. `\"bluetooth\"`\n *\n * * audioMode - The audio mode to use for the audio session. Defaults to 'normal'.\n *\n * * audioFocusMode - The focus mode to use for the audio session. Defaults to 'gain'.\n *\n * See [AudioManager](https://developer.android.com/reference/android/media/AudioManager) for details\n * on audio and focus modes.\n *\n * ----\n * iOS\n *\n * * defaultOutput - The default preferred output to use when a wired headset or bluetooth output is unavailable.\n *\n * By default, this is set to `\"speaker\"`\n */\nexport type AudioConfiguration = {\n android?: {\n preferredOutputList?: ('speaker' | 'earpiece' | 'headset' | 'bluetooth')[];\n audioMode?:\n | 'normal'\n | 'callScreening'\n | 'inCall'\n | 'inCommunication'\n | 'ringtone';\n audioFocusMode?:\n | 'gain'\n | 'gainTransient'\n | 'gainTransientExclusive'\n | 'gainTransientMayDuck';\n };\n ios?: {\n defaultOutput?: 'speaker' | 'earpiece';\n };\n};\n\nexport default class AudioSession {\n /**\n * Applies the provided audio configuration to the underlying AudioSession.\n *\n * Must be called prior to connecting to a Room for the configuration to apply correctly.\n */\n static configureAudio = async (config: AudioConfiguration) => {\n await LivekitReactNative.configureAudio(config);\n };\n\n /**\n * Starts an AudioSession.\n */\n static startAudioSession = async () => {\n await LivekitReactNative.startAudioSession();\n };\n\n /**\n * Stops the existing AudioSession.\n */\n static stopAudioSession = async () => {\n await LivekitReactNative.stopAudioSession();\n };\n\n /**\n * Gets the available audio outputs for use with {@link selectAudioOutput}.\n *\n * {@link startAudioSession} must be called prior to using this method.\n *\n * For Android, will return if available:\n * * \"speaker\"\n * * \"earpiece\"\n * * \"headset\"\n * * \"bluetooth\"\n *\n * Note: For applications targeting SDK versions over 30, the runtime BLUETOOTH_CONNECT\n * permission must be requested to send audio to bluetooth headsets.\n *\n * ----\n *\n * For iOS, due to OS limitations, the only available types are:\n * * \"default\" - Use default iOS audio routing\n * * \"force_speaker\" - Force audio output through speaker\n *\n * See also {@link showAudioRoutePicker} to display a route picker that\n * can choose between other audio devices (i.e. headset/bluetooth/airplay),\n * or use a library like `react-native-avroutepicker` for a native platform\n * control.\n *\n * @returns the available audio output types\n */\n static getAudioOutputs = async (): Promise<string[]> => {\n if (Platform.OS === 'ios') {\n return ['default', 'force_speaker'];\n } else if (Platform.OS === 'android') {\n return (await LivekitReactNative.getAudioOutputs()) as string[];\n } else {\n return [];\n }\n };\n\n /**\n * Select the provided audio output if available.\n *\n * {@link startAudioSession} must be called prior to using this method.\n *\n * @param deviceId A deviceId retrieved from {@link getAudioOutputs}\n */\n static selectAudioOutput = async (deviceId: string) => {\n await LivekitReactNative.selectAudioOutput(deviceId);\n };\n\n /**\n * iOS only, requires iOS 11+.\n *\n * Displays an AVRoutePickerView for the user to choose their audio output.\n */\n static showAudioRoutePicker = async () => {\n if (Platform.OS === 'ios') {\n await LivekitReactNative.showAudioRoutePicker();\n }\n };\n}\n"]}
1
+ {"version":3,"sources":["AudioSession.ts"],"names":["LINKING_ERROR","Platform","select","ios","default","LivekitReactNative","NativeModules","Proxy","get","Error","AndroidAudioTypePresets","communication","manageAudioFocus","audioMode","audioFocusMode","audioStreamType","audioAttributesUsageType","audioAttributesContentType","media","AudioSession","config","configureAudio","startAudioSession","stopAudioSession","OS","getAudioOutputs","deviceId","selectAudioOutput","showAudioRoutePicker"],"mappings":";;;;;;;AAAA;;;;AACA,MAAMA,aAAa,GAChB,gFAAD,GACAC,sBAASC,MAAT,CAAgB;AAAEC,EAAAA,GAAG,EAAE,gCAAP;AAAyCC,EAAAA,OAAO,EAAE;AAAlD,CAAhB,CADA,GAEA,sDAFA,GAGA,6CAJF;AAMA,MAAMC,kBAAkB,GAAGC,2BAAcD,kBAAd,GACvBC,2BAAcD,kBADS,GAEvB,IAAIE,KAAJ,CACE,EADF,EAEE;AACEC,EAAAA,GAAG,GAAG;AACJ,UAAM,IAAIC,KAAJ,CAAUT,aAAV,CAAN;AACD;;AAHH,CAFF,CAFJ;AAWA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AA6GO,MAAMU,uBASZ,GAAG;AACFC,EAAAA,aAAa,EAAE;AACbC,IAAAA,gBAAgB,EAAE,IADL;AAEbC,IAAAA,SAAS,EAAE,iBAFE;AAGbC,IAAAA,cAAc,EAAE,MAHH;AAIbC,IAAAA,eAAe,EAAE,WAJJ;AAKbC,IAAAA,wBAAwB,EAAE,oBALb;AAMbC,IAAAA,0BAA0B,EAAE;AANf,GADb;AASFC,EAAAA,KAAK,EAAE;AACLN,IAAAA,gBAAgB,EAAE,IADb;AAELC,IAAAA,SAAS,EAAE,QAFN;AAGLC,IAAAA,cAAc,EAAE,MAHX;AAILC,IAAAA,eAAe,EAAE,OAJZ;AAKLC,IAAAA,wBAAwB,EAAE,OALrB;AAMLC,IAAAA,0BAA0B,EAAE;AANvB;AATL,CATG;;;AA4BQ,MAAME,YAAN,CAAmB;;;;gBAAbA,Y,oBAMK,MAAOC,MAAP,IAAsC;AAC5D,QAAMf,kBAAkB,CAACgB,cAAnB,CAAkCD,MAAlC,CAAN;AACD,C;;gBARkBD,Y,uBAaQ,YAAY;AACrC,QAAMd,kBAAkB,CAACiB,iBAAnB,EAAN;AACD,C;;gBAfkBH,Y,sBAoBO,YAAY;AACpC,QAAMd,kBAAkB,CAACkB,gBAAnB,EAAN;AACD,C;;gBAtBkBJ,Y,qBAgDM,YAA+B;AACtD,MAAIlB,sBAASuB,EAAT,KAAgB,KAApB,EAA2B;AACzB,WAAO,CAAC,SAAD,EAAY,eAAZ,CAAP;AACD,GAFD,MAEO,IAAIvB,sBAASuB,EAAT,KAAgB,SAApB,EAA+B;AACpC,WAAQ,MAAMnB,kBAAkB,CAACoB,eAAnB,EAAd;AACD,GAFM,MAEA;AACL,WAAO,EAAP;AACD;AACF,C;;gBAxDkBN,Y,uBAiEQ,MAAOO,QAAP,IAA4B;AACrD,QAAMrB,kBAAkB,CAACsB,iBAAnB,CAAqCD,QAArC,CAAN;AACD,C;;gBAnEkBP,Y,0BA0EW,YAAY;AACxC,MAAIlB,sBAASuB,EAAT,KAAgB,KAApB,EAA2B;AACzB,UAAMnB,kBAAkB,CAACuB,oBAAnB,EAAN;AACD;AACF,C","sourcesContent":["import { NativeModules, Platform } from 'react-native';\nconst LINKING_ERROR =\n `The package '@livekit/react-native' doesn't seem to be linked. Make sure: \\n\\n` +\n Platform.select({ ios: \"- You have run 'pod install'\\n\", default: '' }) +\n '- You rebuilt the app after installing the package\\n' +\n '- You are not using Expo managed workflow\\n';\n\nconst LivekitReactNative = NativeModules.LivekitReactNative\n ? NativeModules.LivekitReactNative\n : new Proxy(\n {},\n {\n get() {\n throw new Error(LINKING_ERROR);\n },\n }\n );\n\n/**\n * Configuration for the underlying AudioSession.\n *\n * ----\n * Android specific options:\n *\n * * preferredOutputList - The preferred order in which to automatically select an audio output.\n * This is ignored when an output is manually selected with {@link AudioSession.selectAudioOutput}.\n *\n * By default, the order is set to:\n * 1. `\"bluetooth\"\n * 2. `\"headset\"``\n * 3. `\"speaker\"`\n * 4. `\"earpiece\"`\n *\n * * audioTypeOptions - An {@link AndroidAudioTypeOptions} object which provides the\n * audio options to use on Android.\n *\n * See {@link AndroidAudioTypePresets} for pre-configured values.\n *\n * ----\n * iOS\n *\n * * defaultOutput - The default preferred output to use when a wired headset or bluetooth output is unavailable.\n *\n * By default, this is set to `\"speaker\"`\n */\nexport type AudioConfiguration = {\n android?: {\n preferredOutputList?: ('speaker' | 'earpiece' | 'headset' | 'bluetooth')[];\n audioTypeOptions: AndroidAudioTypeOptions;\n };\n ios?: {\n defaultOutput?: 'speaker' | 'earpiece';\n };\n};\n\nexport type AndroidAudioTypeOptions = {\n /**\n * Whether LiveKit should handle managing the audio focus or not.\n *\n * Defaults to true.\n */\n manageAudioFocus?: boolean;\n\n /**\n * Corresponds to {@link https://developer.android.com/reference/android/media/AudioManager#setMode(int)}\n *\n * Defaults to 'inCommunication'.\n */\n audioMode?:\n | 'normal'\n | 'callScreening'\n | 'inCall'\n | 'inCommunication'\n | 'ringtone';\n\n /**\n * Corresponds to the duration hint when requesting audio focus.\n *\n * Defaults to 'gain'.\n *\n * See also {@link https://developer.android.com/reference/android/media/AudioManager#AUDIOFOCUS_GAIN}\n */\n audioFocusMode?:\n | 'gain'\n | 'gainTransient'\n | 'gainTransientExclusive'\n | 'gainTransientMayDuck';\n\n /**\n * Corresponds to Android's AudioAttributes usage type.\n *\n * Defaults to 'voiceCommunication'.\n *\n * See also {@link https://developer.android.com/reference/android/media/AudioAttributes}\n */\n audioAttributesUsageType?:\n | 'alarm'\n | 'assistanceAccessibility'\n | 'assistanceNavigationGuidance'\n | 'assistanceSonification'\n | 'assistant'\n | 'game'\n | 'media'\n | 'notification'\n | 'notificationEvent'\n | 'notificationRingtone'\n | 'unknown'\n | 'voiceCommunication'\n | 'voiceCommunicationSignalling';\n\n /**\n * Corresponds to Android's AndroidAttributes content type.\n *\n * Defaults to 'speech'.\n *\n * See also {@link https://developer.android.com/reference/android/media/AudioAttributes}\n */\n audioAttributesContentType?:\n | 'movie'\n | 'music'\n | 'sonification'\n | 'speech'\n | 'unknown';\n\n /**\n * Corresponds to the stream type when requesting audio focus. Used on pre-O devices.\n *\n * Defaults to 'voiceCall'\n *\n * See also {@link https://developer.android.com/reference/android/media/AudioManager#STREAM_VOICE_CALL}\n */\n audioStreamType?:\n | 'accessibility'\n | 'alarm'\n | 'dtmf'\n | 'music'\n | 'notification'\n | 'ring'\n | 'system'\n | 'voiceCall';\n\n /**\n * On certain Android devices, audio routing does not function properly and\n * bluetooth microphones will not work unless audio mode is set to\n * `inCommunication` or `inCall`. Audio routing is turned off those cases.\n *\n * If this set to true, will attempt to do audio routing regardless of audio mode.\n *\n * Defaults to false.\n */\n forceHandleAudioRouting?: boolean;\n};\n\nexport const AndroidAudioTypePresets: {\n /**\n * A pre-configured AndroidAudioConfiguration for voice communication.\n */\n communication: AndroidAudioTypeOptions;\n /**\n * A pre-configured AndroidAudioConfiguration for media playback.\n */\n media: AndroidAudioTypeOptions;\n} = {\n communication: {\n manageAudioFocus: true,\n audioMode: 'inCommunication',\n audioFocusMode: 'gain',\n audioStreamType: 'voiceCall',\n audioAttributesUsageType: 'voiceCommunication',\n audioAttributesContentType: 'speech',\n },\n media: {\n manageAudioFocus: true,\n audioMode: 'normal',\n audioFocusMode: 'gain',\n audioStreamType: 'music',\n audioAttributesUsageType: 'media',\n audioAttributesContentType: 'unknown',\n },\n} as const;\n\nexport default class AudioSession {\n /**\n * Applies the provided audio configuration to the underlying AudioSession.\n *\n * Must be called prior to connecting to a Room for the configuration to apply correctly.\n */\n static configureAudio = async (config: AudioConfiguration) => {\n await LivekitReactNative.configureAudio(config);\n };\n\n /**\n * Starts an AudioSession.\n */\n static startAudioSession = async () => {\n await LivekitReactNative.startAudioSession();\n };\n\n /**\n * Stops the existing AudioSession.\n */\n static stopAudioSession = async () => {\n await LivekitReactNative.stopAudioSession();\n };\n\n /**\n * Gets the available audio outputs for use with {@link selectAudioOutput}.\n *\n * {@link startAudioSession} must be called prior to using this method.\n *\n * For Android, will return if available:\n * * \"speaker\"\n * * \"earpiece\"\n * * \"headset\"\n * * \"bluetooth\"\n *\n * ----\n *\n * For iOS, due to OS limitations, the only available types are:\n * * \"default\" - Use default iOS audio routing\n * * \"force_speaker\" - Force audio output through speaker\n *\n * See also {@link showAudioRoutePicker} to display a route picker that\n * can choose between other audio devices (i.e. headset/bluetooth/airplay),\n * or use a library like `react-native-avroutepicker` for a native platform\n * control.\n *\n * @returns the available audio output types\n */\n static getAudioOutputs = async (): Promise<string[]> => {\n if (Platform.OS === 'ios') {\n return ['default', 'force_speaker'];\n } else if (Platform.OS === 'android') {\n return (await LivekitReactNative.getAudioOutputs()) as string[];\n } else {\n return [];\n }\n };\n\n /**\n * Select the provided audio output if available.\n *\n * {@link startAudioSession} must be called prior to using this method.\n *\n * @param deviceId A deviceId retrieved from {@link getAudioOutputs}\n */\n static selectAudioOutput = async (deviceId: string) => {\n await LivekitReactNative.selectAudioOutput(deviceId);\n };\n\n /**\n * iOS only, requires iOS 11+.\n *\n * Displays an AVRoutePickerView for the user to choose their audio output.\n */\n static showAudioRoutePicker = async () => {\n if (Platform.OS === 'ios') {\n await LivekitReactNative.showAudioRoutePicker();\n }\n };\n}\n"]}
@@ -5,8 +5,22 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  var _exportNames = {
7
7
  registerGlobals: true,
8
- AudioSession: true
8
+ AudioSession: true,
9
+ AndroidAudioTypePresets: true,
10
+ AndroidAudioTypeOptions: true
9
11
  };
12
+ Object.defineProperty(exports, "AndroidAudioTypeOptions", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _AudioSession.AndroidAudioTypeOptions;
16
+ }
17
+ });
18
+ Object.defineProperty(exports, "AndroidAudioTypePresets", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _AudioSession.AndroidAudioTypePresets;
22
+ }
23
+ });
10
24
  Object.defineProperty(exports, "AudioSession", {
11
25
  enumerable: true,
12
26
  get: function () {
@@ -19,7 +33,9 @@ var _reactNativeWebrtc = require("@livekit/react-native-webrtc");
19
33
 
20
34
  var _reactNativeUrlPolyfill = require("react-native-url-polyfill");
21
35
 
22
- var _AudioSession = _interopRequireDefault(require("./audio/AudioSession"));
36
+ require("fastestsmallesttextencoderdecoder");
37
+
38
+ var _AudioSession = _interopRequireWildcard(require("./audio/AudioSession"));
23
39
 
24
40
  var _reactNative = require("react-native");
25
41
 
@@ -65,7 +81,9 @@ Object.keys(_useRoom).forEach(function (key) {
65
81
  });
66
82
  });
67
83
 
68
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
84
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
85
+
86
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
69
87
 
70
88
  /**
71
89
  * Registers the required globals needed for LiveKit to work.
@@ -79,6 +97,8 @@ function registerGlobals() {
79
97
  fixWebrtcAdapter();
80
98
  shimPromiseAllSettled();
81
99
  shimArrayAt();
100
+ shimAsyncIterator();
101
+ shimIterator();
82
102
  }
83
103
 
84
104
  function livekitRegisterGlobals() {
@@ -122,4 +142,16 @@ function shimArrayAt() {
122
142
  at.shim();
123
143
  }
124
144
  }
145
+
146
+ function shimAsyncIterator() {
147
+ var shim = require('well-known-symbols/Symbol.asyncIterator/shim');
148
+
149
+ shim();
150
+ }
151
+
152
+ function shimIterator() {
153
+ var shim = require('well-known-symbols/Symbol.iterator/shim');
154
+
155
+ shim();
156
+ }
125
157
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["index.tsx"],"names":["registerGlobals","livekitRegisterGlobals","fixWebrtcAdapter","shimPromiseAllSettled","shimArrayAt","lkGlobal","platform","Platform","OS","devicePixelRatio","PixelRatio","get","global","LiveKitReactNativeGlobal","window","navigator","undefined","userAgent","product","allSettled","require","shim","Array","prototype","at"],"mappings":";;;;;;;;;;;;;;;;;AAAA;;AACA;;AACA;;AAEA;;AAkDA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AACA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AACA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;AAjDA;AACA;AACA;AACA;AACA;AACO,SAASA,eAAT,GAA2B;AAChC;AACAC,EAAAA,sBAAsB;AACtB;AACAC,EAAAA,gBAAgB;AAChBC,EAAAA,qBAAqB;AACrBC,EAAAA,WAAW;AACZ;;AACD,SAASH,sBAAT,GAAkC;AAChC,MAAII,QAAgC,GAAG;AACrCC,IAAAA,QAAQ,EAAEC,sBAASC,EADkB;AAErCC,IAAAA,gBAAgB,EAAEC,wBAAWC,GAAX;AAFmB,GAAvC,CADgC,CAMhC;;AACAC,EAAAA,MAAM,CAACC,wBAAP,GAAkCR,QAAlC;AACD;;AAED,SAASH,gBAAT,GAA4B;AAAA;;AAC1B;AACA,MAAI,YAAAY,MAAM,UAAN,0CAAQC,SAAR,MAAsBC,SAA1B,EAAqC;AACnC;AACA,UAAM;AAAED,MAAAA;AAAF,QAAgBD,MAAtB;;AACA,QAAIC,SAAS,CAACE,SAAV,KAAwBD,SAA5B,EAAuC;AAAA;;AACrCD,MAAAA,SAAS,CAACE,SAAV,yBAAsBF,SAAS,CAACG,OAAhC,mEAA2C,SAA3C;AACD;AACF;AACF;;AAED,SAASf,qBAAT,GAAiC;AAC/B,MAAIgB,UAAU,GAAGC,OAAO,CAAC,oBAAD,CAAxB;;AACAD,EAAAA,UAAU,CAACE,IAAX;AACD;;AAED,SAASjB,WAAT,GAAuB;AACrB;AACA,MAAI,CAACkB,KAAK,CAACC,SAAN,CAAgBC,EAArB,EAAyB;AACvB,QAAIA,EAAE,GAAGJ,OAAO,CAAC,oBAAD,CAAhB;;AACAI,IAAAA,EAAE,CAACH,IAAH;AACD;AACF","sourcesContent":["import { registerGlobals as webrtcRegisterGlobals } from '@livekit/react-native-webrtc';\nimport { setupURLPolyfill } from 'react-native-url-polyfill';\nimport AudioSession from './audio/AudioSession';\nimport type { AudioConfiguration } from './audio/AudioSession';\nimport { PixelRatio, Platform } from 'react-native';\nimport type { LiveKitReactNativeInfo } from 'livekit-client';\n\n/**\n * Registers the required globals needed for LiveKit to work.\n *\n * Must be called before using LiveKit.\n */\nexport function registerGlobals() {\n webrtcRegisterGlobals();\n livekitRegisterGlobals();\n setupURLPolyfill();\n fixWebrtcAdapter();\n shimPromiseAllSettled();\n shimArrayAt();\n}\nfunction livekitRegisterGlobals() {\n let lkGlobal: LiveKitReactNativeInfo = {\n platform: Platform.OS,\n devicePixelRatio: PixelRatio.get(),\n };\n\n // @ts-ignore\n global.LiveKitReactNativeGlobal = lkGlobal;\n}\n\nfunction fixWebrtcAdapter() {\n // @ts-ignore\n if (window?.navigator !== undefined) {\n // @ts-ignore\n const { navigator } = window;\n if (navigator.userAgent === undefined) {\n navigator.userAgent = navigator.product ?? 'Unknown';\n }\n }\n}\n\nfunction shimPromiseAllSettled() {\n var allSettled = require('promise.allsettled');\n allSettled.shim();\n}\n\nfunction shimArrayAt() {\n // Some versions of RN don't have Array.prototype.at, which is used by sdp-transform\n if (!Array.prototype.at) {\n var at = require('array.prototype.at');\n at.shim();\n }\n}\n\nexport * from './components/VideoView';\nexport * from './useParticipant';\nexport * from './useRoom';\nexport { AudioSession, AudioConfiguration };\n"]}
1
+ {"version":3,"sources":["index.tsx"],"names":["registerGlobals","livekitRegisterGlobals","fixWebrtcAdapter","shimPromiseAllSettled","shimArrayAt","shimAsyncIterator","shimIterator","lkGlobal","platform","Platform","OS","devicePixelRatio","PixelRatio","get","global","LiveKitReactNativeGlobal","window","navigator","undefined","userAgent","product","allSettled","require","shim","Array","prototype","at"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;AACA;;AACA;;AACA;;AAKA;;AA8DA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AACA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AACA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;AA7DA;AACA;AACA;AACA;AACA;AACO,SAASA,eAAT,GAA2B;AAChC;AACAC,EAAAA,sBAAsB;AACtB;AACAC,EAAAA,gBAAgB;AAChBC,EAAAA,qBAAqB;AACrBC,EAAAA,WAAW;AACXC,EAAAA,iBAAiB;AACjBC,EAAAA,YAAY;AACb;;AACD,SAASL,sBAAT,GAAkC;AAChC,MAAIM,QAAgC,GAAG;AACrCC,IAAAA,QAAQ,EAAEC,sBAASC,EADkB;AAErCC,IAAAA,gBAAgB,EAAEC,wBAAWC,GAAX;AAFmB,GAAvC,CADgC,CAMhC;;AACAC,EAAAA,MAAM,CAACC,wBAAP,GAAkCR,QAAlC;AACD;;AAED,SAASL,gBAAT,GAA4B;AAAA;;AAC1B;AACA,MAAI,YAAAc,MAAM,UAAN,0CAAQC,SAAR,MAAsBC,SAA1B,EAAqC;AACnC;AACA,UAAM;AAAED,MAAAA;AAAF,QAAgBD,MAAtB;;AACA,QAAIC,SAAS,CAACE,SAAV,KAAwBD,SAA5B,EAAuC;AAAA;;AACrCD,MAAAA,SAAS,CAACE,SAAV,yBAAsBF,SAAS,CAACG,OAAhC,mEAA2C,SAA3C;AACD;AACF;AACF;;AAED,SAASjB,qBAAT,GAAiC;AAC/B,MAAIkB,UAAU,GAAGC,OAAO,CAAC,oBAAD,CAAxB;;AACAD,EAAAA,UAAU,CAACE,IAAX;AACD;;AAED,SAASnB,WAAT,GAAuB;AACrB;AACA,MAAI,CAACoB,KAAK,CAACC,SAAN,CAAgBC,EAArB,EAAyB;AACvB,QAAIA,EAAE,GAAGJ,OAAO,CAAC,oBAAD,CAAhB;;AACAI,IAAAA,EAAE,CAACH,IAAH;AACD;AACF;;AAED,SAASlB,iBAAT,GAA6B;AAC3B,MAAIkB,IAAI,GAAGD,OAAO,CAAC,8CAAD,CAAlB;;AACAC,EAAAA,IAAI;AACL;;AAED,SAASjB,YAAT,GAAwB;AACtB,MAAIiB,IAAI,GAAGD,OAAO,CAAC,yCAAD,CAAlB;;AACAC,EAAAA,IAAI;AACL","sourcesContent":["import { registerGlobals as webrtcRegisterGlobals } from '@livekit/react-native-webrtc';\nimport { setupURLPolyfill } from 'react-native-url-polyfill';\nimport 'fastestsmallesttextencoderdecoder';\nimport AudioSession, {\n AndroidAudioTypePresets,\n AndroidAudioTypeOptions,\n} from './audio/AudioSession';\nimport type { AudioConfiguration } from './audio/AudioSession';\nimport { PixelRatio, Platform } from 'react-native';\nimport type { LiveKitReactNativeInfo } from 'livekit-client';\n\n/**\n * Registers the required globals needed for LiveKit to work.\n *\n * Must be called before using LiveKit.\n */\nexport function registerGlobals() {\n webrtcRegisterGlobals();\n livekitRegisterGlobals();\n setupURLPolyfill();\n fixWebrtcAdapter();\n shimPromiseAllSettled();\n shimArrayAt();\n shimAsyncIterator();\n shimIterator();\n}\nfunction livekitRegisterGlobals() {\n let lkGlobal: LiveKitReactNativeInfo = {\n platform: Platform.OS,\n devicePixelRatio: PixelRatio.get(),\n };\n\n // @ts-ignore\n global.LiveKitReactNativeGlobal = lkGlobal;\n}\n\nfunction fixWebrtcAdapter() {\n // @ts-ignore\n if (window?.navigator !== undefined) {\n // @ts-ignore\n const { navigator } = window;\n if (navigator.userAgent === undefined) {\n navigator.userAgent = navigator.product ?? 'Unknown';\n }\n }\n}\n\nfunction shimPromiseAllSettled() {\n var allSettled = require('promise.allsettled');\n allSettled.shim();\n}\n\nfunction shimArrayAt() {\n // Some versions of RN don't have Array.prototype.at, which is used by sdp-transform\n if (!Array.prototype.at) {\n var at = require('array.prototype.at');\n at.shim();\n }\n}\n\nfunction shimAsyncIterator() {\n var shim = require('well-known-symbols/Symbol.asyncIterator/shim');\n shim();\n}\n\nfunction shimIterator() {\n var shim = require('well-known-symbols/Symbol.iterator/shim');\n shim();\n}\n\nexport * from './components/VideoView';\nexport * from './useParticipant';\nexport * from './useRoom';\nexport {\n AudioSession,\n AudioConfiguration,\n AndroidAudioTypeOptions,\n AndroidAudioTypePresets,\n};\n"]}
@@ -21,17 +21,15 @@ const LivekitReactNative = NativeModules.LivekitReactNative ? NativeModules.Live
21
21
  * This is ignored when an output is manually selected with {@link AudioSession.selectAudioOutput}.
22
22
  *
23
23
  * By default, the order is set to:
24
- * 1. `"speaker"`
25
- * 2. `"earpiece"`
26
- * 3. `"headset"`
27
- * 4. `"bluetooth"`
24
+ * 1. `"bluetooth"
25
+ * 2. `"headset"``
26
+ * 3. `"speaker"`
27
+ * 4. `"earpiece"`
28
28
  *
29
- * * audioMode - The audio mode to use for the audio session. Defaults to 'normal'.
29
+ * * audioTypeOptions - An {@link AndroidAudioTypeOptions} object which provides the
30
+ * audio options to use on Android.
30
31
  *
31
- * * audioFocusMode - The focus mode to use for the audio session. Defaults to 'gain'.
32
- *
33
- * See [AudioManager](https://developer.android.com/reference/android/media/AudioManager) for details
34
- * on audio and focus modes.
32
+ * See {@link AndroidAudioTypePresets} for pre-configured values.
35
33
  *
36
34
  * ----
37
35
  * iOS
@@ -41,6 +39,24 @@ const LivekitReactNative = NativeModules.LivekitReactNative ? NativeModules.Live
41
39
  * By default, this is set to `"speaker"`
42
40
  */
43
41
 
42
+ export const AndroidAudioTypePresets = {
43
+ communication: {
44
+ manageAudioFocus: true,
45
+ audioMode: 'inCommunication',
46
+ audioFocusMode: 'gain',
47
+ audioStreamType: 'voiceCall',
48
+ audioAttributesUsageType: 'voiceCommunication',
49
+ audioAttributesContentType: 'speech'
50
+ },
51
+ media: {
52
+ manageAudioFocus: true,
53
+ audioMode: 'normal',
54
+ audioFocusMode: 'gain',
55
+ audioStreamType: 'music',
56
+ audioAttributesUsageType: 'media',
57
+ audioAttributesContentType: 'unknown'
58
+ }
59
+ };
44
60
  export default class AudioSession {}
45
61
 
46
62
  _defineProperty(AudioSession, "configureAudio", async config => {
@@ -1 +1 @@
1
- {"version":3,"sources":["AudioSession.ts"],"names":["NativeModules","Platform","LINKING_ERROR","select","ios","default","LivekitReactNative","Proxy","get","Error","AudioSession","config","configureAudio","startAudioSession","stopAudioSession","OS","getAudioOutputs","deviceId","selectAudioOutput","showAudioRoutePicker"],"mappings":";;AAAA,SAASA,aAAT,EAAwBC,QAAxB,QAAwC,cAAxC;AACA,MAAMC,aAAa,GAChB,gFAAD,GACAD,QAAQ,CAACE,MAAT,CAAgB;AAAEC,EAAAA,GAAG,EAAE,gCAAP;AAAyCC,EAAAA,OAAO,EAAE;AAAlD,CAAhB,CADA,GAEA,sDAFA,GAGA,6CAJF;AAMA,MAAMC,kBAAkB,GAAGN,aAAa,CAACM,kBAAd,GACvBN,aAAa,CAACM,kBADS,GAEvB,IAAIC,KAAJ,CACE,EADF,EAEE;AACEC,EAAAA,GAAG,GAAG;AACJ,UAAM,IAAIC,KAAJ,CAAUP,aAAV,CAAN;AACD;;AAHH,CAFF,CAFJ;AAWA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAqBA,eAAe,MAAMQ,YAAN,CAAmB;;gBAAbA,Y,oBAMK,MAAOC,MAAP,IAAsC;AAC5D,QAAML,kBAAkB,CAACM,cAAnB,CAAkCD,MAAlC,CAAN;AACD,C;;gBARkBD,Y,uBAaQ,YAAY;AACrC,QAAMJ,kBAAkB,CAACO,iBAAnB,EAAN;AACD,C;;gBAfkBH,Y,sBAoBO,YAAY;AACpC,QAAMJ,kBAAkB,CAACQ,gBAAnB,EAAN;AACD,C;;gBAtBkBJ,Y,qBAmDM,YAA+B;AACtD,MAAIT,QAAQ,CAACc,EAAT,KAAgB,KAApB,EAA2B;AACzB,WAAO,CAAC,SAAD,EAAY,eAAZ,CAAP;AACD,GAFD,MAEO,IAAId,QAAQ,CAACc,EAAT,KAAgB,SAApB,EAA+B;AACpC,WAAQ,MAAMT,kBAAkB,CAACU,eAAnB,EAAd;AACD,GAFM,MAEA;AACL,WAAO,EAAP;AACD;AACF,C;;gBA3DkBN,Y,uBAoEQ,MAAOO,QAAP,IAA4B;AACrD,QAAMX,kBAAkB,CAACY,iBAAnB,CAAqCD,QAArC,CAAN;AACD,C;;gBAtEkBP,Y,0BA6EW,YAAY;AACxC,MAAIT,QAAQ,CAACc,EAAT,KAAgB,KAApB,EAA2B;AACzB,UAAMT,kBAAkB,CAACa,oBAAnB,EAAN;AACD;AACF,C","sourcesContent":["import { NativeModules, Platform } from 'react-native';\nconst LINKING_ERROR =\n `The package '@livekit/react-native' doesn't seem to be linked. Make sure: \\n\\n` +\n Platform.select({ ios: \"- You have run 'pod install'\\n\", default: '' }) +\n '- You rebuilt the app after installing the package\\n' +\n '- You are not using Expo managed workflow\\n';\n\nconst LivekitReactNative = NativeModules.LivekitReactNative\n ? NativeModules.LivekitReactNative\n : new Proxy(\n {},\n {\n get() {\n throw new Error(LINKING_ERROR);\n },\n }\n );\n\n/**\n * Configuration for the underlying AudioSession.\n *\n * ----\n * Android specific options:\n *\n * * preferredOutputList - The preferred order in which to automatically select an audio output.\n * This is ignored when an output is manually selected with {@link AudioSession.selectAudioOutput}.\n *\n * By default, the order is set to:\n * 1. `\"speaker\"`\n * 2. `\"earpiece\"`\n * 3. `\"headset\"`\n * 4. `\"bluetooth\"`\n *\n * * audioMode - The audio mode to use for the audio session. Defaults to 'normal'.\n *\n * * audioFocusMode - The focus mode to use for the audio session. Defaults to 'gain'.\n *\n * See [AudioManager](https://developer.android.com/reference/android/media/AudioManager) for details\n * on audio and focus modes.\n *\n * ----\n * iOS\n *\n * * defaultOutput - The default preferred output to use when a wired headset or bluetooth output is unavailable.\n *\n * By default, this is set to `\"speaker\"`\n */\nexport type AudioConfiguration = {\n android?: {\n preferredOutputList?: ('speaker' | 'earpiece' | 'headset' | 'bluetooth')[];\n audioMode?:\n | 'normal'\n | 'callScreening'\n | 'inCall'\n | 'inCommunication'\n | 'ringtone';\n audioFocusMode?:\n | 'gain'\n | 'gainTransient'\n | 'gainTransientExclusive'\n | 'gainTransientMayDuck';\n };\n ios?: {\n defaultOutput?: 'speaker' | 'earpiece';\n };\n};\n\nexport default class AudioSession {\n /**\n * Applies the provided audio configuration to the underlying AudioSession.\n *\n * Must be called prior to connecting to a Room for the configuration to apply correctly.\n */\n static configureAudio = async (config: AudioConfiguration) => {\n await LivekitReactNative.configureAudio(config);\n };\n\n /**\n * Starts an AudioSession.\n */\n static startAudioSession = async () => {\n await LivekitReactNative.startAudioSession();\n };\n\n /**\n * Stops the existing AudioSession.\n */\n static stopAudioSession = async () => {\n await LivekitReactNative.stopAudioSession();\n };\n\n /**\n * Gets the available audio outputs for use with {@link selectAudioOutput}.\n *\n * {@link startAudioSession} must be called prior to using this method.\n *\n * For Android, will return if available:\n * * \"speaker\"\n * * \"earpiece\"\n * * \"headset\"\n * * \"bluetooth\"\n *\n * Note: For applications targeting SDK versions over 30, the runtime BLUETOOTH_CONNECT\n * permission must be requested to send audio to bluetooth headsets.\n *\n * ----\n *\n * For iOS, due to OS limitations, the only available types are:\n * * \"default\" - Use default iOS audio routing\n * * \"force_speaker\" - Force audio output through speaker\n *\n * See also {@link showAudioRoutePicker} to display a route picker that\n * can choose between other audio devices (i.e. headset/bluetooth/airplay),\n * or use a library like `react-native-avroutepicker` for a native platform\n * control.\n *\n * @returns the available audio output types\n */\n static getAudioOutputs = async (): Promise<string[]> => {\n if (Platform.OS === 'ios') {\n return ['default', 'force_speaker'];\n } else if (Platform.OS === 'android') {\n return (await LivekitReactNative.getAudioOutputs()) as string[];\n } else {\n return [];\n }\n };\n\n /**\n * Select the provided audio output if available.\n *\n * {@link startAudioSession} must be called prior to using this method.\n *\n * @param deviceId A deviceId retrieved from {@link getAudioOutputs}\n */\n static selectAudioOutput = async (deviceId: string) => {\n await LivekitReactNative.selectAudioOutput(deviceId);\n };\n\n /**\n * iOS only, requires iOS 11+.\n *\n * Displays an AVRoutePickerView for the user to choose their audio output.\n */\n static showAudioRoutePicker = async () => {\n if (Platform.OS === 'ios') {\n await LivekitReactNative.showAudioRoutePicker();\n }\n };\n}\n"]}
1
+ {"version":3,"sources":["AudioSession.ts"],"names":["NativeModules","Platform","LINKING_ERROR","select","ios","default","LivekitReactNative","Proxy","get","Error","AndroidAudioTypePresets","communication","manageAudioFocus","audioMode","audioFocusMode","audioStreamType","audioAttributesUsageType","audioAttributesContentType","media","AudioSession","config","configureAudio","startAudioSession","stopAudioSession","OS","getAudioOutputs","deviceId","selectAudioOutput","showAudioRoutePicker"],"mappings":";;AAAA,SAASA,aAAT,EAAwBC,QAAxB,QAAwC,cAAxC;AACA,MAAMC,aAAa,GAChB,gFAAD,GACAD,QAAQ,CAACE,MAAT,CAAgB;AAAEC,EAAAA,GAAG,EAAE,gCAAP;AAAyCC,EAAAA,OAAO,EAAE;AAAlD,CAAhB,CADA,GAEA,sDAFA,GAGA,6CAJF;AAMA,MAAMC,kBAAkB,GAAGN,aAAa,CAACM,kBAAd,GACvBN,aAAa,CAACM,kBADS,GAEvB,IAAIC,KAAJ,CACE,EADF,EAEE;AACEC,EAAAA,GAAG,GAAG;AACJ,UAAM,IAAIC,KAAJ,CAAUP,aAAV,CAAN;AACD;;AAHH,CAFF,CAFJ;AAWA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AA6GA,OAAO,MAAMQ,uBASZ,GAAG;AACFC,EAAAA,aAAa,EAAE;AACbC,IAAAA,gBAAgB,EAAE,IADL;AAEbC,IAAAA,SAAS,EAAE,iBAFE;AAGbC,IAAAA,cAAc,EAAE,MAHH;AAIbC,IAAAA,eAAe,EAAE,WAJJ;AAKbC,IAAAA,wBAAwB,EAAE,oBALb;AAMbC,IAAAA,0BAA0B,EAAE;AANf,GADb;AASFC,EAAAA,KAAK,EAAE;AACLN,IAAAA,gBAAgB,EAAE,IADb;AAELC,IAAAA,SAAS,EAAE,QAFN;AAGLC,IAAAA,cAAc,EAAE,MAHX;AAILC,IAAAA,eAAe,EAAE,OAJZ;AAKLC,IAAAA,wBAAwB,EAAE,OALrB;AAMLC,IAAAA,0BAA0B,EAAE;AANvB;AATL,CATG;AA4BP,eAAe,MAAME,YAAN,CAAmB;;gBAAbA,Y,oBAMK,MAAOC,MAAP,IAAsC;AAC5D,QAAMd,kBAAkB,CAACe,cAAnB,CAAkCD,MAAlC,CAAN;AACD,C;;gBARkBD,Y,uBAaQ,YAAY;AACrC,QAAMb,kBAAkB,CAACgB,iBAAnB,EAAN;AACD,C;;gBAfkBH,Y,sBAoBO,YAAY;AACpC,QAAMb,kBAAkB,CAACiB,gBAAnB,EAAN;AACD,C;;gBAtBkBJ,Y,qBAgDM,YAA+B;AACtD,MAAIlB,QAAQ,CAACuB,EAAT,KAAgB,KAApB,EAA2B;AACzB,WAAO,CAAC,SAAD,EAAY,eAAZ,CAAP;AACD,GAFD,MAEO,IAAIvB,QAAQ,CAACuB,EAAT,KAAgB,SAApB,EAA+B;AACpC,WAAQ,MAAMlB,kBAAkB,CAACmB,eAAnB,EAAd;AACD,GAFM,MAEA;AACL,WAAO,EAAP;AACD;AACF,C;;gBAxDkBN,Y,uBAiEQ,MAAOO,QAAP,IAA4B;AACrD,QAAMpB,kBAAkB,CAACqB,iBAAnB,CAAqCD,QAArC,CAAN;AACD,C;;gBAnEkBP,Y,0BA0EW,YAAY;AACxC,MAAIlB,QAAQ,CAACuB,EAAT,KAAgB,KAApB,EAA2B;AACzB,UAAMlB,kBAAkB,CAACsB,oBAAnB,EAAN;AACD;AACF,C","sourcesContent":["import { NativeModules, Platform } from 'react-native';\nconst LINKING_ERROR =\n `The package '@livekit/react-native' doesn't seem to be linked. Make sure: \\n\\n` +\n Platform.select({ ios: \"- You have run 'pod install'\\n\", default: '' }) +\n '- You rebuilt the app after installing the package\\n' +\n '- You are not using Expo managed workflow\\n';\n\nconst LivekitReactNative = NativeModules.LivekitReactNative\n ? NativeModules.LivekitReactNative\n : new Proxy(\n {},\n {\n get() {\n throw new Error(LINKING_ERROR);\n },\n }\n );\n\n/**\n * Configuration for the underlying AudioSession.\n *\n * ----\n * Android specific options:\n *\n * * preferredOutputList - The preferred order in which to automatically select an audio output.\n * This is ignored when an output is manually selected with {@link AudioSession.selectAudioOutput}.\n *\n * By default, the order is set to:\n * 1. `\"bluetooth\"\n * 2. `\"headset\"``\n * 3. `\"speaker\"`\n * 4. `\"earpiece\"`\n *\n * * audioTypeOptions - An {@link AndroidAudioTypeOptions} object which provides the\n * audio options to use on Android.\n *\n * See {@link AndroidAudioTypePresets} for pre-configured values.\n *\n * ----\n * iOS\n *\n * * defaultOutput - The default preferred output to use when a wired headset or bluetooth output is unavailable.\n *\n * By default, this is set to `\"speaker\"`\n */\nexport type AudioConfiguration = {\n android?: {\n preferredOutputList?: ('speaker' | 'earpiece' | 'headset' | 'bluetooth')[];\n audioTypeOptions: AndroidAudioTypeOptions;\n };\n ios?: {\n defaultOutput?: 'speaker' | 'earpiece';\n };\n};\n\nexport type AndroidAudioTypeOptions = {\n /**\n * Whether LiveKit should handle managing the audio focus or not.\n *\n * Defaults to true.\n */\n manageAudioFocus?: boolean;\n\n /**\n * Corresponds to {@link https://developer.android.com/reference/android/media/AudioManager#setMode(int)}\n *\n * Defaults to 'inCommunication'.\n */\n audioMode?:\n | 'normal'\n | 'callScreening'\n | 'inCall'\n | 'inCommunication'\n | 'ringtone';\n\n /**\n * Corresponds to the duration hint when requesting audio focus.\n *\n * Defaults to 'gain'.\n *\n * See also {@link https://developer.android.com/reference/android/media/AudioManager#AUDIOFOCUS_GAIN}\n */\n audioFocusMode?:\n | 'gain'\n | 'gainTransient'\n | 'gainTransientExclusive'\n | 'gainTransientMayDuck';\n\n /**\n * Corresponds to Android's AudioAttributes usage type.\n *\n * Defaults to 'voiceCommunication'.\n *\n * See also {@link https://developer.android.com/reference/android/media/AudioAttributes}\n */\n audioAttributesUsageType?:\n | 'alarm'\n | 'assistanceAccessibility'\n | 'assistanceNavigationGuidance'\n | 'assistanceSonification'\n | 'assistant'\n | 'game'\n | 'media'\n | 'notification'\n | 'notificationEvent'\n | 'notificationRingtone'\n | 'unknown'\n | 'voiceCommunication'\n | 'voiceCommunicationSignalling';\n\n /**\n * Corresponds to Android's AndroidAttributes content type.\n *\n * Defaults to 'speech'.\n *\n * See also {@link https://developer.android.com/reference/android/media/AudioAttributes}\n */\n audioAttributesContentType?:\n | 'movie'\n | 'music'\n | 'sonification'\n | 'speech'\n | 'unknown';\n\n /**\n * Corresponds to the stream type when requesting audio focus. Used on pre-O devices.\n *\n * Defaults to 'voiceCall'\n *\n * See also {@link https://developer.android.com/reference/android/media/AudioManager#STREAM_VOICE_CALL}\n */\n audioStreamType?:\n | 'accessibility'\n | 'alarm'\n | 'dtmf'\n | 'music'\n | 'notification'\n | 'ring'\n | 'system'\n | 'voiceCall';\n\n /**\n * On certain Android devices, audio routing does not function properly and\n * bluetooth microphones will not work unless audio mode is set to\n * `inCommunication` or `inCall`. Audio routing is turned off those cases.\n *\n * If this set to true, will attempt to do audio routing regardless of audio mode.\n *\n * Defaults to false.\n */\n forceHandleAudioRouting?: boolean;\n};\n\nexport const AndroidAudioTypePresets: {\n /**\n * A pre-configured AndroidAudioConfiguration for voice communication.\n */\n communication: AndroidAudioTypeOptions;\n /**\n * A pre-configured AndroidAudioConfiguration for media playback.\n */\n media: AndroidAudioTypeOptions;\n} = {\n communication: {\n manageAudioFocus: true,\n audioMode: 'inCommunication',\n audioFocusMode: 'gain',\n audioStreamType: 'voiceCall',\n audioAttributesUsageType: 'voiceCommunication',\n audioAttributesContentType: 'speech',\n },\n media: {\n manageAudioFocus: true,\n audioMode: 'normal',\n audioFocusMode: 'gain',\n audioStreamType: 'music',\n audioAttributesUsageType: 'media',\n audioAttributesContentType: 'unknown',\n },\n} as const;\n\nexport default class AudioSession {\n /**\n * Applies the provided audio configuration to the underlying AudioSession.\n *\n * Must be called prior to connecting to a Room for the configuration to apply correctly.\n */\n static configureAudio = async (config: AudioConfiguration) => {\n await LivekitReactNative.configureAudio(config);\n };\n\n /**\n * Starts an AudioSession.\n */\n static startAudioSession = async () => {\n await LivekitReactNative.startAudioSession();\n };\n\n /**\n * Stops the existing AudioSession.\n */\n static stopAudioSession = async () => {\n await LivekitReactNative.stopAudioSession();\n };\n\n /**\n * Gets the available audio outputs for use with {@link selectAudioOutput}.\n *\n * {@link startAudioSession} must be called prior to using this method.\n *\n * For Android, will return if available:\n * * \"speaker\"\n * * \"earpiece\"\n * * \"headset\"\n * * \"bluetooth\"\n *\n * ----\n *\n * For iOS, due to OS limitations, the only available types are:\n * * \"default\" - Use default iOS audio routing\n * * \"force_speaker\" - Force audio output through speaker\n *\n * See also {@link showAudioRoutePicker} to display a route picker that\n * can choose between other audio devices (i.e. headset/bluetooth/airplay),\n * or use a library like `react-native-avroutepicker` for a native platform\n * control.\n *\n * @returns the available audio output types\n */\n static getAudioOutputs = async (): Promise<string[]> => {\n if (Platform.OS === 'ios') {\n return ['default', 'force_speaker'];\n } else if (Platform.OS === 'android') {\n return (await LivekitReactNative.getAudioOutputs()) as string[];\n } else {\n return [];\n }\n };\n\n /**\n * Select the provided audio output if available.\n *\n * {@link startAudioSession} must be called prior to using this method.\n *\n * @param deviceId A deviceId retrieved from {@link getAudioOutputs}\n */\n static selectAudioOutput = async (deviceId: string) => {\n await LivekitReactNative.selectAudioOutput(deviceId);\n };\n\n /**\n * iOS only, requires iOS 11+.\n *\n * Displays an AVRoutePickerView for the user to choose their audio output.\n */\n static showAudioRoutePicker = async () => {\n if (Platform.OS === 'ios') {\n await LivekitReactNative.showAudioRoutePicker();\n }\n };\n}\n"]}
@@ -1,6 +1,7 @@
1
1
  import { registerGlobals as webrtcRegisterGlobals } from '@livekit/react-native-webrtc';
2
2
  import { setupURLPolyfill } from 'react-native-url-polyfill';
3
- import AudioSession from './audio/AudioSession';
3
+ import 'fastestsmallesttextencoderdecoder';
4
+ import AudioSession, { AndroidAudioTypePresets, AndroidAudioTypeOptions } from './audio/AudioSession';
4
5
  import { PixelRatio, Platform } from 'react-native';
5
6
 
6
7
  /**
@@ -15,6 +16,8 @@ export function registerGlobals() {
15
16
  fixWebrtcAdapter();
16
17
  shimPromiseAllSettled();
17
18
  shimArrayAt();
19
+ shimAsyncIterator();
20
+ shimIterator();
18
21
  }
19
22
 
20
23
  function livekitRegisterGlobals() {
@@ -59,8 +62,20 @@ function shimArrayAt() {
59
62
  }
60
63
  }
61
64
 
65
+ function shimAsyncIterator() {
66
+ var shim = require('well-known-symbols/Symbol.asyncIterator/shim');
67
+
68
+ shim();
69
+ }
70
+
71
+ function shimIterator() {
72
+ var shim = require('well-known-symbols/Symbol.iterator/shim');
73
+
74
+ shim();
75
+ }
76
+
62
77
  export * from './components/VideoView';
63
78
  export * from './useParticipant';
64
79
  export * from './useRoom';
65
- export { AudioSession };
80
+ export { AudioSession, AndroidAudioTypeOptions, AndroidAudioTypePresets };
66
81
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["index.tsx"],"names":["registerGlobals","webrtcRegisterGlobals","setupURLPolyfill","AudioSession","PixelRatio","Platform","livekitRegisterGlobals","fixWebrtcAdapter","shimPromiseAllSettled","shimArrayAt","lkGlobal","platform","OS","devicePixelRatio","get","global","LiveKitReactNativeGlobal","window","navigator","undefined","userAgent","product","allSettled","require","shim","Array","prototype","at"],"mappings":"AAAA,SAASA,eAAe,IAAIC,qBAA5B,QAAyD,8BAAzD;AACA,SAASC,gBAAT,QAAiC,2BAAjC;AACA,OAAOC,YAAP,MAAyB,sBAAzB;AAEA,SAASC,UAAT,EAAqBC,QAArB,QAAqC,cAArC;;AAGA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASL,eAAT,GAA2B;AAChCC,EAAAA,qBAAqB;AACrBK,EAAAA,sBAAsB;AACtBJ,EAAAA,gBAAgB;AAChBK,EAAAA,gBAAgB;AAChBC,EAAAA,qBAAqB;AACrBC,EAAAA,WAAW;AACZ;;AACD,SAASH,sBAAT,GAAkC;AAChC,MAAII,QAAgC,GAAG;AACrCC,IAAAA,QAAQ,EAAEN,QAAQ,CAACO,EADkB;AAErCC,IAAAA,gBAAgB,EAAET,UAAU,CAACU,GAAX;AAFmB,GAAvC,CADgC,CAMhC;;AACAC,EAAAA,MAAM,CAACC,wBAAP,GAAkCN,QAAlC;AACD;;AAED,SAASH,gBAAT,GAA4B;AAAA;;AAC1B;AACA,MAAI,YAAAU,MAAM,UAAN,0CAAQC,SAAR,MAAsBC,SAA1B,EAAqC;AACnC;AACA,UAAM;AAAED,MAAAA;AAAF,QAAgBD,MAAtB;;AACA,QAAIC,SAAS,CAACE,SAAV,KAAwBD,SAA5B,EAAuC;AAAA;;AACrCD,MAAAA,SAAS,CAACE,SAAV,yBAAsBF,SAAS,CAACG,OAAhC,mEAA2C,SAA3C;AACD;AACF;AACF;;AAED,SAASb,qBAAT,GAAiC;AAC/B,MAAIc,UAAU,GAAGC,OAAO,CAAC,oBAAD,CAAxB;;AACAD,EAAAA,UAAU,CAACE,IAAX;AACD;;AAED,SAASf,WAAT,GAAuB;AACrB;AACA,MAAI,CAACgB,KAAK,CAACC,SAAN,CAAgBC,EAArB,EAAyB;AACvB,QAAIA,EAAE,GAAGJ,OAAO,CAAC,oBAAD,CAAhB;;AACAI,IAAAA,EAAE,CAACH,IAAH;AACD;AACF;;AAED,cAAc,wBAAd;AACA,cAAc,kBAAd;AACA,cAAc,WAAd;AACA,SAASrB,YAAT","sourcesContent":["import { registerGlobals as webrtcRegisterGlobals } from '@livekit/react-native-webrtc';\nimport { setupURLPolyfill } from 'react-native-url-polyfill';\nimport AudioSession from './audio/AudioSession';\nimport type { AudioConfiguration } from './audio/AudioSession';\nimport { PixelRatio, Platform } from 'react-native';\nimport type { LiveKitReactNativeInfo } from 'livekit-client';\n\n/**\n * Registers the required globals needed for LiveKit to work.\n *\n * Must be called before using LiveKit.\n */\nexport function registerGlobals() {\n webrtcRegisterGlobals();\n livekitRegisterGlobals();\n setupURLPolyfill();\n fixWebrtcAdapter();\n shimPromiseAllSettled();\n shimArrayAt();\n}\nfunction livekitRegisterGlobals() {\n let lkGlobal: LiveKitReactNativeInfo = {\n platform: Platform.OS,\n devicePixelRatio: PixelRatio.get(),\n };\n\n // @ts-ignore\n global.LiveKitReactNativeGlobal = lkGlobal;\n}\n\nfunction fixWebrtcAdapter() {\n // @ts-ignore\n if (window?.navigator !== undefined) {\n // @ts-ignore\n const { navigator } = window;\n if (navigator.userAgent === undefined) {\n navigator.userAgent = navigator.product ?? 'Unknown';\n }\n }\n}\n\nfunction shimPromiseAllSettled() {\n var allSettled = require('promise.allsettled');\n allSettled.shim();\n}\n\nfunction shimArrayAt() {\n // Some versions of RN don't have Array.prototype.at, which is used by sdp-transform\n if (!Array.prototype.at) {\n var at = require('array.prototype.at');\n at.shim();\n }\n}\n\nexport * from './components/VideoView';\nexport * from './useParticipant';\nexport * from './useRoom';\nexport { AudioSession, AudioConfiguration };\n"]}
1
+ {"version":3,"sources":["index.tsx"],"names":["registerGlobals","webrtcRegisterGlobals","setupURLPolyfill","AudioSession","AndroidAudioTypePresets","AndroidAudioTypeOptions","PixelRatio","Platform","livekitRegisterGlobals","fixWebrtcAdapter","shimPromiseAllSettled","shimArrayAt","shimAsyncIterator","shimIterator","lkGlobal","platform","OS","devicePixelRatio","get","global","LiveKitReactNativeGlobal","window","navigator","undefined","userAgent","product","allSettled","require","shim","Array","prototype","at"],"mappings":"AAAA,SAASA,eAAe,IAAIC,qBAA5B,QAAyD,8BAAzD;AACA,SAASC,gBAAT,QAAiC,2BAAjC;AACA,OAAO,mCAAP;AACA,OAAOC,YAAP,IACEC,uBADF,EAEEC,uBAFF,QAGO,sBAHP;AAKA,SAASC,UAAT,EAAqBC,QAArB,QAAqC,cAArC;;AAGA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASP,eAAT,GAA2B;AAChCC,EAAAA,qBAAqB;AACrBO,EAAAA,sBAAsB;AACtBN,EAAAA,gBAAgB;AAChBO,EAAAA,gBAAgB;AAChBC,EAAAA,qBAAqB;AACrBC,EAAAA,WAAW;AACXC,EAAAA,iBAAiB;AACjBC,EAAAA,YAAY;AACb;;AACD,SAASL,sBAAT,GAAkC;AAChC,MAAIM,QAAgC,GAAG;AACrCC,IAAAA,QAAQ,EAAER,QAAQ,CAACS,EADkB;AAErCC,IAAAA,gBAAgB,EAAEX,UAAU,CAACY,GAAX;AAFmB,GAAvC,CADgC,CAMhC;;AACAC,EAAAA,MAAM,CAACC,wBAAP,GAAkCN,QAAlC;AACD;;AAED,SAASL,gBAAT,GAA4B;AAAA;;AAC1B;AACA,MAAI,YAAAY,MAAM,UAAN,0CAAQC,SAAR,MAAsBC,SAA1B,EAAqC;AACnC;AACA,UAAM;AAAED,MAAAA;AAAF,QAAgBD,MAAtB;;AACA,QAAIC,SAAS,CAACE,SAAV,KAAwBD,SAA5B,EAAuC;AAAA;;AACrCD,MAAAA,SAAS,CAACE,SAAV,yBAAsBF,SAAS,CAACG,OAAhC,mEAA2C,SAA3C;AACD;AACF;AACF;;AAED,SAASf,qBAAT,GAAiC;AAC/B,MAAIgB,UAAU,GAAGC,OAAO,CAAC,oBAAD,CAAxB;;AACAD,EAAAA,UAAU,CAACE,IAAX;AACD;;AAED,SAASjB,WAAT,GAAuB;AACrB;AACA,MAAI,CAACkB,KAAK,CAACC,SAAN,CAAgBC,EAArB,EAAyB;AACvB,QAAIA,EAAE,GAAGJ,OAAO,CAAC,oBAAD,CAAhB;;AACAI,IAAAA,EAAE,CAACH,IAAH;AACD;AACF;;AAED,SAAShB,iBAAT,GAA6B;AAC3B,MAAIgB,IAAI,GAAGD,OAAO,CAAC,8CAAD,CAAlB;;AACAC,EAAAA,IAAI;AACL;;AAED,SAASf,YAAT,GAAwB;AACtB,MAAIe,IAAI,GAAGD,OAAO,CAAC,yCAAD,CAAlB;;AACAC,EAAAA,IAAI;AACL;;AAED,cAAc,wBAAd;AACA,cAAc,kBAAd;AACA,cAAc,WAAd;AACA,SACEzB,YADF,EAGEE,uBAHF,EAIED,uBAJF","sourcesContent":["import { registerGlobals as webrtcRegisterGlobals } from '@livekit/react-native-webrtc';\nimport { setupURLPolyfill } from 'react-native-url-polyfill';\nimport 'fastestsmallesttextencoderdecoder';\nimport AudioSession, {\n AndroidAudioTypePresets,\n AndroidAudioTypeOptions,\n} from './audio/AudioSession';\nimport type { AudioConfiguration } from './audio/AudioSession';\nimport { PixelRatio, Platform } from 'react-native';\nimport type { LiveKitReactNativeInfo } from 'livekit-client';\n\n/**\n * Registers the required globals needed for LiveKit to work.\n *\n * Must be called before using LiveKit.\n */\nexport function registerGlobals() {\n webrtcRegisterGlobals();\n livekitRegisterGlobals();\n setupURLPolyfill();\n fixWebrtcAdapter();\n shimPromiseAllSettled();\n shimArrayAt();\n shimAsyncIterator();\n shimIterator();\n}\nfunction livekitRegisterGlobals() {\n let lkGlobal: LiveKitReactNativeInfo = {\n platform: Platform.OS,\n devicePixelRatio: PixelRatio.get(),\n };\n\n // @ts-ignore\n global.LiveKitReactNativeGlobal = lkGlobal;\n}\n\nfunction fixWebrtcAdapter() {\n // @ts-ignore\n if (window?.navigator !== undefined) {\n // @ts-ignore\n const { navigator } = window;\n if (navigator.userAgent === undefined) {\n navigator.userAgent = navigator.product ?? 'Unknown';\n }\n }\n}\n\nfunction shimPromiseAllSettled() {\n var allSettled = require('promise.allsettled');\n allSettled.shim();\n}\n\nfunction shimArrayAt() {\n // Some versions of RN don't have Array.prototype.at, which is used by sdp-transform\n if (!Array.prototype.at) {\n var at = require('array.prototype.at');\n at.shim();\n }\n}\n\nfunction shimAsyncIterator() {\n var shim = require('well-known-symbols/Symbol.asyncIterator/shim');\n shim();\n}\n\nfunction shimIterator() {\n var shim = require('well-known-symbols/Symbol.iterator/shim');\n shim();\n}\n\nexport * from './components/VideoView';\nexport * from './useParticipant';\nexport * from './useRoom';\nexport {\n AudioSession,\n AudioConfiguration,\n AndroidAudioTypeOptions,\n AndroidAudioTypePresets,\n};\n"]}
@@ -8,17 +8,15 @@
8
8
  * This is ignored when an output is manually selected with {@link AudioSession.selectAudioOutput}.
9
9
  *
10
10
  * By default, the order is set to:
11
- * 1. `"speaker"`
12
- * 2. `"earpiece"`
13
- * 3. `"headset"`
14
- * 4. `"bluetooth"`
11
+ * 1. `"bluetooth"
12
+ * 2. `"headset"``
13
+ * 3. `"speaker"`
14
+ * 4. `"earpiece"`
15
15
  *
16
- * * audioMode - The audio mode to use for the audio session. Defaults to 'normal'.
16
+ * * audioTypeOptions - An {@link AndroidAudioTypeOptions} object which provides the
17
+ * audio options to use on Android.
17
18
  *
18
- * * audioFocusMode - The focus mode to use for the audio session. Defaults to 'gain'.
19
- *
20
- * See [AudioManager](https://developer.android.com/reference/android/media/AudioManager) for details
21
- * on audio and focus modes.
19
+ * See {@link AndroidAudioTypePresets} for pre-configured values.
22
20
  *
23
21
  * ----
24
22
  * iOS
@@ -30,13 +28,78 @@
30
28
  export declare type AudioConfiguration = {
31
29
  android?: {
32
30
  preferredOutputList?: ('speaker' | 'earpiece' | 'headset' | 'bluetooth')[];
33
- audioMode?: 'normal' | 'callScreening' | 'inCall' | 'inCommunication' | 'ringtone';
34
- audioFocusMode?: 'gain' | 'gainTransient' | 'gainTransientExclusive' | 'gainTransientMayDuck';
31
+ audioTypeOptions: AndroidAudioTypeOptions;
35
32
  };
36
33
  ios?: {
37
34
  defaultOutput?: 'speaker' | 'earpiece';
38
35
  };
39
36
  };
37
+ export declare type AndroidAudioTypeOptions = {
38
+ /**
39
+ * Whether LiveKit should handle managing the audio focus or not.
40
+ *
41
+ * Defaults to true.
42
+ */
43
+ manageAudioFocus?: boolean;
44
+ /**
45
+ * Corresponds to {@link https://developer.android.com/reference/android/media/AudioManager#setMode(int)}
46
+ *
47
+ * Defaults to 'inCommunication'.
48
+ */
49
+ audioMode?: 'normal' | 'callScreening' | 'inCall' | 'inCommunication' | 'ringtone';
50
+ /**
51
+ * Corresponds to the duration hint when requesting audio focus.
52
+ *
53
+ * Defaults to 'gain'.
54
+ *
55
+ * See also {@link https://developer.android.com/reference/android/media/AudioManager#AUDIOFOCUS_GAIN}
56
+ */
57
+ audioFocusMode?: 'gain' | 'gainTransient' | 'gainTransientExclusive' | 'gainTransientMayDuck';
58
+ /**
59
+ * Corresponds to Android's AudioAttributes usage type.
60
+ *
61
+ * Defaults to 'voiceCommunication'.
62
+ *
63
+ * See also {@link https://developer.android.com/reference/android/media/AudioAttributes}
64
+ */
65
+ audioAttributesUsageType?: 'alarm' | 'assistanceAccessibility' | 'assistanceNavigationGuidance' | 'assistanceSonification' | 'assistant' | 'game' | 'media' | 'notification' | 'notificationEvent' | 'notificationRingtone' | 'unknown' | 'voiceCommunication' | 'voiceCommunicationSignalling';
66
+ /**
67
+ * Corresponds to Android's AndroidAttributes content type.
68
+ *
69
+ * Defaults to 'speech'.
70
+ *
71
+ * See also {@link https://developer.android.com/reference/android/media/AudioAttributes}
72
+ */
73
+ audioAttributesContentType?: 'movie' | 'music' | 'sonification' | 'speech' | 'unknown';
74
+ /**
75
+ * Corresponds to the stream type when requesting audio focus. Used on pre-O devices.
76
+ *
77
+ * Defaults to 'voiceCall'
78
+ *
79
+ * See also {@link https://developer.android.com/reference/android/media/AudioManager#STREAM_VOICE_CALL}
80
+ */
81
+ audioStreamType?: 'accessibility' | 'alarm' | 'dtmf' | 'music' | 'notification' | 'ring' | 'system' | 'voiceCall';
82
+ /**
83
+ * On certain Android devices, audio routing does not function properly and
84
+ * bluetooth microphones will not work unless audio mode is set to
85
+ * `inCommunication` or `inCall`. Audio routing is turned off those cases.
86
+ *
87
+ * If this set to true, will attempt to do audio routing regardless of audio mode.
88
+ *
89
+ * Defaults to false.
90
+ */
91
+ forceHandleAudioRouting?: boolean;
92
+ };
93
+ export declare const AndroidAudioTypePresets: {
94
+ /**
95
+ * A pre-configured AndroidAudioConfiguration for voice communication.
96
+ */
97
+ communication: AndroidAudioTypeOptions;
98
+ /**
99
+ * A pre-configured AndroidAudioConfiguration for media playback.
100
+ */
101
+ media: AndroidAudioTypeOptions;
102
+ };
40
103
  export default class AudioSession {
41
104
  /**
42
105
  * Applies the provided audio configuration to the underlying AudioSession.
@@ -63,9 +126,6 @@ export default class AudioSession {
63
126
  * * "headset"
64
127
  * * "bluetooth"
65
128
  *
66
- * Note: For applications targeting SDK versions over 30, the runtime BLUETOOTH_CONNECT
67
- * permission must be requested to send audio to bluetooth headsets.
68
- *
69
129
  * ----
70
130
  *
71
131
  * For iOS, due to OS limitations, the only available types are:
@@ -1,4 +1,5 @@
1
- import AudioSession from './audio/AudioSession';
1
+ import 'fastestsmallesttextencoderdecoder';
2
+ import AudioSession, { AndroidAudioTypePresets, AndroidAudioTypeOptions } from './audio/AudioSession';
2
3
  import type { AudioConfiguration } from './audio/AudioSession';
3
4
  /**
4
5
  * Registers the required globals needed for LiveKit to work.
@@ -9,4 +10,4 @@ export declare function registerGlobals(): void;
9
10
  export * from './components/VideoView';
10
11
  export * from './useParticipant';
11
12
  export * from './useRoom';
12
- export { AudioSession, AudioConfiguration };
13
+ export { AudioSession, AudioConfiguration, AndroidAudioTypeOptions, AndroidAudioTypePresets, };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@livekit/react-native",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "LiveKit for React Native",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -43,9 +43,11 @@
43
43
  ],
44
44
  "dependencies": {
45
45
  "array.prototype.at": "^1.1.1",
46
+ "fastestsmallesttextencoderdecoder": "^1.0.22",
46
47
  "livekit-client": "^1.8.0",
47
48
  "promise.allsettled": "^1.0.5",
48
- "react-native-url-polyfill": "^1.3.0"
49
+ "react-native-url-polyfill": "^1.3.0",
50
+ "well-known-symbols": "^4.0.0"
49
51
  },
50
52
  "devDependencies": {
51
53
  "@babel/core": "^7.20.0",
@@ -56,6 +58,7 @@
56
58
  "@react-native-community/eslint-config": "^3.2.0",
57
59
  "@release-it/conventional-changelog": "^4.2.0",
58
60
  "@tsconfig/react-native": "^2.0.2",
61
+ "@types/fastestsmallesttextencoderdecoder": "^1.0.0",
59
62
  "@types/jest": "^29.2.1",
60
63
  "@types/react": "^18.0.24",
61
64
  "@types/react-native": "^0.71.3",
@@ -26,17 +26,15 @@ const LivekitReactNative = NativeModules.LivekitReactNative
26
26
  * This is ignored when an output is manually selected with {@link AudioSession.selectAudioOutput}.
27
27
  *
28
28
  * By default, the order is set to:
29
- * 1. `"speaker"`
30
- * 2. `"earpiece"`
31
- * 3. `"headset"`
32
- * 4. `"bluetooth"`
29
+ * 1. `"bluetooth"
30
+ * 2. `"headset"``
31
+ * 3. `"speaker"`
32
+ * 4. `"earpiece"`
33
33
  *
34
- * * audioMode - The audio mode to use for the audio session. Defaults to 'normal'.
34
+ * * audioTypeOptions - An {@link AndroidAudioTypeOptions} object which provides the
35
+ * audio options to use on Android.
35
36
  *
36
- * * audioFocusMode - The focus mode to use for the audio session. Defaults to 'gain'.
37
- *
38
- * See [AudioManager](https://developer.android.com/reference/android/media/AudioManager) for details
39
- * on audio and focus modes.
37
+ * See {@link AndroidAudioTypePresets} for pre-configured values.
40
38
  *
41
39
  * ----
42
40
  * iOS
@@ -48,23 +46,139 @@ const LivekitReactNative = NativeModules.LivekitReactNative
48
46
  export type AudioConfiguration = {
49
47
  android?: {
50
48
  preferredOutputList?: ('speaker' | 'earpiece' | 'headset' | 'bluetooth')[];
51
- audioMode?:
52
- | 'normal'
53
- | 'callScreening'
54
- | 'inCall'
55
- | 'inCommunication'
56
- | 'ringtone';
57
- audioFocusMode?:
58
- | 'gain'
59
- | 'gainTransient'
60
- | 'gainTransientExclusive'
61
- | 'gainTransientMayDuck';
49
+ audioTypeOptions: AndroidAudioTypeOptions;
62
50
  };
63
51
  ios?: {
64
52
  defaultOutput?: 'speaker' | 'earpiece';
65
53
  };
66
54
  };
67
55
 
56
+ export type AndroidAudioTypeOptions = {
57
+ /**
58
+ * Whether LiveKit should handle managing the audio focus or not.
59
+ *
60
+ * Defaults to true.
61
+ */
62
+ manageAudioFocus?: boolean;
63
+
64
+ /**
65
+ * Corresponds to {@link https://developer.android.com/reference/android/media/AudioManager#setMode(int)}
66
+ *
67
+ * Defaults to 'inCommunication'.
68
+ */
69
+ audioMode?:
70
+ | 'normal'
71
+ | 'callScreening'
72
+ | 'inCall'
73
+ | 'inCommunication'
74
+ | 'ringtone';
75
+
76
+ /**
77
+ * Corresponds to the duration hint when requesting audio focus.
78
+ *
79
+ * Defaults to 'gain'.
80
+ *
81
+ * See also {@link https://developer.android.com/reference/android/media/AudioManager#AUDIOFOCUS_GAIN}
82
+ */
83
+ audioFocusMode?:
84
+ | 'gain'
85
+ | 'gainTransient'
86
+ | 'gainTransientExclusive'
87
+ | 'gainTransientMayDuck';
88
+
89
+ /**
90
+ * Corresponds to Android's AudioAttributes usage type.
91
+ *
92
+ * Defaults to 'voiceCommunication'.
93
+ *
94
+ * See also {@link https://developer.android.com/reference/android/media/AudioAttributes}
95
+ */
96
+ audioAttributesUsageType?:
97
+ | 'alarm'
98
+ | 'assistanceAccessibility'
99
+ | 'assistanceNavigationGuidance'
100
+ | 'assistanceSonification'
101
+ | 'assistant'
102
+ | 'game'
103
+ | 'media'
104
+ | 'notification'
105
+ | 'notificationEvent'
106
+ | 'notificationRingtone'
107
+ | 'unknown'
108
+ | 'voiceCommunication'
109
+ | 'voiceCommunicationSignalling';
110
+
111
+ /**
112
+ * Corresponds to Android's AndroidAttributes content type.
113
+ *
114
+ * Defaults to 'speech'.
115
+ *
116
+ * See also {@link https://developer.android.com/reference/android/media/AudioAttributes}
117
+ */
118
+ audioAttributesContentType?:
119
+ | 'movie'
120
+ | 'music'
121
+ | 'sonification'
122
+ | 'speech'
123
+ | 'unknown';
124
+
125
+ /**
126
+ * Corresponds to the stream type when requesting audio focus. Used on pre-O devices.
127
+ *
128
+ * Defaults to 'voiceCall'
129
+ *
130
+ * See also {@link https://developer.android.com/reference/android/media/AudioManager#STREAM_VOICE_CALL}
131
+ */
132
+ audioStreamType?:
133
+ | 'accessibility'
134
+ | 'alarm'
135
+ | 'dtmf'
136
+ | 'music'
137
+ | 'notification'
138
+ | 'ring'
139
+ | 'system'
140
+ | 'voiceCall';
141
+
142
+ /**
143
+ * On certain Android devices, audio routing does not function properly and
144
+ * bluetooth microphones will not work unless audio mode is set to
145
+ * `inCommunication` or `inCall`. Audio routing is turned off those cases.
146
+ *
147
+ * If this set to true, will attempt to do audio routing regardless of audio mode.
148
+ *
149
+ * Defaults to false.
150
+ */
151
+ forceHandleAudioRouting?: boolean;
152
+ };
153
+
154
+ export const AndroidAudioTypePresets: {
155
+ /**
156
+ * A pre-configured AndroidAudioConfiguration for voice communication.
157
+ */
158
+ communication: AndroidAudioTypeOptions;
159
+ /**
160
+ * A pre-configured AndroidAudioConfiguration for media playback.
161
+ */
162
+ media: AndroidAudioTypeOptions;
163
+ } = {
164
+ communication: {
165
+ manageAudioFocus: true,
166
+ audioMode: 'inCommunication',
167
+ audioFocusMode: 'gain',
168
+ audioStreamType: 'voiceCall',
169
+ audioAttributesUsageType: 'voiceCommunication',
170
+ audioAttributesContentType: 'speech',
171
+ },
172
+ media: {
173
+ manageAudioFocus: true,
174
+ audioMode: 'normal',
175
+ audioFocusMode: 'gain',
176
+ audioStreamType: 'music',
177
+ audioAttributesUsageType: 'media',
178
+ audioAttributesContentType: 'unknown',
179
+ },
180
+ } as const;
181
+
68
182
  export default class AudioSession {
69
183
  /**
70
184
  * Applies the provided audio configuration to the underlying AudioSession.
@@ -100,9 +214,6 @@ export default class AudioSession {
100
214
  * * "headset"
101
215
  * * "bluetooth"
102
216
  *
103
- * Note: For applications targeting SDK versions over 30, the runtime BLUETOOTH_CONNECT
104
- * permission must be requested to send audio to bluetooth headsets.
105
- *
106
217
  * ----
107
218
  *
108
219
  * For iOS, due to OS limitations, the only available types are:
package/src/index.tsx CHANGED
@@ -1,6 +1,10 @@
1
1
  import { registerGlobals as webrtcRegisterGlobals } from '@livekit/react-native-webrtc';
2
2
  import { setupURLPolyfill } from 'react-native-url-polyfill';
3
- import AudioSession from './audio/AudioSession';
3
+ import 'fastestsmallesttextencoderdecoder';
4
+ import AudioSession, {
5
+ AndroidAudioTypePresets,
6
+ AndroidAudioTypeOptions,
7
+ } from './audio/AudioSession';
4
8
  import type { AudioConfiguration } from './audio/AudioSession';
5
9
  import { PixelRatio, Platform } from 'react-native';
6
10
  import type { LiveKitReactNativeInfo } from 'livekit-client';
@@ -17,6 +21,8 @@ export function registerGlobals() {
17
21
  fixWebrtcAdapter();
18
22
  shimPromiseAllSettled();
19
23
  shimArrayAt();
24
+ shimAsyncIterator();
25
+ shimIterator();
20
26
  }
21
27
  function livekitRegisterGlobals() {
22
28
  let lkGlobal: LiveKitReactNativeInfo = {
@@ -52,7 +58,22 @@ function shimArrayAt() {
52
58
  }
53
59
  }
54
60
 
61
+ function shimAsyncIterator() {
62
+ var shim = require('well-known-symbols/Symbol.asyncIterator/shim');
63
+ shim();
64
+ }
65
+
66
+ function shimIterator() {
67
+ var shim = require('well-known-symbols/Symbol.iterator/shim');
68
+ shim();
69
+ }
70
+
55
71
  export * from './components/VideoView';
56
72
  export * from './useParticipant';
57
73
  export * from './useRoom';
58
- export { AudioSession, AudioConfiguration };
74
+ export {
75
+ AudioSession,
76
+ AudioConfiguration,
77
+ AndroidAudioTypeOptions,
78
+ AndroidAudioTypePresets,
79
+ };