@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 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.filterNot { entry -> entry.value == sink }
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
- }, /*#__PURE__*/React.createElement(_reactNativeWebrtc.RTCView, {
88
- style: styles.videoTrack,
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
- }, [options]);
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 (mediaStreamTrack) {
45
- reactTag = _LKNativeModule.default.createMultibandVolumeProcessor(opts, mediaStreamTrack._peerConnectionId ?? -1, mediaStreamTrack.id);
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 (mediaStreamTrack) {
59
+ if (hasMediaStreamTrack) {
55
60
  (0, _EventEmitter.removeListener)(listener);
56
61
  if (reactTag) {
57
- _LKNativeModule.default.deleteMultibandVolumeProcessor(reactTag, mediaStreamTrack._peerConnectionId ?? -1, mediaStreamTrack.id);
62
+ _LKNativeModule.default.deleteMultibandVolumeProcessor(reactTag, peerConnectionId, mediaStreamTrackId);
58
63
  }
59
64
  }
60
65
  };
61
- }, [mediaStreamTrack, opts]);
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","magnitudes","setMagnitudes","useState","useEffect","listener","Object","reactTag","LiveKitModule","createMultibandVolumeProcessor","_peerConnectionId","id","addListener","event","console","log","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 }, [options]);\n const mediaStreamTrack = track?.mediaStreamTrack;\n\n let [magnitudes, setMagnitudes] = useState<number[]>([]);\n useEffect(() => {\n let listener = Object();\n let reactTag: string | null = null;\n if (mediaStreamTrack) {\n reactTag = LiveKitModule.createMultibandVolumeProcessor(\n opts,\n mediaStreamTrack._peerConnectionId ?? -1,\n mediaStreamTrack.id\n );\n addListener(listener, 'LK_MULTIBAND_PROCESSED', (event: any) => {\n if (event.magnitudes && reactTag && event.id === reactTag) {\n console.log('event received: ', event.magnitudes[0]);\n setMagnitudes(event.magnitudes);\n }\n });\n }\n return () => {\n if (mediaStreamTrack) {\n removeListener(listener);\n if (reactTag) {\n LiveKitModule.deleteMultibandVolumeProcessor(\n reactTag,\n mediaStreamTrack._peerConnectionId ?? -1,\n mediaStreamTrack.id\n );\n }\n }\n };\n }, [mediaStreamTrack, 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,OAAoC,GAAG,CAAC,CAAC,EACzC;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;EAC7C,CAAC,EAAE,CAACA,OAAO,CAAC,CAAC;EACb,MAAMO,gBAAgB,GAAGL,KAAK,aAALA,KAAK,uBAALA,KAAK,CAAEK,gBAAgB;EAEhD,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,IAAIP,gBAAgB,EAAE;MACpBO,QAAQ,GAAGC,uBAAa,CAACC,8BAA8B,CACrDX,IAAI,EACJE,gBAAgB,CAACU,iBAAiB,IAAI,CAAC,CAAC,EACxCV,gBAAgB,CAACW,EACnB,CAAC;MACD,IAAAC,yBAAW,EAACP,QAAQ,EAAE,wBAAwB,EAAGQ,KAAU,IAAK;QAC9D,IAAIA,KAAK,CAACZ,UAAU,IAAIM,QAAQ,IAAIM,KAAK,CAACF,EAAE,KAAKJ,QAAQ,EAAE;UACzDO,OAAO,CAACC,GAAG,CAAC,kBAAkB,EAAEF,KAAK,CAACZ,UAAU,CAAC,CAAC,CAAC,CAAC;UACpDC,aAAa,CAACW,KAAK,CAACZ,UAAU,CAAC;QACjC;MACF,CAAC,CAAC;IACJ;IACA,OAAO,MAAM;MACX,IAAID,gBAAgB,EAAE;QACpB,IAAAgB,4BAAc,EAACX,QAAQ,CAAC;QACxB,IAAIE,QAAQ,EAAE;UACZC,uBAAa,CAACS,8BAA8B,CAC1CV,QAAQ,EACRP,gBAAgB,CAACU,iBAAiB,IAAI,CAAC,CAAC,EACxCV,gBAAgB,CAACW,EACnB,CAAC;QACH;MACF;IACF,CAAC;EACH,CAAC,EAAE,CAACX,gBAAgB,EAAEF,IAAI,CAAC,CAAC;EAE5B,OAAOG,UAAU;AACnB","ignoreList":[]}
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 (mediaStreamTrack) {
27
- reactTag = _LKNativeModule.default.createVolumeProcessor(mediaStreamTrack._peerConnectionId ?? -1, mediaStreamTrack.id);
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 (mediaStreamTrack) {
38
+ if (hasMediaStreamTrack) {
36
39
  (0, _EventEmitter.removeListener)(listener);
37
40
  if (reactTag) {
38
- _LKNativeModule.default.deleteVolumeProcessor(reactTag, mediaStreamTrack._peerConnectionId ?? -1, mediaStreamTrack.id);
41
+ _LKNativeModule.default.deleteVolumeProcessor(reactTag, peerConnectionId, mediaStreamTrackId);
39
42
  }
40
43
  }
41
44
  };
42
- }, [mediaStreamTrack]);
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","_peerConnectionId","id","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\n let [volume, setVolume] = useState(0.0);\n useEffect(() => {\n let listener = Object();\n let reactTag: string | null = null;\n if (mediaStreamTrack) {\n reactTag = LiveKitModule.createVolumeProcessor(\n mediaStreamTrack._peerConnectionId ?? -1,\n mediaStreamTrack.id\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 (mediaStreamTrack) {\n removeListener(listener);\n if (reactTag) {\n LiveKitModule.deleteVolumeProcessor(\n reactTag,\n mediaStreamTrack._peerConnectionId ?? -1,\n mediaStreamTrack.id\n );\n }\n }\n };\n }, [mediaStreamTrack]);\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;EAEhD,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,IAAIP,gBAAgB,EAAE;MACpBO,QAAQ,GAAGC,uBAAa,CAACC,qBAAqB,CAC5CT,gBAAgB,CAACU,iBAAiB,IAAI,CAAC,CAAC,EACxCV,gBAAgB,CAACW,EACnB,CAAC;MACD,IAAAC,yBAAW,EAACP,QAAQ,EAAE,qBAAqB,EAAGQ,KAAU,IAAK;QAC3D,IAAIA,KAAK,CAACZ,MAAM,IAAIM,QAAQ,IAAIM,KAAK,CAACF,EAAE,KAAKJ,QAAQ,EAAE;UACrDL,SAAS,CAACW,KAAK,CAACZ,MAAM,CAAC;QACzB;MACF,CAAC,CAAC;IACJ;IACA,OAAO,MAAM;MACX,IAAID,gBAAgB,EAAE;QACpB,IAAAc,4BAAc,EAACT,QAAQ,CAAC;QACxB,IAAIE,QAAQ,EAAE;UACZC,uBAAa,CAACO,qBAAqB,CACjCR,QAAQ,EACRP,gBAAgB,CAACU,iBAAiB,IAAI,CAAC,CAAC,EACxCV,gBAAgB,CAACW,EACnB,CAAC;QACH;MACF;IACF,CAAC;EACH,CAAC,EAAE,CAACX,gBAAgB,CAAC,CAAC;EAEtB,OAAOC,MAAM;AACf","ignoreList":[]}
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
- }, /*#__PURE__*/React.createElement(RTCView, {
81
- style: styles.videoTrack,
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":";;;AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAE9B,SAEEC,UAAU,EACVC,IAAI,QAEC,cAAc;AACrB,SAEEC,eAAe,EAEfC,UAAU,QACL,gBAAgB;AACvB,SAASC,OAAO,QAAQ,8BAA8B;AACtD,SAASC,WAAW,EAAEC,SAAS,EAAEC,OAAO,EAAEC,QAAQ,QAAQ,OAAO;AACjE,SAASC,gBAAgB,QAAQ,gBAAgB;AACjD,OAAOC,gBAAgB,MAAM,oBAAoB;;AAGjD;AACA;AACA;AACA;;AA2CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,UAAU,GAAGA,CAAC;EACzBC,KAAK,GAAG,CAAC,CAAC;EACVC,QAAQ;EACRC,SAAS,GAAG,OAAO;EACnBC,MAAM;EACNC;AACe,CAAC,KAAK;EACrB,MAAM,CAACC,WAAW,CAAC,GAAGT,QAAQ,CAAC,MAAM;IAAA,IAAAU,qBAAA;IACnC,IAAIC,IAAI,GAAG,IAAIC,qBAAqB,CAAC,CAAC;IACtCD,IAAI,CAACE,EAAE,GAAGR,QAAQ,aAARA,QAAQ,gBAAAK,qBAAA,GAARL,QAAQ,CAAES,WAAW,cAAAJ,qBAAA,uBAArBA,qBAAA,CAAuBK,QAAQ;IACzC,OAAOJ,IAAI;EACb,CAAC,CAAC;EAEF,MAAMK,cAAc,GAAGnB,WAAW,CAC/BoB,KAAwB,IAAKR,WAAW,CAACS,QAAQ,CAACD,KAAK,CAAC,EACzD,CAACR,WAAW,CACd,CAAC;EACD,MAAMU,kBAAkB,GAAGtB,WAAW,CACnCuB,SAAkB,IAAKX,WAAW,CAACY,YAAY,CAACD,SAAS,CAAC,EAC3D,CAACX,WAAW,CACd,CAAC;EAED,MAAMa,UAAU,GAAGjB,QAAQ,aAARA,QAAQ,uBAARA,QAAQ,CAAES,WAAW,CAACS,KAAK;EAE9C,MAAMC,uBAAuB,GAAGzB,OAAO,CAAC,MAAM;IAC5C,OACEuB,UAAU,YAAYrB,gBAAgB,IAAIqB,UAAU,CAACG,gBAAgB;EAEzE,CAAC,EAAE,CAACH,UAAU,CAAC,CAAC;EAEhB,MAAM,CAACI,WAAW,EAAEC,cAAc,CAAC,GAAG3B,QAAQ,CAACsB,UAAU,aAAVA,UAAU,uBAAVA,UAAU,CAAEI,WAAW,CAAC;EACvE5B,SAAS,CAAC,MAAM;IACd6B,cAAc,CAACL,UAAU,aAAVA,UAAU,uBAAVA,UAAU,CAAEI,WAAW,CAAC;IACvC,IAAIJ,UAAU,YAAY5B,eAAe,EAAE;MACzC,MAAMkC,WAAW,GAAIL,KAAmB,IAAK;QAC3CI,cAAc,CAACJ,KAAK,aAALA,KAAK,uBAALA,KAAK,CAAEG,WAAW,CAAC;MACpC,CAAC;MACDJ,UAAU,CAACO,EAAE,CAAClC,UAAU,CAACmC,SAAS,EAAEF,WAAW,CAAC;MAEhD,OAAO,MAAM;QACXN,UAAU,CAACS,GAAG,CAACpC,UAAU,CAACmC,SAAS,EAAEF,WAAW,CAAC;MACnD,CAAC;IACH,CAAC,MAAM;MACL,OAAO,MAAM,CAAC,CAAC;IACjB;EACF,CAAC,EAAE,CAACN,UAAU,CAAC,CAAC;EAEhBxB,SAAS,CAAC,MAAM;IACd,IAAIwB,UAAU,YAAYrB,gBAAgB,IAAIqB,UAAU,CAACG,gBAAgB,EAAE;MACzEH,UAAU,aAAVA,UAAU,eAAVA,UAAU,CAAEU,kBAAkB,CAACvB,WAAW,CAAC;MAC3C,OAAO,MAAM;QACXa,UAAU,aAAVA,UAAU,eAAVA,UAAU,CAAEW,wBAAwB,CAACxB,WAAW,CAAC;MACnD,CAAC;IACH,CAAC,MAAM;MACL,OAAO,MAAM,CAAC,CAAC;IACjB;EACF,CAAC,EAAE,CAACa,UAAU,EAAEb,WAAW,CAAC,CAAC;EAE7B,oBACElB,KAAA,CAAA2C,aAAA,CAACzC,IAAI;IAACW,KAAK,EAAE;MAAE,GAAGA,KAAK;MAAE,GAAG+B,MAAM,CAACC;IAAU,CAAE;IAAClB,QAAQ,EAAEF;EAAe,gBACvEzB,KAAA,CAAA2C,aAAA,CAAChC,gBAAgB;IACfmC,QAAQ,EAAElB,kBAAmB;IAC7Bf,KAAK,EAAE+B,MAAM,CAACb,UAAW;IACzBgB,QAAQ,EAAE,CAACd,uBAAwB;IACnCe,OAAO,EAAEjB;EAAW,gBAEpB/B,KAAA,CAAA2C,aAAA,CAACtC,OAAO;IACNQ,KAAK,EAAE+B,MAAM,CAACb,UAAW;IACzBkB,SAAS,EAAE,CAAAd,WAAW,aAAXA,WAAW,uBAAXA,WAAW,CAAEe,KAAK,CAAC,CAAC,KAAI,EAAG;IACtCnC,SAAS,EAAEA,SAAU;IACrBC,MAAM,EAAEA,MAAO;IACfC,MAAM,EAAEA;EAAO,CAChB,CACe,CACd,CAAC;AAEX,CAAC;AAED,MAAM2B,MAAM,GAAG3C,UAAU,CAACkD,MAAM,CAAC;EAC/BN,SAAS,EAAE,CAAC,CAAC;EACbd,UAAU,EAAE;IACVqB,IAAI,EAAE,CAAC;IACPC,KAAK,EAAE;EACT;AACF,CAAC,CAAC;AAEF,MAAMhC,qBAAqB,CAAwB;EAAAiC,YAAA;IAAAC,eAAA,kBAC/B,CAAC,CAAC;IAAAA,eAAA;IAAAA,eAAA;IAAAA,eAAA,iBAGX,CAAC;IAAAA,eAAA,kBACA,CAAC;IAAAA,eAAA,qBACE,KAAK;IAAAA,eAAA,kBACC,IAAI;IAAAA,eAAA;IAAAA,eAAA,2BAEJ,KAAK;IAAAA,eAAA;IAAAA,eAAA;IAAAA,eAAA,gBAGhB,MAAM,IAAI,CAACC,MAAM;IAAAD,eAAA,iBAChB,MAAM,IAAI,CAACE,OAAO;EAAA;EAE3BC,OAAOA,CAAA,EAAS;IACd,IAAI,CAACC,UAAU,GAAG,IAAI;EACxB;EAEAC,aAAaA,CAAA,EAAS;IACpB,IAAI,CAACD,UAAU,GAAG,KAAK;EACzB;EAEAhC,QAAQA,CAACD,KAAwB,EAAE;IACjC,IAAI;MAAE2B,KAAK;MAAEQ;IAAO,CAAC,GAAGnC,KAAK,CAACoC,WAAW,CAACC,MAAM;IAChD,IAAI,CAACP,MAAM,GAAGH,KAAK;IACnB,IAAI,CAACI,OAAO,GAAGI,MAAM;IAErB,IAAI,IAAI,CAACF,UAAU,EAAE;MAAA,IAAAK,kBAAA;MACnB,CAAAA,kBAAA,OAAI,CAACC,YAAY,cAAAD,kBAAA,eAAjBA,kBAAA,CAAAE,IAAA,KAAoB,CAAC;IACvB;EACF;EAEApC,YAAYA,CAACD,SAAkB,EAAE;IAC/B,IAAI,IAAI,CAACsC,OAAO,KAAKtC,SAAS,EAAE;MAC9B,IAAI,CAACsC,OAAO,GAAGtC,SAAS;MACxB,IAAI,CAACuC,mBAAmB,GAAGC,IAAI,CAACC,GAAG,CAAC,CAAC;MACrC,IAAI,IAAI,CAACX,UAAU,EAAE;QAAA,IAAAY,qBAAA;QACnB,CAAAA,qBAAA,OAAI,CAACC,uBAAuB,cAAAD,qBAAA,eAA5BA,qBAAA,CAAAL,IAAA,KAA+B,CAAC;MAClC;IACF;EACF;AACF","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
- }, [options]);
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 (mediaStreamTrack) {
39
- reactTag = LiveKitModule.createMultibandVolumeProcessor(opts, mediaStreamTrack._peerConnectionId ?? -1, mediaStreamTrack.id);
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 (mediaStreamTrack) {
53
+ if (hasMediaStreamTrack) {
49
54
  removeListener(listener);
50
55
  if (reactTag) {
51
- LiveKitModule.deleteMultibandVolumeProcessor(reactTag, mediaStreamTrack._peerConnectionId ?? -1, mediaStreamTrack.id);
56
+ LiveKitModule.deleteMultibandVolumeProcessor(reactTag, peerConnectionId, mediaStreamTrackId);
52
57
  }
53
58
  }
54
59
  };
55
- }, [mediaStreamTrack, opts]);
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","magnitudes","setMagnitudes","listener","Object","reactTag","createMultibandVolumeProcessor","_peerConnectionId","id","event","console","log","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 }, [options]);\n const mediaStreamTrack = track?.mediaStreamTrack;\n\n let [magnitudes, setMagnitudes] = useState<number[]>([]);\n useEffect(() => {\n let listener = Object();\n let reactTag: string | null = null;\n if (mediaStreamTrack) {\n reactTag = LiveKitModule.createMultibandVolumeProcessor(\n opts,\n mediaStreamTrack._peerConnectionId ?? -1,\n mediaStreamTrack.id\n );\n addListener(listener, 'LK_MULTIBAND_PROCESSED', (event: any) => {\n if (event.magnitudes && reactTag && event.id === reactTag) {\n console.log('event received: ', event.magnitudes[0]);\n setMagnitudes(event.magnitudes);\n }\n });\n }\n return () => {\n if (mediaStreamTrack) {\n removeListener(listener);\n if (reactTag) {\n LiveKitModule.deleteMultibandVolumeProcessor(\n reactTag,\n mediaStreamTrack._peerConnectionId ?? -1,\n mediaStreamTrack.id\n );\n }\n }\n };\n }, [mediaStreamTrack, 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,OAAoC,GAAG,CAAC,CAAC,EACzC;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;EAC7C,CAAC,EAAE,CAACA,OAAO,CAAC,CAAC;EACb,MAAMK,gBAAgB,GAAGH,KAAK,aAALA,KAAK,uBAALA,KAAK,CAAEG,gBAAgB;EAEhD,IAAI,CAACC,UAAU,EAAEC,aAAa,CAAC,GAAGlB,QAAQ,CAAW,EAAE,CAAC;EACxDF,SAAS,CAAC,MAAM;IACd,IAAIqB,QAAQ,GAAGC,MAAM,CAAC,CAAC;IACvB,IAAIC,QAAuB,GAAG,IAAI;IAClC,IAAIL,gBAAgB,EAAE;MACpBK,QAAQ,GAAGlB,aAAa,CAACmB,8BAA8B,CACrDP,IAAI,EACJC,gBAAgB,CAACO,iBAAiB,IAAI,CAAC,CAAC,EACxCP,gBAAgB,CAACQ,EACnB,CAAC;MACDvB,WAAW,CAACkB,QAAQ,EAAE,wBAAwB,EAAGM,KAAU,IAAK;QAC9D,IAAIA,KAAK,CAACR,UAAU,IAAII,QAAQ,IAAII,KAAK,CAACD,EAAE,KAAKH,QAAQ,EAAE;UACzDK,OAAO,CAACC,GAAG,CAAC,kBAAkB,EAAEF,KAAK,CAACR,UAAU,CAAC,CAAC,CAAC,CAAC;UACpDC,aAAa,CAACO,KAAK,CAACR,UAAU,CAAC;QACjC;MACF,CAAC,CAAC;IACJ;IACA,OAAO,MAAM;MACX,IAAID,gBAAgB,EAAE;QACpBd,cAAc,CAACiB,QAAQ,CAAC;QACxB,IAAIE,QAAQ,EAAE;UACZlB,aAAa,CAACyB,8BAA8B,CAC1CP,QAAQ,EACRL,gBAAgB,CAACO,iBAAiB,IAAI,CAAC,CAAC,EACxCP,gBAAgB,CAACQ,EACnB,CAAC;QACH;MACF;IACF,CAAC;EACH,CAAC,EAAE,CAACR,gBAAgB,EAAED,IAAI,CAAC,CAAC;EAE5B,OAAOE,UAAU;AACnB","ignoreList":[]}
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 (mediaStreamTrack) {
21
- reactTag = LiveKitModule.createVolumeProcessor(mediaStreamTrack._peerConnectionId ?? -1, mediaStreamTrack.id);
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 (mediaStreamTrack) {
32
+ if (hasMediaStreamTrack) {
30
33
  removeListener(listener);
31
34
  if (reactTag) {
32
- LiveKitModule.deleteVolumeProcessor(reactTag, mediaStreamTrack._peerConnectionId ?? -1, mediaStreamTrack.id);
35
+ LiveKitModule.deleteVolumeProcessor(reactTag, peerConnectionId, mediaStreamTrackId);
33
36
  }
34
37
  }
35
38
  };
36
- }, [mediaStreamTrack]);
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","_peerConnectionId","id","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\n let [volume, setVolume] = useState(0.0);\n useEffect(() => {\n let listener = Object();\n let reactTag: string | null = null;\n if (mediaStreamTrack) {\n reactTag = LiveKitModule.createVolumeProcessor(\n mediaStreamTrack._peerConnectionId ?? -1,\n mediaStreamTrack.id\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 (mediaStreamTrack) {\n removeListener(listener);\n if (reactTag) {\n LiveKitModule.deleteVolumeProcessor(\n reactTag,\n mediaStreamTrack._peerConnectionId ?? -1,\n mediaStreamTrack.id\n );\n }\n }\n };\n }, [mediaStreamTrack]);\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;EAEhD,IAAI,CAACC,MAAM,EAAEC,SAAS,CAAC,GAAGX,QAAQ,CAAC,GAAG,CAAC;EACvCD,SAAS,CAAC,MAAM;IACd,IAAIa,QAAQ,GAAGC,MAAM,CAAC,CAAC;IACvB,IAAIC,QAAuB,GAAG,IAAI;IAClC,IAAIL,gBAAgB,EAAE;MACpBK,QAAQ,GAAGX,aAAa,CAACY,qBAAqB,CAC5CN,gBAAgB,CAACO,iBAAiB,IAAI,CAAC,CAAC,EACxCP,gBAAgB,CAACQ,EACnB,CAAC;MACDhB,WAAW,CAACW,QAAQ,EAAE,qBAAqB,EAAGM,KAAU,IAAK;QAC3D,IAAIA,KAAK,CAACR,MAAM,IAAII,QAAQ,IAAII,KAAK,CAACD,EAAE,KAAKH,QAAQ,EAAE;UACrDH,SAAS,CAACO,KAAK,CAACR,MAAM,CAAC;QACzB;MACF,CAAC,CAAC;IACJ;IACA,OAAO,MAAM;MACX,IAAID,gBAAgB,EAAE;QACpBP,cAAc,CAACU,QAAQ,CAAC;QACxB,IAAIE,QAAQ,EAAE;UACZX,aAAa,CAACgB,qBAAqB,CACjCL,QAAQ,EACRL,gBAAgB,CAACO,iBAAiB,IAAI,CAAC,CAAC,EACxCP,gBAAgB,CAACQ,EACnB,CAAC;QACH;MACF;IACF,CAAC;EACH,CAAC,EAAE,CAACR,gBAAgB,CAAC,CAAC;EAEtB,OAAOC,MAAM;AACf","ignoreList":[]}
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?: {}): any;
8
+ export function useMultibandTrackVolume(trackOrTrackReference: any, options: any): any;
@@ -1,9 +1,14 @@
1
- export function VideoTrack({ style, trackRef, objectFit, zOrder, mirror }: {
2
- style?: {} | undefined;
3
- trackRef: any;
4
- objectFit?: string | undefined;
5
- zOrder: any;
6
- mirror: any;
7
- }): React.CElement<import("react-native").ViewProps, View>;
8
- import { View } from 'react-native';
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?: {}): never[];
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: ({ style, trackRef, objectFit, zOrder, mirror, }: VideoTrackProps) => React.JSX.Element;
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.6.4",
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.0",
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 { RTCView } from '@livekit/react-native-webrtc';
16
- import { useCallback, useEffect, useMemo, useState } from 'react';
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
- style = {},
77
- trackRef,
78
- objectFit = 'cover',
79
- zOrder,
80
- mirror,
81
- }: VideoTrackProps) => {
82
- const [elementInfo] = useState(() => {
83
- let info = new VideoTrackElementInfo();
84
- info.id = trackRef?.publication?.trackSid;
85
- return info;
86
- });
87
-
88
- const layoutOnChange = useCallback(
89
- (event: LayoutChangeEvent) => elementInfo.onLayout(event),
90
- [elementInfo]
91
- );
92
- const visibilityOnChange = useCallback(
93
- (isVisible: boolean) => elementInfo.onVisibility(isVisible),
94
- [elementInfo]
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
- }, [videoTrack]);
104
-
105
- const [mediaStream, setMediaStream] = useState(videoTrack?.mediaStream);
106
- useEffect(() => {
107
- setMediaStream(videoTrack?.mediaStream);
108
- if (videoTrack instanceof LocalVideoTrack) {
109
- const onRestarted = (track: Track | null) => {
110
- setMediaStream(track?.mediaStream);
111
- };
112
- videoTrack.on(TrackEvent.Restarted, onRestarted);
113
-
114
- return () => {
115
- videoTrack.off(TrackEvent.Restarted, onRestarted);
116
- };
117
- } else {
118
- return () => {};
119
- }
120
- }, [videoTrack]);
121
-
122
- useEffect(() => {
123
- if (videoTrack instanceof RemoteVideoTrack && videoTrack.isAdaptiveStream) {
124
- videoTrack?.observeElementInfo(elementInfo);
125
- return () => {
126
- videoTrack?.stopObservingElementInfo(elementInfo);
127
- };
128
- } else {
129
- return () => {};
130
- }
131
- }, [videoTrack, elementInfo]);
132
-
133
- return (
134
- <View style={{ ...style, ...styles.container }} onLayout={layoutOnChange}>
135
- <ViewPortDetector
136
- onChange={visibilityOnChange}
137
- style={styles.videoTrack}
138
- disabled={!shouldObserveVisibility}
139
- propKey={videoTrack}
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
- </ViewPortDetector>
149
- </View>
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: MultiBandTrackVolumeOptions = {}
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
- }, [options]);
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 (mediaStreamTrack) {
75
+ if (hasMediaStreamTrack) {
70
76
  reactTag = LiveKitModule.createMultibandVolumeProcessor(
71
77
  opts,
72
- mediaStreamTrack._peerConnectionId ?? -1,
73
- mediaStreamTrack.id
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 (mediaStreamTrack) {
88
+ if (hasMediaStreamTrack) {
84
89
  removeListener(listener);
85
90
  if (reactTag) {
86
91
  LiveKitModule.deleteMultibandVolumeProcessor(
87
92
  reactTag,
88
- mediaStreamTrack._peerConnectionId ?? -1,
89
- mediaStreamTrack.id
93
+ peerConnectionId,
94
+ mediaStreamTrackId
90
95
  );
91
96
  }
92
97
  }
93
98
  };
94
- }, [mediaStreamTrack, opts]);
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 (mediaStreamTrack) {
39
+ if (hasMediaStreamTrack) {
37
40
  reactTag = LiveKitModule.createVolumeProcessor(
38
- mediaStreamTrack._peerConnectionId ?? -1,
39
- mediaStreamTrack.id
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 (mediaStreamTrack) {
51
+ if (hasMediaStreamTrack) {
49
52
  removeListener(listener);
50
53
  if (reactTag) {
51
54
  LiveKitModule.deleteVolumeProcessor(
52
55
  reactTag,
53
- mediaStreamTrack._peerConnectionId ?? -1,
54
- mediaStreamTrack.id
56
+ peerConnectionId,
57
+ mediaStreamTrackId
55
58
  );
56
59
  }
57
60
  }
58
61
  };
59
- }, [mediaStreamTrack]);
62
+ }, [hasMediaStreamTrack, peerConnectionId, mediaStreamTrackId]);
60
63
 
61
64
  return volume;
62
65
  }