@livekit/react-native 2.6.4 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/android/src/main/java/com/livekit/reactnative/audio/processing/AudioRecordSamplesDispatcher.kt +2 -1
- package/android/src/main/java/com/livekit/reactnative/audio/processing/AudioSinkManager.kt +8 -2
- package/lib/commonjs/components/VideoTrack.js +32 -12
- package/lib/commonjs/components/VideoTrack.js.map +1 -1
- package/lib/commonjs/hooks/useMultibandTrackVolume.js +13 -8
- package/lib/commonjs/hooks/useMultibandTrackVolume.js.map +1 -1
- package/lib/commonjs/hooks/useTrackVolume.js +8 -5
- package/lib/commonjs/hooks/useTrackVolume.js.map +1 -1
- package/lib/module/components/VideoTrack.js +35 -14
- package/lib/module/components/VideoTrack.js.map +1 -1
- package/lib/module/hooks/useMultibandTrackVolume.js +13 -8
- package/lib/module/hooks/useMultibandTrackVolume.js.map +1 -1
- package/lib/module/hooks/useTrackVolume.js +8 -5
- package/lib/module/hooks/useTrackVolume.js.map +1 -1
- package/lib/typescript/lib/commonjs/components/VideoTrack.d.ts +1 -19
- package/lib/typescript/lib/commonjs/hooks/useMultibandTrackVolume.d.ts +1 -1
- package/lib/typescript/lib/module/components/VideoTrack.d.ts +13 -8
- package/lib/typescript/lib/module/hooks/useMultibandTrackVolume.d.ts +1 -1
- package/lib/typescript/src/components/VideoTrack.d.ts +46 -1
- package/package.json +2 -2
- package/src/components/VideoTrack.tsx +159 -71
- package/src/hooks/useMultibandTrackVolume.ts +15 -10
- package/src/hooks/useTrackVolume.ts +10 -7
package/README.md
CHANGED
|
@@ -89,6 +89,7 @@ In your [AppDelegate.m](https://github.com/livekit/client-sdk-react-native/blob/
|
|
|
89
89
|
|
|
90
90
|
```objc
|
|
91
91
|
#import "LivekitReactNative.h"
|
|
92
|
+
#import "WebRTCModuleOptions.h"
|
|
92
93
|
|
|
93
94
|
@implementation AppDelegate
|
|
94
95
|
|
|
@@ -97,6 +98,12 @@ In your [AppDelegate.m](https://github.com/livekit/client-sdk-react-native/blob/
|
|
|
97
98
|
// Place this above any other RN related initialization
|
|
98
99
|
[LivekitReactNative setup];
|
|
99
100
|
|
|
101
|
+
// Uncomment the following lines if you want to use the camera in the background
|
|
102
|
+
// Requires voip background mode and iOS 18+.
|
|
103
|
+
|
|
104
|
+
// WebRTCModuleOptions *options = [WebRTCModuleOptions sharedInstance];
|
|
105
|
+
// options.enableMultitaskingCameraAccess = YES;
|
|
106
|
+
|
|
100
107
|
//...
|
|
101
108
|
}
|
|
102
109
|
```
|
|
@@ -21,13 +21,14 @@ import android.os.SystemClock
|
|
|
21
21
|
import org.webrtc.AudioTrackSink
|
|
22
22
|
import org.webrtc.audio.JavaAudioDeviceModule
|
|
23
23
|
import java.nio.ByteBuffer
|
|
24
|
+
import java.util.Collections
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* Dispatches recorded audio samples from the local microphone.
|
|
27
28
|
*/
|
|
28
29
|
class AudioRecordSamplesDispatcher : JavaAudioDeviceModule.SamplesReadyCallback {
|
|
29
30
|
|
|
30
|
-
private val sinks = mutableSetOf<AudioTrackSink>()
|
|
31
|
+
private val sinks = Collections.synchronizedSet(mutableSetOf<AudioTrackSink>())
|
|
31
32
|
|
|
32
33
|
@Synchronized
|
|
33
34
|
fun registerSink(sink: AudioTrackSink) {
|
|
@@ -5,13 +5,14 @@ import com.livekit.reactnative.LiveKitReactNative
|
|
|
5
5
|
import com.oney.WebRTCModule.WebRTCModule
|
|
6
6
|
import org.webrtc.AudioTrack
|
|
7
7
|
import org.webrtc.AudioTrackSink
|
|
8
|
+
import java.util.Collections
|
|
8
9
|
import java.util.UUID
|
|
9
10
|
|
|
10
11
|
private const val LOCAL_PC_ID = -1
|
|
11
12
|
|
|
12
13
|
class AudioSinkManager(val reactContext: ReactContext) {
|
|
13
14
|
|
|
14
|
-
private val sinks = mutableMapOf<String, AudioTrackSink>()
|
|
15
|
+
private val sinks = Collections.synchronizedMap(mutableMapOf<String, AudioTrackSink>())
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Registers a sink to this manager.
|
|
@@ -35,7 +36,12 @@ class AudioSinkManager(val reactContext: ReactContext) {
|
|
|
35
36
|
* Unregisters a sink from this manager. Does not detach the sink from tracks.
|
|
36
37
|
*/
|
|
37
38
|
fun unregisterSink(sink: AudioTrackSink) {
|
|
38
|
-
sinks
|
|
39
|
+
synchronized(sinks) {
|
|
40
|
+
val keysToRemove = sinks.filterValues { it == sink }.keys
|
|
41
|
+
for(key in keysToRemove) {
|
|
42
|
+
sinks.remove(key)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
39
45
|
}
|
|
40
46
|
|
|
41
47
|
fun getSink(reactTag: String) = sinks[reactTag]
|
|
@@ -29,13 +29,14 @@ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e =
|
|
|
29
29
|
* @returns A React component that renders the given video track.
|
|
30
30
|
* @public
|
|
31
31
|
*/
|
|
32
|
-
const VideoTrack = ({
|
|
32
|
+
const VideoTrack = exports.VideoTrack = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
33
33
|
style = {},
|
|
34
34
|
trackRef,
|
|
35
35
|
objectFit = 'cover',
|
|
36
36
|
zOrder,
|
|
37
|
-
mirror
|
|
38
|
-
|
|
37
|
+
mirror,
|
|
38
|
+
iosPIP
|
|
39
|
+
}, ref) => {
|
|
39
40
|
const [elementInfo] = (0, _react.useState)(() => {
|
|
40
41
|
var _trackRef$publication;
|
|
41
42
|
let info = new VideoTrackElementInfo();
|
|
@@ -73,6 +74,32 @@ const VideoTrack = ({
|
|
|
73
74
|
return () => {};
|
|
74
75
|
}
|
|
75
76
|
}, [videoTrack, elementInfo]);
|
|
77
|
+
let videoView;
|
|
78
|
+
if (!iosPIP || _reactNative.Platform.OS !== 'ios') {
|
|
79
|
+
videoView = /*#__PURE__*/React.createElement(_reactNativeWebrtc.RTCView, {
|
|
80
|
+
style: styles.videoTrack,
|
|
81
|
+
streamURL: (mediaStream === null || mediaStream === void 0 ? void 0 : mediaStream.toURL()) ?? '',
|
|
82
|
+
objectFit: objectFit,
|
|
83
|
+
zOrder: zOrder,
|
|
84
|
+
mirror: mirror
|
|
85
|
+
// @ts-ignore
|
|
86
|
+
,
|
|
87
|
+
ref: ref
|
|
88
|
+
});
|
|
89
|
+
} else {
|
|
90
|
+
videoView = /*#__PURE__*/React.createElement(_reactNativeWebrtc.RTCPIPView, {
|
|
91
|
+
style: styles.videoTrack,
|
|
92
|
+
streamURL: (mediaStream === null || mediaStream === void 0 ? void 0 : mediaStream.toURL()) ?? '',
|
|
93
|
+
objectFit: objectFit,
|
|
94
|
+
zOrder: zOrder,
|
|
95
|
+
mirror: mirror
|
|
96
|
+
// TODO: fix this up in react-native-webrtc side.
|
|
97
|
+
// @ts-expect-error
|
|
98
|
+
,
|
|
99
|
+
iosPIP: iosPIP,
|
|
100
|
+
ref: ref
|
|
101
|
+
});
|
|
102
|
+
}
|
|
76
103
|
return /*#__PURE__*/React.createElement(_reactNative.View, {
|
|
77
104
|
style: {
|
|
78
105
|
...style,
|
|
@@ -84,15 +111,8 @@ const VideoTrack = ({
|
|
|
84
111
|
style: styles.videoTrack,
|
|
85
112
|
disabled: !shouldObserveVisibility,
|
|
86
113
|
propKey: videoTrack
|
|
87
|
-
},
|
|
88
|
-
|
|
89
|
-
streamURL: (mediaStream === null || mediaStream === void 0 ? void 0 : mediaStream.toURL()) ?? '',
|
|
90
|
-
objectFit: objectFit,
|
|
91
|
-
zOrder: zOrder,
|
|
92
|
-
mirror: mirror
|
|
93
|
-
})));
|
|
94
|
-
};
|
|
95
|
-
exports.VideoTrack = VideoTrack;
|
|
114
|
+
}, videoView));
|
|
115
|
+
});
|
|
96
116
|
const styles = _reactNative.StyleSheet.create({
|
|
97
117
|
container: {},
|
|
98
118
|
videoTrack: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","_interopRequireWildcard","require","React","_reactNative","_livekitClient","_reactNativeWebrtc","_ViewPortDetector","_interopRequireDefault","e","__esModule","default","_getRequireWildcardCache","WeakMap","r","t","has","get","n","__proto__","a","Object","defineProperty","getOwnPropertyDescriptor","u","hasOwnProperty","call","i","set","_defineProperty","_toPropertyKey","value","enumerable","configurable","writable","_toPrimitive","Symbol","toPrimitive","TypeError","String","Number","VideoTrack","style","trackRef","objectFit","zOrder","mirror","elementInfo","useState","_trackRef$publication","info","VideoTrackElementInfo","id","publication","trackSid","layoutOnChange","useCallback","event","onLayout","visibilityOnChange","isVisible","onVisibility","videoTrack","track","shouldObserveVisibility","useMemo","RemoteVideoTrack","isAdaptiveStream","mediaStream","setMediaStream","useEffect","LocalVideoTrack","onRestarted","on","TrackEvent","Restarted","off","observeElementInfo","stopObservingElementInfo","createElement","View","styles","container","onChange","disabled","propKey","RTCView","streamURL","toURL","exports","StyleSheet","create","flex","width","constructor","_width","_height","observe","_observing","stopObserving","height","nativeEvent","layout","_this$handleResize","handleResize","visible","visibilityChangedAt","Date","now","_this$handleVisibilit","handleVisibilityChanged"],"sources":["VideoTrack.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport {\n type LayoutChangeEvent,\n StyleSheet,\n View,\n type ViewStyle,\n} from 'react-native';\nimport {\n type ElementInfo,\n LocalVideoTrack,\n Track,\n TrackEvent,\n} from 'livekit-client';\nimport { RTCView } from '@livekit/react-native-webrtc';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { RemoteVideoTrack } from 'livekit-client';\nimport ViewPortDetector from './ViewPortDetector';\nimport type { TrackReference } from '@livekit/components-react';\n\n/**\n * Props for the VideoTrack component.\n * @public\n */\nexport type VideoTrackProps = {\n /**\n * The track reference to display. This should be a TrackReference object\n * or undefined if no track is available.\n */\n trackRef: TrackReference | undefined;\n /**\n * Custom React Native styles for the video container.\n */\n style?: ViewStyle;\n /**\n * Specifies how the video content should be resized to fit its container.\n * 'cover' (default): The video will fill the entire container, potentially cropping the video.\n * 'contain': The entire video will be visible within the container, potentially leaving empty space.\n */\n objectFit?: 'cover' | 'contain' | undefined;\n /**\n * Indicates whether the video should be mirrored during rendering.\n * This is commonly used for front-facing cameras.\n */\n mirror?: boolean;\n /**\n * Specifies the depth-stacking order of this video view in the stacking space of all video views.\n * A larger zOrder value generally causes the view to cover those with lower values.\n *\n * The support for zOrder is platform-dependent and/or\n * implementation-specific. Thus, specifying a value for zOrder is to be\n * thought of as giving a hint rather than as imposing a requirement. For\n * example, video renderers such as RTCView are commonly implemented using\n * OpenGL and OpenGL views may have different numbers of layers in their\n * stacking space. Android has three: a layer bellow the window (aka\n * default), a layer bellow the window again but above the previous layer\n * (aka media overlay), and above the window. Consequently, it is advisable\n * to limit the number of utilized layers in the stacking space to the\n * minimum sufficient for the desired display. For example, a video call\n * application usually needs a maximum of two zOrder values: 0 for the\n * remote video(s) which appear in the background, and 1 for the local\n * video(s) which appear above the remote video(s).\n */\n zOrder?: number;\n};\n\n/**\n * VideoTrack component for displaying video tracks in a React Native application.\n * It supports both local and remote video tracks from LiveKit, and handles adaptive streaming for remote tracks.\n *\n * @param props - See VideoTrackProps for details.\n * @returns A React component that renders the given video track.\n * @public\n */\nexport const VideoTrack = ({\n style = {},\n trackRef,\n objectFit = 'cover',\n zOrder,\n mirror,\n}: VideoTrackProps) => {\n const [elementInfo] = useState(() => {\n let info = new VideoTrackElementInfo();\n info.id = trackRef?.publication?.trackSid;\n return info;\n });\n\n const layoutOnChange = useCallback(\n (event: LayoutChangeEvent) => elementInfo.onLayout(event),\n [elementInfo]\n );\n const visibilityOnChange = useCallback(\n (isVisible: boolean) => elementInfo.onVisibility(isVisible),\n [elementInfo]\n );\n\n const videoTrack = trackRef?.publication.track;\n\n const shouldObserveVisibility = useMemo(() => {\n return (\n videoTrack instanceof RemoteVideoTrack && videoTrack.isAdaptiveStream\n );\n }, [videoTrack]);\n\n const [mediaStream, setMediaStream] = useState(videoTrack?.mediaStream);\n useEffect(() => {\n setMediaStream(videoTrack?.mediaStream);\n if (videoTrack instanceof LocalVideoTrack) {\n const onRestarted = (track: Track | null) => {\n setMediaStream(track?.mediaStream);\n };\n videoTrack.on(TrackEvent.Restarted, onRestarted);\n\n return () => {\n videoTrack.off(TrackEvent.Restarted, onRestarted);\n };\n } else {\n return () => {};\n }\n }, [videoTrack]);\n\n useEffect(() => {\n if (videoTrack instanceof RemoteVideoTrack && videoTrack.isAdaptiveStream) {\n videoTrack?.observeElementInfo(elementInfo);\n return () => {\n videoTrack?.stopObservingElementInfo(elementInfo);\n };\n } else {\n return () => {};\n }\n }, [videoTrack, elementInfo]);\n\n return (\n <View style={{ ...style, ...styles.container }} onLayout={layoutOnChange}>\n <ViewPortDetector\n onChange={visibilityOnChange}\n style={styles.videoTrack}\n disabled={!shouldObserveVisibility}\n propKey={videoTrack}\n >\n <RTCView\n style={styles.videoTrack}\n streamURL={mediaStream?.toURL() ?? ''}\n objectFit={objectFit}\n zOrder={zOrder}\n mirror={mirror}\n />\n </ViewPortDetector>\n </View>\n );\n};\n\nconst styles = StyleSheet.create({\n container: {},\n videoTrack: {\n flex: 1,\n width: '100%',\n },\n});\n\nclass VideoTrackElementInfo implements ElementInfo {\n element: object = {};\n something?: any;\n id?: string;\n _width = 0;\n _height = 0;\n _observing = false;\n visible: boolean = true;\n visibilityChangedAt: number | undefined;\n pictureInPicture = false;\n handleResize?: (() => void) | undefined;\n handleVisibilityChanged?: (() => void) | undefined;\n width = () => this._width;\n height = () => this._height;\n\n observe(): void {\n this._observing = true;\n }\n\n stopObserving(): void {\n this._observing = false;\n }\n\n onLayout(event: LayoutChangeEvent) {\n let { width, height } = event.nativeEvent.layout;\n this._width = width;\n this._height = height;\n\n if (this._observing) {\n this.handleResize?.();\n }\n }\n\n onVisibility(isVisible: boolean) {\n if (this.visible !== isVisible) {\n this.visible = isVisible;\n this.visibilityChangedAt = Date.now();\n if (this._observing) {\n this.handleVisibilityChanged?.();\n }\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireWildcard","require","React","_reactNative","_livekitClient","_reactNativeWebrtc","_ViewPortDetector","_interopRequireDefault","e","__esModule","default","_getRequireWildcardCache","WeakMap","r","t","has","get","n","__proto__","a","Object","defineProperty","getOwnPropertyDescriptor","u","hasOwnProperty","call","i","set","_defineProperty","_toPropertyKey","value","enumerable","configurable","writable","_toPrimitive","Symbol","toPrimitive","TypeError","String","Number","VideoTrack","exports","forwardRef","style","trackRef","objectFit","zOrder","mirror","iosPIP","ref","elementInfo","useState","_trackRef$publication","info","VideoTrackElementInfo","id","publication","trackSid","layoutOnChange","useCallback","event","onLayout","visibilityOnChange","isVisible","onVisibility","videoTrack","track","shouldObserveVisibility","useMemo","RemoteVideoTrack","isAdaptiveStream","mediaStream","setMediaStream","useEffect","LocalVideoTrack","onRestarted","on","TrackEvent","Restarted","off","observeElementInfo","stopObservingElementInfo","videoView","Platform","OS","createElement","RTCView","styles","streamURL","toURL","RTCPIPView","View","container","onChange","disabled","propKey","StyleSheet","create","flex","width","constructor","_width","_height","observe","_observing","stopObserving","height","nativeEvent","layout","_this$handleResize","handleResize","visible","visibilityChangedAt","Date","now","_this$handleVisibilit","handleVisibilityChanged"],"sources":["VideoTrack.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport {\n type LayoutChangeEvent,\n Platform,\n StyleSheet,\n View,\n type ViewStyle,\n} from 'react-native';\nimport {\n type ElementInfo,\n LocalVideoTrack,\n Track,\n TrackEvent,\n} from 'livekit-client';\nimport {\n RTCView,\n RTCPIPView,\n type RTCIOSPIPOptions,\n} from '@livekit/react-native-webrtc';\nimport {\n Component,\n forwardRef,\n useCallback,\n useEffect,\n useMemo,\n useState,\n type ReactNode,\n} from 'react';\nimport { RemoteVideoTrack } from 'livekit-client';\nimport ViewPortDetector from './ViewPortDetector';\nimport type { TrackReference } from '@livekit/components-react';\n\n/**\n * Props for the VideoTrack component.\n * @public\n */\nexport type VideoTrackProps = {\n /**\n * The track reference to display. This should be a TrackReference object\n * or undefined if no track is available.\n */\n trackRef: TrackReference | undefined;\n /**\n * Custom React Native styles for the video container.\n */\n style?: ViewStyle;\n /**\n * Specifies how the video content should be resized to fit its container.\n * 'cover' (default): The video will fill the entire container, potentially cropping the video.\n * 'contain': The entire video will be visible within the container, potentially leaving empty space.\n */\n objectFit?: 'cover' | 'contain' | undefined;\n /**\n * Indicates whether the video should be mirrored during rendering.\n * This is commonly used for front-facing cameras.\n */\n mirror?: boolean;\n /**\n * Specifies the depth-stacking order of this video view in the stacking space of all video views.\n * A larger zOrder value generally causes the view to cover those with lower values.\n *\n * The support for zOrder is platform-dependent and/or\n * implementation-specific. Thus, specifying a value for zOrder is to be\n * thought of as giving a hint rather than as imposing a requirement. For\n * example, video renderers such as RTCView are commonly implemented using\n * OpenGL and OpenGL views may have different numbers of layers in their\n * stacking space. Android has three: a layer bellow the window (aka\n * default), a layer bellow the window again but above the previous layer\n * (aka media overlay), and above the window. Consequently, it is advisable\n * to limit the number of utilized layers in the stacking space to the\n * minimum sufficient for the desired display. For example, a video call\n * application usually needs a maximum of two zOrder values: 0 for the\n * remote video(s) which appear in the background, and 1 for the local\n * video(s) which appear above the remote video(s).\n */\n zOrder?: number;\n\n /**\n * Picture in picture options for this view. Disabled if not supplied.\n *\n * iOS only. Requires iOS 15.0 or above, and the PIP background mode capability.\n *\n * If `iosPIP.enabled` is true, startIOSPIP and stopIOSPIP can be used to manually\n * trigger the PIP mode. `iosPIP.startAutomatically` can be used to automatically\n * enter PIP when backgrounding the app.\n *\n * @example\n * ```tsx\n * import { startIOSPIP, stopIOSPIP } from '@livekit/react-native-webrtc';\n *\n * // Obtain a ref to the view\n * const videoRef = useRef<Component>(null);\n * const videoView = (\n * <VideoTrack\n * ref={videoRef}\n * iosPIP={{\n * enabled: true,\n * startAutomatically: true,\n * preferredSize: {\n * width: 800,\n * height: 800,\n * },\n * }}\n * ...\n * />\n * );\n *\n * // Start/stop manually\n * startIOSPIP(videoRef);\n * stopIOSPIP(videoRef);\n * ```\n *\n */\n iosPIP?: RTCIOSPIPOptions & {\n preferredSize: {\n width: number;\n height: number;\n };\n fallbackView?: ReactNode;\n };\n};\n\n/**\n * VideoTrack component for displaying video tracks in a React Native application.\n * It supports both local and remote video tracks from LiveKit, and handles adaptive streaming for remote tracks.\n *\n * @param props - See VideoTrackProps for details.\n * @returns A React component that renders the given video track.\n * @public\n */\nexport const VideoTrack = forwardRef<Component, VideoTrackProps>(\n (\n {\n style = {},\n trackRef,\n objectFit = 'cover',\n zOrder,\n mirror,\n iosPIP,\n }: VideoTrackProps,\n ref\n ) => {\n const [elementInfo] = useState(() => {\n let info = new VideoTrackElementInfo();\n info.id = trackRef?.publication?.trackSid;\n return info;\n });\n\n const layoutOnChange = useCallback(\n (event: LayoutChangeEvent) => elementInfo.onLayout(event),\n [elementInfo]\n );\n const visibilityOnChange = useCallback(\n (isVisible: boolean) => elementInfo.onVisibility(isVisible),\n [elementInfo]\n );\n\n const videoTrack = trackRef?.publication.track;\n\n const shouldObserveVisibility = useMemo(() => {\n return (\n videoTrack instanceof RemoteVideoTrack && videoTrack.isAdaptiveStream\n );\n }, [videoTrack]);\n\n const [mediaStream, setMediaStream] = useState(videoTrack?.mediaStream);\n useEffect(() => {\n setMediaStream(videoTrack?.mediaStream);\n if (videoTrack instanceof LocalVideoTrack) {\n const onRestarted = (track: Track | null) => {\n setMediaStream(track?.mediaStream);\n };\n videoTrack.on(TrackEvent.Restarted, onRestarted);\n\n return () => {\n videoTrack.off(TrackEvent.Restarted, onRestarted);\n };\n } else {\n return () => {};\n }\n }, [videoTrack]);\n\n useEffect(() => {\n if (\n videoTrack instanceof RemoteVideoTrack &&\n videoTrack.isAdaptiveStream\n ) {\n videoTrack?.observeElementInfo(elementInfo);\n return () => {\n videoTrack?.stopObservingElementInfo(elementInfo);\n };\n } else {\n return () => {};\n }\n }, [videoTrack, elementInfo]);\n\n let videoView;\n if (!iosPIP || Platform.OS !== 'ios') {\n videoView = (\n <RTCView\n style={styles.videoTrack}\n streamURL={mediaStream?.toURL() ?? ''}\n objectFit={objectFit}\n zOrder={zOrder}\n mirror={mirror}\n // @ts-ignore\n ref={ref}\n />\n );\n } else {\n videoView = (\n <RTCPIPView\n style={styles.videoTrack}\n streamURL={mediaStream?.toURL() ?? ''}\n objectFit={objectFit}\n zOrder={zOrder}\n mirror={mirror}\n // TODO: fix this up in react-native-webrtc side.\n // @ts-expect-error\n iosPIP={iosPIP}\n ref={ref}\n />\n );\n }\n return (\n <View style={{ ...style, ...styles.container }} onLayout={layoutOnChange}>\n <ViewPortDetector\n onChange={visibilityOnChange}\n style={styles.videoTrack}\n disabled={!shouldObserveVisibility}\n propKey={videoTrack}\n >\n {videoView}\n </ViewPortDetector>\n </View>\n );\n }\n);\n\nconst styles = StyleSheet.create({\n container: {},\n videoTrack: {\n flex: 1,\n width: '100%',\n },\n});\n\nclass VideoTrackElementInfo implements ElementInfo {\n element: object = {};\n something?: any;\n id?: string;\n _width = 0;\n _height = 0;\n _observing = false;\n visible: boolean = true;\n visibilityChangedAt: number | undefined;\n pictureInPicture = false;\n handleResize?: (() => void) | undefined;\n handleVisibilityChanged?: (() => void) | undefined;\n width = () => this._width;\n height = () => this._height;\n\n observe(): void {\n this._observing = true;\n }\n\n stopObserving(): void {\n this._observing = false;\n }\n\n onLayout(event: LayoutChangeEvent) {\n let { width, height } = event.nativeEvent.layout;\n this._width = width;\n this._height = height;\n\n if (this._observing) {\n this.handleResize?.();\n }\n }\n\n onVisibility(isVisible: boolean) {\n if (this.visible !== isVisible) {\n this.visible = isVisible;\n this.visibilityChangedAt = Date.now();\n if (this._observing) {\n this.handleVisibilityChanged?.();\n }\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -27,7 +27,7 @@ const multibandDefaults = {
|
|
|
27
27
|
* @param trackOrTrackReference
|
|
28
28
|
* @returns A number array containing the volume for each frequency band.
|
|
29
29
|
*/
|
|
30
|
-
function useMultibandTrackVolume(trackOrTrackReference, options
|
|
30
|
+
function useMultibandTrackVolume(trackOrTrackReference, options) {
|
|
31
31
|
var _trackOrTrackReferenc;
|
|
32
32
|
const track = trackOrTrackReference instanceof _livekitClient.Track ? trackOrTrackReference : trackOrTrackReference === null || trackOrTrackReference === void 0 || (_trackOrTrackReferenc = trackOrTrackReference.publication) === null || _trackOrTrackReferenc === void 0 ? void 0 : _trackOrTrackReferenc.track;
|
|
33
33
|
const opts = (0, _react.useMemo)(() => {
|
|
@@ -35,30 +35,35 @@ function useMultibandTrackVolume(trackOrTrackReference, options = {}) {
|
|
|
35
35
|
...multibandDefaults,
|
|
36
36
|
...options
|
|
37
37
|
};
|
|
38
|
-
|
|
38
|
+
|
|
39
|
+
// disabled due to use of JSON.stringify, dependencies are reference equality
|
|
40
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
41
|
+
}, [JSON.stringify(options)]);
|
|
39
42
|
const mediaStreamTrack = track === null || track === void 0 ? void 0 : track.mediaStreamTrack;
|
|
43
|
+
const hasMediaStreamTrack = mediaStreamTrack != null;
|
|
44
|
+
const peerConnectionId = (mediaStreamTrack === null || mediaStreamTrack === void 0 ? void 0 : mediaStreamTrack.peerConnectionId) ?? -1;
|
|
45
|
+
const mediaStreamTrackId = mediaStreamTrack === null || mediaStreamTrack === void 0 ? void 0 : mediaStreamTrack.id;
|
|
40
46
|
let [magnitudes, setMagnitudes] = (0, _react.useState)([]);
|
|
41
47
|
(0, _react.useEffect)(() => {
|
|
42
48
|
let listener = Object();
|
|
43
49
|
let reactTag = null;
|
|
44
|
-
if (
|
|
45
|
-
reactTag = _LKNativeModule.default.createMultibandVolumeProcessor(opts,
|
|
50
|
+
if (hasMediaStreamTrack) {
|
|
51
|
+
reactTag = _LKNativeModule.default.createMultibandVolumeProcessor(opts, peerConnectionId, mediaStreamTrackId);
|
|
46
52
|
(0, _EventEmitter.addListener)(listener, 'LK_MULTIBAND_PROCESSED', event => {
|
|
47
53
|
if (event.magnitudes && reactTag && event.id === reactTag) {
|
|
48
|
-
console.log('event received: ', event.magnitudes[0]);
|
|
49
54
|
setMagnitudes(event.magnitudes);
|
|
50
55
|
}
|
|
51
56
|
});
|
|
52
57
|
}
|
|
53
58
|
return () => {
|
|
54
|
-
if (
|
|
59
|
+
if (hasMediaStreamTrack) {
|
|
55
60
|
(0, _EventEmitter.removeListener)(listener);
|
|
56
61
|
if (reactTag) {
|
|
57
|
-
_LKNativeModule.default.deleteMultibandVolumeProcessor(reactTag,
|
|
62
|
+
_LKNativeModule.default.deleteMultibandVolumeProcessor(reactTag, peerConnectionId, mediaStreamTrackId);
|
|
58
63
|
}
|
|
59
64
|
}
|
|
60
65
|
};
|
|
61
|
-
}, [
|
|
66
|
+
}, [hasMediaStreamTrack, peerConnectionId, mediaStreamTrackId, opts]);
|
|
62
67
|
return magnitudes;
|
|
63
68
|
}
|
|
64
69
|
//# sourceMappingURL=useMultibandTrackVolume.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_livekitClient","require","_react","_EventEmitter","_LKNativeModule","_interopRequireDefault","e","__esModule","default","multibandDefaults","bands","minFrequency","maxFrequency","updateInterval","useMultibandTrackVolume","trackOrTrackReference","options","_trackOrTrackReferenc","track","Track","publication","opts","useMemo","mediaStreamTrack","
|
|
1
|
+
{"version":3,"names":["_livekitClient","require","_react","_EventEmitter","_LKNativeModule","_interopRequireDefault","e","__esModule","default","multibandDefaults","bands","minFrequency","maxFrequency","updateInterval","useMultibandTrackVolume","trackOrTrackReference","options","_trackOrTrackReferenc","track","Track","publication","opts","useMemo","JSON","stringify","mediaStreamTrack","hasMediaStreamTrack","peerConnectionId","mediaStreamTrackId","id","magnitudes","setMagnitudes","useState","useEffect","listener","Object","reactTag","LiveKitModule","createMultibandVolumeProcessor","addListener","event","removeListener","deleteMultibandVolumeProcessor"],"sources":["useMultibandTrackVolume.ts"],"sourcesContent":["import { type TrackReferenceOrPlaceholder } from '@livekit/components-react';\nimport {\n Track,\n type LocalAudioTrack,\n type RemoteAudioTrack,\n} from 'livekit-client';\nimport { useEffect, useMemo, useState } from 'react';\nimport { addListener, removeListener } from '../events/EventEmitter';\nimport LiveKitModule from '../LKNativeModule';\n\n/**\n * Interface for configuring options for the useMultibandTrackVolume hook.\n * @alpha\n */\nexport interface MultiBandTrackVolumeOptions {\n /**\n * the number of bands to split the audio into\n */\n bands?: number;\n /**\n * cut off frequency on the lower end\n */\n minFrequency?: number;\n /**\n * cut off frequency on the higher end\n */\n maxFrequency?: number;\n /**\n * update should run every x ms\n */\n updateInterval?: number;\n}\n\nconst multibandDefaults = {\n bands: 5,\n minFrequency: 1000,\n maxFrequency: 8000,\n updateInterval: 40,\n} as const satisfies MultiBandTrackVolumeOptions;\n\n/**\n * A hook for tracking the volume of an audio track across multiple frequency bands.\n *\n * @param trackOrTrackReference\n * @returns A number array containing the volume for each frequency band.\n */\nexport function useMultibandTrackVolume(\n trackOrTrackReference?:\n | LocalAudioTrack\n | RemoteAudioTrack\n | TrackReferenceOrPlaceholder,\n options?: MultiBandTrackVolumeOptions\n) {\n const track =\n trackOrTrackReference instanceof Track\n ? trackOrTrackReference\n : <LocalAudioTrack | RemoteAudioTrack | undefined>(\n trackOrTrackReference?.publication?.track\n );\n const opts = useMemo(() => {\n return { ...multibandDefaults, ...options };\n\n // disabled due to use of JSON.stringify, dependencies are reference equality\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [JSON.stringify(options)]);\n const mediaStreamTrack = track?.mediaStreamTrack;\n const hasMediaStreamTrack = mediaStreamTrack != null;\n const peerConnectionId = mediaStreamTrack?.peerConnectionId ?? -1;\n const mediaStreamTrackId = mediaStreamTrack?.id;\n\n let [magnitudes, setMagnitudes] = useState<number[]>([]);\n useEffect(() => {\n let listener = Object();\n let reactTag: string | null = null;\n if (hasMediaStreamTrack) {\n reactTag = LiveKitModule.createMultibandVolumeProcessor(\n opts,\n peerConnectionId,\n mediaStreamTrackId\n );\n addListener(listener, 'LK_MULTIBAND_PROCESSED', (event: any) => {\n if (event.magnitudes && reactTag && event.id === reactTag) {\n setMagnitudes(event.magnitudes);\n }\n });\n }\n return () => {\n if (hasMediaStreamTrack) {\n removeListener(listener);\n if (reactTag) {\n LiveKitModule.deleteMultibandVolumeProcessor(\n reactTag,\n peerConnectionId,\n mediaStreamTrackId\n );\n }\n }\n };\n }, [hasMediaStreamTrack, peerConnectionId, mediaStreamTrackId, opts]);\n\n return magnitudes;\n}\n"],"mappings":";;;;;;AACA,IAAAA,cAAA,GAAAC,OAAA;AAKA,IAAAC,MAAA,GAAAD,OAAA;AACA,IAAAE,aAAA,GAAAF,OAAA;AACA,IAAAG,eAAA,GAAAC,sBAAA,CAAAJ,OAAA;AAA8C,SAAAI,uBAAAC,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAE9C;AACA;AACA;AACA;;AAoBA,MAAMG,iBAAiB,GAAG;EACxBC,KAAK,EAAE,CAAC;EACRC,YAAY,EAAE,IAAI;EAClBC,YAAY,EAAE,IAAI;EAClBC,cAAc,EAAE;AAClB,CAAgD;;AAEhD;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,uBAAuBA,CACrCC,qBAG+B,EAC/BC,OAAqC,EACrC;EAAA,IAAAC,qBAAA;EACA,MAAMC,KAAK,GACTH,qBAAqB,YAAYI,oBAAK,GAClCJ,qBAAqB,GAEnBA,qBAAqB,aAArBA,qBAAqB,gBAAAE,qBAAA,GAArBF,qBAAqB,CAAEK,WAAW,cAAAH,qBAAA,uBAAlCA,qBAAA,CAAoCC,KACrC;EACP,MAAMG,IAAI,GAAG,IAAAC,cAAO,EAAC,MAAM;IACzB,OAAO;MAAE,GAAGb,iBAAiB;MAAE,GAAGO;IAAQ,CAAC;;IAE3C;IACA;EACF,CAAC,EAAE,CAACO,IAAI,CAACC,SAAS,CAACR,OAAO,CAAC,CAAC,CAAC;EAC7B,MAAMS,gBAAgB,GAAGP,KAAK,aAALA,KAAK,uBAALA,KAAK,CAAEO,gBAAgB;EAChD,MAAMC,mBAAmB,GAAGD,gBAAgB,IAAI,IAAI;EACpD,MAAME,gBAAgB,GAAG,CAAAF,gBAAgB,aAAhBA,gBAAgB,uBAAhBA,gBAAgB,CAAEE,gBAAgB,KAAI,CAAC,CAAC;EACjE,MAAMC,kBAAkB,GAAGH,gBAAgB,aAAhBA,gBAAgB,uBAAhBA,gBAAgB,CAAEI,EAAE;EAE/C,IAAI,CAACC,UAAU,EAAEC,aAAa,CAAC,GAAG,IAAAC,eAAQ,EAAW,EAAE,CAAC;EACxD,IAAAC,gBAAS,EAAC,MAAM;IACd,IAAIC,QAAQ,GAAGC,MAAM,CAAC,CAAC;IACvB,IAAIC,QAAuB,GAAG,IAAI;IAClC,IAAIV,mBAAmB,EAAE;MACvBU,QAAQ,GAAGC,uBAAa,CAACC,8BAA8B,CACrDjB,IAAI,EACJM,gBAAgB,EAChBC,kBACF,CAAC;MACD,IAAAW,yBAAW,EAACL,QAAQ,EAAE,wBAAwB,EAAGM,KAAU,IAAK;QAC9D,IAAIA,KAAK,CAACV,UAAU,IAAIM,QAAQ,IAAII,KAAK,CAACX,EAAE,KAAKO,QAAQ,EAAE;UACzDL,aAAa,CAACS,KAAK,CAACV,UAAU,CAAC;QACjC;MACF,CAAC,CAAC;IACJ;IACA,OAAO,MAAM;MACX,IAAIJ,mBAAmB,EAAE;QACvB,IAAAe,4BAAc,EAACP,QAAQ,CAAC;QACxB,IAAIE,QAAQ,EAAE;UACZC,uBAAa,CAACK,8BAA8B,CAC1CN,QAAQ,EACRT,gBAAgB,EAChBC,kBACF,CAAC;QACH;MACF;IACF,CAAC;EACH,CAAC,EAAE,CAACF,mBAAmB,EAAEC,gBAAgB,EAAEC,kBAAkB,EAAEP,IAAI,CAAC,CAAC;EAErE,OAAOS,UAAU;AACnB","ignoreList":[]}
|
|
@@ -19,12 +19,15 @@ function useTrackVolume(trackOrTrackReference) {
|
|
|
19
19
|
var _trackOrTrackReferenc;
|
|
20
20
|
const track = trackOrTrackReference instanceof _livekitClient.Track ? trackOrTrackReference : trackOrTrackReference === null || trackOrTrackReference === void 0 || (_trackOrTrackReferenc = trackOrTrackReference.publication) === null || _trackOrTrackReferenc === void 0 ? void 0 : _trackOrTrackReferenc.track;
|
|
21
21
|
const mediaStreamTrack = track === null || track === void 0 ? void 0 : track.mediaStreamTrack;
|
|
22
|
+
const hasMediaStreamTrack = mediaStreamTrack != null;
|
|
23
|
+
const peerConnectionId = mediaStreamTrack.peerConnectionId ?? -1;
|
|
24
|
+
const mediaStreamTrackId = mediaStreamTrack.id;
|
|
22
25
|
let [volume, setVolume] = (0, _react.useState)(0.0);
|
|
23
26
|
(0, _react.useEffect)(() => {
|
|
24
27
|
let listener = Object();
|
|
25
28
|
let reactTag = null;
|
|
26
|
-
if (
|
|
27
|
-
reactTag = _LKNativeModule.default.createVolumeProcessor(
|
|
29
|
+
if (hasMediaStreamTrack) {
|
|
30
|
+
reactTag = _LKNativeModule.default.createVolumeProcessor(peerConnectionId, mediaStreamTrackId);
|
|
28
31
|
(0, _EventEmitter.addListener)(listener, 'LK_VOLUME_PROCESSED', event => {
|
|
29
32
|
if (event.volume && reactTag && event.id === reactTag) {
|
|
30
33
|
setVolume(event.volume);
|
|
@@ -32,14 +35,14 @@ function useTrackVolume(trackOrTrackReference) {
|
|
|
32
35
|
});
|
|
33
36
|
}
|
|
34
37
|
return () => {
|
|
35
|
-
if (
|
|
38
|
+
if (hasMediaStreamTrack) {
|
|
36
39
|
(0, _EventEmitter.removeListener)(listener);
|
|
37
40
|
if (reactTag) {
|
|
38
|
-
_LKNativeModule.default.deleteVolumeProcessor(reactTag,
|
|
41
|
+
_LKNativeModule.default.deleteVolumeProcessor(reactTag, peerConnectionId, mediaStreamTrackId);
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
44
|
};
|
|
42
|
-
}, [
|
|
45
|
+
}, [hasMediaStreamTrack, peerConnectionId, mediaStreamTrackId]);
|
|
43
46
|
return volume;
|
|
44
47
|
}
|
|
45
48
|
//# sourceMappingURL=useTrackVolume.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_livekitClient","require","_react","_EventEmitter","_LKNativeModule","_interopRequireDefault","e","__esModule","default","useTrackVolume","trackOrTrackReference","_trackOrTrackReferenc","track","Track","publication","mediaStreamTrack","volume","setVolume","useState","useEffect","listener","Object","reactTag","LiveKitModule","createVolumeProcessor","
|
|
1
|
+
{"version":3,"names":["_livekitClient","require","_react","_EventEmitter","_LKNativeModule","_interopRequireDefault","e","__esModule","default","useTrackVolume","trackOrTrackReference","_trackOrTrackReferenc","track","Track","publication","mediaStreamTrack","hasMediaStreamTrack","peerConnectionId","mediaStreamTrackId","id","volume","setVolume","useState","useEffect","listener","Object","reactTag","LiveKitModule","createVolumeProcessor","addListener","event","removeListener","deleteVolumeProcessor"],"sources":["useTrackVolume.ts"],"sourcesContent":["import { type TrackReferenceOrPlaceholder } from '@livekit/components-react';\nimport {\n Track,\n type LocalAudioTrack,\n type RemoteAudioTrack,\n} from 'livekit-client';\nimport { useEffect, useState } from 'react';\nimport { addListener, removeListener } from '../events/EventEmitter';\nimport LiveKitModule from '../LKNativeModule';\n\n/**\n * A hook for tracking the volume of an audio track.\n *\n * @param trackOrTrackReference\n * @returns A number between 0-1 representing the volume.\n */\nexport function useTrackVolume(\n trackOrTrackReference?:\n | LocalAudioTrack\n | RemoteAudioTrack\n | TrackReferenceOrPlaceholder\n) {\n const track =\n trackOrTrackReference instanceof Track\n ? trackOrTrackReference\n : <LocalAudioTrack | RemoteAudioTrack | undefined>(\n trackOrTrackReference?.publication?.track\n );\n\n const mediaStreamTrack = track?.mediaStreamTrack;\n const hasMediaStreamTrack = mediaStreamTrack != null;\n const peerConnectionId = mediaStreamTrack.peerConnectionId ?? -1;\n const mediaStreamTrackId = mediaStreamTrack.id;\n\n let [volume, setVolume] = useState(0.0);\n useEffect(() => {\n let listener = Object();\n let reactTag: string | null = null;\n if (hasMediaStreamTrack) {\n reactTag = LiveKitModule.createVolumeProcessor(\n peerConnectionId,\n mediaStreamTrackId\n );\n addListener(listener, 'LK_VOLUME_PROCESSED', (event: any) => {\n if (event.volume && reactTag && event.id === reactTag) {\n setVolume(event.volume);\n }\n });\n }\n return () => {\n if (hasMediaStreamTrack) {\n removeListener(listener);\n if (reactTag) {\n LiveKitModule.deleteVolumeProcessor(\n reactTag,\n peerConnectionId,\n mediaStreamTrackId\n );\n }\n }\n };\n }, [hasMediaStreamTrack, peerConnectionId, mediaStreamTrackId]);\n\n return volume;\n}\n"],"mappings":";;;;;;AACA,IAAAA,cAAA,GAAAC,OAAA;AAKA,IAAAC,MAAA,GAAAD,OAAA;AACA,IAAAE,aAAA,GAAAF,OAAA;AACA,IAAAG,eAAA,GAAAC,sBAAA,CAAAJ,OAAA;AAA8C,SAAAI,uBAAAC,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAE9C;AACA;AACA;AACA;AACA;AACA;AACO,SAASG,cAAcA,CAC5BC,qBAG+B,EAC/B;EAAA,IAAAC,qBAAA;EACA,MAAMC,KAAK,GACTF,qBAAqB,YAAYG,oBAAK,GAClCH,qBAAqB,GAEnBA,qBAAqB,aAArBA,qBAAqB,gBAAAC,qBAAA,GAArBD,qBAAqB,CAAEI,WAAW,cAAAH,qBAAA,uBAAlCA,qBAAA,CAAoCC,KACrC;EAEP,MAAMG,gBAAgB,GAAGH,KAAK,aAALA,KAAK,uBAALA,KAAK,CAAEG,gBAAgB;EAChD,MAAMC,mBAAmB,GAAGD,gBAAgB,IAAI,IAAI;EACpD,MAAME,gBAAgB,GAAGF,gBAAgB,CAACE,gBAAgB,IAAI,CAAC,CAAC;EAChE,MAAMC,kBAAkB,GAAGH,gBAAgB,CAACI,EAAE;EAE9C,IAAI,CAACC,MAAM,EAAEC,SAAS,CAAC,GAAG,IAAAC,eAAQ,EAAC,GAAG,CAAC;EACvC,IAAAC,gBAAS,EAAC,MAAM;IACd,IAAIC,QAAQ,GAAGC,MAAM,CAAC,CAAC;IACvB,IAAIC,QAAuB,GAAG,IAAI;IAClC,IAAIV,mBAAmB,EAAE;MACvBU,QAAQ,GAAGC,uBAAa,CAACC,qBAAqB,CAC5CX,gBAAgB,EAChBC,kBACF,CAAC;MACD,IAAAW,yBAAW,EAACL,QAAQ,EAAE,qBAAqB,EAAGM,KAAU,IAAK;QAC3D,IAAIA,KAAK,CAACV,MAAM,IAAIM,QAAQ,IAAII,KAAK,CAACX,EAAE,KAAKO,QAAQ,EAAE;UACrDL,SAAS,CAACS,KAAK,CAACV,MAAM,CAAC;QACzB;MACF,CAAC,CAAC;IACJ;IACA,OAAO,MAAM;MACX,IAAIJ,mBAAmB,EAAE;QACvB,IAAAe,4BAAc,EAACP,QAAQ,CAAC;QACxB,IAAIE,QAAQ,EAAE;UACZC,uBAAa,CAACK,qBAAqB,CACjCN,QAAQ,EACRT,gBAAgB,EAChBC,kBACF,CAAC;QACH;MACF;IACF,CAAC;EACH,CAAC,EAAE,CAACF,mBAAmB,EAAEC,gBAAgB,EAAEC,kBAAkB,CAAC,CAAC;EAE/D,OAAOE,MAAM;AACf","ignoreList":[]}
|
|
@@ -2,10 +2,10 @@ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object
|
|
|
2
2
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
3
3
|
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
4
4
|
import * as React from 'react';
|
|
5
|
-
import { StyleSheet, View } from 'react-native';
|
|
5
|
+
import { Platform, StyleSheet, View } from 'react-native';
|
|
6
6
|
import { LocalVideoTrack, TrackEvent } from 'livekit-client';
|
|
7
|
-
import { RTCView } from '@livekit/react-native-webrtc';
|
|
8
|
-
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
7
|
+
import { RTCView, RTCPIPView } from '@livekit/react-native-webrtc';
|
|
8
|
+
import { forwardRef, useCallback, useEffect, useMemo, useState } from 'react';
|
|
9
9
|
import { RemoteVideoTrack } from 'livekit-client';
|
|
10
10
|
import ViewPortDetector from './ViewPortDetector';
|
|
11
11
|
|
|
@@ -22,13 +22,14 @@ import ViewPortDetector from './ViewPortDetector';
|
|
|
22
22
|
* @returns A React component that renders the given video track.
|
|
23
23
|
* @public
|
|
24
24
|
*/
|
|
25
|
-
export const VideoTrack = ({
|
|
25
|
+
export const VideoTrack = /*#__PURE__*/forwardRef(({
|
|
26
26
|
style = {},
|
|
27
27
|
trackRef,
|
|
28
28
|
objectFit = 'cover',
|
|
29
29
|
zOrder,
|
|
30
|
-
mirror
|
|
31
|
-
|
|
30
|
+
mirror,
|
|
31
|
+
iosPIP
|
|
32
|
+
}, ref) => {
|
|
32
33
|
const [elementInfo] = useState(() => {
|
|
33
34
|
var _trackRef$publication;
|
|
34
35
|
let info = new VideoTrackElementInfo();
|
|
@@ -66,6 +67,32 @@ export const VideoTrack = ({
|
|
|
66
67
|
return () => {};
|
|
67
68
|
}
|
|
68
69
|
}, [videoTrack, elementInfo]);
|
|
70
|
+
let videoView;
|
|
71
|
+
if (!iosPIP || Platform.OS !== 'ios') {
|
|
72
|
+
videoView = /*#__PURE__*/React.createElement(RTCView, {
|
|
73
|
+
style: styles.videoTrack,
|
|
74
|
+
streamURL: (mediaStream === null || mediaStream === void 0 ? void 0 : mediaStream.toURL()) ?? '',
|
|
75
|
+
objectFit: objectFit,
|
|
76
|
+
zOrder: zOrder,
|
|
77
|
+
mirror: mirror
|
|
78
|
+
// @ts-ignore
|
|
79
|
+
,
|
|
80
|
+
ref: ref
|
|
81
|
+
});
|
|
82
|
+
} else {
|
|
83
|
+
videoView = /*#__PURE__*/React.createElement(RTCPIPView, {
|
|
84
|
+
style: styles.videoTrack,
|
|
85
|
+
streamURL: (mediaStream === null || mediaStream === void 0 ? void 0 : mediaStream.toURL()) ?? '',
|
|
86
|
+
objectFit: objectFit,
|
|
87
|
+
zOrder: zOrder,
|
|
88
|
+
mirror: mirror
|
|
89
|
+
// TODO: fix this up in react-native-webrtc side.
|
|
90
|
+
// @ts-expect-error
|
|
91
|
+
,
|
|
92
|
+
iosPIP: iosPIP,
|
|
93
|
+
ref: ref
|
|
94
|
+
});
|
|
95
|
+
}
|
|
69
96
|
return /*#__PURE__*/React.createElement(View, {
|
|
70
97
|
style: {
|
|
71
98
|
...style,
|
|
@@ -77,14 +104,8 @@ export const VideoTrack = ({
|
|
|
77
104
|
style: styles.videoTrack,
|
|
78
105
|
disabled: !shouldObserveVisibility,
|
|
79
106
|
propKey: videoTrack
|
|
80
|
-
},
|
|
81
|
-
|
|
82
|
-
streamURL: (mediaStream === null || mediaStream === void 0 ? void 0 : mediaStream.toURL()) ?? '',
|
|
83
|
-
objectFit: objectFit,
|
|
84
|
-
zOrder: zOrder,
|
|
85
|
-
mirror: mirror
|
|
86
|
-
})));
|
|
87
|
-
};
|
|
107
|
+
}, videoView));
|
|
108
|
+
});
|
|
88
109
|
const styles = StyleSheet.create({
|
|
89
110
|
container: {},
|
|
90
111
|
videoTrack: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","StyleSheet","View","LocalVideoTrack","TrackEvent","RTCView","useCallback","useEffect","useMemo","useState","RemoteVideoTrack","ViewPortDetector","VideoTrack","style","trackRef","objectFit","zOrder","mirror","elementInfo","_trackRef$publication","info","VideoTrackElementInfo","id","publication","trackSid","layoutOnChange","event","onLayout","visibilityOnChange","isVisible","onVisibility","videoTrack","track","shouldObserveVisibility","isAdaptiveStream","mediaStream","setMediaStream","onRestarted","on","Restarted","off","observeElementInfo","stopObservingElementInfo","createElement","styles","container","onChange","disabled","propKey","streamURL","toURL","create","flex","width","constructor","_defineProperty","_width","_height","observe","_observing","stopObserving","height","nativeEvent","layout","_this$handleResize","handleResize","call","visible","visibilityChangedAt","Date","now","_this$handleVisibilit","handleVisibilityChanged"],"sources":["VideoTrack.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport {\n type LayoutChangeEvent,\n StyleSheet,\n View,\n type ViewStyle,\n} from 'react-native';\nimport {\n type ElementInfo,\n LocalVideoTrack,\n Track,\n TrackEvent,\n} from 'livekit-client';\nimport { RTCView } from '@livekit/react-native-webrtc';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { RemoteVideoTrack } from 'livekit-client';\nimport ViewPortDetector from './ViewPortDetector';\nimport type { TrackReference } from '@livekit/components-react';\n\n/**\n * Props for the VideoTrack component.\n * @public\n */\nexport type VideoTrackProps = {\n /**\n * The track reference to display. This should be a TrackReference object\n * or undefined if no track is available.\n */\n trackRef: TrackReference | undefined;\n /**\n * Custom React Native styles for the video container.\n */\n style?: ViewStyle;\n /**\n * Specifies how the video content should be resized to fit its container.\n * 'cover' (default): The video will fill the entire container, potentially cropping the video.\n * 'contain': The entire video will be visible within the container, potentially leaving empty space.\n */\n objectFit?: 'cover' | 'contain' | undefined;\n /**\n * Indicates whether the video should be mirrored during rendering.\n * This is commonly used for front-facing cameras.\n */\n mirror?: boolean;\n /**\n * Specifies the depth-stacking order of this video view in the stacking space of all video views.\n * A larger zOrder value generally causes the view to cover those with lower values.\n *\n * The support for zOrder is platform-dependent and/or\n * implementation-specific. Thus, specifying a value for zOrder is to be\n * thought of as giving a hint rather than as imposing a requirement. For\n * example, video renderers such as RTCView are commonly implemented using\n * OpenGL and OpenGL views may have different numbers of layers in their\n * stacking space. Android has three: a layer bellow the window (aka\n * default), a layer bellow the window again but above the previous layer\n * (aka media overlay), and above the window. Consequently, it is advisable\n * to limit the number of utilized layers in the stacking space to the\n * minimum sufficient for the desired display. For example, a video call\n * application usually needs a maximum of two zOrder values: 0 for the\n * remote video(s) which appear in the background, and 1 for the local\n * video(s) which appear above the remote video(s).\n */\n zOrder?: number;\n};\n\n/**\n * VideoTrack component for displaying video tracks in a React Native application.\n * It supports both local and remote video tracks from LiveKit, and handles adaptive streaming for remote tracks.\n *\n * @param props - See VideoTrackProps for details.\n * @returns A React component that renders the given video track.\n * @public\n */\nexport const VideoTrack = ({\n style = {},\n trackRef,\n objectFit = 'cover',\n zOrder,\n mirror,\n}: VideoTrackProps) => {\n const [elementInfo] = useState(() => {\n let info = new VideoTrackElementInfo();\n info.id = trackRef?.publication?.trackSid;\n return info;\n });\n\n const layoutOnChange = useCallback(\n (event: LayoutChangeEvent) => elementInfo.onLayout(event),\n [elementInfo]\n );\n const visibilityOnChange = useCallback(\n (isVisible: boolean) => elementInfo.onVisibility(isVisible),\n [elementInfo]\n );\n\n const videoTrack = trackRef?.publication.track;\n\n const shouldObserveVisibility = useMemo(() => {\n return (\n videoTrack instanceof RemoteVideoTrack && videoTrack.isAdaptiveStream\n );\n }, [videoTrack]);\n\n const [mediaStream, setMediaStream] = useState(videoTrack?.mediaStream);\n useEffect(() => {\n setMediaStream(videoTrack?.mediaStream);\n if (videoTrack instanceof LocalVideoTrack) {\n const onRestarted = (track: Track | null) => {\n setMediaStream(track?.mediaStream);\n };\n videoTrack.on(TrackEvent.Restarted, onRestarted);\n\n return () => {\n videoTrack.off(TrackEvent.Restarted, onRestarted);\n };\n } else {\n return () => {};\n }\n }, [videoTrack]);\n\n useEffect(() => {\n if (videoTrack instanceof RemoteVideoTrack && videoTrack.isAdaptiveStream) {\n videoTrack?.observeElementInfo(elementInfo);\n return () => {\n videoTrack?.stopObservingElementInfo(elementInfo);\n };\n } else {\n return () => {};\n }\n }, [videoTrack, elementInfo]);\n\n return (\n <View style={{ ...style, ...styles.container }} onLayout={layoutOnChange}>\n <ViewPortDetector\n onChange={visibilityOnChange}\n style={styles.videoTrack}\n disabled={!shouldObserveVisibility}\n propKey={videoTrack}\n >\n <RTCView\n style={styles.videoTrack}\n streamURL={mediaStream?.toURL() ?? ''}\n objectFit={objectFit}\n zOrder={zOrder}\n mirror={mirror}\n />\n </ViewPortDetector>\n </View>\n );\n};\n\nconst styles = StyleSheet.create({\n container: {},\n videoTrack: {\n flex: 1,\n width: '100%',\n },\n});\n\nclass VideoTrackElementInfo implements ElementInfo {\n element: object = {};\n something?: any;\n id?: string;\n _width = 0;\n _height = 0;\n _observing = false;\n visible: boolean = true;\n visibilityChangedAt: number | undefined;\n pictureInPicture = false;\n handleResize?: (() => void) | undefined;\n handleVisibilityChanged?: (() => void) | undefined;\n width = () => this._width;\n height = () => this._height;\n\n observe(): void {\n this._observing = true;\n }\n\n stopObserving(): void {\n this._observing = false;\n }\n\n onLayout(event: LayoutChangeEvent) {\n let { width, height } = event.nativeEvent.layout;\n this._width = width;\n this._height = height;\n\n if (this._observing) {\n this.handleResize?.();\n }\n }\n\n onVisibility(isVisible: boolean) {\n if (this.visible !== isVisible) {\n this.visible = isVisible;\n this.visibilityChangedAt = Date.now();\n if (this._observing) {\n this.handleVisibilityChanged?.();\n }\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["React","Platform","StyleSheet","View","LocalVideoTrack","TrackEvent","RTCView","RTCPIPView","forwardRef","useCallback","useEffect","useMemo","useState","RemoteVideoTrack","ViewPortDetector","VideoTrack","style","trackRef","objectFit","zOrder","mirror","iosPIP","ref","elementInfo","_trackRef$publication","info","VideoTrackElementInfo","id","publication","trackSid","layoutOnChange","event","onLayout","visibilityOnChange","isVisible","onVisibility","videoTrack","track","shouldObserveVisibility","isAdaptiveStream","mediaStream","setMediaStream","onRestarted","on","Restarted","off","observeElementInfo","stopObservingElementInfo","videoView","OS","createElement","styles","streamURL","toURL","container","onChange","disabled","propKey","create","flex","width","constructor","_defineProperty","_width","_height","observe","_observing","stopObserving","height","nativeEvent","layout","_this$handleResize","handleResize","call","visible","visibilityChangedAt","Date","now","_this$handleVisibilit","handleVisibilityChanged"],"sources":["VideoTrack.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport {\n type LayoutChangeEvent,\n Platform,\n StyleSheet,\n View,\n type ViewStyle,\n} from 'react-native';\nimport {\n type ElementInfo,\n LocalVideoTrack,\n Track,\n TrackEvent,\n} from 'livekit-client';\nimport {\n RTCView,\n RTCPIPView,\n type RTCIOSPIPOptions,\n} from '@livekit/react-native-webrtc';\nimport {\n Component,\n forwardRef,\n useCallback,\n useEffect,\n useMemo,\n useState,\n type ReactNode,\n} from 'react';\nimport { RemoteVideoTrack } from 'livekit-client';\nimport ViewPortDetector from './ViewPortDetector';\nimport type { TrackReference } from '@livekit/components-react';\n\n/**\n * Props for the VideoTrack component.\n * @public\n */\nexport type VideoTrackProps = {\n /**\n * The track reference to display. This should be a TrackReference object\n * or undefined if no track is available.\n */\n trackRef: TrackReference | undefined;\n /**\n * Custom React Native styles for the video container.\n */\n style?: ViewStyle;\n /**\n * Specifies how the video content should be resized to fit its container.\n * 'cover' (default): The video will fill the entire container, potentially cropping the video.\n * 'contain': The entire video will be visible within the container, potentially leaving empty space.\n */\n objectFit?: 'cover' | 'contain' | undefined;\n /**\n * Indicates whether the video should be mirrored during rendering.\n * This is commonly used for front-facing cameras.\n */\n mirror?: boolean;\n /**\n * Specifies the depth-stacking order of this video view in the stacking space of all video views.\n * A larger zOrder value generally causes the view to cover those with lower values.\n *\n * The support for zOrder is platform-dependent and/or\n * implementation-specific. Thus, specifying a value for zOrder is to be\n * thought of as giving a hint rather than as imposing a requirement. For\n * example, video renderers such as RTCView are commonly implemented using\n * OpenGL and OpenGL views may have different numbers of layers in their\n * stacking space. Android has three: a layer bellow the window (aka\n * default), a layer bellow the window again but above the previous layer\n * (aka media overlay), and above the window. Consequently, it is advisable\n * to limit the number of utilized layers in the stacking space to the\n * minimum sufficient for the desired display. For example, a video call\n * application usually needs a maximum of two zOrder values: 0 for the\n * remote video(s) which appear in the background, and 1 for the local\n * video(s) which appear above the remote video(s).\n */\n zOrder?: number;\n\n /**\n * Picture in picture options for this view. Disabled if not supplied.\n *\n * iOS only. Requires iOS 15.0 or above, and the PIP background mode capability.\n *\n * If `iosPIP.enabled` is true, startIOSPIP and stopIOSPIP can be used to manually\n * trigger the PIP mode. `iosPIP.startAutomatically` can be used to automatically\n * enter PIP when backgrounding the app.\n *\n * @example\n * ```tsx\n * import { startIOSPIP, stopIOSPIP } from '@livekit/react-native-webrtc';\n *\n * // Obtain a ref to the view\n * const videoRef = useRef<Component>(null);\n * const videoView = (\n * <VideoTrack\n * ref={videoRef}\n * iosPIP={{\n * enabled: true,\n * startAutomatically: true,\n * preferredSize: {\n * width: 800,\n * height: 800,\n * },\n * }}\n * ...\n * />\n * );\n *\n * // Start/stop manually\n * startIOSPIP(videoRef);\n * stopIOSPIP(videoRef);\n * ```\n *\n */\n iosPIP?: RTCIOSPIPOptions & {\n preferredSize: {\n width: number;\n height: number;\n };\n fallbackView?: ReactNode;\n };\n};\n\n/**\n * VideoTrack component for displaying video tracks in a React Native application.\n * It supports both local and remote video tracks from LiveKit, and handles adaptive streaming for remote tracks.\n *\n * @param props - See VideoTrackProps for details.\n * @returns A React component that renders the given video track.\n * @public\n */\nexport const VideoTrack = forwardRef<Component, VideoTrackProps>(\n (\n {\n style = {},\n trackRef,\n objectFit = 'cover',\n zOrder,\n mirror,\n iosPIP,\n }: VideoTrackProps,\n ref\n ) => {\n const [elementInfo] = useState(() => {\n let info = new VideoTrackElementInfo();\n info.id = trackRef?.publication?.trackSid;\n return info;\n });\n\n const layoutOnChange = useCallback(\n (event: LayoutChangeEvent) => elementInfo.onLayout(event),\n [elementInfo]\n );\n const visibilityOnChange = useCallback(\n (isVisible: boolean) => elementInfo.onVisibility(isVisible),\n [elementInfo]\n );\n\n const videoTrack = trackRef?.publication.track;\n\n const shouldObserveVisibility = useMemo(() => {\n return (\n videoTrack instanceof RemoteVideoTrack && videoTrack.isAdaptiveStream\n );\n }, [videoTrack]);\n\n const [mediaStream, setMediaStream] = useState(videoTrack?.mediaStream);\n useEffect(() => {\n setMediaStream(videoTrack?.mediaStream);\n if (videoTrack instanceof LocalVideoTrack) {\n const onRestarted = (track: Track | null) => {\n setMediaStream(track?.mediaStream);\n };\n videoTrack.on(TrackEvent.Restarted, onRestarted);\n\n return () => {\n videoTrack.off(TrackEvent.Restarted, onRestarted);\n };\n } else {\n return () => {};\n }\n }, [videoTrack]);\n\n useEffect(() => {\n if (\n videoTrack instanceof RemoteVideoTrack &&\n videoTrack.isAdaptiveStream\n ) {\n videoTrack?.observeElementInfo(elementInfo);\n return () => {\n videoTrack?.stopObservingElementInfo(elementInfo);\n };\n } else {\n return () => {};\n }\n }, [videoTrack, elementInfo]);\n\n let videoView;\n if (!iosPIP || Platform.OS !== 'ios') {\n videoView = (\n <RTCView\n style={styles.videoTrack}\n streamURL={mediaStream?.toURL() ?? ''}\n objectFit={objectFit}\n zOrder={zOrder}\n mirror={mirror}\n // @ts-ignore\n ref={ref}\n />\n );\n } else {\n videoView = (\n <RTCPIPView\n style={styles.videoTrack}\n streamURL={mediaStream?.toURL() ?? ''}\n objectFit={objectFit}\n zOrder={zOrder}\n mirror={mirror}\n // TODO: fix this up in react-native-webrtc side.\n // @ts-expect-error\n iosPIP={iosPIP}\n ref={ref}\n />\n );\n }\n return (\n <View style={{ ...style, ...styles.container }} onLayout={layoutOnChange}>\n <ViewPortDetector\n onChange={visibilityOnChange}\n style={styles.videoTrack}\n disabled={!shouldObserveVisibility}\n propKey={videoTrack}\n >\n {videoView}\n </ViewPortDetector>\n </View>\n );\n }\n);\n\nconst styles = StyleSheet.create({\n container: {},\n videoTrack: {\n flex: 1,\n width: '100%',\n },\n});\n\nclass VideoTrackElementInfo implements ElementInfo {\n element: object = {};\n something?: any;\n id?: string;\n _width = 0;\n _height = 0;\n _observing = false;\n visible: boolean = true;\n visibilityChangedAt: number | undefined;\n pictureInPicture = false;\n handleResize?: (() => void) | undefined;\n handleVisibilityChanged?: (() => void) | undefined;\n width = () => this._width;\n height = () => this._height;\n\n observe(): void {\n this._observing = true;\n }\n\n stopObserving(): void {\n this._observing = false;\n }\n\n onLayout(event: LayoutChangeEvent) {\n let { width, height } = event.nativeEvent.layout;\n this._width = width;\n this._height = height;\n\n if (this._observing) {\n this.handleResize?.();\n }\n }\n\n onVisibility(isVisible: boolean) {\n if (this.visible !== isVisible) {\n this.visible = isVisible;\n this.visibilityChangedAt = Date.now();\n if (this._observing) {\n this.handleVisibilityChanged?.();\n }\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -21,7 +21,7 @@ const multibandDefaults = {
|
|
|
21
21
|
* @param trackOrTrackReference
|
|
22
22
|
* @returns A number array containing the volume for each frequency band.
|
|
23
23
|
*/
|
|
24
|
-
export function useMultibandTrackVolume(trackOrTrackReference, options
|
|
24
|
+
export function useMultibandTrackVolume(trackOrTrackReference, options) {
|
|
25
25
|
var _trackOrTrackReferenc;
|
|
26
26
|
const track = trackOrTrackReference instanceof Track ? trackOrTrackReference : trackOrTrackReference === null || trackOrTrackReference === void 0 || (_trackOrTrackReferenc = trackOrTrackReference.publication) === null || _trackOrTrackReferenc === void 0 ? void 0 : _trackOrTrackReferenc.track;
|
|
27
27
|
const opts = useMemo(() => {
|
|
@@ -29,30 +29,35 @@ export function useMultibandTrackVolume(trackOrTrackReference, options = {}) {
|
|
|
29
29
|
...multibandDefaults,
|
|
30
30
|
...options
|
|
31
31
|
};
|
|
32
|
-
|
|
32
|
+
|
|
33
|
+
// disabled due to use of JSON.stringify, dependencies are reference equality
|
|
34
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
35
|
+
}, [JSON.stringify(options)]);
|
|
33
36
|
const mediaStreamTrack = track === null || track === void 0 ? void 0 : track.mediaStreamTrack;
|
|
37
|
+
const hasMediaStreamTrack = mediaStreamTrack != null;
|
|
38
|
+
const peerConnectionId = (mediaStreamTrack === null || mediaStreamTrack === void 0 ? void 0 : mediaStreamTrack.peerConnectionId) ?? -1;
|
|
39
|
+
const mediaStreamTrackId = mediaStreamTrack === null || mediaStreamTrack === void 0 ? void 0 : mediaStreamTrack.id;
|
|
34
40
|
let [magnitudes, setMagnitudes] = useState([]);
|
|
35
41
|
useEffect(() => {
|
|
36
42
|
let listener = Object();
|
|
37
43
|
let reactTag = null;
|
|
38
|
-
if (
|
|
39
|
-
reactTag = LiveKitModule.createMultibandVolumeProcessor(opts,
|
|
44
|
+
if (hasMediaStreamTrack) {
|
|
45
|
+
reactTag = LiveKitModule.createMultibandVolumeProcessor(opts, peerConnectionId, mediaStreamTrackId);
|
|
40
46
|
addListener(listener, 'LK_MULTIBAND_PROCESSED', event => {
|
|
41
47
|
if (event.magnitudes && reactTag && event.id === reactTag) {
|
|
42
|
-
console.log('event received: ', event.magnitudes[0]);
|
|
43
48
|
setMagnitudes(event.magnitudes);
|
|
44
49
|
}
|
|
45
50
|
});
|
|
46
51
|
}
|
|
47
52
|
return () => {
|
|
48
|
-
if (
|
|
53
|
+
if (hasMediaStreamTrack) {
|
|
49
54
|
removeListener(listener);
|
|
50
55
|
if (reactTag) {
|
|
51
|
-
LiveKitModule.deleteMultibandVolumeProcessor(reactTag,
|
|
56
|
+
LiveKitModule.deleteMultibandVolumeProcessor(reactTag, peerConnectionId, mediaStreamTrackId);
|
|
52
57
|
}
|
|
53
58
|
}
|
|
54
59
|
};
|
|
55
|
-
}, [
|
|
60
|
+
}, [hasMediaStreamTrack, peerConnectionId, mediaStreamTrackId, opts]);
|
|
56
61
|
return magnitudes;
|
|
57
62
|
}
|
|
58
63
|
//# sourceMappingURL=useMultibandTrackVolume.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["Track","useEffect","useMemo","useState","addListener","removeListener","LiveKitModule","multibandDefaults","bands","minFrequency","maxFrequency","updateInterval","useMultibandTrackVolume","trackOrTrackReference","options","_trackOrTrackReferenc","track","publication","opts","mediaStreamTrack","
|
|
1
|
+
{"version":3,"names":["Track","useEffect","useMemo","useState","addListener","removeListener","LiveKitModule","multibandDefaults","bands","minFrequency","maxFrequency","updateInterval","useMultibandTrackVolume","trackOrTrackReference","options","_trackOrTrackReferenc","track","publication","opts","JSON","stringify","mediaStreamTrack","hasMediaStreamTrack","peerConnectionId","mediaStreamTrackId","id","magnitudes","setMagnitudes","listener","Object","reactTag","createMultibandVolumeProcessor","event","deleteMultibandVolumeProcessor"],"sources":["useMultibandTrackVolume.ts"],"sourcesContent":["import { type TrackReferenceOrPlaceholder } from '@livekit/components-react';\nimport {\n Track,\n type LocalAudioTrack,\n type RemoteAudioTrack,\n} from 'livekit-client';\nimport { useEffect, useMemo, useState } from 'react';\nimport { addListener, removeListener } from '../events/EventEmitter';\nimport LiveKitModule from '../LKNativeModule';\n\n/**\n * Interface for configuring options for the useMultibandTrackVolume hook.\n * @alpha\n */\nexport interface MultiBandTrackVolumeOptions {\n /**\n * the number of bands to split the audio into\n */\n bands?: number;\n /**\n * cut off frequency on the lower end\n */\n minFrequency?: number;\n /**\n * cut off frequency on the higher end\n */\n maxFrequency?: number;\n /**\n * update should run every x ms\n */\n updateInterval?: number;\n}\n\nconst multibandDefaults = {\n bands: 5,\n minFrequency: 1000,\n maxFrequency: 8000,\n updateInterval: 40,\n} as const satisfies MultiBandTrackVolumeOptions;\n\n/**\n * A hook for tracking the volume of an audio track across multiple frequency bands.\n *\n * @param trackOrTrackReference\n * @returns A number array containing the volume for each frequency band.\n */\nexport function useMultibandTrackVolume(\n trackOrTrackReference?:\n | LocalAudioTrack\n | RemoteAudioTrack\n | TrackReferenceOrPlaceholder,\n options?: MultiBandTrackVolumeOptions\n) {\n const track =\n trackOrTrackReference instanceof Track\n ? trackOrTrackReference\n : <LocalAudioTrack | RemoteAudioTrack | undefined>(\n trackOrTrackReference?.publication?.track\n );\n const opts = useMemo(() => {\n return { ...multibandDefaults, ...options };\n\n // disabled due to use of JSON.stringify, dependencies are reference equality\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [JSON.stringify(options)]);\n const mediaStreamTrack = track?.mediaStreamTrack;\n const hasMediaStreamTrack = mediaStreamTrack != null;\n const peerConnectionId = mediaStreamTrack?.peerConnectionId ?? -1;\n const mediaStreamTrackId = mediaStreamTrack?.id;\n\n let [magnitudes, setMagnitudes] = useState<number[]>([]);\n useEffect(() => {\n let listener = Object();\n let reactTag: string | null = null;\n if (hasMediaStreamTrack) {\n reactTag = LiveKitModule.createMultibandVolumeProcessor(\n opts,\n peerConnectionId,\n mediaStreamTrackId\n );\n addListener(listener, 'LK_MULTIBAND_PROCESSED', (event: any) => {\n if (event.magnitudes && reactTag && event.id === reactTag) {\n setMagnitudes(event.magnitudes);\n }\n });\n }\n return () => {\n if (hasMediaStreamTrack) {\n removeListener(listener);\n if (reactTag) {\n LiveKitModule.deleteMultibandVolumeProcessor(\n reactTag,\n peerConnectionId,\n mediaStreamTrackId\n );\n }\n }\n };\n }, [hasMediaStreamTrack, peerConnectionId, mediaStreamTrackId, opts]);\n\n return magnitudes;\n}\n"],"mappings":"AACA,SACEA,KAAK,QAGA,gBAAgB;AACvB,SAASC,SAAS,EAAEC,OAAO,EAAEC,QAAQ,QAAQ,OAAO;AACpD,SAASC,WAAW,EAAEC,cAAc,QAAQ,wBAAwB;AACpE,OAAOC,aAAa,MAAM,mBAAmB;;AAE7C;AACA;AACA;AACA;;AAoBA,MAAMC,iBAAiB,GAAG;EACxBC,KAAK,EAAE,CAAC;EACRC,YAAY,EAAE,IAAI;EAClBC,YAAY,EAAE,IAAI;EAClBC,cAAc,EAAE;AAClB,CAAgD;;AAEhD;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,uBAAuBA,CACrCC,qBAG+B,EAC/BC,OAAqC,EACrC;EAAA,IAAAC,qBAAA;EACA,MAAMC,KAAK,GACTH,qBAAqB,YAAYb,KAAK,GAClCa,qBAAqB,GAEnBA,qBAAqB,aAArBA,qBAAqB,gBAAAE,qBAAA,GAArBF,qBAAqB,CAAEI,WAAW,cAAAF,qBAAA,uBAAlCA,qBAAA,CAAoCC,KACrC;EACP,MAAME,IAAI,GAAGhB,OAAO,CAAC,MAAM;IACzB,OAAO;MAAE,GAAGK,iBAAiB;MAAE,GAAGO;IAAQ,CAAC;;IAE3C;IACA;EACF,CAAC,EAAE,CAACK,IAAI,CAACC,SAAS,CAACN,OAAO,CAAC,CAAC,CAAC;EAC7B,MAAMO,gBAAgB,GAAGL,KAAK,aAALA,KAAK,uBAALA,KAAK,CAAEK,gBAAgB;EAChD,MAAMC,mBAAmB,GAAGD,gBAAgB,IAAI,IAAI;EACpD,MAAME,gBAAgB,GAAG,CAAAF,gBAAgB,aAAhBA,gBAAgB,uBAAhBA,gBAAgB,CAAEE,gBAAgB,KAAI,CAAC,CAAC;EACjE,MAAMC,kBAAkB,GAAGH,gBAAgB,aAAhBA,gBAAgB,uBAAhBA,gBAAgB,CAAEI,EAAE;EAE/C,IAAI,CAACC,UAAU,EAAEC,aAAa,CAAC,GAAGxB,QAAQ,CAAW,EAAE,CAAC;EACxDF,SAAS,CAAC,MAAM;IACd,IAAI2B,QAAQ,GAAGC,MAAM,CAAC,CAAC;IACvB,IAAIC,QAAuB,GAAG,IAAI;IAClC,IAAIR,mBAAmB,EAAE;MACvBQ,QAAQ,GAAGxB,aAAa,CAACyB,8BAA8B,CACrDb,IAAI,EACJK,gBAAgB,EAChBC,kBACF,CAAC;MACDpB,WAAW,CAACwB,QAAQ,EAAE,wBAAwB,EAAGI,KAAU,IAAK;QAC9D,IAAIA,KAAK,CAACN,UAAU,IAAII,QAAQ,IAAIE,KAAK,CAACP,EAAE,KAAKK,QAAQ,EAAE;UACzDH,aAAa,CAACK,KAAK,CAACN,UAAU,CAAC;QACjC;MACF,CAAC,CAAC;IACJ;IACA,OAAO,MAAM;MACX,IAAIJ,mBAAmB,EAAE;QACvBjB,cAAc,CAACuB,QAAQ,CAAC;QACxB,IAAIE,QAAQ,EAAE;UACZxB,aAAa,CAAC2B,8BAA8B,CAC1CH,QAAQ,EACRP,gBAAgB,EAChBC,kBACF,CAAC;QACH;MACF;IACF,CAAC;EACH,CAAC,EAAE,CAACF,mBAAmB,EAAEC,gBAAgB,EAAEC,kBAAkB,EAAEN,IAAI,CAAC,CAAC;EAErE,OAAOQ,UAAU;AACnB","ignoreList":[]}
|
|
@@ -13,12 +13,15 @@ export function useTrackVolume(trackOrTrackReference) {
|
|
|
13
13
|
var _trackOrTrackReferenc;
|
|
14
14
|
const track = trackOrTrackReference instanceof Track ? trackOrTrackReference : trackOrTrackReference === null || trackOrTrackReference === void 0 || (_trackOrTrackReferenc = trackOrTrackReference.publication) === null || _trackOrTrackReferenc === void 0 ? void 0 : _trackOrTrackReferenc.track;
|
|
15
15
|
const mediaStreamTrack = track === null || track === void 0 ? void 0 : track.mediaStreamTrack;
|
|
16
|
+
const hasMediaStreamTrack = mediaStreamTrack != null;
|
|
17
|
+
const peerConnectionId = mediaStreamTrack.peerConnectionId ?? -1;
|
|
18
|
+
const mediaStreamTrackId = mediaStreamTrack.id;
|
|
16
19
|
let [volume, setVolume] = useState(0.0);
|
|
17
20
|
useEffect(() => {
|
|
18
21
|
let listener = Object();
|
|
19
22
|
let reactTag = null;
|
|
20
|
-
if (
|
|
21
|
-
reactTag = LiveKitModule.createVolumeProcessor(
|
|
23
|
+
if (hasMediaStreamTrack) {
|
|
24
|
+
reactTag = LiveKitModule.createVolumeProcessor(peerConnectionId, mediaStreamTrackId);
|
|
22
25
|
addListener(listener, 'LK_VOLUME_PROCESSED', event => {
|
|
23
26
|
if (event.volume && reactTag && event.id === reactTag) {
|
|
24
27
|
setVolume(event.volume);
|
|
@@ -26,14 +29,14 @@ export function useTrackVolume(trackOrTrackReference) {
|
|
|
26
29
|
});
|
|
27
30
|
}
|
|
28
31
|
return () => {
|
|
29
|
-
if (
|
|
32
|
+
if (hasMediaStreamTrack) {
|
|
30
33
|
removeListener(listener);
|
|
31
34
|
if (reactTag) {
|
|
32
|
-
LiveKitModule.deleteVolumeProcessor(reactTag,
|
|
35
|
+
LiveKitModule.deleteVolumeProcessor(reactTag, peerConnectionId, mediaStreamTrackId);
|
|
33
36
|
}
|
|
34
37
|
}
|
|
35
38
|
};
|
|
36
|
-
}, [
|
|
39
|
+
}, [hasMediaStreamTrack, peerConnectionId, mediaStreamTrackId]);
|
|
37
40
|
return volume;
|
|
38
41
|
}
|
|
39
42
|
//# sourceMappingURL=useTrackVolume.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["Track","useEffect","useState","addListener","removeListener","LiveKitModule","useTrackVolume","trackOrTrackReference","_trackOrTrackReferenc","track","publication","mediaStreamTrack","volume","setVolume","listener","Object","reactTag","createVolumeProcessor","
|
|
1
|
+
{"version":3,"names":["Track","useEffect","useState","addListener","removeListener","LiveKitModule","useTrackVolume","trackOrTrackReference","_trackOrTrackReferenc","track","publication","mediaStreamTrack","hasMediaStreamTrack","peerConnectionId","mediaStreamTrackId","id","volume","setVolume","listener","Object","reactTag","createVolumeProcessor","event","deleteVolumeProcessor"],"sources":["useTrackVolume.ts"],"sourcesContent":["import { type TrackReferenceOrPlaceholder } from '@livekit/components-react';\nimport {\n Track,\n type LocalAudioTrack,\n type RemoteAudioTrack,\n} from 'livekit-client';\nimport { useEffect, useState } from 'react';\nimport { addListener, removeListener } from '../events/EventEmitter';\nimport LiveKitModule from '../LKNativeModule';\n\n/**\n * A hook for tracking the volume of an audio track.\n *\n * @param trackOrTrackReference\n * @returns A number between 0-1 representing the volume.\n */\nexport function useTrackVolume(\n trackOrTrackReference?:\n | LocalAudioTrack\n | RemoteAudioTrack\n | TrackReferenceOrPlaceholder\n) {\n const track =\n trackOrTrackReference instanceof Track\n ? trackOrTrackReference\n : <LocalAudioTrack | RemoteAudioTrack | undefined>(\n trackOrTrackReference?.publication?.track\n );\n\n const mediaStreamTrack = track?.mediaStreamTrack;\n const hasMediaStreamTrack = mediaStreamTrack != null;\n const peerConnectionId = mediaStreamTrack.peerConnectionId ?? -1;\n const mediaStreamTrackId = mediaStreamTrack.id;\n\n let [volume, setVolume] = useState(0.0);\n useEffect(() => {\n let listener = Object();\n let reactTag: string | null = null;\n if (hasMediaStreamTrack) {\n reactTag = LiveKitModule.createVolumeProcessor(\n peerConnectionId,\n mediaStreamTrackId\n );\n addListener(listener, 'LK_VOLUME_PROCESSED', (event: any) => {\n if (event.volume && reactTag && event.id === reactTag) {\n setVolume(event.volume);\n }\n });\n }\n return () => {\n if (hasMediaStreamTrack) {\n removeListener(listener);\n if (reactTag) {\n LiveKitModule.deleteVolumeProcessor(\n reactTag,\n peerConnectionId,\n mediaStreamTrackId\n );\n }\n }\n };\n }, [hasMediaStreamTrack, peerConnectionId, mediaStreamTrackId]);\n\n return volume;\n}\n"],"mappings":"AACA,SACEA,KAAK,QAGA,gBAAgB;AACvB,SAASC,SAAS,EAAEC,QAAQ,QAAQ,OAAO;AAC3C,SAASC,WAAW,EAAEC,cAAc,QAAQ,wBAAwB;AACpE,OAAOC,aAAa,MAAM,mBAAmB;;AAE7C;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,cAAcA,CAC5BC,qBAG+B,EAC/B;EAAA,IAAAC,qBAAA;EACA,MAAMC,KAAK,GACTF,qBAAqB,YAAYP,KAAK,GAClCO,qBAAqB,GAEnBA,qBAAqB,aAArBA,qBAAqB,gBAAAC,qBAAA,GAArBD,qBAAqB,CAAEG,WAAW,cAAAF,qBAAA,uBAAlCA,qBAAA,CAAoCC,KACrC;EAEP,MAAME,gBAAgB,GAAGF,KAAK,aAALA,KAAK,uBAALA,KAAK,CAAEE,gBAAgB;EAChD,MAAMC,mBAAmB,GAAGD,gBAAgB,IAAI,IAAI;EACpD,MAAME,gBAAgB,GAAGF,gBAAgB,CAACE,gBAAgB,IAAI,CAAC,CAAC;EAChE,MAAMC,kBAAkB,GAAGH,gBAAgB,CAACI,EAAE;EAE9C,IAAI,CAACC,MAAM,EAAEC,SAAS,CAAC,GAAGf,QAAQ,CAAC,GAAG,CAAC;EACvCD,SAAS,CAAC,MAAM;IACd,IAAIiB,QAAQ,GAAGC,MAAM,CAAC,CAAC;IACvB,IAAIC,QAAuB,GAAG,IAAI;IAClC,IAAIR,mBAAmB,EAAE;MACvBQ,QAAQ,GAAGf,aAAa,CAACgB,qBAAqB,CAC5CR,gBAAgB,EAChBC,kBACF,CAAC;MACDX,WAAW,CAACe,QAAQ,EAAE,qBAAqB,EAAGI,KAAU,IAAK;QAC3D,IAAIA,KAAK,CAACN,MAAM,IAAII,QAAQ,IAAIE,KAAK,CAACP,EAAE,KAAKK,QAAQ,EAAE;UACrDH,SAAS,CAACK,KAAK,CAACN,MAAM,CAAC;QACzB;MACF,CAAC,CAAC;IACJ;IACA,OAAO,MAAM;MACX,IAAIJ,mBAAmB,EAAE;QACvBR,cAAc,CAACc,QAAQ,CAAC;QACxB,IAAIE,QAAQ,EAAE;UACZf,aAAa,CAACkB,qBAAqB,CACjCH,QAAQ,EACRP,gBAAgB,EAChBC,kBACF,CAAC;QACH;MACF;IACF,CAAC;EACH,CAAC,EAAE,CAACF,mBAAmB,EAAEC,gBAAgB,EAAEC,kBAAkB,CAAC,CAAC;EAE/D,OAAOE,MAAM;AACf","ignoreList":[]}
|
|
@@ -1,20 +1,2 @@
|
|
|
1
1
|
export const __esModule: boolean;
|
|
2
|
-
|
|
3
|
-
* Props for the VideoTrack component.
|
|
4
|
-
* @public
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* VideoTrack component for displaying video tracks in a React Native application.
|
|
8
|
-
* It supports both local and remote video tracks from LiveKit, and handles adaptive streaming for remote tracks.
|
|
9
|
-
*
|
|
10
|
-
* @param props - See VideoTrackProps for details.
|
|
11
|
-
* @returns A React component that renders the given video track.
|
|
12
|
-
* @public
|
|
13
|
-
*/
|
|
14
|
-
export function VideoTrack({ style, trackRef, objectFit, zOrder, mirror }: {
|
|
15
|
-
style?: {} | undefined;
|
|
16
|
-
trackRef: any;
|
|
17
|
-
objectFit?: string | undefined;
|
|
18
|
-
zOrder: any;
|
|
19
|
-
mirror: any;
|
|
20
|
-
}): any;
|
|
2
|
+
export const VideoTrack: any;
|
|
@@ -5,4 +5,4 @@ export const __esModule: boolean;
|
|
|
5
5
|
* @param trackOrTrackReference
|
|
6
6
|
* @returns A number array containing the volume for each frequency band.
|
|
7
7
|
*/
|
|
8
|
-
export function useMultibandTrackVolume(trackOrTrackReference: any, options
|
|
8
|
+
export function useMultibandTrackVolume(trackOrTrackReference: any, options: any): any;
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Props for the VideoTrack component.
|
|
3
|
+
* @public
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* VideoTrack component for displaying video tracks in a React Native application.
|
|
7
|
+
* It supports both local and remote video tracks from LiveKit, and handles adaptive streaming for remote tracks.
|
|
8
|
+
*
|
|
9
|
+
* @param props - See VideoTrackProps for details.
|
|
10
|
+
* @returns A React component that renders the given video track.
|
|
11
|
+
* @public
|
|
12
|
+
*/
|
|
13
|
+
export const VideoTrack: React.ForwardRefExoticComponent<React.RefAttributes<any>>;
|
|
9
14
|
import * as React from 'react';
|
|
@@ -4,4 +4,4 @@
|
|
|
4
4
|
* @param trackOrTrackReference
|
|
5
5
|
* @returns A number array containing the volume for each frequency band.
|
|
6
6
|
*/
|
|
7
|
-
export function useMultibandTrackVolume(trackOrTrackReference: any, options
|
|
7
|
+
export function useMultibandTrackVolume(trackOrTrackReference: any, options: any): never[];
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { type ViewStyle } from 'react-native';
|
|
3
|
+
import { type RTCIOSPIPOptions } from '@livekit/react-native-webrtc';
|
|
4
|
+
import { type ReactNode } from 'react';
|
|
3
5
|
import type { TrackReference } from '@livekit/components-react';
|
|
4
6
|
/**
|
|
5
7
|
* Props for the VideoTrack component.
|
|
@@ -45,6 +47,49 @@ export type VideoTrackProps = {
|
|
|
45
47
|
* video(s) which appear above the remote video(s).
|
|
46
48
|
*/
|
|
47
49
|
zOrder?: number;
|
|
50
|
+
/**
|
|
51
|
+
* Picture in picture options for this view. Disabled if not supplied.
|
|
52
|
+
*
|
|
53
|
+
* iOS only. Requires iOS 15.0 or above, and the PIP background mode capability.
|
|
54
|
+
*
|
|
55
|
+
* If `iosPIP.enabled` is true, startIOSPIP and stopIOSPIP can be used to manually
|
|
56
|
+
* trigger the PIP mode. `iosPIP.startAutomatically` can be used to automatically
|
|
57
|
+
* enter PIP when backgrounding the app.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```tsx
|
|
61
|
+
* import { startIOSPIP, stopIOSPIP } from '@livekit/react-native-webrtc';
|
|
62
|
+
*
|
|
63
|
+
* // Obtain a ref to the view
|
|
64
|
+
* const videoRef = useRef<Component>(null);
|
|
65
|
+
* const videoView = (
|
|
66
|
+
* <VideoTrack
|
|
67
|
+
* ref={videoRef}
|
|
68
|
+
* iosPIP={{
|
|
69
|
+
* enabled: true,
|
|
70
|
+
* startAutomatically: true,
|
|
71
|
+
* preferredSize: {
|
|
72
|
+
* width: 800,
|
|
73
|
+
* height: 800,
|
|
74
|
+
* },
|
|
75
|
+
* }}
|
|
76
|
+
* ...
|
|
77
|
+
* />
|
|
78
|
+
* );
|
|
79
|
+
*
|
|
80
|
+
* // Start/stop manually
|
|
81
|
+
* startIOSPIP(videoRef);
|
|
82
|
+
* stopIOSPIP(videoRef);
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
85
|
+
*/
|
|
86
|
+
iosPIP?: RTCIOSPIPOptions & {
|
|
87
|
+
preferredSize: {
|
|
88
|
+
width: number;
|
|
89
|
+
height: number;
|
|
90
|
+
};
|
|
91
|
+
fallbackView?: ReactNode;
|
|
92
|
+
};
|
|
48
93
|
};
|
|
49
94
|
/**
|
|
50
95
|
* VideoTrack component for displaying video tracks in a React Native application.
|
|
@@ -54,4 +99,4 @@ export type VideoTrackProps = {
|
|
|
54
99
|
* @returns A React component that renders the given video track.
|
|
55
100
|
* @public
|
|
56
101
|
*/
|
|
57
|
-
export declare const VideoTrack:
|
|
102
|
+
export declare const VideoTrack: React.ForwardRefExoticComponent<VideoTrackProps & React.RefAttributes<React.Component<{}, {}, any>>>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livekit/react-native",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"description": "LiveKit for React Native",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/module/index",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"eslint-plugin-prettier": "^4.2.1",
|
|
73
73
|
"husky": "^7.0.4",
|
|
74
74
|
"jest": "^29.6.3",
|
|
75
|
-
"livekit-client": "^2.9.
|
|
75
|
+
"livekit-client": "^2.9.8",
|
|
76
76
|
"pod-install": "^0.2.2",
|
|
77
77
|
"prettier": "2.8.8",
|
|
78
78
|
"react": "18.2.0",
|
|
@@ -2,6 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
type LayoutChangeEvent,
|
|
5
|
+
Platform,
|
|
5
6
|
StyleSheet,
|
|
6
7
|
View,
|
|
7
8
|
type ViewStyle,
|
|
@@ -12,8 +13,20 @@ import {
|
|
|
12
13
|
Track,
|
|
13
14
|
TrackEvent,
|
|
14
15
|
} from 'livekit-client';
|
|
15
|
-
import {
|
|
16
|
-
|
|
16
|
+
import {
|
|
17
|
+
RTCView,
|
|
18
|
+
RTCPIPView,
|
|
19
|
+
type RTCIOSPIPOptions,
|
|
20
|
+
} from '@livekit/react-native-webrtc';
|
|
21
|
+
import {
|
|
22
|
+
Component,
|
|
23
|
+
forwardRef,
|
|
24
|
+
useCallback,
|
|
25
|
+
useEffect,
|
|
26
|
+
useMemo,
|
|
27
|
+
useState,
|
|
28
|
+
type ReactNode,
|
|
29
|
+
} from 'react';
|
|
17
30
|
import { RemoteVideoTrack } from 'livekit-client';
|
|
18
31
|
import ViewPortDetector from './ViewPortDetector';
|
|
19
32
|
import type { TrackReference } from '@livekit/components-react';
|
|
@@ -62,6 +75,50 @@ export type VideoTrackProps = {
|
|
|
62
75
|
* video(s) which appear above the remote video(s).
|
|
63
76
|
*/
|
|
64
77
|
zOrder?: number;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Picture in picture options for this view. Disabled if not supplied.
|
|
81
|
+
*
|
|
82
|
+
* iOS only. Requires iOS 15.0 or above, and the PIP background mode capability.
|
|
83
|
+
*
|
|
84
|
+
* If `iosPIP.enabled` is true, startIOSPIP and stopIOSPIP can be used to manually
|
|
85
|
+
* trigger the PIP mode. `iosPIP.startAutomatically` can be used to automatically
|
|
86
|
+
* enter PIP when backgrounding the app.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```tsx
|
|
90
|
+
* import { startIOSPIP, stopIOSPIP } from '@livekit/react-native-webrtc';
|
|
91
|
+
*
|
|
92
|
+
* // Obtain a ref to the view
|
|
93
|
+
* const videoRef = useRef<Component>(null);
|
|
94
|
+
* const videoView = (
|
|
95
|
+
* <VideoTrack
|
|
96
|
+
* ref={videoRef}
|
|
97
|
+
* iosPIP={{
|
|
98
|
+
* enabled: true,
|
|
99
|
+
* startAutomatically: true,
|
|
100
|
+
* preferredSize: {
|
|
101
|
+
* width: 800,
|
|
102
|
+
* height: 800,
|
|
103
|
+
* },
|
|
104
|
+
* }}
|
|
105
|
+
* ...
|
|
106
|
+
* />
|
|
107
|
+
* );
|
|
108
|
+
*
|
|
109
|
+
* // Start/stop manually
|
|
110
|
+
* startIOSPIP(videoRef);
|
|
111
|
+
* stopIOSPIP(videoRef);
|
|
112
|
+
* ```
|
|
113
|
+
*
|
|
114
|
+
*/
|
|
115
|
+
iosPIP?: RTCIOSPIPOptions & {
|
|
116
|
+
preferredSize: {
|
|
117
|
+
width: number;
|
|
118
|
+
height: number;
|
|
119
|
+
};
|
|
120
|
+
fallbackView?: ReactNode;
|
|
121
|
+
};
|
|
65
122
|
};
|
|
66
123
|
|
|
67
124
|
/**
|
|
@@ -72,83 +129,114 @@ export type VideoTrackProps = {
|
|
|
72
129
|
* @returns A React component that renders the given video track.
|
|
73
130
|
* @public
|
|
74
131
|
*/
|
|
75
|
-
export const VideoTrack = (
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const videoTrack = trackRef?.publication.track;
|
|
98
|
-
|
|
99
|
-
const shouldObserveVisibility = useMemo(() => {
|
|
100
|
-
return (
|
|
101
|
-
videoTrack instanceof RemoteVideoTrack && videoTrack.isAdaptiveStream
|
|
132
|
+
export const VideoTrack = forwardRef<Component, VideoTrackProps>(
|
|
133
|
+
(
|
|
134
|
+
{
|
|
135
|
+
style = {},
|
|
136
|
+
trackRef,
|
|
137
|
+
objectFit = 'cover',
|
|
138
|
+
zOrder,
|
|
139
|
+
mirror,
|
|
140
|
+
iosPIP,
|
|
141
|
+
}: VideoTrackProps,
|
|
142
|
+
ref
|
|
143
|
+
) => {
|
|
144
|
+
const [elementInfo] = useState(() => {
|
|
145
|
+
let info = new VideoTrackElementInfo();
|
|
146
|
+
info.id = trackRef?.publication?.trackSid;
|
|
147
|
+
return info;
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const layoutOnChange = useCallback(
|
|
151
|
+
(event: LayoutChangeEvent) => elementInfo.onLayout(event),
|
|
152
|
+
[elementInfo]
|
|
102
153
|
);
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
154
|
+
const visibilityOnChange = useCallback(
|
|
155
|
+
(isVisible: boolean) => elementInfo.onVisibility(isVisible),
|
|
156
|
+
[elementInfo]
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
const videoTrack = trackRef?.publication.track;
|
|
160
|
+
|
|
161
|
+
const shouldObserveVisibility = useMemo(() => {
|
|
162
|
+
return (
|
|
163
|
+
videoTrack instanceof RemoteVideoTrack && videoTrack.isAdaptiveStream
|
|
164
|
+
);
|
|
165
|
+
}, [videoTrack]);
|
|
166
|
+
|
|
167
|
+
const [mediaStream, setMediaStream] = useState(videoTrack?.mediaStream);
|
|
168
|
+
useEffect(() => {
|
|
169
|
+
setMediaStream(videoTrack?.mediaStream);
|
|
170
|
+
if (videoTrack instanceof LocalVideoTrack) {
|
|
171
|
+
const onRestarted = (track: Track | null) => {
|
|
172
|
+
setMediaStream(track?.mediaStream);
|
|
173
|
+
};
|
|
174
|
+
videoTrack.on(TrackEvent.Restarted, onRestarted);
|
|
175
|
+
|
|
176
|
+
return () => {
|
|
177
|
+
videoTrack.off(TrackEvent.Restarted, onRestarted);
|
|
178
|
+
};
|
|
179
|
+
} else {
|
|
180
|
+
return () => {};
|
|
181
|
+
}
|
|
182
|
+
}, [videoTrack]);
|
|
183
|
+
|
|
184
|
+
useEffect(() => {
|
|
185
|
+
if (
|
|
186
|
+
videoTrack instanceof RemoteVideoTrack &&
|
|
187
|
+
videoTrack.isAdaptiveStream
|
|
188
|
+
) {
|
|
189
|
+
videoTrack?.observeElementInfo(elementInfo);
|
|
190
|
+
return () => {
|
|
191
|
+
videoTrack?.stopObservingElementInfo(elementInfo);
|
|
192
|
+
};
|
|
193
|
+
} else {
|
|
194
|
+
return () => {};
|
|
195
|
+
}
|
|
196
|
+
}, [videoTrack, elementInfo]);
|
|
197
|
+
|
|
198
|
+
let videoView;
|
|
199
|
+
if (!iosPIP || Platform.OS !== 'ios') {
|
|
200
|
+
videoView = (
|
|
141
201
|
<RTCView
|
|
142
202
|
style={styles.videoTrack}
|
|
143
203
|
streamURL={mediaStream?.toURL() ?? ''}
|
|
144
204
|
objectFit={objectFit}
|
|
145
205
|
zOrder={zOrder}
|
|
146
206
|
mirror={mirror}
|
|
207
|
+
// @ts-ignore
|
|
208
|
+
ref={ref}
|
|
147
209
|
/>
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
210
|
+
);
|
|
211
|
+
} else {
|
|
212
|
+
videoView = (
|
|
213
|
+
<RTCPIPView
|
|
214
|
+
style={styles.videoTrack}
|
|
215
|
+
streamURL={mediaStream?.toURL() ?? ''}
|
|
216
|
+
objectFit={objectFit}
|
|
217
|
+
zOrder={zOrder}
|
|
218
|
+
mirror={mirror}
|
|
219
|
+
// TODO: fix this up in react-native-webrtc side.
|
|
220
|
+
// @ts-expect-error
|
|
221
|
+
iosPIP={iosPIP}
|
|
222
|
+
ref={ref}
|
|
223
|
+
/>
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
return (
|
|
227
|
+
<View style={{ ...style, ...styles.container }} onLayout={layoutOnChange}>
|
|
228
|
+
<ViewPortDetector
|
|
229
|
+
onChange={visibilityOnChange}
|
|
230
|
+
style={styles.videoTrack}
|
|
231
|
+
disabled={!shouldObserveVisibility}
|
|
232
|
+
propKey={videoTrack}
|
|
233
|
+
>
|
|
234
|
+
{videoView}
|
|
235
|
+
</ViewPortDetector>
|
|
236
|
+
</View>
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
);
|
|
152
240
|
|
|
153
241
|
const styles = StyleSheet.create({
|
|
154
242
|
container: {},
|
|
@@ -49,7 +49,7 @@ export function useMultibandTrackVolume(
|
|
|
49
49
|
| LocalAudioTrack
|
|
50
50
|
| RemoteAudioTrack
|
|
51
51
|
| TrackReferenceOrPlaceholder,
|
|
52
|
-
options
|
|
52
|
+
options?: MultiBandTrackVolumeOptions
|
|
53
53
|
) {
|
|
54
54
|
const track =
|
|
55
55
|
trackOrTrackReference instanceof Track
|
|
@@ -59,39 +59,44 @@ export function useMultibandTrackVolume(
|
|
|
59
59
|
);
|
|
60
60
|
const opts = useMemo(() => {
|
|
61
61
|
return { ...multibandDefaults, ...options };
|
|
62
|
-
|
|
62
|
+
|
|
63
|
+
// disabled due to use of JSON.stringify, dependencies are reference equality
|
|
64
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
65
|
+
}, [JSON.stringify(options)]);
|
|
63
66
|
const mediaStreamTrack = track?.mediaStreamTrack;
|
|
67
|
+
const hasMediaStreamTrack = mediaStreamTrack != null;
|
|
68
|
+
const peerConnectionId = mediaStreamTrack?.peerConnectionId ?? -1;
|
|
69
|
+
const mediaStreamTrackId = mediaStreamTrack?.id;
|
|
64
70
|
|
|
65
71
|
let [magnitudes, setMagnitudes] = useState<number[]>([]);
|
|
66
72
|
useEffect(() => {
|
|
67
73
|
let listener = Object();
|
|
68
74
|
let reactTag: string | null = null;
|
|
69
|
-
if (
|
|
75
|
+
if (hasMediaStreamTrack) {
|
|
70
76
|
reactTag = LiveKitModule.createMultibandVolumeProcessor(
|
|
71
77
|
opts,
|
|
72
|
-
|
|
73
|
-
|
|
78
|
+
peerConnectionId,
|
|
79
|
+
mediaStreamTrackId
|
|
74
80
|
);
|
|
75
81
|
addListener(listener, 'LK_MULTIBAND_PROCESSED', (event: any) => {
|
|
76
82
|
if (event.magnitudes && reactTag && event.id === reactTag) {
|
|
77
|
-
console.log('event received: ', event.magnitudes[0]);
|
|
78
83
|
setMagnitudes(event.magnitudes);
|
|
79
84
|
}
|
|
80
85
|
});
|
|
81
86
|
}
|
|
82
87
|
return () => {
|
|
83
|
-
if (
|
|
88
|
+
if (hasMediaStreamTrack) {
|
|
84
89
|
removeListener(listener);
|
|
85
90
|
if (reactTag) {
|
|
86
91
|
LiveKitModule.deleteMultibandVolumeProcessor(
|
|
87
92
|
reactTag,
|
|
88
|
-
|
|
89
|
-
|
|
93
|
+
peerConnectionId,
|
|
94
|
+
mediaStreamTrackId
|
|
90
95
|
);
|
|
91
96
|
}
|
|
92
97
|
}
|
|
93
98
|
};
|
|
94
|
-
}, [
|
|
99
|
+
}, [hasMediaStreamTrack, peerConnectionId, mediaStreamTrackId, opts]);
|
|
95
100
|
|
|
96
101
|
return magnitudes;
|
|
97
102
|
}
|
|
@@ -28,15 +28,18 @@ export function useTrackVolume(
|
|
|
28
28
|
);
|
|
29
29
|
|
|
30
30
|
const mediaStreamTrack = track?.mediaStreamTrack;
|
|
31
|
+
const hasMediaStreamTrack = mediaStreamTrack != null;
|
|
32
|
+
const peerConnectionId = mediaStreamTrack.peerConnectionId ?? -1;
|
|
33
|
+
const mediaStreamTrackId = mediaStreamTrack.id;
|
|
31
34
|
|
|
32
35
|
let [volume, setVolume] = useState(0.0);
|
|
33
36
|
useEffect(() => {
|
|
34
37
|
let listener = Object();
|
|
35
38
|
let reactTag: string | null = null;
|
|
36
|
-
if (
|
|
39
|
+
if (hasMediaStreamTrack) {
|
|
37
40
|
reactTag = LiveKitModule.createVolumeProcessor(
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
peerConnectionId,
|
|
42
|
+
mediaStreamTrackId
|
|
40
43
|
);
|
|
41
44
|
addListener(listener, 'LK_VOLUME_PROCESSED', (event: any) => {
|
|
42
45
|
if (event.volume && reactTag && event.id === reactTag) {
|
|
@@ -45,18 +48,18 @@ export function useTrackVolume(
|
|
|
45
48
|
});
|
|
46
49
|
}
|
|
47
50
|
return () => {
|
|
48
|
-
if (
|
|
51
|
+
if (hasMediaStreamTrack) {
|
|
49
52
|
removeListener(listener);
|
|
50
53
|
if (reactTag) {
|
|
51
54
|
LiveKitModule.deleteVolumeProcessor(
|
|
52
55
|
reactTag,
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
peerConnectionId,
|
|
57
|
+
mediaStreamTrackId
|
|
55
58
|
);
|
|
56
59
|
}
|
|
57
60
|
}
|
|
58
61
|
};
|
|
59
|
-
}, [
|
|
62
|
+
}, [hasMediaStreamTrack, peerConnectionId, mediaStreamTrackId]);
|
|
60
63
|
|
|
61
64
|
return volume;
|
|
62
65
|
}
|