@livekit/react-native 1.4.1 → 2.0.1
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 +51 -24
- package/ios/LivekitReactNative.h +1 -0
- package/ios/LivekitReactNative.m +0 -1
- package/lib/commonjs/audio/AudioManager.js +15 -6
- package/lib/commonjs/audio/AudioManager.js.map +1 -1
- package/lib/commonjs/audio/AudioSession.js +2 -0
- package/lib/commonjs/audio/AudioSession.js.map +1 -1
- package/lib/commonjs/useParticipant.js +9 -9
- package/lib/commonjs/useParticipant.js.map +1 -1
- package/lib/commonjs/useRoom.js +5 -5
- package/lib/commonjs/useRoom.js.map +1 -1
- package/lib/module/audio/AudioManager.js +15 -6
- package/lib/module/audio/AudioManager.js.map +1 -1
- package/lib/module/audio/AudioSession.js +2 -0
- package/lib/module/audio/AudioSession.js.map +1 -1
- package/lib/module/useParticipant.js +9 -9
- package/lib/module/useParticipant.js.map +1 -1
- package/lib/module/useRoom.js +5 -5
- package/lib/module/useRoom.js.map +1 -1
- package/lib/typescript/audio/AudioManager.d.ts +1 -1
- package/lib/typescript/audio/AudioSession.d.ts +2 -0
- package/package.json +2 -2
- package/src/audio/AudioManager.ts +18 -8
- package/src/audio/AudioSession.ts +2 -0
- package/src/useParticipant.ts +15 -9
- package/src/useRoom.ts +5 -5
package/README.md
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
<!--BEGIN_BANNER_IMAGE-->
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="/.github/banner_dark.png">
|
|
5
|
+
<source media="(prefers-color-scheme: light)" srcset="/.github/banner_light.png">
|
|
6
|
+
<img style="width:100%;" alt="The LiveKit icon, the name of the repository and some sample code in the background." src="https://raw.githubusercontent.com/livekit/client-sdk-react-native/main/.github/banner_light.png">
|
|
7
|
+
</picture>
|
|
8
|
+
|
|
9
|
+
<!--END_BANNER_IMAGE-->
|
|
8
10
|
|
|
9
11
|
# livekit-react-native
|
|
10
12
|
|
|
11
|
-
<!--BEGIN_DESCRIPTION-->
|
|
13
|
+
<!--BEGIN_DESCRIPTION-->
|
|
14
|
+
Use this SDK to add real-time video, audio and data features to your React Native app. By connecting to a self- or cloud-hosted <a href="https://livekit.io/">LiveKit</a> server, you can quickly build applications like interactive live streaming or video calls with just a few lines of code.
|
|
15
|
+
<!--END_DESCRIPTION-->
|
|
12
16
|
|
|
13
17
|
## Installation
|
|
14
18
|
|
|
@@ -37,7 +41,8 @@ Once the `@livekit/react-native-webrtc` dependency is installed, one last step i
|
|
|
37
41
|
|
|
38
42
|
In your [MainApplication.java](https://github.com/livekit/client-sdk-react-native/blob/main/example/android/app/src/main/java/com/example/livekitreactnative/MainApplication.java) file:
|
|
39
43
|
|
|
40
|
-
|
|
44
|
+
#### Java
|
|
45
|
+
```java
|
|
41
46
|
import com.livekit.reactnative.LiveKitReactNative;
|
|
42
47
|
import com.livekit.reactnative.audio.AudioType;
|
|
43
48
|
|
|
@@ -46,8 +51,8 @@ public class MainApplication extends Application implements ReactApplication {
|
|
|
46
51
|
@Override
|
|
47
52
|
public void onCreate() {
|
|
48
53
|
// Place this above any other RN related initialization
|
|
49
|
-
// When AudioType is omitted, it'll default to CommunicationAudioType
|
|
50
|
-
//
|
|
54
|
+
// When AudioType is omitted, it'll default to CommunicationAudioType.
|
|
55
|
+
// Use MediaAudioType if user is only consuming audio, and not publishing.
|
|
51
56
|
LiveKitReactNative.setup(this, new AudioType.CommunicationAudioType());
|
|
52
57
|
|
|
53
58
|
//...
|
|
@@ -55,11 +60,30 @@ public class MainApplication extends Application implements ReactApplication {
|
|
|
55
60
|
}
|
|
56
61
|
```
|
|
57
62
|
|
|
63
|
+
Or in your **MainApplication.kt** if you are using RN 0.73+
|
|
64
|
+
#### Kotlin
|
|
65
|
+
```kotlin
|
|
66
|
+
import com.livekit.reactnative.LiveKitReactNative
|
|
67
|
+
import com.livekit.reactnative.audio.AudioType
|
|
68
|
+
|
|
69
|
+
class MainApplication : Application, ReactApplication() {
|
|
70
|
+
override fun onCreate() {
|
|
71
|
+
// Place this above any other RN related initialization
|
|
72
|
+
// When AudioType is omitted, it'll default to CommunicationAudioType.
|
|
73
|
+
// Use MediaAudioType if user is only consuming audio, and not publishing.
|
|
74
|
+
LiveKitReactNative.setup(this, AudioType.CommunicationAudioType())
|
|
75
|
+
|
|
76
|
+
//...
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
----
|
|
81
|
+
|
|
58
82
|
### iOS
|
|
59
83
|
|
|
60
84
|
In your [AppDelegate.m](https://github.com/livekit/client-sdk-react-native/blob/main/example/ios/LivekitReactNativeExample/AppDelegate.mm) file:
|
|
61
85
|
|
|
62
|
-
```
|
|
86
|
+
```objc
|
|
63
87
|
#import "LivekitReactNative.h"
|
|
64
88
|
|
|
65
89
|
@implementation AppDelegate
|
|
@@ -135,12 +159,13 @@ Additional documentation for the LiveKit SDK can be found at https://docs.liveki
|
|
|
135
159
|
|
|
136
160
|
## Audio sessions
|
|
137
161
|
|
|
138
|
-
As seen in the above example, we've introduced a
|
|
162
|
+
As seen in the above example, we've introduced a class `AudioSession` that helps
|
|
139
163
|
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.
|
|
140
164
|
|
|
141
165
|
You can customize the configuration of the audio session with `configureAudio`.
|
|
142
166
|
|
|
143
|
-
###
|
|
167
|
+
### Android
|
|
168
|
+
#### Media playback
|
|
144
169
|
|
|
145
170
|
By default, the audio session is set up for bidirectional communication. In this mode, the audio framework exhibits the following behaviors:
|
|
146
171
|
|
|
@@ -150,8 +175,6 @@ By default, the audio session is set up for bidirectional communication. In this
|
|
|
150
175
|
|
|
151
176
|
If you're leveraging LiveKit primarily for media playback, you have the option to reconfigure the audio session to better suit media playback. Here's how:
|
|
152
177
|
|
|
153
|
-
Note: iOS audio session customization is in development, and will be documented here when released.
|
|
154
|
-
|
|
155
178
|
```js
|
|
156
179
|
useEffect(() => {
|
|
157
180
|
let connect = async () => {
|
|
@@ -173,7 +196,7 @@ useEffect(() => {
|
|
|
173
196
|
}, [url, token, room]);
|
|
174
197
|
```
|
|
175
198
|
|
|
176
|
-
|
|
199
|
+
#### Customizing audio session
|
|
177
200
|
|
|
178
201
|
Instead of using our presets, you can further customize the audio session to suit your specific needs.
|
|
179
202
|
|
|
@@ -196,6 +219,12 @@ await AudioSession.configureAudio({
|
|
|
196
219
|
await AudioSession.startAudioSession();
|
|
197
220
|
```
|
|
198
221
|
|
|
222
|
+
### iOS
|
|
223
|
+
|
|
224
|
+
For iOS, the most appropriate audio configuration may change over time when local/remote
|
|
225
|
+
audio tracks publish and unpublish from the room. To adapt to this, the [`useIOSAudioManagement`](https://htmlpreview.github.io/?https://raw.githubusercontent.com/livekit/client-sdk-react-native/main/docs/functions/useIOSAudioManagement.html)
|
|
226
|
+
hook is advised over just configuring the audio session once for the entire audio session.
|
|
227
|
+
|
|
199
228
|
## Screenshare
|
|
200
229
|
|
|
201
230
|
Enabling screenshare requires extra installation steps:
|
|
@@ -207,9 +236,8 @@ Android screenshare requires a foreground service with type `mediaProjection` to
|
|
|
207
236
|
The example app uses [@voximplant/react-native-foreground-service](https://github.com/voximplant/react-native-foreground-service) for this.
|
|
208
237
|
Ensure that the service is labelled a `mediaProjection` service like so:
|
|
209
238
|
|
|
210
|
-
```
|
|
211
|
-
<service android:name="com.voximplant.foregroundservice.VIForegroundService"
|
|
212
|
-
android:foregroundServiceType="mediaProjection" />
|
|
239
|
+
```xml
|
|
240
|
+
<service android:name="com.voximplant.foregroundservice.VIForegroundService" android:foregroundServiceType="mediaProjection" />
|
|
213
241
|
```
|
|
214
242
|
|
|
215
243
|
Once setup, start the foreground service prior to using screenshare.
|
|
@@ -277,14 +305,13 @@ See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the
|
|
|
277
305
|
Apache License 2.0
|
|
278
306
|
|
|
279
307
|
<!--BEGIN_REPO_NAV-->
|
|
280
|
-
|
|
281
308
|
<br/><table>
|
|
282
|
-
|
|
283
309
|
<thead><tr><th colspan="2">LiveKit Ecosystem</th></tr></thead>
|
|
284
310
|
<tbody>
|
|
285
|
-
<tr><td>
|
|
286
|
-
<tr><td>Server
|
|
287
|
-
<tr><td>
|
|
311
|
+
<tr><td>Real-time SDKs</td><td><a href="https://github.com/livekit/components-js">React 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>
|
|
312
|
+
<tr><td>Server APIs</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/livekit/client-sdk-python">Python</a> · <a href="https://github.com/livekit/client-sdk-rust">Rust</a> · <a href="https://github.com/agence104/livekit-server-sdk-php">PHP (community)</a></td></tr><tr></tr>
|
|
313
|
+
<tr><td>Agents Frameworks</td><td><a href="https://github.com/livekit/agents">Python</a> · <a href="https://github.com/livekit/agent-playground">Playground</a></td></tr><tr></tr>
|
|
314
|
+
<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> · <a href="https://github.com/livekit/sip">SIP</a></td></tr><tr></tr>
|
|
288
315
|
<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>
|
|
289
316
|
</tbody>
|
|
290
317
|
</table>
|
package/ios/LivekitReactNative.h
CHANGED
package/ios/LivekitReactNative.m
CHANGED
|
@@ -33,14 +33,23 @@ function useIOSAudioManagement(room) {
|
|
|
33
33
|
const [localTrackCount, setLocalTrackCount] = (0, _react.useState)(0);
|
|
34
34
|
const [remoteTrackCount, setRemoteTrackCount] = (0, _react.useState)(0);
|
|
35
35
|
const trackState = (0, _react.useMemo)(() => computeAudioTrackState(localTrackCount, remoteTrackCount), [localTrackCount, remoteTrackCount]);
|
|
36
|
+
(0, _react.useEffect)(() => {
|
|
37
|
+
let recalculateTrackCounts = () => {
|
|
38
|
+
setLocalTrackCount(getLocalAudioTrackCount(room));
|
|
39
|
+
setRemoteTrackCount(getRemoteAudioTrackCount(room));
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
recalculateTrackCounts();
|
|
43
|
+
room.on(_livekitClient.RoomEvent.Connected, recalculateTrackCounts);
|
|
44
|
+
return () => {
|
|
45
|
+
room.off(_livekitClient.RoomEvent.Connected, recalculateTrackCounts);
|
|
46
|
+
};
|
|
47
|
+
}, [room]);
|
|
36
48
|
(0, _react.useEffect)(() => {
|
|
37
49
|
if (_reactNative.Platform.OS !== 'ios') {
|
|
38
50
|
return () => {};
|
|
39
51
|
}
|
|
40
52
|
|
|
41
|
-
setLocalTrackCount(getLocalAudioTrackCount(room));
|
|
42
|
-
setRemoteTrackCount(getRemoteAudioTrackCount(room));
|
|
43
|
-
|
|
44
53
|
let onLocalPublished = () => {
|
|
45
54
|
setLocalTrackCount(localTrackCount + 1);
|
|
46
55
|
};
|
|
@@ -95,13 +104,13 @@ function computeAudioTrackState(localTracks, remoteTracks) {
|
|
|
95
104
|
}
|
|
96
105
|
|
|
97
106
|
function getLocalAudioTrackCount(room) {
|
|
98
|
-
return room.localParticipant.
|
|
107
|
+
return room.localParticipant.audioTrackPublications.size;
|
|
99
108
|
}
|
|
100
109
|
|
|
101
110
|
function getRemoteAudioTrackCount(room) {
|
|
102
111
|
var audioTracks = 0;
|
|
103
|
-
room.
|
|
104
|
-
audioTracks += participant.
|
|
112
|
+
room.remoteParticipants.forEach(participant => {
|
|
113
|
+
audioTracks += participant.audioTrackPublications.size;
|
|
105
114
|
});
|
|
106
115
|
return audioTracks;
|
|
107
116
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["AudioManager.ts"],"names":["useIOSAudioManagement","room","preferSpeakerOutput","onConfigureNativeAudio","localTrackCount","setLocalTrackCount","remoteTrackCount","setRemoteTrackCount","trackState","computeAudioTrackState","
|
|
1
|
+
{"version":3,"sources":["AudioManager.ts"],"names":["useIOSAudioManagement","room","preferSpeakerOutput","onConfigureNativeAudio","localTrackCount","setLocalTrackCount","remoteTrackCount","setRemoteTrackCount","trackState","computeAudioTrackState","recalculateTrackCounts","getLocalAudioTrackCount","getRemoteAudioTrackCount","on","RoomEvent","Connected","off","Platform","OS","onLocalPublished","onLocalUnpublished","log","warn","Math","max","onRemotePublished","onRemoteUnpublished","LocalTrackPublished","LocalTrackUnpublished","TrackPublished","TrackUnpublished","configFunc","getDefaultAppleAudioConfigurationForMode","audioConfig","AudioSession","setAppleAudioConfiguration","localTracks","remoteTracks","localParticipant","audioTrackPublications","size","audioTracks","remoteParticipants","forEach","participant"],"mappings":";;;;;;;AAAA;;AACA;;AACA;;AACA;;AAKA;;;;;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASA,qBAAT,CACLC,IADK,EAOL;AAAA,MALAC,mBAKA,uEAL+B,IAK/B;AAAA,MAJAC,sBAIA;AACA,QAAM,CAACC,eAAD,EAAkBC,kBAAlB,IAAwC,qBAAS,CAAT,CAA9C;AACA,QAAM,CAACC,gBAAD,EAAmBC,mBAAnB,IAA0C,qBAAS,CAAT,CAAhD;AACA,QAAMC,UAAU,GAAG,oBACjB,MAAMC,sBAAsB,CAACL,eAAD,EAAkBE,gBAAlB,CADX,EAEjB,CAACF,eAAD,EAAkBE,gBAAlB,CAFiB,CAAnB;AAKA,wBAAU,MAAM;AACd,QAAII,sBAAsB,GAAG,MAAM;AACjCL,MAAAA,kBAAkB,CAACM,uBAAuB,CAACV,IAAD,CAAxB,CAAlB;AACAM,MAAAA,mBAAmB,CAACK,wBAAwB,CAACX,IAAD,CAAzB,CAAnB;AACD,KAHD;;AAKAS,IAAAA,sBAAsB;AAEtBT,IAAAA,IAAI,CAACY,EAAL,CAAQC,yBAAUC,SAAlB,EAA6BL,sBAA7B;AAEA,WAAO,MAAM;AACXT,MAAAA,IAAI,CAACe,GAAL,CAASF,yBAAUC,SAAnB,EAA8BL,sBAA9B;AACD,KAFD;AAGD,GAbD,EAaG,CAACT,IAAD,CAbH;AAcA,wBAAU,MAAM;AACd,QAAIgB,sBAASC,EAAT,KAAgB,KAApB,EAA2B;AACzB,aAAO,MAAM,CAAE,CAAf;AACD;;AAED,QAAIC,gBAAgB,GAAG,MAAM;AAC3Bd,MAAAA,kBAAkB,CAACD,eAAe,GAAG,CAAnB,CAAlB;AACD,KAFD;;AAGA,QAAIgB,kBAAkB,GAAG,MAAM;AAC7B,UAAIhB,eAAe,GAAG,CAAlB,GAAsB,CAA1B,EAA6B;AAC3BiB,cAAIC,IAAJ,CACE,iFADF;AAGD;;AACDjB,MAAAA,kBAAkB,CAACkB,IAAI,CAACC,GAAL,CAASpB,eAAe,GAAG,CAA3B,EAA8B,CAA9B,CAAD,CAAlB;AACD,KAPD;;AAQA,QAAIqB,iBAAiB,GAAG,MAAM;AAC5BlB,MAAAA,mBAAmB,CAACD,gBAAgB,GAAG,CAApB,CAAnB;AACD,KAFD;;AAGA,QAAIoB,mBAAmB,GAAG,MAAM;AAC9B,UAAIpB,gBAAgB,GAAG,CAAnB,GAAuB,CAA3B,EAA8B;AAC5Be,cAAIC,IAAJ,CACE,kFADF;AAGD;;AACDf,MAAAA,mBAAmB,CAACgB,IAAI,CAACC,GAAL,CAASlB,gBAAgB,GAAG,CAA5B,EAA+B,CAA/B,CAAD,CAAnB;AACD,KAPD;;AASAL,IAAAA,IAAI,CACDY,EADH,CACMC,yBAAUa,mBADhB,EACqCR,gBADrC,EAEGN,EAFH,CAEMC,yBAAUc,qBAFhB,EAEuCR,kBAFvC,EAGGP,EAHH,CAGMC,yBAAUe,cAHhB,EAGgCJ,iBAHhC,EAIGZ,EAJH,CAIMC,yBAAUgB,gBAJhB,EAIkCJ,mBAJlC;AAMA,WAAO,MAAM;AACXzB,MAAAA,IAAI,CACDe,GADH,CACOF,yBAAUa,mBADjB,EACsCR,gBADtC,EAEGH,GAFH,CAEOF,yBAAUc,qBAFjB,EAEwCR,kBAFxC,EAGGJ,GAHH,CAGOF,yBAAUe,cAHjB,EAGiCJ,iBAHjC,EAIGT,GAJH,CAIOF,yBAAUgB,gBAJjB,EAImCJ,mBAJnC;AAKD,KAND;AAOD,GAzCD,EAyCG,CAACzB,IAAD,EAAOG,eAAP,EAAwBE,gBAAxB,CAzCH;AA2CA,wBAAU,MAAM;AACd,QAAIW,sBAASC,EAAT,KAAgB,KAApB,EAA2B;AACzB;AACD;;AAED,QAAIa,UAAU,GACZ5B,sBADY,aACZA,sBADY,cACZA,sBADY,GACc6B,sDAD5B;AAEA,QAAIC,WAAW,GAAGF,UAAU,CAACvB,UAAD,EAAaN,mBAAb,CAA5B;;AACAgC,0BAAaC,0BAAb,CAAwCF,WAAxC;AACD,GATD,EASG,CAACzB,UAAD,EAAaL,sBAAb,EAAqCD,mBAArC,CATH;AAUD;;AAED,SAASO,sBAAT,CACE2B,WADF,EAEEC,YAFF,EAGmB;AACjB,MAAID,WAAW,GAAG,CAAd,IAAmBC,YAAY,GAAG,CAAtC,EAAyC;AACvC,WAAO,gBAAP;AACD,GAFD,MAEO,IAAID,WAAW,GAAG,CAAd,IAAmBC,YAAY,KAAK,CAAxC,EAA2C;AAChD,WAAO,WAAP;AACD,GAFM,MAEA,IAAID,WAAW,KAAK,CAAhB,IAAqBC,YAAY,GAAG,CAAxC,EAA2C;AAChD,WAAO,YAAP;AACD,GAFM,MAEA;AACL,WAAO,MAAP;AACD;AACF;;AAED,SAAS1B,uBAAT,CAAiCV,IAAjC,EAAqD;AACnD,SAAOA,IAAI,CAACqC,gBAAL,CAAsBC,sBAAtB,CAA6CC,IAApD;AACD;;AAED,SAAS5B,wBAAT,CAAkCX,IAAlC,EAAsD;AACpD,MAAIwC,WAAW,GAAG,CAAlB;AACAxC,EAAAA,IAAI,CAACyC,kBAAL,CAAwBC,OAAxB,CAAiCC,WAAD,IAAiB;AAC/CH,IAAAA,WAAW,IAAIG,WAAW,CAACL,sBAAZ,CAAmCC,IAAlD;AACD,GAFD;AAIA,SAAOC,WAAP;AACD","sourcesContent":["import { useState, useEffect, useMemo } from 'react';\nimport { Platform } from 'react-native';\nimport { RoomEvent, Room } from 'livekit-client';\nimport AudioSession, {\n getDefaultAppleAudioConfigurationForMode,\n type AppleAudioConfiguration,\n type AudioTrackState,\n} from './AudioSession';\nimport { log } from '..';\n\n/**\n * Handles setting the appropriate AVAudioSession options automatically\n * depending on the audio track states of the Room.\n *\n * @param room\n * @param preferSpeakerOutput\n * @param onConfigureNativeAudio A custom method for determining options used.\n */\nexport function useIOSAudioManagement(\n room: Room,\n preferSpeakerOutput: boolean = true,\n onConfigureNativeAudio?: (\n trackState: AudioTrackState,\n preferSpeakerOutput: boolean\n ) => AppleAudioConfiguration\n) {\n const [localTrackCount, setLocalTrackCount] = useState(0);\n const [remoteTrackCount, setRemoteTrackCount] = useState(0);\n const trackState = useMemo(\n () => computeAudioTrackState(localTrackCount, remoteTrackCount),\n [localTrackCount, remoteTrackCount]\n );\n\n useEffect(() => {\n let recalculateTrackCounts = () => {\n setLocalTrackCount(getLocalAudioTrackCount(room));\n setRemoteTrackCount(getRemoteAudioTrackCount(room));\n };\n\n recalculateTrackCounts();\n\n room.on(RoomEvent.Connected, recalculateTrackCounts);\n\n return () => {\n room.off(RoomEvent.Connected, recalculateTrackCounts);\n };\n }, [room]);\n useEffect(() => {\n if (Platform.OS !== 'ios') {\n return () => {};\n }\n\n let onLocalPublished = () => {\n setLocalTrackCount(localTrackCount + 1);\n };\n let onLocalUnpublished = () => {\n if (localTrackCount - 1 < 0) {\n log.warn(\n 'mismatched local audio track count! attempted to reduce track count below zero.'\n );\n }\n setLocalTrackCount(Math.max(localTrackCount - 1, 0));\n };\n let onRemotePublished = () => {\n setRemoteTrackCount(remoteTrackCount + 1);\n };\n let onRemoteUnpublished = () => {\n if (remoteTrackCount - 1 < 0) {\n log.warn(\n 'mismatched remote audio track count! attempted to reduce track count below zero.'\n );\n }\n setRemoteTrackCount(Math.max(remoteTrackCount - 1, 0));\n };\n\n room\n .on(RoomEvent.LocalTrackPublished, onLocalPublished)\n .on(RoomEvent.LocalTrackUnpublished, onLocalUnpublished)\n .on(RoomEvent.TrackPublished, onRemotePublished)\n .on(RoomEvent.TrackUnpublished, onRemoteUnpublished);\n\n return () => {\n room\n .off(RoomEvent.LocalTrackPublished, onLocalPublished)\n .off(RoomEvent.LocalTrackUnpublished, onLocalUnpublished)\n .off(RoomEvent.TrackPublished, onRemotePublished)\n .off(RoomEvent.TrackUnpublished, onRemoteUnpublished);\n };\n }, [room, localTrackCount, remoteTrackCount]);\n\n useEffect(() => {\n if (Platform.OS !== 'ios') {\n return;\n }\n\n let configFunc =\n onConfigureNativeAudio ?? getDefaultAppleAudioConfigurationForMode;\n let audioConfig = configFunc(trackState, preferSpeakerOutput);\n AudioSession.setAppleAudioConfiguration(audioConfig);\n }, [trackState, onConfigureNativeAudio, preferSpeakerOutput]);\n}\n\nfunction computeAudioTrackState(\n localTracks: number,\n remoteTracks: number\n): AudioTrackState {\n if (localTracks > 0 && remoteTracks > 0) {\n return 'localAndRemote';\n } else if (localTracks > 0 && remoteTracks === 0) {\n return 'localOnly';\n } else if (localTracks === 0 && remoteTracks > 0) {\n return 'remoteOnly';\n } else {\n return 'none';\n }\n}\n\nfunction getLocalAudioTrackCount(room: Room): number {\n return room.localParticipant.audioTrackPublications.size;\n}\n\nfunction getRemoteAudioTrackCount(room: Room): number {\n var audioTracks = 0;\n room.remoteParticipants.forEach((participant) => {\n audioTracks += participant.audioTrackPublications.size;\n });\n\n return audioTracks;\n}\n"]}
|
|
@@ -40,6 +40,8 @@ const LivekitReactNative = _reactNative.NativeModules.LivekitReactNative ? _reac
|
|
|
40
40
|
*
|
|
41
41
|
* See {@link AndroidAudioTypePresets} for pre-configured values.
|
|
42
42
|
*
|
|
43
|
+
* NOTE: If `audioTypeOptions` is set, this must also be reflected in your android MainApplication setup.
|
|
44
|
+
*
|
|
43
45
|
* ----
|
|
44
46
|
* iOS
|
|
45
47
|
*
|
|
@@ -1 +1 @@
|
|
|
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","getDefaultAppleAudioConfigurationForMode","mode","preferSpeakerOutput","audioCategory","audioCategoryOptions","AudioSession","config","configureAudio","startAudioSession","stopAudioSession","OS","getAudioOutputs","deviceId","selectAudioOutput","showAudioRoutePicker","setAppleAudioConfiguration"],"mappings":"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","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 type AppleAudioMode =\n | 'default'\n | 'gameChat'\n | 'measurement'\n | 'moviePlayback'\n | 'spokenAudio'\n | 'videoChat'\n | 'videoRecording'\n | 'voiceChat'\n | 'voicePrompt';\n\nexport type AppleAudioCategory =\n | 'soloAmbient'\n | 'playback'\n | 'record'\n | 'playAndRecord'\n | 'multiRoute';\n\nexport type AppleAudioCategoryOption =\n | 'mixWithOthers'\n | 'duckOthers'\n | 'interruptSpokenAudioAndMixWithOthers'\n | 'allowBluetooth'\n | 'allowBluetoothA2DP'\n | 'allowAirPlay'\n | 'defaultToSpeaker';\n\nexport type AppleAudioConfiguration = {\n audioCategory?: AppleAudioCategory;\n audioCategoryOptions?: AppleAudioCategoryOption[];\n audioMode?: AppleAudioMode;\n};\n\nexport type AudioTrackState =\n | 'none'\n | 'remoteOnly'\n | 'localOnly'\n | 'localAndRemote';\n\nexport function getDefaultAppleAudioConfigurationForMode(\n mode: AudioTrackState,\n preferSpeakerOutput: boolean = true\n): AppleAudioConfiguration {\n if (mode === 'remoteOnly') {\n return {\n audioCategory: 'playback',\n audioCategoryOptions: ['mixWithOthers'],\n audioMode: 'spokenAudio',\n };\n } else if (mode === 'localAndRemote' || mode === 'localOnly') {\n return {\n audioCategory: 'playAndRecord',\n audioCategoryOptions: ['allowBluetooth', 'mixWithOthers'],\n audioMode: preferSpeakerOutput ? 'videoChat' : 'voiceChat',\n };\n }\n\n return {\n audioCategory: 'soloAmbient',\n audioCategoryOptions: [],\n audioMode: 'default',\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 * See also useIOSAudioManagement for automatic configuration of iOS audio options.\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 static setAppleAudioConfiguration = async (\n config: AppleAudioConfiguration\n ) => {\n if (Platform.OS === 'ios') {\n await LivekitReactNative.setAppleAudioConfiguration(config);\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","getDefaultAppleAudioConfigurationForMode","mode","preferSpeakerOutput","audioCategory","audioCategoryOptions","AudioSession","config","configureAudio","startAudioSession","stopAudioSession","OS","getAudioOutputs","deviceId","selectAudioOutput","showAudioRoutePicker","setAppleAudioConfiguration"],"mappings":"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","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 * NOTE: If `audioTypeOptions` is set, this must also be reflected in your android MainApplication setup.\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 type AppleAudioMode =\n | 'default'\n | 'gameChat'\n | 'measurement'\n | 'moviePlayback'\n | 'spokenAudio'\n | 'videoChat'\n | 'videoRecording'\n | 'voiceChat'\n | 'voicePrompt';\n\nexport type AppleAudioCategory =\n | 'soloAmbient'\n | 'playback'\n | 'record'\n | 'playAndRecord'\n | 'multiRoute';\n\nexport type AppleAudioCategoryOption =\n | 'mixWithOthers'\n | 'duckOthers'\n | 'interruptSpokenAudioAndMixWithOthers'\n | 'allowBluetooth'\n | 'allowBluetoothA2DP'\n | 'allowAirPlay'\n | 'defaultToSpeaker';\n\nexport type AppleAudioConfiguration = {\n audioCategory?: AppleAudioCategory;\n audioCategoryOptions?: AppleAudioCategoryOption[];\n audioMode?: AppleAudioMode;\n};\n\nexport type AudioTrackState =\n | 'none'\n | 'remoteOnly'\n | 'localOnly'\n | 'localAndRemote';\n\nexport function getDefaultAppleAudioConfigurationForMode(\n mode: AudioTrackState,\n preferSpeakerOutput: boolean = true\n): AppleAudioConfiguration {\n if (mode === 'remoteOnly') {\n return {\n audioCategory: 'playback',\n audioCategoryOptions: ['mixWithOthers'],\n audioMode: 'spokenAudio',\n };\n } else if (mode === 'localAndRemote' || mode === 'localOnly') {\n return {\n audioCategory: 'playAndRecord',\n audioCategoryOptions: ['allowBluetooth', 'mixWithOthers'],\n audioMode: preferSpeakerOutput ? 'videoChat' : 'voiceChat',\n };\n }\n\n return {\n audioCategory: 'soloAmbient',\n audioCategoryOptions: [],\n audioMode: 'default',\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 * See also useIOSAudioManagement for automatic configuration of iOS audio options.\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 static setAppleAudioConfiguration = async (\n config: AppleAudioConfiguration\n ) => {\n if (Platform.OS === 'ios') {\n await LivekitReactNative.setAppleAudioConfiguration(config);\n }\n };\n}\n"]}
|
|
@@ -17,16 +17,16 @@ function useParticipant(participant) {
|
|
|
17
17
|
const [metadata, setMetadata] = (0, _react.useState)();
|
|
18
18
|
const [publications, setPublications] = (0, _react.useState)([]);
|
|
19
19
|
const [subscribedTracks, setSubscribedTracks] = (0, _react.useState)([]);
|
|
20
|
-
const [cameraPublication, setCameraPublication] = (0, _react.useState)(participant.
|
|
21
|
-
const [microphonePublication, setMicrophonePublication] = (0, _react.useState)(participant.
|
|
22
|
-
const [screenSharePublication, setScreenSharePublication] = (0, _react.useState)(participant.
|
|
20
|
+
const [cameraPublication, setCameraPublication] = (0, _react.useState)(participant.getTrackPublication(_livekitClient.Track.Source.Camera));
|
|
21
|
+
const [microphonePublication, setMicrophonePublication] = (0, _react.useState)(participant.getTrackPublication(_livekitClient.Track.Source.Microphone));
|
|
22
|
+
const [screenSharePublication, setScreenSharePublication] = (0, _react.useState)(participant.getTrackPublication(_livekitClient.Track.Source.ScreenShare));
|
|
23
23
|
(0, _react.useEffect)(() => {
|
|
24
24
|
const onPublicationsChanged = () => {
|
|
25
|
-
setPublications(Array.from(participant.
|
|
26
|
-
setCameraPublication(participant.
|
|
27
|
-
setMicrophonePublication(participant.
|
|
28
|
-
setScreenSharePublication(participant.
|
|
29
|
-
setSubscribedTracks(Array.from(participant.
|
|
25
|
+
setPublications(Array.from(participant.trackPublications.values()));
|
|
26
|
+
setCameraPublication(participant.getTrackPublication(_livekitClient.Track.Source.Camera));
|
|
27
|
+
setMicrophonePublication(participant.getTrackPublication(_livekitClient.Track.Source.Microphone));
|
|
28
|
+
setScreenSharePublication(participant.getTrackPublication(_livekitClient.Track.Source.ScreenShare));
|
|
29
|
+
setSubscribedTracks(Array.from(participant.trackPublications.values()).filter(pub => {
|
|
30
30
|
return pub.isSubscribed && pub.track !== undefined;
|
|
31
31
|
}));
|
|
32
32
|
};
|
|
@@ -73,7 +73,7 @@ function useParticipant(participant) {
|
|
|
73
73
|
};
|
|
74
74
|
}, [participant]);
|
|
75
75
|
let muted;
|
|
76
|
-
participant.
|
|
76
|
+
participant.audioTrackPublications.forEach(pub => {
|
|
77
77
|
muted = pub.isMuted;
|
|
78
78
|
});
|
|
79
79
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["useParticipant.ts"],"names":["useParticipant","participant","isAudioMuted","setAudioMuted","setVideoMuted","connectionQuality","setConnectionQuality","isSpeaking","setSpeaking","metadata","setMetadata","publications","setPublications","subscribedTracks","setSubscribedTracks","cameraPublication","setCameraPublication","getTrack","Track","Source","Camera","microphonePublication","setMicrophonePublication","Microphone","screenSharePublication","setScreenSharePublication","ScreenShare","onPublicationsChanged","Array","from","tracks","values","filter","pub","isSubscribed","track","undefined","onMuted","kind","Kind","Audio","Video","onUnmuted","onMetadataChanged","onIsSpeakingChanged","onConnectionQualityUpdate","on","ParticipantEvent","TrackMuted","TrackUnmuted","ParticipantMetadataChanged","IsSpeakingChanged","TrackPublished","TrackUnpublished","TrackSubscribed","TrackUnsubscribed","LocalTrackPublished","LocalTrackUnpublished","ConnectionQualityChanged","off","muted","audioTracks","forEach","isMuted","isLocal","LocalParticipant"],"mappings":"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","sourcesContent":["import {\n ConnectionQuality,\n LocalParticipant,\n Participant,\n ParticipantEvent,\n Track,\n TrackPublication,\n} from 'livekit-client';\nimport { useEffect, useState } from 'react';\n\nexport interface ParticipantState {\n isSpeaking: boolean;\n connectionQuality: ConnectionQuality;\n isLocal: boolean;\n metadata?: string;\n publications: TrackPublication[];\n subscribedTracks: TrackPublication[];\n cameraPublication?: TrackPublication;\n microphonePublication?: TrackPublication;\n screenSharePublication?: TrackPublication;\n}\n\nexport function useParticipant(participant: Participant): ParticipantState {\n const [isAudioMuted, setAudioMuted] = useState(false);\n const [, setVideoMuted] = useState(false);\n const [connectionQuality, setConnectionQuality] = useState<ConnectionQuality>(\n participant.connectionQuality\n );\n const [isSpeaking, setSpeaking] = useState(false);\n const [metadata, setMetadata] = useState<string>();\n const [publications, setPublications] = useState<TrackPublication[]>([]);\n const [subscribedTracks, setSubscribedTracks] = useState<TrackPublication[]>(\n []\n );\n\n const [cameraPublication, setCameraPublication] = useState(\n participant.getTrack(Track.Source.Camera)\n );\n const [microphonePublication, setMicrophonePublication] = useState(\n participant.getTrack(Track.Source.Microphone)\n );\n const [screenSharePublication, setScreenSharePublication] = useState(\n participant.getTrack(Track.Source.ScreenShare)\n );\n useEffect(() => {\n const onPublicationsChanged = () => {\n setPublications(Array.from(participant.tracks.values()));\n setCameraPublication(participant.getTrack(Track.Source.Camera));\n setMicrophonePublication(participant.getTrack(Track.Source.Microphone));\n setScreenSharePublication(participant.getTrack(Track.Source.ScreenShare));\n setSubscribedTracks(\n Array.from(participant.tracks.values()).filter((pub) => {\n return pub.isSubscribed && pub.track !== undefined;\n })\n );\n };\n const onMuted = (pub: TrackPublication) => {\n if (pub.kind === Track.Kind.Audio) {\n setAudioMuted(true);\n } else if (pub.kind === Track.Kind.Video) {\n setVideoMuted(true);\n }\n };\n const onUnmuted = (pub: TrackPublication) => {\n if (pub.kind === Track.Kind.Audio) {\n setAudioMuted(false);\n } else if (pub.kind === Track.Kind.Video) {\n setVideoMuted(false);\n }\n };\n const onMetadataChanged = () => {\n if (participant.metadata) {\n setMetadata(participant.metadata);\n }\n };\n const onIsSpeakingChanged = () => {\n setSpeaking(participant.isSpeaking);\n };\n const onConnectionQualityUpdate = () => {\n setConnectionQuality(participant.connectionQuality);\n };\n\n // register listeners\n participant\n .on(ParticipantEvent.TrackMuted, onMuted)\n .on(ParticipantEvent.TrackUnmuted, onUnmuted)\n .on(ParticipantEvent.ParticipantMetadataChanged, onMetadataChanged)\n .on(ParticipantEvent.IsSpeakingChanged, onIsSpeakingChanged)\n .on(ParticipantEvent.TrackPublished, onPublicationsChanged)\n .on(ParticipantEvent.TrackUnpublished, onPublicationsChanged)\n .on(ParticipantEvent.TrackSubscribed, onPublicationsChanged)\n .on(ParticipantEvent.TrackUnsubscribed, onPublicationsChanged)\n .on(ParticipantEvent.LocalTrackPublished, onPublicationsChanged)\n .on(ParticipantEvent.LocalTrackUnpublished, onPublicationsChanged)\n .on(ParticipantEvent.ConnectionQualityChanged, onConnectionQualityUpdate);\n\n // set initial state\n onMetadataChanged();\n onIsSpeakingChanged();\n onPublicationsChanged();\n\n return () => {\n // cleanup\n participant\n .off(ParticipantEvent.TrackMuted, onMuted)\n .off(ParticipantEvent.TrackUnmuted, onUnmuted)\n .off(ParticipantEvent.ParticipantMetadataChanged, onMetadataChanged)\n .off(ParticipantEvent.IsSpeakingChanged, onIsSpeakingChanged)\n .off(ParticipantEvent.TrackPublished, onPublicationsChanged)\n .off(ParticipantEvent.TrackUnpublished, onPublicationsChanged)\n .off(ParticipantEvent.TrackSubscribed, onPublicationsChanged)\n .off(ParticipantEvent.TrackUnsubscribed, onPublicationsChanged)\n .off(ParticipantEvent.LocalTrackPublished, onPublicationsChanged)\n .off(ParticipantEvent.LocalTrackUnpublished, onPublicationsChanged)\n .off(\n ParticipantEvent.ConnectionQualityChanged,\n onConnectionQualityUpdate\n );\n };\n }, [participant]);\n\n let muted: boolean | undefined;\n participant.audioTracks.forEach((pub) => {\n muted = pub.isMuted;\n });\n if (muted === undefined) {\n muted = true;\n }\n if (isAudioMuted !== muted) {\n setAudioMuted(muted);\n }\n\n return {\n isLocal: participant instanceof LocalParticipant,\n isSpeaking,\n connectionQuality,\n publications,\n subscribedTracks,\n cameraPublication,\n microphonePublication,\n screenSharePublication,\n metadata,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["useParticipant.ts"],"names":["useParticipant","participant","isAudioMuted","setAudioMuted","setVideoMuted","connectionQuality","setConnectionQuality","isSpeaking","setSpeaking","metadata","setMetadata","publications","setPublications","subscribedTracks","setSubscribedTracks","cameraPublication","setCameraPublication","getTrackPublication","Track","Source","Camera","microphonePublication","setMicrophonePublication","Microphone","screenSharePublication","setScreenSharePublication","ScreenShare","onPublicationsChanged","Array","from","trackPublications","values","filter","pub","isSubscribed","track","undefined","onMuted","kind","Kind","Audio","Video","onUnmuted","onMetadataChanged","onIsSpeakingChanged","onConnectionQualityUpdate","on","ParticipantEvent","TrackMuted","TrackUnmuted","ParticipantMetadataChanged","IsSpeakingChanged","TrackPublished","TrackUnpublished","TrackSubscribed","TrackUnsubscribed","LocalTrackPublished","LocalTrackUnpublished","ConnectionQualityChanged","off","muted","audioTrackPublications","forEach","isMuted","isLocal","LocalParticipant"],"mappings":"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","sourcesContent":["import {\n ConnectionQuality,\n LocalParticipant,\n Participant,\n ParticipantEvent,\n Track,\n TrackPublication,\n} from 'livekit-client';\nimport { useEffect, useState } from 'react';\n\nexport interface ParticipantState {\n isSpeaking: boolean;\n connectionQuality: ConnectionQuality;\n isLocal: boolean;\n metadata?: string;\n publications: TrackPublication[];\n subscribedTracks: TrackPublication[];\n cameraPublication?: TrackPublication;\n microphonePublication?: TrackPublication;\n screenSharePublication?: TrackPublication;\n}\n\nexport function useParticipant(participant: Participant): ParticipantState {\n const [isAudioMuted, setAudioMuted] = useState(false);\n const [, setVideoMuted] = useState(false);\n const [connectionQuality, setConnectionQuality] = useState<ConnectionQuality>(\n participant.connectionQuality\n );\n const [isSpeaking, setSpeaking] = useState(false);\n const [metadata, setMetadata] = useState<string>();\n const [publications, setPublications] = useState<TrackPublication[]>([]);\n const [subscribedTracks, setSubscribedTracks] = useState<TrackPublication[]>(\n []\n );\n\n const [cameraPublication, setCameraPublication] = useState(\n participant.getTrackPublication(Track.Source.Camera)\n );\n const [microphonePublication, setMicrophonePublication] = useState(\n participant.getTrackPublication(Track.Source.Microphone)\n );\n const [screenSharePublication, setScreenSharePublication] = useState(\n participant.getTrackPublication(Track.Source.ScreenShare)\n );\n useEffect(() => {\n const onPublicationsChanged = () => {\n setPublications(Array.from(participant.trackPublications.values()));\n setCameraPublication(\n participant.getTrackPublication(Track.Source.Camera)\n );\n setMicrophonePublication(\n participant.getTrackPublication(Track.Source.Microphone)\n );\n setScreenSharePublication(\n participant.getTrackPublication(Track.Source.ScreenShare)\n );\n setSubscribedTracks(\n Array.from(participant.trackPublications.values()).filter((pub) => {\n return pub.isSubscribed && pub.track !== undefined;\n })\n );\n };\n const onMuted = (pub: TrackPublication) => {\n if (pub.kind === Track.Kind.Audio) {\n setAudioMuted(true);\n } else if (pub.kind === Track.Kind.Video) {\n setVideoMuted(true);\n }\n };\n const onUnmuted = (pub: TrackPublication) => {\n if (pub.kind === Track.Kind.Audio) {\n setAudioMuted(false);\n } else if (pub.kind === Track.Kind.Video) {\n setVideoMuted(false);\n }\n };\n const onMetadataChanged = () => {\n if (participant.metadata) {\n setMetadata(participant.metadata);\n }\n };\n const onIsSpeakingChanged = () => {\n setSpeaking(participant.isSpeaking);\n };\n const onConnectionQualityUpdate = () => {\n setConnectionQuality(participant.connectionQuality);\n };\n\n // register listeners\n participant\n .on(ParticipantEvent.TrackMuted, onMuted)\n .on(ParticipantEvent.TrackUnmuted, onUnmuted)\n .on(ParticipantEvent.ParticipantMetadataChanged, onMetadataChanged)\n .on(ParticipantEvent.IsSpeakingChanged, onIsSpeakingChanged)\n .on(ParticipantEvent.TrackPublished, onPublicationsChanged)\n .on(ParticipantEvent.TrackUnpublished, onPublicationsChanged)\n .on(ParticipantEvent.TrackSubscribed, onPublicationsChanged)\n .on(ParticipantEvent.TrackUnsubscribed, onPublicationsChanged)\n .on(ParticipantEvent.LocalTrackPublished, onPublicationsChanged)\n .on(ParticipantEvent.LocalTrackUnpublished, onPublicationsChanged)\n .on(ParticipantEvent.ConnectionQualityChanged, onConnectionQualityUpdate);\n\n // set initial state\n onMetadataChanged();\n onIsSpeakingChanged();\n onPublicationsChanged();\n\n return () => {\n // cleanup\n participant\n .off(ParticipantEvent.TrackMuted, onMuted)\n .off(ParticipantEvent.TrackUnmuted, onUnmuted)\n .off(ParticipantEvent.ParticipantMetadataChanged, onMetadataChanged)\n .off(ParticipantEvent.IsSpeakingChanged, onIsSpeakingChanged)\n .off(ParticipantEvent.TrackPublished, onPublicationsChanged)\n .off(ParticipantEvent.TrackUnpublished, onPublicationsChanged)\n .off(ParticipantEvent.TrackSubscribed, onPublicationsChanged)\n .off(ParticipantEvent.TrackUnsubscribed, onPublicationsChanged)\n .off(ParticipantEvent.LocalTrackPublished, onPublicationsChanged)\n .off(ParticipantEvent.LocalTrackUnpublished, onPublicationsChanged)\n .off(\n ParticipantEvent.ConnectionQualityChanged,\n onConnectionQualityUpdate\n );\n };\n }, [participant]);\n\n let muted: boolean | undefined;\n participant.audioTrackPublications.forEach((pub) => {\n muted = pub.isMuted;\n });\n if (muted === undefined) {\n muted = true;\n }\n if (isAudioMuted !== muted) {\n setAudioMuted(muted);\n }\n\n return {\n isLocal: participant instanceof LocalParticipant,\n isSpeaking,\n connectionQuality,\n publications,\n subscribedTracks,\n cameraPublication,\n microphonePublication,\n screenSharePublication,\n metadata,\n };\n}\n"]}
|
package/lib/commonjs/useRoom.js
CHANGED
|
@@ -19,7 +19,7 @@ function useRoom(room, options) {
|
|
|
19
19
|
const sortFunc = (_options$sortParticip = options === null || options === void 0 ? void 0 : options.sortParticipants) !== null && _options$sortParticip !== void 0 ? _options$sortParticip : sortParticipants;
|
|
20
20
|
(0, _react.useEffect)(() => {
|
|
21
21
|
const onParticipantsChanged = () => {
|
|
22
|
-
const remotes = Array.from(room.
|
|
22
|
+
const remotes = Array.from(room.remoteParticipants.values());
|
|
23
23
|
const newParticipants = [room.localParticipant];
|
|
24
24
|
newParticipants.push(...remotes);
|
|
25
25
|
sortFunc(newParticipants, room.localParticipant);
|
|
@@ -35,8 +35,8 @@ function useRoom(room, options) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
const tracks = [];
|
|
38
|
-
room.
|
|
39
|
-
p.
|
|
38
|
+
room.remoteParticipants.forEach(p => {
|
|
39
|
+
p.audioTrackPublications.forEach(pub => {
|
|
40
40
|
if (pub.audioTrack) {
|
|
41
41
|
tracks.push(pub.audioTrack);
|
|
42
42
|
}
|
|
@@ -105,8 +105,8 @@ function sortParticipants(participants, localParticipant) {
|
|
|
105
105
|
} // video on
|
|
106
106
|
|
|
107
107
|
|
|
108
|
-
const aVideo = a.
|
|
109
|
-
const bVideo = b.
|
|
108
|
+
const aVideo = a.videoTrackPublications.size > 0;
|
|
109
|
+
const bVideo = b.videoTrackPublications.size > 0;
|
|
110
110
|
|
|
111
111
|
if (aVideo !== bVideo) {
|
|
112
112
|
if (aVideo) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["useRoom.ts"],"names":["useRoom","room","options","error","participants","setParticipants","audioTracks","setAudioTracks","sortFunc","sortParticipants","onParticipantsChanged","remotes","Array","from","values","newParticipants","localParticipant","push","onSubscribedTrackChanged","track","kind","Track","Kind","Audio","tracks","forEach","p","pub","audioTrack","onConnectionStateChanged","state","ConnectionState","Connected","once","RoomEvent","Disconnected","off","ParticipantConnected","ParticipantDisconnected","ActiveSpeakersChanged","TrackSubscribed","TrackUnsubscribed","LocalTrackPublished","LocalTrackUnpublished","AudioPlaybackStatusChanged","ConnectionStateChanged","on","Reconnected","disconnect","sort","a","b","isSpeaking","audioLevel","lastSpokeAt","aLast","getTime","bLast","aVideo","videoTracks","size","bVideo","joinedAt","localIdx","indexOf","splice","length"],"mappings":"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","sourcesContent":["import {\n AudioTrack,\n ConnectionState,\n LocalParticipant,\n Participant,\n RemoteTrack,\n Room,\n RoomEvent,\n Track,\n} from 'livekit-client';\nimport { useEffect, useState } from 'react';\n\nexport interface RoomState {\n room?: Room;\n /* all participants in the room, including the local participant. */\n participants: Participant[];\n /* all subscribed audio tracks in the room, not including local participant. */\n audioTracks: AudioTrack[];\n error?: Error;\n}\n\nexport interface RoomOptions {\n sortParticipants?: (participants: Participant[]) => void;\n}\n\nexport function useRoom(room: Room, options?: RoomOptions): RoomState {\n const [error] = useState<Error>();\n const [participants, setParticipants] = useState<Participant[]>([]);\n const [audioTracks, setAudioTracks] = useState<AudioTrack[]>([]);\n\n const sortFunc = options?.sortParticipants ?? sortParticipants;\n\n useEffect(() => {\n const onParticipantsChanged = () => {\n const remotes = Array.from(room.participants.values());\n const newParticipants: Participant[] = [room.localParticipant];\n newParticipants.push(...remotes);\n sortFunc(newParticipants, room.localParticipant);\n setParticipants(newParticipants);\n };\n const onSubscribedTrackChanged = (track?: RemoteTrack) => {\n // ordering may have changed, re-sort\n onParticipantsChanged();\n if (track && track.kind !== Track.Kind.Audio) {\n return;\n }\n const tracks: AudioTrack[] = [];\n room.participants.forEach((p) => {\n p.audioTracks.forEach((pub) => {\n if (pub.audioTrack) {\n tracks.push(pub.audioTrack);\n }\n });\n });\n setAudioTracks(tracks);\n };\n\n const onConnectionStateChanged = (state: ConnectionState) => {\n if (state === ConnectionState.Connected) {\n onParticipantsChanged();\n }\n };\n\n room.once(RoomEvent.Disconnected, () => {\n room\n .off(RoomEvent.ParticipantConnected, onParticipantsChanged)\n .off(RoomEvent.ParticipantDisconnected, onParticipantsChanged)\n .off(RoomEvent.ActiveSpeakersChanged, onParticipantsChanged)\n .off(RoomEvent.TrackSubscribed, onSubscribedTrackChanged)\n .off(RoomEvent.TrackUnsubscribed, onSubscribedTrackChanged)\n .off(RoomEvent.LocalTrackPublished, onParticipantsChanged)\n .off(RoomEvent.LocalTrackUnpublished, onParticipantsChanged)\n .off(RoomEvent.AudioPlaybackStatusChanged, onParticipantsChanged)\n .off(RoomEvent.ConnectionStateChanged, onConnectionStateChanged);\n });\n room\n .on(RoomEvent.ConnectionStateChanged, onConnectionStateChanged)\n .on(RoomEvent.Reconnected, onParticipantsChanged)\n .on(RoomEvent.ParticipantConnected, onParticipantsChanged)\n .on(RoomEvent.ParticipantDisconnected, onParticipantsChanged)\n .on(RoomEvent.ActiveSpeakersChanged, onParticipantsChanged)\n .on(RoomEvent.TrackSubscribed, onSubscribedTrackChanged)\n .on(RoomEvent.TrackUnsubscribed, onSubscribedTrackChanged)\n .on(RoomEvent.LocalTrackPublished, onParticipantsChanged)\n .on(RoomEvent.LocalTrackUnpublished, onParticipantsChanged)\n // trigger a state change by re-sorting participants\n .on(RoomEvent.AudioPlaybackStatusChanged, onParticipantsChanged);\n\n onSubscribedTrackChanged();\n\n return () => {\n room.disconnect();\n };\n }, [room, sortFunc]);\n\n return {\n error,\n participants,\n audioTracks,\n };\n}\n\n/**\n * Default sort for participants, it'll order participants by:\n * 1. dominant speaker (speaker with the loudest audio level)\n * 2. local participant\n * 3. other speakers that are recently active\n * 4. participants with video on\n * 5. by joinedAt\n */\nexport function sortParticipants(\n participants: Participant[],\n localParticipant?: LocalParticipant\n) {\n participants.sort((a, b) => {\n // loudest speaker first\n if (a.isSpeaking && b.isSpeaking) {\n return b.audioLevel - a.audioLevel;\n }\n\n // speaker goes first\n if (a.isSpeaking !== b.isSpeaking) {\n if (a.isSpeaking) {\n return -1;\n } else {\n return 1;\n }\n }\n\n // last active speaker first\n if (a.lastSpokeAt !== b.lastSpokeAt) {\n const aLast = a.lastSpokeAt?.getTime() ?? 0;\n const bLast = b.lastSpokeAt?.getTime() ?? 0;\n return bLast - aLast;\n }\n\n // video on\n const aVideo = a.videoTracks.size > 0;\n const bVideo = b.videoTracks.size > 0;\n if (aVideo !== bVideo) {\n if (aVideo) {\n return -1;\n } else {\n return 1;\n }\n }\n\n // joinedAt\n return (a.joinedAt?.getTime() ?? 0) - (b.joinedAt?.getTime() ?? 0);\n });\n\n if (localParticipant) {\n const localIdx = participants.indexOf(localParticipant);\n if (localIdx >= 0) {\n participants.splice(localIdx, 1);\n if (participants.length > 0) {\n participants.splice(1, 0, localParticipant);\n } else {\n participants.push(localParticipant);\n }\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["useRoom.ts"],"names":["useRoom","room","options","error","participants","setParticipants","audioTracks","setAudioTracks","sortFunc","sortParticipants","onParticipantsChanged","remotes","Array","from","remoteParticipants","values","newParticipants","localParticipant","push","onSubscribedTrackChanged","track","kind","Track","Kind","Audio","tracks","forEach","p","audioTrackPublications","pub","audioTrack","onConnectionStateChanged","state","ConnectionState","Connected","once","RoomEvent","Disconnected","off","ParticipantConnected","ParticipantDisconnected","ActiveSpeakersChanged","TrackSubscribed","TrackUnsubscribed","LocalTrackPublished","LocalTrackUnpublished","AudioPlaybackStatusChanged","ConnectionStateChanged","on","Reconnected","disconnect","sort","a","b","isSpeaking","audioLevel","lastSpokeAt","aLast","getTime","bLast","aVideo","videoTrackPublications","size","bVideo","joinedAt","localIdx","indexOf","splice","length"],"mappings":"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","sourcesContent":["import {\n AudioTrack,\n ConnectionState,\n LocalParticipant,\n Participant,\n RemoteTrack,\n Room,\n RoomEvent,\n Track,\n} from 'livekit-client';\nimport { useEffect, useState } from 'react';\n\nexport interface RoomState {\n room?: Room;\n /* all participants in the room, including the local participant. */\n participants: Participant[];\n /* all subscribed audio tracks in the room, not including local participant. */\n audioTracks: AudioTrack[];\n error?: Error;\n}\n\nexport interface RoomOptions {\n sortParticipants?: (participants: Participant[]) => void;\n}\n\nexport function useRoom(room: Room, options?: RoomOptions): RoomState {\n const [error] = useState<Error>();\n const [participants, setParticipants] = useState<Participant[]>([]);\n const [audioTracks, setAudioTracks] = useState<AudioTrack[]>([]);\n\n const sortFunc = options?.sortParticipants ?? sortParticipants;\n\n useEffect(() => {\n const onParticipantsChanged = () => {\n const remotes = Array.from(room.remoteParticipants.values());\n const newParticipants: Participant[] = [room.localParticipant];\n newParticipants.push(...remotes);\n sortFunc(newParticipants, room.localParticipant);\n setParticipants(newParticipants);\n };\n const onSubscribedTrackChanged = (track?: RemoteTrack) => {\n // ordering may have changed, re-sort\n onParticipantsChanged();\n if (track && track.kind !== Track.Kind.Audio) {\n return;\n }\n const tracks: AudioTrack[] = [];\n room.remoteParticipants.forEach((p) => {\n p.audioTrackPublications.forEach((pub) => {\n if (pub.audioTrack) {\n tracks.push(pub.audioTrack);\n }\n });\n });\n setAudioTracks(tracks);\n };\n\n const onConnectionStateChanged = (state: ConnectionState) => {\n if (state === ConnectionState.Connected) {\n onParticipantsChanged();\n }\n };\n\n room.once(RoomEvent.Disconnected, () => {\n room\n .off(RoomEvent.ParticipantConnected, onParticipantsChanged)\n .off(RoomEvent.ParticipantDisconnected, onParticipantsChanged)\n .off(RoomEvent.ActiveSpeakersChanged, onParticipantsChanged)\n .off(RoomEvent.TrackSubscribed, onSubscribedTrackChanged)\n .off(RoomEvent.TrackUnsubscribed, onSubscribedTrackChanged)\n .off(RoomEvent.LocalTrackPublished, onParticipantsChanged)\n .off(RoomEvent.LocalTrackUnpublished, onParticipantsChanged)\n .off(RoomEvent.AudioPlaybackStatusChanged, onParticipantsChanged)\n .off(RoomEvent.ConnectionStateChanged, onConnectionStateChanged);\n });\n room\n .on(RoomEvent.ConnectionStateChanged, onConnectionStateChanged)\n .on(RoomEvent.Reconnected, onParticipantsChanged)\n .on(RoomEvent.ParticipantConnected, onParticipantsChanged)\n .on(RoomEvent.ParticipantDisconnected, onParticipantsChanged)\n .on(RoomEvent.ActiveSpeakersChanged, onParticipantsChanged)\n .on(RoomEvent.TrackSubscribed, onSubscribedTrackChanged)\n .on(RoomEvent.TrackUnsubscribed, onSubscribedTrackChanged)\n .on(RoomEvent.LocalTrackPublished, onParticipantsChanged)\n .on(RoomEvent.LocalTrackUnpublished, onParticipantsChanged)\n // trigger a state change by re-sorting participants\n .on(RoomEvent.AudioPlaybackStatusChanged, onParticipantsChanged);\n\n onSubscribedTrackChanged();\n\n return () => {\n room.disconnect();\n };\n }, [room, sortFunc]);\n\n return {\n error,\n participants,\n audioTracks,\n };\n}\n\n/**\n * Default sort for participants, it'll order participants by:\n * 1. dominant speaker (speaker with the loudest audio level)\n * 2. local participant\n * 3. other speakers that are recently active\n * 4. participants with video on\n * 5. by joinedAt\n */\nexport function sortParticipants(\n participants: Participant[],\n localParticipant?: LocalParticipant\n) {\n participants.sort((a, b) => {\n // loudest speaker first\n if (a.isSpeaking && b.isSpeaking) {\n return b.audioLevel - a.audioLevel;\n }\n\n // speaker goes first\n if (a.isSpeaking !== b.isSpeaking) {\n if (a.isSpeaking) {\n return -1;\n } else {\n return 1;\n }\n }\n\n // last active speaker first\n if (a.lastSpokeAt !== b.lastSpokeAt) {\n const aLast = a.lastSpokeAt?.getTime() ?? 0;\n const bLast = b.lastSpokeAt?.getTime() ?? 0;\n return bLast - aLast;\n }\n\n // video on\n const aVideo = a.videoTrackPublications.size > 0;\n const bVideo = b.videoTrackPublications.size > 0;\n if (aVideo !== bVideo) {\n if (aVideo) {\n return -1;\n } else {\n return 1;\n }\n }\n\n // joinedAt\n return (a.joinedAt?.getTime() ?? 0) - (b.joinedAt?.getTime() ?? 0);\n });\n\n if (localParticipant) {\n const localIdx = participants.indexOf(localParticipant);\n if (localIdx >= 0) {\n participants.splice(localIdx, 1);\n if (participants.length > 0) {\n participants.splice(1, 0, localParticipant);\n } else {\n participants.push(localParticipant);\n }\n }\n }\n}\n"]}
|
|
@@ -18,14 +18,23 @@ export function useIOSAudioManagement(room) {
|
|
|
18
18
|
const [localTrackCount, setLocalTrackCount] = useState(0);
|
|
19
19
|
const [remoteTrackCount, setRemoteTrackCount] = useState(0);
|
|
20
20
|
const trackState = useMemo(() => computeAudioTrackState(localTrackCount, remoteTrackCount), [localTrackCount, remoteTrackCount]);
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
let recalculateTrackCounts = () => {
|
|
23
|
+
setLocalTrackCount(getLocalAudioTrackCount(room));
|
|
24
|
+
setRemoteTrackCount(getRemoteAudioTrackCount(room));
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
recalculateTrackCounts();
|
|
28
|
+
room.on(RoomEvent.Connected, recalculateTrackCounts);
|
|
29
|
+
return () => {
|
|
30
|
+
room.off(RoomEvent.Connected, recalculateTrackCounts);
|
|
31
|
+
};
|
|
32
|
+
}, [room]);
|
|
21
33
|
useEffect(() => {
|
|
22
34
|
if (Platform.OS !== 'ios') {
|
|
23
35
|
return () => {};
|
|
24
36
|
}
|
|
25
37
|
|
|
26
|
-
setLocalTrackCount(getLocalAudioTrackCount(room));
|
|
27
|
-
setRemoteTrackCount(getRemoteAudioTrackCount(room));
|
|
28
|
-
|
|
29
38
|
let onLocalPublished = () => {
|
|
30
39
|
setLocalTrackCount(localTrackCount + 1);
|
|
31
40
|
};
|
|
@@ -79,13 +88,13 @@ function computeAudioTrackState(localTracks, remoteTracks) {
|
|
|
79
88
|
}
|
|
80
89
|
|
|
81
90
|
function getLocalAudioTrackCount(room) {
|
|
82
|
-
return room.localParticipant.
|
|
91
|
+
return room.localParticipant.audioTrackPublications.size;
|
|
83
92
|
}
|
|
84
93
|
|
|
85
94
|
function getRemoteAudioTrackCount(room) {
|
|
86
95
|
var audioTracks = 0;
|
|
87
|
-
room.
|
|
88
|
-
audioTracks += participant.
|
|
96
|
+
room.remoteParticipants.forEach(participant => {
|
|
97
|
+
audioTracks += participant.audioTrackPublications.size;
|
|
89
98
|
});
|
|
90
99
|
return audioTracks;
|
|
91
100
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["AudioManager.ts"],"names":["useState","useEffect","useMemo","Platform","RoomEvent","AudioSession","getDefaultAppleAudioConfigurationForMode","log","useIOSAudioManagement","room","preferSpeakerOutput","onConfigureNativeAudio","localTrackCount","setLocalTrackCount","remoteTrackCount","setRemoteTrackCount","trackState","computeAudioTrackState","
|
|
1
|
+
{"version":3,"sources":["AudioManager.ts"],"names":["useState","useEffect","useMemo","Platform","RoomEvent","AudioSession","getDefaultAppleAudioConfigurationForMode","log","useIOSAudioManagement","room","preferSpeakerOutput","onConfigureNativeAudio","localTrackCount","setLocalTrackCount","remoteTrackCount","setRemoteTrackCount","trackState","computeAudioTrackState","recalculateTrackCounts","getLocalAudioTrackCount","getRemoteAudioTrackCount","on","Connected","off","OS","onLocalPublished","onLocalUnpublished","warn","Math","max","onRemotePublished","onRemoteUnpublished","LocalTrackPublished","LocalTrackUnpublished","TrackPublished","TrackUnpublished","configFunc","audioConfig","setAppleAudioConfiguration","localTracks","remoteTracks","localParticipant","audioTrackPublications","size","audioTracks","remoteParticipants","forEach","participant"],"mappings":"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","sourcesContent":["import { useState, useEffect, useMemo } from 'react';\nimport { Platform } from 'react-native';\nimport { RoomEvent, Room } from 'livekit-client';\nimport AudioSession, {\n getDefaultAppleAudioConfigurationForMode,\n type AppleAudioConfiguration,\n type AudioTrackState,\n} from './AudioSession';\nimport { log } from '..';\n\n/**\n * Handles setting the appropriate AVAudioSession options automatically\n * depending on the audio track states of the Room.\n *\n * @param room\n * @param preferSpeakerOutput\n * @param onConfigureNativeAudio A custom method for determining options used.\n */\nexport function useIOSAudioManagement(\n room: Room,\n preferSpeakerOutput: boolean = true,\n onConfigureNativeAudio?: (\n trackState: AudioTrackState,\n preferSpeakerOutput: boolean\n ) => AppleAudioConfiguration\n) {\n const [localTrackCount, setLocalTrackCount] = useState(0);\n const [remoteTrackCount, setRemoteTrackCount] = useState(0);\n const trackState = useMemo(\n () => computeAudioTrackState(localTrackCount, remoteTrackCount),\n [localTrackCount, remoteTrackCount]\n );\n\n useEffect(() => {\n let recalculateTrackCounts = () => {\n setLocalTrackCount(getLocalAudioTrackCount(room));\n setRemoteTrackCount(getRemoteAudioTrackCount(room));\n };\n\n recalculateTrackCounts();\n\n room.on(RoomEvent.Connected, recalculateTrackCounts);\n\n return () => {\n room.off(RoomEvent.Connected, recalculateTrackCounts);\n };\n }, [room]);\n useEffect(() => {\n if (Platform.OS !== 'ios') {\n return () => {};\n }\n\n let onLocalPublished = () => {\n setLocalTrackCount(localTrackCount + 1);\n };\n let onLocalUnpublished = () => {\n if (localTrackCount - 1 < 0) {\n log.warn(\n 'mismatched local audio track count! attempted to reduce track count below zero.'\n );\n }\n setLocalTrackCount(Math.max(localTrackCount - 1, 0));\n };\n let onRemotePublished = () => {\n setRemoteTrackCount(remoteTrackCount + 1);\n };\n let onRemoteUnpublished = () => {\n if (remoteTrackCount - 1 < 0) {\n log.warn(\n 'mismatched remote audio track count! attempted to reduce track count below zero.'\n );\n }\n setRemoteTrackCount(Math.max(remoteTrackCount - 1, 0));\n };\n\n room\n .on(RoomEvent.LocalTrackPublished, onLocalPublished)\n .on(RoomEvent.LocalTrackUnpublished, onLocalUnpublished)\n .on(RoomEvent.TrackPublished, onRemotePublished)\n .on(RoomEvent.TrackUnpublished, onRemoteUnpublished);\n\n return () => {\n room\n .off(RoomEvent.LocalTrackPublished, onLocalPublished)\n .off(RoomEvent.LocalTrackUnpublished, onLocalUnpublished)\n .off(RoomEvent.TrackPublished, onRemotePublished)\n .off(RoomEvent.TrackUnpublished, onRemoteUnpublished);\n };\n }, [room, localTrackCount, remoteTrackCount]);\n\n useEffect(() => {\n if (Platform.OS !== 'ios') {\n return;\n }\n\n let configFunc =\n onConfigureNativeAudio ?? getDefaultAppleAudioConfigurationForMode;\n let audioConfig = configFunc(trackState, preferSpeakerOutput);\n AudioSession.setAppleAudioConfiguration(audioConfig);\n }, [trackState, onConfigureNativeAudio, preferSpeakerOutput]);\n}\n\nfunction computeAudioTrackState(\n localTracks: number,\n remoteTracks: number\n): AudioTrackState {\n if (localTracks > 0 && remoteTracks > 0) {\n return 'localAndRemote';\n } else if (localTracks > 0 && remoteTracks === 0) {\n return 'localOnly';\n } else if (localTracks === 0 && remoteTracks > 0) {\n return 'remoteOnly';\n } else {\n return 'none';\n }\n}\n\nfunction getLocalAudioTrackCount(room: Room): number {\n return room.localParticipant.audioTrackPublications.size;\n}\n\nfunction getRemoteAudioTrackCount(room: Room): number {\n var audioTracks = 0;\n room.remoteParticipants.forEach((participant) => {\n audioTracks += participant.audioTrackPublications.size;\n });\n\n return audioTracks;\n}\n"]}
|
|
@@ -31,6 +31,8 @@ const LivekitReactNative = NativeModules.LivekitReactNative ? NativeModules.Live
|
|
|
31
31
|
*
|
|
32
32
|
* See {@link AndroidAudioTypePresets} for pre-configured values.
|
|
33
33
|
*
|
|
34
|
+
* NOTE: If `audioTypeOptions` is set, this must also be reflected in your android MainApplication setup.
|
|
35
|
+
*
|
|
34
36
|
* ----
|
|
35
37
|
* iOS
|
|
36
38
|
*
|
|
@@ -1 +1 @@
|
|
|
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","getDefaultAppleAudioConfigurationForMode","mode","preferSpeakerOutput","audioCategory","audioCategoryOptions","AudioSession","config","configureAudio","startAudioSession","stopAudioSession","OS","getAudioOutputs","deviceId","selectAudioOutput","showAudioRoutePicker","setAppleAudioConfiguration"],"mappings":"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","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 type AppleAudioMode =\n | 'default'\n | 'gameChat'\n | 'measurement'\n | 'moviePlayback'\n | 'spokenAudio'\n | 'videoChat'\n | 'videoRecording'\n | 'voiceChat'\n | 'voicePrompt';\n\nexport type AppleAudioCategory =\n | 'soloAmbient'\n | 'playback'\n | 'record'\n | 'playAndRecord'\n | 'multiRoute';\n\nexport type AppleAudioCategoryOption =\n | 'mixWithOthers'\n | 'duckOthers'\n | 'interruptSpokenAudioAndMixWithOthers'\n | 'allowBluetooth'\n | 'allowBluetoothA2DP'\n | 'allowAirPlay'\n | 'defaultToSpeaker';\n\nexport type AppleAudioConfiguration = {\n audioCategory?: AppleAudioCategory;\n audioCategoryOptions?: AppleAudioCategoryOption[];\n audioMode?: AppleAudioMode;\n};\n\nexport type AudioTrackState =\n | 'none'\n | 'remoteOnly'\n | 'localOnly'\n | 'localAndRemote';\n\nexport function getDefaultAppleAudioConfigurationForMode(\n mode: AudioTrackState,\n preferSpeakerOutput: boolean = true\n): AppleAudioConfiguration {\n if (mode === 'remoteOnly') {\n return {\n audioCategory: 'playback',\n audioCategoryOptions: ['mixWithOthers'],\n audioMode: 'spokenAudio',\n };\n } else if (mode === 'localAndRemote' || mode === 'localOnly') {\n return {\n audioCategory: 'playAndRecord',\n audioCategoryOptions: ['allowBluetooth', 'mixWithOthers'],\n audioMode: preferSpeakerOutput ? 'videoChat' : 'voiceChat',\n };\n }\n\n return {\n audioCategory: 'soloAmbient',\n audioCategoryOptions: [],\n audioMode: 'default',\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 * See also useIOSAudioManagement for automatic configuration of iOS audio options.\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 static setAppleAudioConfiguration = async (\n config: AppleAudioConfiguration\n ) => {\n if (Platform.OS === 'ios') {\n await LivekitReactNative.setAppleAudioConfiguration(config);\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","getDefaultAppleAudioConfigurationForMode","mode","preferSpeakerOutput","audioCategory","audioCategoryOptions","AudioSession","config","configureAudio","startAudioSession","stopAudioSession","OS","getAudioOutputs","deviceId","selectAudioOutput","showAudioRoutePicker","setAppleAudioConfiguration"],"mappings":"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","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 * NOTE: If `audioTypeOptions` is set, this must also be reflected in your android MainApplication setup.\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 type AppleAudioMode =\n | 'default'\n | 'gameChat'\n | 'measurement'\n | 'moviePlayback'\n | 'spokenAudio'\n | 'videoChat'\n | 'videoRecording'\n | 'voiceChat'\n | 'voicePrompt';\n\nexport type AppleAudioCategory =\n | 'soloAmbient'\n | 'playback'\n | 'record'\n | 'playAndRecord'\n | 'multiRoute';\n\nexport type AppleAudioCategoryOption =\n | 'mixWithOthers'\n | 'duckOthers'\n | 'interruptSpokenAudioAndMixWithOthers'\n | 'allowBluetooth'\n | 'allowBluetoothA2DP'\n | 'allowAirPlay'\n | 'defaultToSpeaker';\n\nexport type AppleAudioConfiguration = {\n audioCategory?: AppleAudioCategory;\n audioCategoryOptions?: AppleAudioCategoryOption[];\n audioMode?: AppleAudioMode;\n};\n\nexport type AudioTrackState =\n | 'none'\n | 'remoteOnly'\n | 'localOnly'\n | 'localAndRemote';\n\nexport function getDefaultAppleAudioConfigurationForMode(\n mode: AudioTrackState,\n preferSpeakerOutput: boolean = true\n): AppleAudioConfiguration {\n if (mode === 'remoteOnly') {\n return {\n audioCategory: 'playback',\n audioCategoryOptions: ['mixWithOthers'],\n audioMode: 'spokenAudio',\n };\n } else if (mode === 'localAndRemote' || mode === 'localOnly') {\n return {\n audioCategory: 'playAndRecord',\n audioCategoryOptions: ['allowBluetooth', 'mixWithOthers'],\n audioMode: preferSpeakerOutput ? 'videoChat' : 'voiceChat',\n };\n }\n\n return {\n audioCategory: 'soloAmbient',\n audioCategoryOptions: [],\n audioMode: 'default',\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 * See also useIOSAudioManagement for automatic configuration of iOS audio options.\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 static setAppleAudioConfiguration = async (\n config: AppleAudioConfiguration\n ) => {\n if (Platform.OS === 'ios') {\n await LivekitReactNative.setAppleAudioConfiguration(config);\n }\n };\n}\n"]}
|
|
@@ -8,16 +8,16 @@ export function useParticipant(participant) {
|
|
|
8
8
|
const [metadata, setMetadata] = useState();
|
|
9
9
|
const [publications, setPublications] = useState([]);
|
|
10
10
|
const [subscribedTracks, setSubscribedTracks] = useState([]);
|
|
11
|
-
const [cameraPublication, setCameraPublication] = useState(participant.
|
|
12
|
-
const [microphonePublication, setMicrophonePublication] = useState(participant.
|
|
13
|
-
const [screenSharePublication, setScreenSharePublication] = useState(participant.
|
|
11
|
+
const [cameraPublication, setCameraPublication] = useState(participant.getTrackPublication(Track.Source.Camera));
|
|
12
|
+
const [microphonePublication, setMicrophonePublication] = useState(participant.getTrackPublication(Track.Source.Microphone));
|
|
13
|
+
const [screenSharePublication, setScreenSharePublication] = useState(participant.getTrackPublication(Track.Source.ScreenShare));
|
|
14
14
|
useEffect(() => {
|
|
15
15
|
const onPublicationsChanged = () => {
|
|
16
|
-
setPublications(Array.from(participant.
|
|
17
|
-
setCameraPublication(participant.
|
|
18
|
-
setMicrophonePublication(participant.
|
|
19
|
-
setScreenSharePublication(participant.
|
|
20
|
-
setSubscribedTracks(Array.from(participant.
|
|
16
|
+
setPublications(Array.from(participant.trackPublications.values()));
|
|
17
|
+
setCameraPublication(participant.getTrackPublication(Track.Source.Camera));
|
|
18
|
+
setMicrophonePublication(participant.getTrackPublication(Track.Source.Microphone));
|
|
19
|
+
setScreenSharePublication(participant.getTrackPublication(Track.Source.ScreenShare));
|
|
20
|
+
setSubscribedTracks(Array.from(participant.trackPublications.values()).filter(pub => {
|
|
21
21
|
return pub.isSubscribed && pub.track !== undefined;
|
|
22
22
|
}));
|
|
23
23
|
};
|
|
@@ -64,7 +64,7 @@ export function useParticipant(participant) {
|
|
|
64
64
|
};
|
|
65
65
|
}, [participant]);
|
|
66
66
|
let muted;
|
|
67
|
-
participant.
|
|
67
|
+
participant.audioTrackPublications.forEach(pub => {
|
|
68
68
|
muted = pub.isMuted;
|
|
69
69
|
});
|
|
70
70
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["useParticipant.ts"],"names":["LocalParticipant","ParticipantEvent","Track","useEffect","useState","useParticipant","participant","isAudioMuted","setAudioMuted","setVideoMuted","connectionQuality","setConnectionQuality","isSpeaking","setSpeaking","metadata","setMetadata","publications","setPublications","subscribedTracks","setSubscribedTracks","cameraPublication","setCameraPublication","getTrack","Source","Camera","microphonePublication","setMicrophonePublication","Microphone","screenSharePublication","setScreenSharePublication","ScreenShare","onPublicationsChanged","Array","from","tracks","values","filter","pub","isSubscribed","track","undefined","onMuted","kind","Kind","Audio","Video","onUnmuted","onMetadataChanged","onIsSpeakingChanged","onConnectionQualityUpdate","on","TrackMuted","TrackUnmuted","ParticipantMetadataChanged","IsSpeakingChanged","TrackPublished","TrackUnpublished","TrackSubscribed","TrackUnsubscribed","LocalTrackPublished","LocalTrackUnpublished","ConnectionQualityChanged","off","muted","audioTracks","forEach","isMuted","isLocal"],"mappings":"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","sourcesContent":["import {\n ConnectionQuality,\n LocalParticipant,\n Participant,\n ParticipantEvent,\n Track,\n TrackPublication,\n} from 'livekit-client';\nimport { useEffect, useState } from 'react';\n\nexport interface ParticipantState {\n isSpeaking: boolean;\n connectionQuality: ConnectionQuality;\n isLocal: boolean;\n metadata?: string;\n publications: TrackPublication[];\n subscribedTracks: TrackPublication[];\n cameraPublication?: TrackPublication;\n microphonePublication?: TrackPublication;\n screenSharePublication?: TrackPublication;\n}\n\nexport function useParticipant(participant: Participant): ParticipantState {\n const [isAudioMuted, setAudioMuted] = useState(false);\n const [, setVideoMuted] = useState(false);\n const [connectionQuality, setConnectionQuality] = useState<ConnectionQuality>(\n participant.connectionQuality\n );\n const [isSpeaking, setSpeaking] = useState(false);\n const [metadata, setMetadata] = useState<string>();\n const [publications, setPublications] = useState<TrackPublication[]>([]);\n const [subscribedTracks, setSubscribedTracks] = useState<TrackPublication[]>(\n []\n );\n\n const [cameraPublication, setCameraPublication] = useState(\n participant.getTrack(Track.Source.Camera)\n );\n const [microphonePublication, setMicrophonePublication] = useState(\n participant.getTrack(Track.Source.Microphone)\n );\n const [screenSharePublication, setScreenSharePublication] = useState(\n participant.getTrack(Track.Source.ScreenShare)\n );\n useEffect(() => {\n const onPublicationsChanged = () => {\n setPublications(Array.from(participant.tracks.values()));\n setCameraPublication(participant.getTrack(Track.Source.Camera));\n setMicrophonePublication(participant.getTrack(Track.Source.Microphone));\n setScreenSharePublication(participant.getTrack(Track.Source.ScreenShare));\n setSubscribedTracks(\n Array.from(participant.tracks.values()).filter((pub) => {\n return pub.isSubscribed && pub.track !== undefined;\n })\n );\n };\n const onMuted = (pub: TrackPublication) => {\n if (pub.kind === Track.Kind.Audio) {\n setAudioMuted(true);\n } else if (pub.kind === Track.Kind.Video) {\n setVideoMuted(true);\n }\n };\n const onUnmuted = (pub: TrackPublication) => {\n if (pub.kind === Track.Kind.Audio) {\n setAudioMuted(false);\n } else if (pub.kind === Track.Kind.Video) {\n setVideoMuted(false);\n }\n };\n const onMetadataChanged = () => {\n if (participant.metadata) {\n setMetadata(participant.metadata);\n }\n };\n const onIsSpeakingChanged = () => {\n setSpeaking(participant.isSpeaking);\n };\n const onConnectionQualityUpdate = () => {\n setConnectionQuality(participant.connectionQuality);\n };\n\n // register listeners\n participant\n .on(ParticipantEvent.TrackMuted, onMuted)\n .on(ParticipantEvent.TrackUnmuted, onUnmuted)\n .on(ParticipantEvent.ParticipantMetadataChanged, onMetadataChanged)\n .on(ParticipantEvent.IsSpeakingChanged, onIsSpeakingChanged)\n .on(ParticipantEvent.TrackPublished, onPublicationsChanged)\n .on(ParticipantEvent.TrackUnpublished, onPublicationsChanged)\n .on(ParticipantEvent.TrackSubscribed, onPublicationsChanged)\n .on(ParticipantEvent.TrackUnsubscribed, onPublicationsChanged)\n .on(ParticipantEvent.LocalTrackPublished, onPublicationsChanged)\n .on(ParticipantEvent.LocalTrackUnpublished, onPublicationsChanged)\n .on(ParticipantEvent.ConnectionQualityChanged, onConnectionQualityUpdate);\n\n // set initial state\n onMetadataChanged();\n onIsSpeakingChanged();\n onPublicationsChanged();\n\n return () => {\n // cleanup\n participant\n .off(ParticipantEvent.TrackMuted, onMuted)\n .off(ParticipantEvent.TrackUnmuted, onUnmuted)\n .off(ParticipantEvent.ParticipantMetadataChanged, onMetadataChanged)\n .off(ParticipantEvent.IsSpeakingChanged, onIsSpeakingChanged)\n .off(ParticipantEvent.TrackPublished, onPublicationsChanged)\n .off(ParticipantEvent.TrackUnpublished, onPublicationsChanged)\n .off(ParticipantEvent.TrackSubscribed, onPublicationsChanged)\n .off(ParticipantEvent.TrackUnsubscribed, onPublicationsChanged)\n .off(ParticipantEvent.LocalTrackPublished, onPublicationsChanged)\n .off(ParticipantEvent.LocalTrackUnpublished, onPublicationsChanged)\n .off(\n ParticipantEvent.ConnectionQualityChanged,\n onConnectionQualityUpdate\n );\n };\n }, [participant]);\n\n let muted: boolean | undefined;\n participant.audioTracks.forEach((pub) => {\n muted = pub.isMuted;\n });\n if (muted === undefined) {\n muted = true;\n }\n if (isAudioMuted !== muted) {\n setAudioMuted(muted);\n }\n\n return {\n isLocal: participant instanceof LocalParticipant,\n isSpeaking,\n connectionQuality,\n publications,\n subscribedTracks,\n cameraPublication,\n microphonePublication,\n screenSharePublication,\n metadata,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["useParticipant.ts"],"names":["LocalParticipant","ParticipantEvent","Track","useEffect","useState","useParticipant","participant","isAudioMuted","setAudioMuted","setVideoMuted","connectionQuality","setConnectionQuality","isSpeaking","setSpeaking","metadata","setMetadata","publications","setPublications","subscribedTracks","setSubscribedTracks","cameraPublication","setCameraPublication","getTrackPublication","Source","Camera","microphonePublication","setMicrophonePublication","Microphone","screenSharePublication","setScreenSharePublication","ScreenShare","onPublicationsChanged","Array","from","trackPublications","values","filter","pub","isSubscribed","track","undefined","onMuted","kind","Kind","Audio","Video","onUnmuted","onMetadataChanged","onIsSpeakingChanged","onConnectionQualityUpdate","on","TrackMuted","TrackUnmuted","ParticipantMetadataChanged","IsSpeakingChanged","TrackPublished","TrackUnpublished","TrackSubscribed","TrackUnsubscribed","LocalTrackPublished","LocalTrackUnpublished","ConnectionQualityChanged","off","muted","audioTrackPublications","forEach","isMuted","isLocal"],"mappings":"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","sourcesContent":["import {\n ConnectionQuality,\n LocalParticipant,\n Participant,\n ParticipantEvent,\n Track,\n TrackPublication,\n} from 'livekit-client';\nimport { useEffect, useState } from 'react';\n\nexport interface ParticipantState {\n isSpeaking: boolean;\n connectionQuality: ConnectionQuality;\n isLocal: boolean;\n metadata?: string;\n publications: TrackPublication[];\n subscribedTracks: TrackPublication[];\n cameraPublication?: TrackPublication;\n microphonePublication?: TrackPublication;\n screenSharePublication?: TrackPublication;\n}\n\nexport function useParticipant(participant: Participant): ParticipantState {\n const [isAudioMuted, setAudioMuted] = useState(false);\n const [, setVideoMuted] = useState(false);\n const [connectionQuality, setConnectionQuality] = useState<ConnectionQuality>(\n participant.connectionQuality\n );\n const [isSpeaking, setSpeaking] = useState(false);\n const [metadata, setMetadata] = useState<string>();\n const [publications, setPublications] = useState<TrackPublication[]>([]);\n const [subscribedTracks, setSubscribedTracks] = useState<TrackPublication[]>(\n []\n );\n\n const [cameraPublication, setCameraPublication] = useState(\n participant.getTrackPublication(Track.Source.Camera)\n );\n const [microphonePublication, setMicrophonePublication] = useState(\n participant.getTrackPublication(Track.Source.Microphone)\n );\n const [screenSharePublication, setScreenSharePublication] = useState(\n participant.getTrackPublication(Track.Source.ScreenShare)\n );\n useEffect(() => {\n const onPublicationsChanged = () => {\n setPublications(Array.from(participant.trackPublications.values()));\n setCameraPublication(\n participant.getTrackPublication(Track.Source.Camera)\n );\n setMicrophonePublication(\n participant.getTrackPublication(Track.Source.Microphone)\n );\n setScreenSharePublication(\n participant.getTrackPublication(Track.Source.ScreenShare)\n );\n setSubscribedTracks(\n Array.from(participant.trackPublications.values()).filter((pub) => {\n return pub.isSubscribed && pub.track !== undefined;\n })\n );\n };\n const onMuted = (pub: TrackPublication) => {\n if (pub.kind === Track.Kind.Audio) {\n setAudioMuted(true);\n } else if (pub.kind === Track.Kind.Video) {\n setVideoMuted(true);\n }\n };\n const onUnmuted = (pub: TrackPublication) => {\n if (pub.kind === Track.Kind.Audio) {\n setAudioMuted(false);\n } else if (pub.kind === Track.Kind.Video) {\n setVideoMuted(false);\n }\n };\n const onMetadataChanged = () => {\n if (participant.metadata) {\n setMetadata(participant.metadata);\n }\n };\n const onIsSpeakingChanged = () => {\n setSpeaking(participant.isSpeaking);\n };\n const onConnectionQualityUpdate = () => {\n setConnectionQuality(participant.connectionQuality);\n };\n\n // register listeners\n participant\n .on(ParticipantEvent.TrackMuted, onMuted)\n .on(ParticipantEvent.TrackUnmuted, onUnmuted)\n .on(ParticipantEvent.ParticipantMetadataChanged, onMetadataChanged)\n .on(ParticipantEvent.IsSpeakingChanged, onIsSpeakingChanged)\n .on(ParticipantEvent.TrackPublished, onPublicationsChanged)\n .on(ParticipantEvent.TrackUnpublished, onPublicationsChanged)\n .on(ParticipantEvent.TrackSubscribed, onPublicationsChanged)\n .on(ParticipantEvent.TrackUnsubscribed, onPublicationsChanged)\n .on(ParticipantEvent.LocalTrackPublished, onPublicationsChanged)\n .on(ParticipantEvent.LocalTrackUnpublished, onPublicationsChanged)\n .on(ParticipantEvent.ConnectionQualityChanged, onConnectionQualityUpdate);\n\n // set initial state\n onMetadataChanged();\n onIsSpeakingChanged();\n onPublicationsChanged();\n\n return () => {\n // cleanup\n participant\n .off(ParticipantEvent.TrackMuted, onMuted)\n .off(ParticipantEvent.TrackUnmuted, onUnmuted)\n .off(ParticipantEvent.ParticipantMetadataChanged, onMetadataChanged)\n .off(ParticipantEvent.IsSpeakingChanged, onIsSpeakingChanged)\n .off(ParticipantEvent.TrackPublished, onPublicationsChanged)\n .off(ParticipantEvent.TrackUnpublished, onPublicationsChanged)\n .off(ParticipantEvent.TrackSubscribed, onPublicationsChanged)\n .off(ParticipantEvent.TrackUnsubscribed, onPublicationsChanged)\n .off(ParticipantEvent.LocalTrackPublished, onPublicationsChanged)\n .off(ParticipantEvent.LocalTrackUnpublished, onPublicationsChanged)\n .off(\n ParticipantEvent.ConnectionQualityChanged,\n onConnectionQualityUpdate\n );\n };\n }, [participant]);\n\n let muted: boolean | undefined;\n participant.audioTrackPublications.forEach((pub) => {\n muted = pub.isMuted;\n });\n if (muted === undefined) {\n muted = true;\n }\n if (isAudioMuted !== muted) {\n setAudioMuted(muted);\n }\n\n return {\n isLocal: participant instanceof LocalParticipant,\n isSpeaking,\n connectionQuality,\n publications,\n subscribedTracks,\n cameraPublication,\n microphonePublication,\n screenSharePublication,\n metadata,\n };\n}\n"]}
|
package/lib/module/useRoom.js
CHANGED
|
@@ -9,7 +9,7 @@ export function useRoom(room, options) {
|
|
|
9
9
|
const sortFunc = (_options$sortParticip = options === null || options === void 0 ? void 0 : options.sortParticipants) !== null && _options$sortParticip !== void 0 ? _options$sortParticip : sortParticipants;
|
|
10
10
|
useEffect(() => {
|
|
11
11
|
const onParticipantsChanged = () => {
|
|
12
|
-
const remotes = Array.from(room.
|
|
12
|
+
const remotes = Array.from(room.remoteParticipants.values());
|
|
13
13
|
const newParticipants = [room.localParticipant];
|
|
14
14
|
newParticipants.push(...remotes);
|
|
15
15
|
sortFunc(newParticipants, room.localParticipant);
|
|
@@ -25,8 +25,8 @@ export function useRoom(room, options) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
const tracks = [];
|
|
28
|
-
room.
|
|
29
|
-
p.
|
|
28
|
+
room.remoteParticipants.forEach(p => {
|
|
29
|
+
p.audioTrackPublications.forEach(pub => {
|
|
30
30
|
if (pub.audioTrack) {
|
|
31
31
|
tracks.push(pub.audioTrack);
|
|
32
32
|
}
|
|
@@ -94,8 +94,8 @@ export function sortParticipants(participants, localParticipant) {
|
|
|
94
94
|
} // video on
|
|
95
95
|
|
|
96
96
|
|
|
97
|
-
const aVideo = a.
|
|
98
|
-
const bVideo = b.
|
|
97
|
+
const aVideo = a.videoTrackPublications.size > 0;
|
|
98
|
+
const bVideo = b.videoTrackPublications.size > 0;
|
|
99
99
|
|
|
100
100
|
if (aVideo !== bVideo) {
|
|
101
101
|
if (aVideo) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["useRoom.ts"],"names":["ConnectionState","RoomEvent","Track","useEffect","useState","useRoom","room","options","error","participants","setParticipants","audioTracks","setAudioTracks","sortFunc","sortParticipants","onParticipantsChanged","remotes","Array","from","values","newParticipants","localParticipant","push","onSubscribedTrackChanged","track","kind","Kind","Audio","tracks","forEach","p","pub","audioTrack","onConnectionStateChanged","state","Connected","once","Disconnected","off","ParticipantConnected","ParticipantDisconnected","ActiveSpeakersChanged","TrackSubscribed","TrackUnsubscribed","LocalTrackPublished","LocalTrackUnpublished","AudioPlaybackStatusChanged","ConnectionStateChanged","on","Reconnected","disconnect","sort","a","b","isSpeaking","audioLevel","lastSpokeAt","aLast","getTime","bLast","aVideo","videoTracks","size","bVideo","joinedAt","localIdx","indexOf","splice","length"],"mappings":"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","sourcesContent":["import {\n AudioTrack,\n ConnectionState,\n LocalParticipant,\n Participant,\n RemoteTrack,\n Room,\n RoomEvent,\n Track,\n} from 'livekit-client';\nimport { useEffect, useState } from 'react';\n\nexport interface RoomState {\n room?: Room;\n /* all participants in the room, including the local participant. */\n participants: Participant[];\n /* all subscribed audio tracks in the room, not including local participant. */\n audioTracks: AudioTrack[];\n error?: Error;\n}\n\nexport interface RoomOptions {\n sortParticipants?: (participants: Participant[]) => void;\n}\n\nexport function useRoom(room: Room, options?: RoomOptions): RoomState {\n const [error] = useState<Error>();\n const [participants, setParticipants] = useState<Participant[]>([]);\n const [audioTracks, setAudioTracks] = useState<AudioTrack[]>([]);\n\n const sortFunc = options?.sortParticipants ?? sortParticipants;\n\n useEffect(() => {\n const onParticipantsChanged = () => {\n const remotes = Array.from(room.participants.values());\n const newParticipants: Participant[] = [room.localParticipant];\n newParticipants.push(...remotes);\n sortFunc(newParticipants, room.localParticipant);\n setParticipants(newParticipants);\n };\n const onSubscribedTrackChanged = (track?: RemoteTrack) => {\n // ordering may have changed, re-sort\n onParticipantsChanged();\n if (track && track.kind !== Track.Kind.Audio) {\n return;\n }\n const tracks: AudioTrack[] = [];\n room.participants.forEach((p) => {\n p.audioTracks.forEach((pub) => {\n if (pub.audioTrack) {\n tracks.push(pub.audioTrack);\n }\n });\n });\n setAudioTracks(tracks);\n };\n\n const onConnectionStateChanged = (state: ConnectionState) => {\n if (state === ConnectionState.Connected) {\n onParticipantsChanged();\n }\n };\n\n room.once(RoomEvent.Disconnected, () => {\n room\n .off(RoomEvent.ParticipantConnected, onParticipantsChanged)\n .off(RoomEvent.ParticipantDisconnected, onParticipantsChanged)\n .off(RoomEvent.ActiveSpeakersChanged, onParticipantsChanged)\n .off(RoomEvent.TrackSubscribed, onSubscribedTrackChanged)\n .off(RoomEvent.TrackUnsubscribed, onSubscribedTrackChanged)\n .off(RoomEvent.LocalTrackPublished, onParticipantsChanged)\n .off(RoomEvent.LocalTrackUnpublished, onParticipantsChanged)\n .off(RoomEvent.AudioPlaybackStatusChanged, onParticipantsChanged)\n .off(RoomEvent.ConnectionStateChanged, onConnectionStateChanged);\n });\n room\n .on(RoomEvent.ConnectionStateChanged, onConnectionStateChanged)\n .on(RoomEvent.Reconnected, onParticipantsChanged)\n .on(RoomEvent.ParticipantConnected, onParticipantsChanged)\n .on(RoomEvent.ParticipantDisconnected, onParticipantsChanged)\n .on(RoomEvent.ActiveSpeakersChanged, onParticipantsChanged)\n .on(RoomEvent.TrackSubscribed, onSubscribedTrackChanged)\n .on(RoomEvent.TrackUnsubscribed, onSubscribedTrackChanged)\n .on(RoomEvent.LocalTrackPublished, onParticipantsChanged)\n .on(RoomEvent.LocalTrackUnpublished, onParticipantsChanged)\n // trigger a state change by re-sorting participants\n .on(RoomEvent.AudioPlaybackStatusChanged, onParticipantsChanged);\n\n onSubscribedTrackChanged();\n\n return () => {\n room.disconnect();\n };\n }, [room, sortFunc]);\n\n return {\n error,\n participants,\n audioTracks,\n };\n}\n\n/**\n * Default sort for participants, it'll order participants by:\n * 1. dominant speaker (speaker with the loudest audio level)\n * 2. local participant\n * 3. other speakers that are recently active\n * 4. participants with video on\n * 5. by joinedAt\n */\nexport function sortParticipants(\n participants: Participant[],\n localParticipant?: LocalParticipant\n) {\n participants.sort((a, b) => {\n // loudest speaker first\n if (a.isSpeaking && b.isSpeaking) {\n return b.audioLevel - a.audioLevel;\n }\n\n // speaker goes first\n if (a.isSpeaking !== b.isSpeaking) {\n if (a.isSpeaking) {\n return -1;\n } else {\n return 1;\n }\n }\n\n // last active speaker first\n if (a.lastSpokeAt !== b.lastSpokeAt) {\n const aLast = a.lastSpokeAt?.getTime() ?? 0;\n const bLast = b.lastSpokeAt?.getTime() ?? 0;\n return bLast - aLast;\n }\n\n // video on\n const aVideo = a.videoTracks.size > 0;\n const bVideo = b.videoTracks.size > 0;\n if (aVideo !== bVideo) {\n if (aVideo) {\n return -1;\n } else {\n return 1;\n }\n }\n\n // joinedAt\n return (a.joinedAt?.getTime() ?? 0) - (b.joinedAt?.getTime() ?? 0);\n });\n\n if (localParticipant) {\n const localIdx = participants.indexOf(localParticipant);\n if (localIdx >= 0) {\n participants.splice(localIdx, 1);\n if (participants.length > 0) {\n participants.splice(1, 0, localParticipant);\n } else {\n participants.push(localParticipant);\n }\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["useRoom.ts"],"names":["ConnectionState","RoomEvent","Track","useEffect","useState","useRoom","room","options","error","participants","setParticipants","audioTracks","setAudioTracks","sortFunc","sortParticipants","onParticipantsChanged","remotes","Array","from","remoteParticipants","values","newParticipants","localParticipant","push","onSubscribedTrackChanged","track","kind","Kind","Audio","tracks","forEach","p","audioTrackPublications","pub","audioTrack","onConnectionStateChanged","state","Connected","once","Disconnected","off","ParticipantConnected","ParticipantDisconnected","ActiveSpeakersChanged","TrackSubscribed","TrackUnsubscribed","LocalTrackPublished","LocalTrackUnpublished","AudioPlaybackStatusChanged","ConnectionStateChanged","on","Reconnected","disconnect","sort","a","b","isSpeaking","audioLevel","lastSpokeAt","aLast","getTime","bLast","aVideo","videoTrackPublications","size","bVideo","joinedAt","localIdx","indexOf","splice","length"],"mappings":"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","sourcesContent":["import {\n AudioTrack,\n ConnectionState,\n LocalParticipant,\n Participant,\n RemoteTrack,\n Room,\n RoomEvent,\n Track,\n} from 'livekit-client';\nimport { useEffect, useState } from 'react';\n\nexport interface RoomState {\n room?: Room;\n /* all participants in the room, including the local participant. */\n participants: Participant[];\n /* all subscribed audio tracks in the room, not including local participant. */\n audioTracks: AudioTrack[];\n error?: Error;\n}\n\nexport interface RoomOptions {\n sortParticipants?: (participants: Participant[]) => void;\n}\n\nexport function useRoom(room: Room, options?: RoomOptions): RoomState {\n const [error] = useState<Error>();\n const [participants, setParticipants] = useState<Participant[]>([]);\n const [audioTracks, setAudioTracks] = useState<AudioTrack[]>([]);\n\n const sortFunc = options?.sortParticipants ?? sortParticipants;\n\n useEffect(() => {\n const onParticipantsChanged = () => {\n const remotes = Array.from(room.remoteParticipants.values());\n const newParticipants: Participant[] = [room.localParticipant];\n newParticipants.push(...remotes);\n sortFunc(newParticipants, room.localParticipant);\n setParticipants(newParticipants);\n };\n const onSubscribedTrackChanged = (track?: RemoteTrack) => {\n // ordering may have changed, re-sort\n onParticipantsChanged();\n if (track && track.kind !== Track.Kind.Audio) {\n return;\n }\n const tracks: AudioTrack[] = [];\n room.remoteParticipants.forEach((p) => {\n p.audioTrackPublications.forEach((pub) => {\n if (pub.audioTrack) {\n tracks.push(pub.audioTrack);\n }\n });\n });\n setAudioTracks(tracks);\n };\n\n const onConnectionStateChanged = (state: ConnectionState) => {\n if (state === ConnectionState.Connected) {\n onParticipantsChanged();\n }\n };\n\n room.once(RoomEvent.Disconnected, () => {\n room\n .off(RoomEvent.ParticipantConnected, onParticipantsChanged)\n .off(RoomEvent.ParticipantDisconnected, onParticipantsChanged)\n .off(RoomEvent.ActiveSpeakersChanged, onParticipantsChanged)\n .off(RoomEvent.TrackSubscribed, onSubscribedTrackChanged)\n .off(RoomEvent.TrackUnsubscribed, onSubscribedTrackChanged)\n .off(RoomEvent.LocalTrackPublished, onParticipantsChanged)\n .off(RoomEvent.LocalTrackUnpublished, onParticipantsChanged)\n .off(RoomEvent.AudioPlaybackStatusChanged, onParticipantsChanged)\n .off(RoomEvent.ConnectionStateChanged, onConnectionStateChanged);\n });\n room\n .on(RoomEvent.ConnectionStateChanged, onConnectionStateChanged)\n .on(RoomEvent.Reconnected, onParticipantsChanged)\n .on(RoomEvent.ParticipantConnected, onParticipantsChanged)\n .on(RoomEvent.ParticipantDisconnected, onParticipantsChanged)\n .on(RoomEvent.ActiveSpeakersChanged, onParticipantsChanged)\n .on(RoomEvent.TrackSubscribed, onSubscribedTrackChanged)\n .on(RoomEvent.TrackUnsubscribed, onSubscribedTrackChanged)\n .on(RoomEvent.LocalTrackPublished, onParticipantsChanged)\n .on(RoomEvent.LocalTrackUnpublished, onParticipantsChanged)\n // trigger a state change by re-sorting participants\n .on(RoomEvent.AudioPlaybackStatusChanged, onParticipantsChanged);\n\n onSubscribedTrackChanged();\n\n return () => {\n room.disconnect();\n };\n }, [room, sortFunc]);\n\n return {\n error,\n participants,\n audioTracks,\n };\n}\n\n/**\n * Default sort for participants, it'll order participants by:\n * 1. dominant speaker (speaker with the loudest audio level)\n * 2. local participant\n * 3. other speakers that are recently active\n * 4. participants with video on\n * 5. by joinedAt\n */\nexport function sortParticipants(\n participants: Participant[],\n localParticipant?: LocalParticipant\n) {\n participants.sort((a, b) => {\n // loudest speaker first\n if (a.isSpeaking && b.isSpeaking) {\n return b.audioLevel - a.audioLevel;\n }\n\n // speaker goes first\n if (a.isSpeaking !== b.isSpeaking) {\n if (a.isSpeaking) {\n return -1;\n } else {\n return 1;\n }\n }\n\n // last active speaker first\n if (a.lastSpokeAt !== b.lastSpokeAt) {\n const aLast = a.lastSpokeAt?.getTime() ?? 0;\n const bLast = b.lastSpokeAt?.getTime() ?? 0;\n return bLast - aLast;\n }\n\n // video on\n const aVideo = a.videoTrackPublications.size > 0;\n const bVideo = b.videoTrackPublications.size > 0;\n if (aVideo !== bVideo) {\n if (aVideo) {\n return -1;\n } else {\n return 1;\n }\n }\n\n // joinedAt\n return (a.joinedAt?.getTime() ?? 0) - (b.joinedAt?.getTime() ?? 0);\n });\n\n if (localParticipant) {\n const localIdx = participants.indexOf(localParticipant);\n if (localIdx >= 0) {\n participants.splice(localIdx, 1);\n if (participants.length > 0) {\n participants.splice(1, 0, localParticipant);\n } else {\n participants.push(localParticipant);\n }\n }\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livekit/react-native",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "LiveKit for React Native",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/module/index",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"array.prototype.at": "^1.1.1",
|
|
46
46
|
"fastestsmallesttextencoderdecoder": "^1.0.22",
|
|
47
|
-
"livekit-client": "^
|
|
47
|
+
"livekit-client": "^2.0.0",
|
|
48
48
|
"loglevel": "^1.8.0",
|
|
49
49
|
"promise.allsettled": "^1.0.5",
|
|
50
50
|
"react-native-url-polyfill": "^1.3.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useState, useEffect, useMemo } from 'react';
|
|
2
2
|
import { Platform } from 'react-native';
|
|
3
|
-
import { RoomEvent,
|
|
3
|
+
import { RoomEvent, Room } from 'livekit-client';
|
|
4
4
|
import AudioSession, {
|
|
5
5
|
getDefaultAppleAudioConfigurationForMode,
|
|
6
6
|
type AppleAudioConfiguration,
|
|
@@ -31,14 +31,25 @@ export function useIOSAudioManagement(
|
|
|
31
31
|
[localTrackCount, remoteTrackCount]
|
|
32
32
|
);
|
|
33
33
|
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
let recalculateTrackCounts = () => {
|
|
36
|
+
setLocalTrackCount(getLocalAudioTrackCount(room));
|
|
37
|
+
setRemoteTrackCount(getRemoteAudioTrackCount(room));
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
recalculateTrackCounts();
|
|
41
|
+
|
|
42
|
+
room.on(RoomEvent.Connected, recalculateTrackCounts);
|
|
43
|
+
|
|
44
|
+
return () => {
|
|
45
|
+
room.off(RoomEvent.Connected, recalculateTrackCounts);
|
|
46
|
+
};
|
|
47
|
+
}, [room]);
|
|
34
48
|
useEffect(() => {
|
|
35
49
|
if (Platform.OS !== 'ios') {
|
|
36
50
|
return () => {};
|
|
37
51
|
}
|
|
38
52
|
|
|
39
|
-
setLocalTrackCount(getLocalAudioTrackCount(room));
|
|
40
|
-
setRemoteTrackCount(getRemoteAudioTrackCount(room));
|
|
41
|
-
|
|
42
53
|
let onLocalPublished = () => {
|
|
43
54
|
setLocalTrackCount(localTrackCount + 1);
|
|
44
55
|
};
|
|
@@ -85,7 +96,6 @@ export function useIOSAudioManagement(
|
|
|
85
96
|
let configFunc =
|
|
86
97
|
onConfigureNativeAudio ?? getDefaultAppleAudioConfigurationForMode;
|
|
87
98
|
let audioConfig = configFunc(trackState, preferSpeakerOutput);
|
|
88
|
-
|
|
89
99
|
AudioSession.setAppleAudioConfiguration(audioConfig);
|
|
90
100
|
}, [trackState, onConfigureNativeAudio, preferSpeakerOutput]);
|
|
91
101
|
}
|
|
@@ -106,13 +116,13 @@ function computeAudioTrackState(
|
|
|
106
116
|
}
|
|
107
117
|
|
|
108
118
|
function getLocalAudioTrackCount(room: Room): number {
|
|
109
|
-
return room.localParticipant.
|
|
119
|
+
return room.localParticipant.audioTrackPublications.size;
|
|
110
120
|
}
|
|
111
121
|
|
|
112
122
|
function getRemoteAudioTrackCount(room: Room): number {
|
|
113
123
|
var audioTracks = 0;
|
|
114
|
-
room.
|
|
115
|
-
audioTracks += participant.
|
|
124
|
+
room.remoteParticipants.forEach((participant) => {
|
|
125
|
+
audioTracks += participant.audioTrackPublications.size;
|
|
116
126
|
});
|
|
117
127
|
|
|
118
128
|
return audioTracks;
|
|
@@ -36,6 +36,8 @@ const LivekitReactNative = NativeModules.LivekitReactNative
|
|
|
36
36
|
*
|
|
37
37
|
* See {@link AndroidAudioTypePresets} for pre-configured values.
|
|
38
38
|
*
|
|
39
|
+
* NOTE: If `audioTypeOptions` is set, this must also be reflected in your android MainApplication setup.
|
|
40
|
+
*
|
|
39
41
|
* ----
|
|
40
42
|
* iOS
|
|
41
43
|
*
|
package/src/useParticipant.ts
CHANGED
|
@@ -34,22 +34,28 @@ export function useParticipant(participant: Participant): ParticipantState {
|
|
|
34
34
|
);
|
|
35
35
|
|
|
36
36
|
const [cameraPublication, setCameraPublication] = useState(
|
|
37
|
-
participant.
|
|
37
|
+
participant.getTrackPublication(Track.Source.Camera)
|
|
38
38
|
);
|
|
39
39
|
const [microphonePublication, setMicrophonePublication] = useState(
|
|
40
|
-
participant.
|
|
40
|
+
participant.getTrackPublication(Track.Source.Microphone)
|
|
41
41
|
);
|
|
42
42
|
const [screenSharePublication, setScreenSharePublication] = useState(
|
|
43
|
-
participant.
|
|
43
|
+
participant.getTrackPublication(Track.Source.ScreenShare)
|
|
44
44
|
);
|
|
45
45
|
useEffect(() => {
|
|
46
46
|
const onPublicationsChanged = () => {
|
|
47
|
-
setPublications(Array.from(participant.
|
|
48
|
-
setCameraPublication(
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
setPublications(Array.from(participant.trackPublications.values()));
|
|
48
|
+
setCameraPublication(
|
|
49
|
+
participant.getTrackPublication(Track.Source.Camera)
|
|
50
|
+
);
|
|
51
|
+
setMicrophonePublication(
|
|
52
|
+
participant.getTrackPublication(Track.Source.Microphone)
|
|
53
|
+
);
|
|
54
|
+
setScreenSharePublication(
|
|
55
|
+
participant.getTrackPublication(Track.Source.ScreenShare)
|
|
56
|
+
);
|
|
51
57
|
setSubscribedTracks(
|
|
52
|
-
Array.from(participant.
|
|
58
|
+
Array.from(participant.trackPublications.values()).filter((pub) => {
|
|
53
59
|
return pub.isSubscribed && pub.track !== undefined;
|
|
54
60
|
})
|
|
55
61
|
);
|
|
@@ -120,7 +126,7 @@ export function useParticipant(participant: Participant): ParticipantState {
|
|
|
120
126
|
}, [participant]);
|
|
121
127
|
|
|
122
128
|
let muted: boolean | undefined;
|
|
123
|
-
participant.
|
|
129
|
+
participant.audioTrackPublications.forEach((pub) => {
|
|
124
130
|
muted = pub.isMuted;
|
|
125
131
|
});
|
|
126
132
|
if (muted === undefined) {
|
package/src/useRoom.ts
CHANGED
|
@@ -32,7 +32,7 @@ export function useRoom(room: Room, options?: RoomOptions): RoomState {
|
|
|
32
32
|
|
|
33
33
|
useEffect(() => {
|
|
34
34
|
const onParticipantsChanged = () => {
|
|
35
|
-
const remotes = Array.from(room.
|
|
35
|
+
const remotes = Array.from(room.remoteParticipants.values());
|
|
36
36
|
const newParticipants: Participant[] = [room.localParticipant];
|
|
37
37
|
newParticipants.push(...remotes);
|
|
38
38
|
sortFunc(newParticipants, room.localParticipant);
|
|
@@ -45,8 +45,8 @@ export function useRoom(room: Room, options?: RoomOptions): RoomState {
|
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
47
|
const tracks: AudioTrack[] = [];
|
|
48
|
-
room.
|
|
49
|
-
p.
|
|
48
|
+
room.remoteParticipants.forEach((p) => {
|
|
49
|
+
p.audioTrackPublications.forEach((pub) => {
|
|
50
50
|
if (pub.audioTrack) {
|
|
51
51
|
tracks.push(pub.audioTrack);
|
|
52
52
|
}
|
|
@@ -135,8 +135,8 @@ export function sortParticipants(
|
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
// video on
|
|
138
|
-
const aVideo = a.
|
|
139
|
-
const bVideo = b.
|
|
138
|
+
const aVideo = a.videoTrackPublications.size > 0;
|
|
139
|
+
const bVideo = b.videoTrackPublications.size > 0;
|
|
140
140
|
if (aVideo !== bVideo) {
|
|
141
141
|
if (aVideo) {
|
|
142
142
|
return -1;
|