@fishjam-cloud/react-native-client 0.19.0 → 0.20.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.
Files changed (54) hide show
  1. package/android/src/main/java/io/fishjam/reactnative/RNFishjamClient.kt +25 -15
  2. package/android/src/main/java/io/fishjam/reactnative/RNFishjamClientModule.kt +12 -0
  3. package/build/components/LivestreamStreamer.d.ts +19 -0
  4. package/build/components/LivestreamStreamer.d.ts.map +1 -0
  5. package/build/components/LivestreamStreamer.js +10 -0
  6. package/build/components/LivestreamStreamer.js.map +1 -0
  7. package/build/components/{LivestreamView.d.ts → LivestreamViewer.d.ts} +6 -6
  8. package/build/components/LivestreamViewer.d.ts.map +1 -0
  9. package/build/components/LivestreamViewer.js +10 -0
  10. package/build/components/LivestreamViewer.js.map +1 -0
  11. package/build/consts/index.d.ts +5 -0
  12. package/build/consts/index.d.ts.map +1 -0
  13. package/build/consts/index.js +8 -0
  14. package/build/consts/index.js.map +1 -0
  15. package/build/hooks/useConnection.d.ts +18 -7
  16. package/build/hooks/useConnection.d.ts.map +1 -1
  17. package/build/hooks/useConnection.js +10 -2
  18. package/build/hooks/useConnection.js.map +1 -1
  19. package/build/hooks/useLivestreamStreamer.d.ts +24 -0
  20. package/build/hooks/useLivestreamStreamer.d.ts.map +1 -0
  21. package/build/hooks/useLivestreamStreamer.js +31 -0
  22. package/build/hooks/useLivestreamStreamer.js.map +1 -0
  23. package/build/hooks/useLivestreamViewer.d.ts +27 -0
  24. package/build/hooks/useLivestreamViewer.d.ts.map +1 -0
  25. package/build/hooks/useLivestreamViewer.js +31 -0
  26. package/build/hooks/useLivestreamViewer.js.map +1 -0
  27. package/build/hooks/useMicrophone.d.ts +6 -2
  28. package/build/hooks/useMicrophone.d.ts.map +1 -1
  29. package/build/hooks/useMicrophone.js +12 -2
  30. package/build/hooks/useMicrophone.js.map +1 -1
  31. package/build/hooks/useSandbox.d.ts +20 -0
  32. package/build/hooks/useSandbox.d.ts.map +1 -0
  33. package/build/hooks/useSandbox.js +56 -0
  34. package/build/hooks/useSandbox.js.map +1 -0
  35. package/build/index.d.ts +13 -5
  36. package/build/index.d.ts.map +1 -1
  37. package/build/index.js +6 -2
  38. package/build/index.js.map +1 -1
  39. package/build/types.d.ts +1 -0
  40. package/build/types.d.ts.map +1 -1
  41. package/build/types.js.map +1 -1
  42. package/ios/RNFishjamClient.swift +31 -20
  43. package/ios/RNFishjamClientModule.swift +8 -0
  44. package/package.json +1 -1
  45. package/plugin/build/types.d.ts +3 -0
  46. package/plugin/build/withFishjamIos.d.ts +1 -1
  47. package/plugin/build/withFishjamIos.js +53 -40
  48. package/build/components/LivestreamView.d.ts.map +0 -1
  49. package/build/components/LivestreamView.js +0 -10
  50. package/build/components/LivestreamView.js.map +0 -1
  51. package/build/hooks/useLivestream.d.ts +0 -6
  52. package/build/hooks/useLivestream.d.ts.map +0 -1
  53. package/build/hooks/useLivestream.js +0 -12
  54. package/build/hooks/useLivestream.js.map +0 -1
@@ -392,15 +392,26 @@ class RNFishjamClient(
392
392
  localTracksSwitchListenerManager.notifySwitched()
393
393
  }
394
394
 
395
- private suspend fun startMicrophone() {
396
- if (!PermissionUtils.requestMicrophonePermission(appContext)) {
397
- emitEvent(EmitableEvent.warning("Microphone permission not granted."))
398
- return
395
+ suspend fun startMicrophone() {
396
+ // If microphone track already exist, just enable it
397
+ if (getLocalAudioTrack() != null) {
398
+ getLocalAudioTrack()?.let { setMicrophoneTrackState(it, true) }
399
+ } else {
400
+ if (!PermissionUtils.requestMicrophonePermission(appContext)) {
401
+ emitEvent(EmitableEvent.warning("Microphone permission not granted."))
402
+ return
403
+ }
404
+
405
+ val microphoneTrack = fishjamClient.createAudioTrack(getMicrophoneTrackMetadata(true))
406
+ setMicrophoneTrackState(microphoneTrack, true)
407
+ emitEndpoints()
399
408
  }
409
+ }
400
410
 
401
- val microphoneTrack = fishjamClient.createAudioTrack(getMicrophoneTrackMetadata())
402
- setMicrophoneTrackState(microphoneTrack, true)
403
- emitEndpoints()
411
+ fun stopMicrophone() {
412
+ if (getLocalAudioTrack() != null) {
413
+ getLocalAudioTrack()?.let { setMicrophoneTrackState(it, false) }
414
+ }
404
415
  }
405
416
 
406
417
  private fun setMicrophoneTrackState(
@@ -409,25 +420,24 @@ class RNFishjamClient(
409
420
  ) {
410
421
  microphoneTrack.setEnabled(isEnabled)
411
422
  isMicrophoneOn = isEnabled
423
+ updateLocalAudioTrackMetadata(getMicrophoneTrackMetadata(isEnabled))
412
424
  emitEvent(EmitableEvent.isMicrophoneOn(isEnabled))
413
425
  }
414
426
 
415
427
  suspend fun toggleMicrophone(): Boolean {
416
- if (getLocalAudioTrack() == null) {
417
- startMicrophone()
428
+ if (isMicrophoneOn) {
429
+ stopMicrophone()
418
430
  } else {
419
- getLocalAudioTrack()?.let { setMicrophoneTrackState(it, !isMicrophoneOn) }
431
+ startMicrophone()
420
432
  }
421
433
 
422
- updateLocalAudioTrackMetadata(getMicrophoneTrackMetadata())
423
-
424
434
  return isMicrophoneOn
425
435
  }
426
436
 
427
- private fun getMicrophoneTrackMetadata(): Map<String, Any> =
437
+ private fun getMicrophoneTrackMetadata(isEnabled: Boolean): Map<String, Any> =
428
438
  mapOf(
429
- "active" to isMicrophoneOn,
430
- "paused" to !isMicrophoneOn, // TODO: FCE-711,
439
+ "active" to isEnabled,
440
+ "paused" to !isEnabled, // TODO: FCE-711,
431
441
  "type" to "microphone"
432
442
  )
433
443
 
@@ -182,6 +182,18 @@ class RNFishjamClientModule : Module() {
182
182
  }
183
183
  }
184
184
 
185
+ AsyncFunction("startMicrophone") Coroutine { ->
186
+ withContext(Dispatchers.Main) {
187
+ rnFishjamClient.startMicrophone()
188
+ }
189
+ }
190
+
191
+ AsyncFunction("stopMicrophone") Coroutine { ->
192
+ withContext(Dispatchers.Main) {
193
+ rnFishjamClient.stopMicrophone()
194
+ }
195
+ }
196
+
185
197
  AsyncFunction("toggleCamera") Coroutine { ->
186
198
  withContext(Dispatchers.Main) {
187
199
  rnFishjamClient.toggleCamera()
@@ -0,0 +1,19 @@
1
+ import { StyleProp, ViewStyle } from 'react-native';
2
+ /**
3
+ * Props of the LivestreamView component
4
+ */
5
+ export type LivestreamStreamerProps = {
6
+ /**
7
+ * Styles of the LivestreamView component
8
+ */
9
+ style?: StyleProp<ViewStyle>;
10
+ };
11
+ /**
12
+ * Renders a video player playing the livestream set up with {@link useLivestreamStreamer} hook.
13
+ *
14
+ * @category Components
15
+ * @param {object} props
16
+ * @param {object} props.style
17
+ */
18
+ export declare const LivestreamStreamer: ({ style }: LivestreamStreamerProps) => import("react").JSX.Element;
19
+ //# sourceMappingURL=LivestreamStreamer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LivestreamStreamer.d.ts","sourceRoot":"","sources":["../../src/components/LivestreamStreamer.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGpD;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAAI,WAAW,uBAAuB,gCAEpE,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { WhipClientView } from 'react-native-whip-whep';
2
+ /**
3
+ * Renders a video player playing the livestream set up with {@link useLivestreamStreamer} hook.
4
+ *
5
+ * @category Components
6
+ * @param {object} props
7
+ * @param {object} props.style
8
+ */
9
+ export const LivestreamStreamer = ({ style }) => (<WhipClientView style={style}/>);
10
+ //# sourceMappingURL=LivestreamStreamer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LivestreamStreamer.js","sourceRoot":"","sources":["../../src/components/LivestreamStreamer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAYxD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,EAAE,KAAK,EAA2B,EAAE,EAAE,CAAC,CACxE,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,KAAsB,CAAC,EAAG,CAClD,CAAC","sourcesContent":["import { CSSProperties } from 'react';\nimport { StyleProp, ViewStyle } from 'react-native';\nimport { WhipClientView } from 'react-native-whip-whep';\n\n/**\n * Props of the LivestreamView component\n */\nexport type LivestreamStreamerProps = {\n /**\n * Styles of the LivestreamView component\n */\n style?: StyleProp<ViewStyle>;\n};\n\n/**\n * Renders a video player playing the livestream set up with {@link useLivestreamStreamer} hook.\n *\n * @category Components\n * @param {object} props\n * @param {object} props.style\n */\nexport const LivestreamStreamer = ({ style }: LivestreamStreamerProps) => (\n <WhipClientView style={style as CSSProperties} />\n);\n"]}
@@ -1,11 +1,11 @@
1
1
  import { Ref } from 'react';
2
2
  import { StyleProp, ViewStyle } from 'react-native';
3
3
  import { WhepClientViewRef } from 'react-native-whip-whep';
4
- export type LivestreamViewRef = WhepClientViewRef;
4
+ export type LivestreamViewerRef = WhepClientViewRef;
5
5
  /**
6
6
  * Props of the LivestreamView component
7
7
  */
8
- export type LivestreamViewProps = {
8
+ export type LivestreamViewerProps = {
9
9
  /**
10
10
  * Styles of the LivestreamView component
11
11
  */
@@ -38,14 +38,14 @@ export type LivestreamViewProps = {
38
38
  width: number;
39
39
  height: number;
40
40
  };
41
- ref?: Ref<LivestreamViewRef>;
41
+ ref?: Ref<LivestreamViewerRef>;
42
42
  };
43
43
  /**
44
- * Renders a video player playing the livestream set up with {@link useLivestream} hook.
44
+ * Renders a video player playing the livestream set up with {@link useLivestreamViewer} hook.
45
45
  *
46
46
  * @category Components
47
47
  * @param {object} props
48
48
  * @param {object} props.style
49
49
  */
50
- export declare const LivestreamView: ({ style, orientation, pipEnabled, autoStartPip, autoStopPip, pipSize, ref, }: LivestreamViewProps) => import("react").JSX.Element;
51
- //# sourceMappingURL=LivestreamView.d.ts.map
50
+ export declare const LivestreamViewer: ({ style, orientation, pipEnabled, autoStartPip, autoStopPip, pipSize, ref, }: LivestreamViewerProps) => import("react").JSX.Element;
51
+ //# sourceMappingURL=LivestreamViewer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LivestreamViewer.d.ts","sourceRoot":"","sources":["../../src/components/LivestreamViewer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,GAAG,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAkB,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3E,MAAM,MAAM,mBAAmB,GAAG,iBAAiB,CAAC;AAEpD;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B;;;OAGG;IACH,WAAW,CAAC,EAAE,WAAW,GAAG,UAAU,CAAC;IACvC;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;OAEG;IACH,OAAO,CAAC,EAAE;QACR,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IAEF,GAAG,CAAC,EAAE,GAAG,CAAC,mBAAmB,CAAC,CAAC;CAChC,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAAI,8EAQ9B,qBAAqB,gCAUvB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { WhepClientView } from 'react-native-whip-whep';
2
+ /**
3
+ * Renders a video player playing the livestream set up with {@link useLivestreamViewer} hook.
4
+ *
5
+ * @category Components
6
+ * @param {object} props
7
+ * @param {object} props.style
8
+ */
9
+ export const LivestreamViewer = ({ style, orientation, pipEnabled, autoStartPip, autoStopPip, pipSize, ref, }) => (<WhepClientView ref={ref} style={style} orientation={orientation} pipEnabled={pipEnabled} autoStartPip={autoStartPip} autoStopPip={autoStopPip} pipSize={pipSize}/>);
10
+ //# sourceMappingURL=LivestreamViewer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LivestreamViewer.js","sourceRoot":"","sources":["../../src/components/LivestreamViewer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAqB,MAAM,wBAAwB,CAAC;AA4C3E;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,EAC/B,KAAK,EACL,WAAW,EACX,UAAU,EACV,YAAY,EACZ,WAAW,EACX,OAAO,EACP,GAAG,GACmB,EAAE,EAAE,CAAC,CAC3B,CAAC,cAAc,CACb,GAAG,CAAC,CAAC,GAAG,CAAC,CACT,KAAK,CAAC,CAAC,KAAsB,CAAC,CAC9B,WAAW,CAAC,CAAC,WAAW,CAAC,CACzB,UAAU,CAAC,CAAC,UAAU,CAAC,CACvB,YAAY,CAAC,CAAC,YAAY,CAAC,CAC3B,WAAW,CAAC,CAAC,WAAW,CAAC,CACzB,OAAO,CAAC,CAAC,OAAO,CAAC,EACjB,CACH,CAAC","sourcesContent":["import { CSSProperties, Ref } from 'react';\nimport { StyleProp, ViewStyle } from 'react-native';\nimport { WhepClientView, WhepClientViewRef } from 'react-native-whip-whep';\n\nexport type LivestreamViewerRef = WhepClientViewRef;\n\n/**\n * Props of the LivestreamView component\n */\nexport type LivestreamViewerProps = {\n /**\n * Styles of the LivestreamView component\n */\n style?: StyleProp<ViewStyle>;\n /**\n * Used to override the orientation of the video (from metadata).\n * Defaults to \"portrait\".\n */\n orientation?: 'landscape' | 'portrait';\n /**\n * A variable deciding whether the Picture-in-Picture is enabled.\n * Defaults to true.\n */\n pipEnabled?: boolean;\n /**\n * A variable deciding whether the Picture-in-Picture mode should be started automatically after the app is backgrounded.\n * Defaults to false.\n */\n autoStartPip?: boolean;\n /**\n * A variable deciding whether the Picture-in-Picture mode should be stopped automatically on iOS after the app is foregrounded.\n * Always enabled on Android as PiP is not supported in foreground.\n * Defaults to false.\n */\n autoStopPip?: boolean;\n /**\n * A variable deciding the size of the Picture-in-Picture mode.\n */\n pipSize?: {\n width: number;\n height: number;\n };\n\n ref?: Ref<LivestreamViewerRef>;\n};\n\n/**\n * Renders a video player playing the livestream set up with {@link useLivestreamViewer} hook.\n *\n * @category Components\n * @param {object} props\n * @param {object} props.style\n */\nexport const LivestreamViewer = ({\n style,\n orientation,\n pipEnabled,\n autoStartPip,\n autoStopPip,\n pipSize,\n ref,\n}: LivestreamViewerProps) => (\n <WhepClientView\n ref={ref}\n style={style as CSSProperties}\n orientation={orientation}\n pipEnabled={pipEnabled}\n autoStartPip={autoStartPip}\n autoStopPip={autoStopPip}\n pipSize={pipSize}\n />\n);\n"]}
@@ -0,0 +1,5 @@
1
+ export declare const FISHJAM_HTTP_CONNECT_URL = "https://fishjam.io/api/v1/connect";
2
+ export declare const FISHJAM_WS_CONNECT_URL = "wss://fishjam.io/api/v1/connect";
3
+ export declare const FISHJAM_WHIP_URL = "https://fishjam.io/api/v1/live/api/whip";
4
+ export declare const FISHJAM_WHEP_URL = "https://fishjam.io/api/v1/live/api/whep";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/consts/index.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,wBAAwB,sCAAoC,CAAC;AAC1E,eAAO,MAAM,sBAAsB,oCAAkC,CAAC;AAItE,eAAO,MAAM,gBAAgB,4CAAiC,CAAC;AAC/D,eAAO,MAAM,gBAAgB,4CAAiC,CAAC"}
@@ -0,0 +1,8 @@
1
+ const FISHJAM_URL_BASE = 'fishjam.io/api/v1';
2
+ const FISHJAM_CONNECT_PATH = `${FISHJAM_URL_BASE}/connect`;
3
+ export const FISHJAM_HTTP_CONNECT_URL = `https://${FISHJAM_CONNECT_PATH}`;
4
+ export const FISHJAM_WS_CONNECT_URL = `wss://${FISHJAM_CONNECT_PATH}`;
5
+ const FISHJAM_LIVE_URL = `https://${FISHJAM_URL_BASE}/live`;
6
+ export const FISHJAM_WHIP_URL = `${FISHJAM_LIVE_URL}/api/whip`;
7
+ export const FISHJAM_WHEP_URL = `${FISHJAM_LIVE_URL}/api/whep`;
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/consts/index.ts"],"names":[],"mappings":"AAAA,MAAM,gBAAgB,GAAG,mBAAmB,CAAC;AAC7C,MAAM,oBAAoB,GAAG,GAAG,gBAAgB,UAAU,CAAC;AAE3D,MAAM,CAAC,MAAM,wBAAwB,GAAG,WAAW,oBAAoB,EAAE,CAAC;AAC1E,MAAM,CAAC,MAAM,sBAAsB,GAAG,SAAS,oBAAoB,EAAE,CAAC;AAEtE,MAAM,gBAAgB,GAAG,WAAW,gBAAgB,OAAO,CAAC;AAE5D,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,gBAAgB,WAAW,CAAC;AAC/D,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,gBAAgB,WAAW,CAAC","sourcesContent":["const FISHJAM_URL_BASE = 'fishjam.io/api/v1';\nconst FISHJAM_CONNECT_PATH = `${FISHJAM_URL_BASE}/connect`;\n\nexport const FISHJAM_HTTP_CONNECT_URL = `https://${FISHJAM_CONNECT_PATH}`;\nexport const FISHJAM_WS_CONNECT_URL = `wss://${FISHJAM_CONNECT_PATH}`;\n\nconst FISHJAM_LIVE_URL = `https://${FISHJAM_URL_BASE}/live`;\n\nexport const FISHJAM_WHIP_URL = `${FISHJAM_LIVE_URL}/api/whip`;\nexport const FISHJAM_WHEP_URL = `${FISHJAM_LIVE_URL}/api/whep`;\n"]}
@@ -18,10 +18,6 @@ export type ReconnectionStatus = 'idle' | 'reconnecting' | 'error';
18
18
  */
19
19
  export type PeerStatus = 'connecting' | 'connected' | 'error' | 'idle';
20
20
  export type JoinRoomConfig<PeerMetadata extends GenericMetadata = GenericMetadata> = {
21
- /**
22
- * Fishjam URL
23
- */
24
- url: string;
25
21
  /**
26
22
  * Token received from server (or Room Manager)
27
23
  */
@@ -31,10 +27,25 @@ export type JoinRoomConfig<PeerMetadata extends GenericMetadata = GenericMetadat
31
27
  */
32
28
  peerMetadata?: PeerMetadata;
33
29
  /**
34
- * Additional connection configuration
30
+ * Additional connection configuration
35
31
  */
36
32
  config?: ConnectionConfig;
37
- };
33
+ } & ({
34
+ /**
35
+ * Fishjam ID, which is used to connect to the room.
36
+ * Only use in sandbox.
37
+ * If provided, `url` must not be set.
38
+ */
39
+ fishjamId: string;
40
+ url?: never;
41
+ } | {
42
+ /**
43
+ * Fishjam URL, used to connect to the room.
44
+ * If provided, `fishjamId` must not be set.
45
+ */
46
+ url: string;
47
+ fishjamId?: never;
48
+ });
38
49
  /**
39
50
  * Connect/leave room. And get connection status.
40
51
  * @group Hooks
@@ -46,7 +57,7 @@ export declare function useConnection(): {
46
57
  *
47
58
  * See {@link JoinRoomConfig} for parameter list
48
59
  */
49
- joinRoom: <PeerMetadata extends GenericMetadata = GenericMetadata>({ url, peerToken, peerMetadata, config, }: JoinRoomConfig<PeerMetadata>) => Promise<void>;
60
+ joinRoom: <PeerMetadata extends GenericMetadata = GenericMetadata>({ url, peerToken, peerMetadata, config, fishjamId, }: JoinRoomConfig<PeerMetadata>) => Promise<void>;
50
61
  /**
51
62
  * Leave room and stop streaming
52
63
  * @type function
@@ -1 +1 @@
1
- {"version":3,"file":"useConnection.d.ts","sourceRoot":"","sources":["../../src/hooks/useConnection.ts"],"names":[],"mappings":"AACA,OAAO,EACL,gBAAgB,EAGjB,MAAM,kBAAkB,CAAC;AAM1B,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3C;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,cAAc,GAAG,OAAO,CAAC;AAEnE;;;;;;;GAOG;AACH,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,WAAW,GAAG,OAAO,GAAG,MAAM,CAAC;AAevE,MAAM,MAAM,cAAc,CACxB,YAAY,SAAS,eAAe,GAAG,eAAe,IACpD;IACF;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B;;OAEG;IACH,MAAM,CAAC,EAAE,gBAAgB,CAAC;CAC3B,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,aAAa;IAoBzB;;;;OAIG;eApBI,YAAY,SAAS,eAAe,+DAKxC,cAAc,CAAC,YAAY,CAAC;IAiB/B;;;OAGG;;;;EAKN"}
1
+ {"version":3,"file":"useConnection.d.ts","sourceRoot":"","sources":["../../src/hooks/useConnection.ts"],"names":[],"mappings":"AACA,OAAO,EACL,gBAAgB,EAGjB,MAAM,kBAAkB,CAAC;AAM1B,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAG3C;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,cAAc,GAAG,OAAO,CAAC;AAEnE;;;;;;;GAOG;AACH,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,WAAW,GAAG,OAAO,GAAG,MAAM,CAAC;AAevE,MAAM,MAAM,cAAc,CACxB,YAAY,SAAS,eAAe,GAAG,eAAe,IACpD;IACF;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B;;OAEG;IACH,MAAM,CAAC,EAAE,gBAAgB,CAAC;CAC3B,GAAG,CACA;IACE;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,KAAK,CAAC;CACb,GACD;IACE;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,KAAK,CAAC;CACnB,CACJ,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,aAAa;IAiCzB;;;;OAIG;eAjCI,YAAY,SAAS,eAAe,0EAMxC,cAAc,CAAC,YAAY,CAAC;IA6B/B;;;OAGG;;;;EAKN"}
@@ -2,6 +2,7 @@ import { useCallback } from 'react';
2
2
  import { joinRoom as joinRoomClient, leaveRoom as leaveRoomClient, } from '../common/client';
3
3
  import RNFishjamClientModule, { ReceivableEvents, } from '../RNFishjamClientModule';
4
4
  import { useFishjamEventState } from './internal/useFishjamEventState';
5
+ import { FISHJAM_WS_CONNECT_URL } from '../consts';
5
6
  function useConnectionStatus() {
6
7
  const peerStatus = useFishjamEventState(ReceivableEvents.PeerStatusChanged, RNFishjamClientModule.peerStatus);
7
8
  const reconnectionStatus = useFishjamEventState(ReceivableEvents.ReconnectionStatusChanged, RNFishjamClientModule.reconnectionStatus);
@@ -14,8 +15,15 @@ function useConnectionStatus() {
14
15
  */
15
16
  export function useConnection() {
16
17
  const { peerStatus, reconnectionStatus } = useConnectionStatus();
17
- const joinRoom = useCallback(async ({ url, peerToken, peerMetadata, config, }) => {
18
- await joinRoomClient(url, peerToken, peerMetadata, config);
18
+ const joinRoom = useCallback(async ({ url, peerToken, peerMetadata, config, fishjamId, }) => {
19
+ const connectUrl = fishjamId
20
+ ? `${FISHJAM_WS_CONNECT_URL}/${fishjamId}`
21
+ : undefined;
22
+ const fishjamUrl = fishjamId ? connectUrl : url;
23
+ if (!fishjamUrl) {
24
+ throw new Error('Either fishjamId or url must be provided to join the room.');
25
+ }
26
+ await joinRoomClient(fishjamUrl, peerToken, peerMetadata, config);
19
27
  }, []);
20
28
  const leaveRoom = useCallback(() => {
21
29
  leaveRoomClient();
@@ -1 +1 @@
1
- {"version":3,"file":"useConnection.js","sourceRoot":"","sources":["../../src/hooks/useConnection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAEL,QAAQ,IAAI,cAAc,EAC1B,SAAS,IAAI,eAAe,GAC7B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,qBAAqB,EAAE,EAC5B,gBAAgB,GACjB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAsBvE,SAAS,mBAAmB;IAC1B,MAAM,UAAU,GAAG,oBAAoB,CACrC,gBAAgB,CAAC,iBAAiB,EAClC,qBAAqB,CAAC,UAAU,CACjC,CAAC;IAEF,MAAM,kBAAkB,GAAG,oBAAoB,CAC7C,gBAAgB,CAAC,yBAAyB,EAC1C,qBAAqB,CAAC,kBAAkB,CACzC,CAAC;IAEF,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAC;AAC5C,CAAC;AAsBD;;;;GAIG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,EAAE,UAAU,EAAE,kBAAkB,EAAE,GAAG,mBAAmB,EAAE,CAAC;IAEjE,MAAM,QAAQ,GAAG,WAAW,CAC1B,KAAK,EAA0D,EAC7D,GAAG,EACH,SAAS,EACT,YAAY,EACZ,MAAM,GACuB,EAAE,EAAE;QACjC,MAAM,cAAc,CAAC,GAAG,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;IAC7D,CAAC,EACD,EAAE,CACH,CAAC;IAEF,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE;QACjC,eAAe,EAAE,CAAC;IACpB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO;QACL;;;;WAIG;QACH,QAAQ;QACR;;;WAGG;QACH,SAAS;QACT,UAAU;QACV,kBAAkB;KACnB,CAAC;AACJ,CAAC","sourcesContent":["import { useCallback } from 'react';\nimport {\n ConnectionConfig,\n joinRoom as joinRoomClient,\n leaveRoom as leaveRoomClient,\n} from '../common/client';\n\nimport RNFishjamClientModule, {\n ReceivableEvents,\n} from '../RNFishjamClientModule';\nimport { useFishjamEventState } from './internal/useFishjamEventState';\nimport { GenericMetadata } from '../types';\n\n/**\n * Represents the possible statuses of a peer while reconnecting to room\n *\n * - `idle` - No reconnection in progress. See {@link PeerStatus} for more details\n * - `reconnecting` - Peer is in the process of reconnecting.\n * - `error` - There was an error in the reconnection process.\n */\nexport type ReconnectionStatus = 'idle' | 'reconnecting' | 'error';\n\n/**\n * Represents the possible statuses of a peer connection to a room (websocket state).\n *\n * - `idle` - Peer is not connected, either never connected or successfully disconnected.\n * - `connecting` - Peer is in the process of connecting.\n * - `connected` - Peer has successfully connected.\n * - `error` - There was an error in the connection process.\n */\nexport type PeerStatus = 'connecting' | 'connected' | 'error' | 'idle';\n\nfunction useConnectionStatus() {\n const peerStatus = useFishjamEventState(\n ReceivableEvents.PeerStatusChanged,\n RNFishjamClientModule.peerStatus,\n );\n\n const reconnectionStatus = useFishjamEventState(\n ReceivableEvents.ReconnectionStatusChanged,\n RNFishjamClientModule.reconnectionStatus,\n );\n\n return { peerStatus, reconnectionStatus };\n}\nexport type JoinRoomConfig<\n PeerMetadata extends GenericMetadata = GenericMetadata,\n> = {\n /**\n * Fishjam URL\n */\n url: string;\n /**\n * Token received from server (or Room Manager)\n */\n peerToken: string;\n /**\n * String indexed record with metadata, that will be available to all other peers\n */\n peerMetadata?: PeerMetadata;\n /**\n * Additional connection configuration\n */\n config?: ConnectionConfig;\n};\n\n/**\n * Connect/leave room. And get connection status.\n * @group Hooks\n * @category Connection\n */\nexport function useConnection() {\n const { peerStatus, reconnectionStatus } = useConnectionStatus();\n\n const joinRoom = useCallback(\n async <PeerMetadata extends GenericMetadata = GenericMetadata>({\n url,\n peerToken,\n peerMetadata,\n config,\n }: JoinRoomConfig<PeerMetadata>) => {\n await joinRoomClient(url, peerToken, peerMetadata, config);\n },\n [],\n );\n\n const leaveRoom = useCallback(() => {\n leaveRoomClient();\n }, []);\n\n return {\n /**\n * Join room and start streaming camera and microphone\n *\n * See {@link JoinRoomConfig} for parameter list\n */\n joinRoom,\n /**\n * Leave room and stop streaming\n * @type function\n */\n leaveRoom,\n peerStatus,\n reconnectionStatus,\n };\n}\n"]}
1
+ {"version":3,"file":"useConnection.js","sourceRoot":"","sources":["../../src/hooks/useConnection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAEL,QAAQ,IAAI,cAAc,EAC1B,SAAS,IAAI,eAAe,GAC7B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,qBAAqB,EAAE,EAC5B,gBAAgB,GACjB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAEvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAqBnD,SAAS,mBAAmB;IAC1B,MAAM,UAAU,GAAG,oBAAoB,CACrC,gBAAgB,CAAC,iBAAiB,EAClC,qBAAqB,CAAC,UAAU,CACjC,CAAC;IAEF,MAAM,kBAAkB,GAAG,oBAAoB,CAC7C,gBAAgB,CAAC,yBAAyB,EAC1C,qBAAqB,CAAC,kBAAkB,CACzC,CAAC;IAEF,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAC;AAC5C,CAAC;AAoCD;;;;GAIG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,EAAE,UAAU,EAAE,kBAAkB,EAAE,GAAG,mBAAmB,EAAE,CAAC;IAEjE,MAAM,QAAQ,GAAG,WAAW,CAC1B,KAAK,EAA0D,EAC7D,GAAG,EACH,SAAS,EACT,YAAY,EACZ,MAAM,EACN,SAAS,GACoB,EAAE,EAAE;QACjC,MAAM,UAAU,GAAG,SAAS;YAC1B,CAAC,CAAC,GAAG,sBAAsB,IAAI,SAAS,EAAE;YAC1C,CAAC,CAAC,SAAS,CAAC;QAEd,MAAM,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC;QAEhD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CACb,4DAA4D,CAC7D,CAAC;QACJ,CAAC;QAED,MAAM,cAAc,CAAC,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;IACpE,CAAC,EACD,EAAE,CACH,CAAC;IAEF,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE;QACjC,eAAe,EAAE,CAAC;IACpB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO;QACL;;;;WAIG;QACH,QAAQ;QACR;;;WAGG;QACH,SAAS;QACT,UAAU;QACV,kBAAkB;KACnB,CAAC;AACJ,CAAC","sourcesContent":["import { useCallback } from 'react';\nimport {\n ConnectionConfig,\n joinRoom as joinRoomClient,\n leaveRoom as leaveRoomClient,\n} from '../common/client';\n\nimport RNFishjamClientModule, {\n ReceivableEvents,\n} from '../RNFishjamClientModule';\nimport { useFishjamEventState } from './internal/useFishjamEventState';\nimport { GenericMetadata } from '../types';\nimport { FISHJAM_WS_CONNECT_URL } from '../consts';\n\n/**\n * Represents the possible statuses of a peer while reconnecting to room\n *\n * - `idle` - No reconnection in progress. See {@link PeerStatus} for more details\n * - `reconnecting` - Peer is in the process of reconnecting.\n * - `error` - There was an error in the reconnection process.\n */\nexport type ReconnectionStatus = 'idle' | 'reconnecting' | 'error';\n\n/**\n * Represents the possible statuses of a peer connection to a room (websocket state).\n *\n * - `idle` - Peer is not connected, either never connected or successfully disconnected.\n * - `connecting` - Peer is in the process of connecting.\n * - `connected` - Peer has successfully connected.\n * - `error` - There was an error in the connection process.\n */\nexport type PeerStatus = 'connecting' | 'connected' | 'error' | 'idle';\n\nfunction useConnectionStatus() {\n const peerStatus = useFishjamEventState(\n ReceivableEvents.PeerStatusChanged,\n RNFishjamClientModule.peerStatus,\n );\n\n const reconnectionStatus = useFishjamEventState(\n ReceivableEvents.ReconnectionStatusChanged,\n RNFishjamClientModule.reconnectionStatus,\n );\n\n return { peerStatus, reconnectionStatus };\n}\nexport type JoinRoomConfig<\n PeerMetadata extends GenericMetadata = GenericMetadata,\n> = {\n /**\n * Token received from server (or Room Manager)\n */\n peerToken: string;\n /**\n * String indexed record with metadata, that will be available to all other peers\n */\n peerMetadata?: PeerMetadata;\n /**\n * Additional connection configuration\n */\n config?: ConnectionConfig;\n} & (\n | {\n /**\n * Fishjam ID, which is used to connect to the room.\n * Only use in sandbox.\n * If provided, `url` must not be set.\n */\n fishjamId: string;\n url?: never;\n }\n | {\n /**\n * Fishjam URL, used to connect to the room.\n * If provided, `fishjamId` must not be set.\n */\n url: string;\n fishjamId?: never;\n }\n);\n\n/**\n * Connect/leave room. And get connection status.\n * @group Hooks\n * @category Connection\n */\nexport function useConnection() {\n const { peerStatus, reconnectionStatus } = useConnectionStatus();\n\n const joinRoom = useCallback(\n async <PeerMetadata extends GenericMetadata = GenericMetadata>({\n url,\n peerToken,\n peerMetadata,\n config,\n fishjamId,\n }: JoinRoomConfig<PeerMetadata>) => {\n const connectUrl = fishjamId\n ? `${FISHJAM_WS_CONNECT_URL}/${fishjamId}`\n : undefined;\n\n const fishjamUrl = fishjamId ? connectUrl : url;\n\n if (!fishjamUrl) {\n throw new Error(\n 'Either fishjamId or url must be provided to join the room.',\n );\n }\n\n await joinRoomClient(fishjamUrl, peerToken, peerMetadata, config);\n },\n [],\n );\n\n const leaveRoom = useCallback(() => {\n leaveRoomClient();\n }, []);\n\n return {\n /**\n * Join room and start streaming camera and microphone\n *\n * See {@link JoinRoomConfig} for parameter list\n */\n joinRoom,\n /**\n * Leave room and stop streaming\n * @type function\n */\n leaveRoom,\n peerStatus,\n reconnectionStatus,\n };\n}\n"]}
@@ -0,0 +1,24 @@
1
+ import { Camera } from 'react-native-whip-whep';
2
+ /**
3
+ * @category Livestream
4
+ */
5
+ export interface useLivestreamStreamerResult {
6
+ /**
7
+ * Callback used to start publishing the selected audio and video media streams.
8
+ *
9
+ * @remarks
10
+ * Calling {@link connect} multiple times will have the effect of only publishing the **last** specified inputs.
11
+ */
12
+ connect: (token: string, urlOverride?: string) => Promise<void>;
13
+ /** Callback to stop publishing anything previously published with {@link connect} */
14
+ disconnect: () => void;
15
+ }
16
+ /**
17
+ * Hook for publishing a livestream, which can be then received with {@link useLivestreamViewer}
18
+ * @category Livestream
19
+ * @group Hooks
20
+ */
21
+ export declare const useLivestreamStreamer: ({ camera, }: {
22
+ camera?: Camera;
23
+ }) => useLivestreamStreamerResult;
24
+ //# sourceMappingURL=useLivestreamStreamer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLivestreamStreamer.d.ts","sourceRoot":"","sources":["../../src/hooks/useLivestreamStreamer.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,MAAM,EACP,MAAM,wBAAwB,CAAC;AAGhC;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C;;;;;OAKG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,qFAAqF;IACrF,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAAI,aAEnC;IACD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,KAAG,2BA+BH,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { useCallback, useRef } from 'react';
2
+ import { connectWhipClient, createWhipClient, disconnectWhipClient, cameras, } from 'react-native-whip-whep';
3
+ import { FISHJAM_WHIP_URL } from '../consts';
4
+ /**
5
+ * Hook for publishing a livestream, which can be then received with {@link useLivestreamViewer}
6
+ * @category Livestream
7
+ * @group Hooks
8
+ */
9
+ export const useLivestreamStreamer = ({ camera, }) => {
10
+ const isWhipClientCreatedRef = useRef(false);
11
+ const connect = useCallback(async (token, urlOverride) => {
12
+ if (isWhipClientCreatedRef.current) {
13
+ return;
14
+ }
15
+ const resolvedUrl = urlOverride ?? FISHJAM_WHIP_URL;
16
+ createWhipClient(resolvedUrl, {
17
+ authToken: token,
18
+ }, camera?.id ?? cameras[0].id);
19
+ isWhipClientCreatedRef.current = true;
20
+ await connectWhipClient();
21
+ }, [camera]);
22
+ const disconnect = useCallback(() => {
23
+ // TODO: Remove when FCE-1786 fixed
24
+ if (isWhipClientCreatedRef.current) {
25
+ disconnectWhipClient();
26
+ isWhipClientCreatedRef.current = false;
27
+ }
28
+ }, []);
29
+ return { connect, disconnect };
30
+ };
31
+ //# sourceMappingURL=useLivestreamStreamer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLivestreamStreamer.js","sourceRoot":"","sources":["../../src/hooks/useLivestreamStreamer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,OAAO,GAER,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAiB7C;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,EACpC,MAAM,GAGP,EAA+B,EAAE;IAChC,MAAM,sBAAsB,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAE7C,MAAM,OAAO,GAAG,WAAW,CACzB,KAAK,EAAE,KAAa,EAAE,WAAoB,EAAE,EAAE;QAC5C,IAAI,sBAAsB,CAAC,OAAO,EAAE,CAAC;YACnC,OAAO;QACT,CAAC;QACD,MAAM,WAAW,GAAG,WAAW,IAAI,gBAAgB,CAAC;QACpD,gBAAgB,CACd,WAAW,EACX;YACE,SAAS,EAAE,KAAK;SACjB,EACD,MAAM,EAAE,EAAE,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAC5B,CAAC;QACF,sBAAsB,CAAC,OAAO,GAAG,IAAI,CAAC;QACtC,MAAM,iBAAiB,EAAE,CAAC;IAC5B,CAAC,EACD,CAAC,MAAM,CAAC,CACT,CAAC;IAEF,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE;QAClC,mCAAmC;QACnC,IAAI,sBAAsB,CAAC,OAAO,EAAE,CAAC;YACnC,oBAAoB,EAAE,CAAC;YACvB,sBAAsB,CAAC,OAAO,GAAG,KAAK,CAAC;QACzC,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;AACjC,CAAC,CAAC","sourcesContent":["import { useCallback, useRef } from 'react';\nimport {\n connectWhipClient,\n createWhipClient,\n disconnectWhipClient,\n cameras,\n Camera,\n} from 'react-native-whip-whep';\nimport { FISHJAM_WHIP_URL } from '../consts';\n\n/**\n * @category Livestream\n */\nexport interface useLivestreamStreamerResult {\n /**\n * Callback used to start publishing the selected audio and video media streams.\n *\n * @remarks\n * Calling {@link connect} multiple times will have the effect of only publishing the **last** specified inputs.\n */\n connect: (token: string, urlOverride?: string) => Promise<void>;\n /** Callback to stop publishing anything previously published with {@link connect} */\n disconnect: () => void;\n}\n\n/**\n * Hook for publishing a livestream, which can be then received with {@link useLivestreamViewer}\n * @category Livestream\n * @group Hooks\n */\nexport const useLivestreamStreamer = ({\n camera,\n}: {\n camera?: Camera;\n}): useLivestreamStreamerResult => {\n const isWhipClientCreatedRef = useRef(false);\n\n const connect = useCallback(\n async (token: string, urlOverride?: string) => {\n if (isWhipClientCreatedRef.current) {\n return;\n }\n const resolvedUrl = urlOverride ?? FISHJAM_WHIP_URL;\n createWhipClient(\n resolvedUrl,\n {\n authToken: token,\n },\n camera?.id ?? cameras[0].id,\n );\n isWhipClientCreatedRef.current = true;\n await connectWhipClient();\n },\n [camera],\n );\n\n const disconnect = useCallback(() => {\n // TODO: Remove when FCE-1786 fixed\n if (isWhipClientCreatedRef.current) {\n disconnectWhipClient();\n isWhipClientCreatedRef.current = false;\n }\n }, []);\n\n return { connect, disconnect };\n};\n"]}
@@ -0,0 +1,27 @@
1
+ export type ConnectViewerConfig = {
2
+ token: string;
3
+ streamId?: never;
4
+ } | {
5
+ streamId: string;
6
+ token?: never;
7
+ };
8
+ /**
9
+ * @category Livestream
10
+ */
11
+ export interface useLivestreamViewerResult {
12
+ /**
13
+ * Callback to start receiving a livestream.
14
+ * If the livestream is private, provide `token`.
15
+ * If the livestream is public, provide `streamId`.
16
+ */
17
+ connect: (config: ConnectViewerConfig, url?: string) => Promise<void>;
18
+ /** Disconnect from a stream previously connected to with {@link connect} */
19
+ disconnect: () => void;
20
+ }
21
+ /**
22
+ * Hook for receiving a published livestream.
23
+ * @category Livestream
24
+ * @group Hooks
25
+ */
26
+ export declare const useLivestreamViewer: () => useLivestreamViewerResult;
27
+ //# sourceMappingURL=useLivestreamViewer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLivestreamViewer.d.ts","sourceRoot":"","sources":["../../src/hooks/useLivestreamViewer.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,mBAAmB,GAC3B;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,KAAK,CAAA;CAAE,GACnC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC;AAOxC;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,OAAO,EAAE,CAAC,MAAM,EAAE,mBAAmB,EAAE,GAAG,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE,4EAA4E;IAC5E,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,QAAO,yBAsBtC,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { useCallback, useRef } from 'react';
2
+ import { connectWhepClient, createWhepClient, disconnectWhepClient, } from 'react-native-whip-whep';
3
+ import { FISHJAM_WHEP_URL } from '../consts';
4
+ const urlFromConfig = (config) => {
5
+ if (config.streamId)
6
+ return `${FISHJAM_WHEP_URL}/${config.streamId}`;
7
+ return FISHJAM_WHEP_URL;
8
+ };
9
+ /**
10
+ * Hook for receiving a published livestream.
11
+ * @category Livestream
12
+ * @group Hooks
13
+ */
14
+ export const useLivestreamViewer = () => {
15
+ const isWhepClientCreatedRef = useRef(false);
16
+ const connect = useCallback(async (config, url) => {
17
+ createWhepClient(url ?? urlFromConfig(config), {
18
+ authToken: config.token,
19
+ });
20
+ isWhepClientCreatedRef.current = true;
21
+ await connectWhepClient();
22
+ }, []);
23
+ const disconnect = useCallback(() => {
24
+ // TODO: Remove when FCE-1786 fixed
25
+ if (isWhepClientCreatedRef.current) {
26
+ disconnectWhepClient();
27
+ }
28
+ }, []);
29
+ return { connect, disconnect };
30
+ };
31
+ //# sourceMappingURL=useLivestreamViewer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLivestreamViewer.js","sourceRoot":"","sources":["../../src/hooks/useLivestreamViewer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAM7C,MAAM,aAAa,GAAG,CAAC,MAA2B,EAAE,EAAE;IACpD,IAAI,MAAM,CAAC,QAAQ;QAAE,OAAO,GAAG,gBAAgB,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;IACrE,OAAO,gBAAgB,CAAC;AAC1B,CAAC,CAAC;AAgBF;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAA8B,EAAE;IACjE,MAAM,sBAAsB,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAE7C,MAAM,OAAO,GAAG,WAAW,CACzB,KAAK,EAAE,MAA2B,EAAE,GAAY,EAAE,EAAE;QAClD,gBAAgB,CAAC,GAAG,IAAI,aAAa,CAAC,MAAM,CAAC,EAAE;YAC7C,SAAS,EAAE,MAAM,CAAC,KAAK;SACxB,CAAC,CAAC;QACH,sBAAsB,CAAC,OAAO,GAAG,IAAI,CAAC;QACtC,MAAM,iBAAiB,EAAE,CAAC;IAC5B,CAAC,EACD,EAAE,CACH,CAAC;IAEF,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE;QAClC,mCAAmC;QACnC,IAAI,sBAAsB,CAAC,OAAO,EAAE,CAAC;YACnC,oBAAoB,EAAE,CAAC;QACzB,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;AACjC,CAAC,CAAC","sourcesContent":["import { useCallback, useRef } from 'react';\nimport {\n connectWhepClient,\n createWhepClient,\n disconnectWhepClient,\n} from 'react-native-whip-whep';\nimport { FISHJAM_WHEP_URL } from '../consts';\n\nexport type ConnectViewerConfig =\n | { token: string; streamId?: never }\n | { streamId: string; token?: never };\n\nconst urlFromConfig = (config: ConnectViewerConfig) => {\n if (config.streamId) return `${FISHJAM_WHEP_URL}/${config.streamId}`;\n return FISHJAM_WHEP_URL;\n};\n\n/**\n * @category Livestream\n */\nexport interface useLivestreamViewerResult {\n /**\n * Callback to start receiving a livestream.\n * If the livestream is private, provide `token`.\n * If the livestream is public, provide `streamId`.\n */\n connect: (config: ConnectViewerConfig, url?: string) => Promise<void>;\n /** Disconnect from a stream previously connected to with {@link connect} */\n disconnect: () => void;\n}\n\n/**\n * Hook for receiving a published livestream.\n * @category Livestream\n * @group Hooks\n */\nexport const useLivestreamViewer = (): useLivestreamViewerResult => {\n const isWhepClientCreatedRef = useRef(false);\n\n const connect = useCallback(\n async (config: ConnectViewerConfig, url?: string) => {\n createWhepClient(url ?? urlFromConfig(config), {\n authToken: config.token,\n });\n isWhepClientCreatedRef.current = true;\n await connectWhepClient();\n },\n [],\n );\n\n const disconnect = useCallback(() => {\n // TODO: Remove when FCE-1786 fixed\n if (isWhepClientCreatedRef.current) {\n disconnectWhepClient();\n }\n }, []);\n\n return { connect, disconnect };\n};\n"]}
@@ -4,9 +4,13 @@
4
4
  * @group Hooks
5
5
  */
6
6
  export declare function useMicrophone(): {
7
- /** Informs if microphone is streaming audio */
7
+ /** Informs if microphone audio track is active */
8
8
  isMicrophoneOn: boolean;
9
- /** Function to toggle microphone on/off */
9
+ /** Toggles microphone on/off based on the value of `isMicrophoneOn` */
10
10
  toggleMicrophone: () => Promise<void>;
11
+ /** Starts microphone and requests permission if needed */
12
+ startMicrophone: () => Promise<void>;
13
+ /** Stops microphone (mutes the track without removing it) */
14
+ stopMicrophone: () => Promise<void>;
11
15
  };
12
16
  //# sourceMappingURL=useMicrophone.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useMicrophone.d.ts","sourceRoot":"","sources":["../../src/hooks/useMicrophone.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,wBAAgB,aAAa;IAWzB,+CAA+C;;IAE/C,2CAA2C;;EAG9C"}
1
+ {"version":3,"file":"useMicrophone.d.ts","sourceRoot":"","sources":["../../src/hooks/useMicrophone.ts"],"names":[],"mappings":"AAMA;;;;GAIG;AACH,wBAAgB,aAAa;IAmBzB,kDAAkD;;IAElD,uEAAuE;;IAEvE,0DAA0D;;IAE1D,6DAA6D;;EAGhE"}
@@ -11,11 +11,21 @@ export function useMicrophone() {
11
11
  const toggleMicrophone = useCallback(async () => {
12
12
  await RNFishjamClientModule.toggleMicrophone();
13
13
  }, []);
14
+ const startMicrophone = useCallback(async () => {
15
+ await RNFishjamClientModule.startMicrophone();
16
+ }, []);
17
+ const stopMicrophone = useCallback(async () => {
18
+ await RNFishjamClientModule.stopMicrophone();
19
+ }, []);
14
20
  return {
15
- /** Informs if microphone is streaming audio */
21
+ /** Informs if microphone audio track is active */
16
22
  isMicrophoneOn,
17
- /** Function to toggle microphone on/off */
23
+ /** Toggles microphone on/off based on the value of `isMicrophoneOn` */
18
24
  toggleMicrophone,
25
+ /** Starts microphone and requests permission if needed */
26
+ startMicrophone,
27
+ /** Stops microphone (mutes the track without removing it) */
28
+ stopMicrophone,
19
29
  };
20
30
  }
21
31
  //# sourceMappingURL=useMicrophone.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useMicrophone.js","sourceRoot":"","sources":["../../src/hooks/useMicrophone.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAEpC,OAAO,qBAAqB,EAAE,EAC5B,gBAAgB,GACjB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAEvE;;;;GAIG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,cAAc,GAAG,oBAAoB,CACzC,gBAAgB,CAAC,cAAc,EAC/B,qBAAqB,CAAC,cAAc,CACrC,CAAC;IAEF,MAAM,gBAAgB,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QAC9C,MAAM,qBAAqB,CAAC,gBAAgB,EAAE,CAAC;IACjD,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO;QACL,+CAA+C;QAC/C,cAAc;QACd,2CAA2C;QAC3C,gBAAgB;KACjB,CAAC;AACJ,CAAC","sourcesContent":["import { useCallback } from 'react';\n\nimport RNFishjamClientModule, {\n ReceivableEvents,\n} from '../RNFishjamClientModule';\nimport { useFishjamEventState } from './internal/useFishjamEventState';\n\n/**\n * This hook can toggle microphone on/off and provides current microphone state.\n * @category Devices\n * @group Hooks\n */\nexport function useMicrophone() {\n const isMicrophoneOn = useFishjamEventState(\n ReceivableEvents.IsMicrophoneOn,\n RNFishjamClientModule.isMicrophoneOn,\n );\n\n const toggleMicrophone = useCallback(async () => {\n await RNFishjamClientModule.toggleMicrophone();\n }, []);\n\n return {\n /** Informs if microphone is streaming audio */\n isMicrophoneOn,\n /** Function to toggle microphone on/off */\n toggleMicrophone,\n };\n}\n"]}
1
+ {"version":3,"file":"useMicrophone.js","sourceRoot":"","sources":["../../src/hooks/useMicrophone.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,qBAAqB,EAAE,EAC5B,gBAAgB,GACjB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAEvE;;;;GAIG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,cAAc,GAAG,oBAAoB,CACzC,gBAAgB,CAAC,cAAc,EAC/B,qBAAqB,CAAC,cAAc,CACrC,CAAC;IAEF,MAAM,gBAAgB,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QAC9C,MAAM,qBAAqB,CAAC,gBAAgB,EAAE,CAAC;IACjD,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,eAAe,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QAC7C,MAAM,qBAAqB,CAAC,eAAe,EAAE,CAAC;IAChD,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,cAAc,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QAC5C,MAAM,qBAAqB,CAAC,cAAc,EAAE,CAAC;IAC/C,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO;QACL,kDAAkD;QAClD,cAAc;QACd,uEAAuE;QACvE,gBAAgB;QAChB,0DAA0D;QAC1D,eAAe;QACf,6DAA6D;QAC7D,cAAc;KACf,CAAC;AACJ,CAAC","sourcesContent":["import { useCallback } from 'react';\nimport RNFishjamClientModule, {\n ReceivableEvents,\n} from '../RNFishjamClientModule';\nimport { useFishjamEventState } from './internal/useFishjamEventState';\n\n/**\n * This hook can toggle microphone on/off and provides current microphone state.\n * @category Devices\n * @group Hooks\n */\nexport function useMicrophone() {\n const isMicrophoneOn = useFishjamEventState(\n ReceivableEvents.IsMicrophoneOn,\n RNFishjamClientModule.isMicrophoneOn,\n );\n\n const toggleMicrophone = useCallback(async () => {\n await RNFishjamClientModule.toggleMicrophone();\n }, []);\n\n const startMicrophone = useCallback(async () => {\n await RNFishjamClientModule.startMicrophone();\n }, []);\n\n const stopMicrophone = useCallback(async () => {\n await RNFishjamClientModule.stopMicrophone();\n }, []);\n\n return {\n /** Informs if microphone audio track is active */\n isMicrophoneOn,\n /** Toggles microphone on/off based on the value of `isMicrophoneOn` */\n toggleMicrophone,\n /** Starts microphone and requests permission if needed */\n startMicrophone,\n /** Stops microphone (mutes the track without removing it) */\n stopMicrophone,\n };\n}\n"]}
@@ -0,0 +1,20 @@
1
+ import { RoomType } from '../types';
2
+ export type UseSandboxProps = {
3
+ fishjamId: string;
4
+ fishjamUrl?: never;
5
+ } | {
6
+ fishjamId?: never;
7
+ fishjamUrl: string;
8
+ };
9
+ export declare const useSandbox: ({ fishjamId, fishjamUrl }: UseSandboxProps) => {
10
+ getSandboxPeerToken: (roomName: string, peerName: string, roomType?: RoomType) => Promise<string>;
11
+ getSandboxViewerToken: (roomName: string) => Promise<string>;
12
+ getSandboxLivestream: (roomName: string, isPublic?: boolean) => Promise<{
13
+ streamerToken: string;
14
+ room: {
15
+ id: string;
16
+ name: string;
17
+ };
18
+ }>;
19
+ };
20
+ //# sourceMappingURL=useSandbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSandbox.d.ts","sourceRoot":"","sources":["../../src/hooks/useSandbox.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAUpC,MAAM,MAAM,eAAe,GACvB;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,KAAK,CAAA;CAAE,GACzC;IAAE,SAAS,CAAC,EAAE,KAAK,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9C,eAAO,MAAM,UAAU,GAAI,2BAA2B,eAAe;oCAMvD,MAAM,YACN,MAAM,aACN,QAAQ;sCA0B2B,MAAM;qCAwBzC,MAAM,aACN,OAAO;uBAiBA,MAAM;cACf;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE;;CASvC,CAAC"}
@@ -0,0 +1,56 @@
1
+ import { FISHJAM_HTTP_CONNECT_URL } from '../consts';
2
+ export const useSandbox = ({ fishjamId, fishjamUrl }) => {
3
+ const managerUrl = fishjamUrl
4
+ ? `${fishjamUrl}/room-manager`
5
+ : `${FISHJAM_HTTP_CONNECT_URL}/${fishjamId}/room-manager`;
6
+ const getSandboxPeerToken = async (roomName, peerName, roomType = 'conference') => {
7
+ try {
8
+ const url = new URL(managerUrl);
9
+ url.searchParams.set('roomName', roomName);
10
+ url.searchParams.set('peerName', peerName);
11
+ url.searchParams.set('roomType', roomType);
12
+ const res = await fetch(url.toString());
13
+ if (!res.ok) {
14
+ throw new Error(`Room '${roomName}' or peer '${peerName}' does not exist or cannot retrieve peer token.`);
15
+ }
16
+ const data = await res.json();
17
+ return data.peerToken;
18
+ }
19
+ catch (error) {
20
+ throw new Error(`Failed to get peer token for room '${roomName}', peer '${peerName}': ${error instanceof Error ? error.message : String(error)}`);
21
+ }
22
+ };
23
+ const getSandboxViewerToken = async (roomName) => {
24
+ try {
25
+ const url = new URL(`${managerUrl}/${roomName}/livestream-viewer-token`);
26
+ const res = await fetch(url);
27
+ if (!res.ok) {
28
+ throw new Error(`Room '${roomName}' does not exist or cannot retrieve viewer token.`);
29
+ }
30
+ const data = await res.json();
31
+ return data.token;
32
+ }
33
+ catch (error) {
34
+ throw new Error(`Failed to get viewer token for room '${roomName}': ${error instanceof Error ? error.message : String(error)}`);
35
+ }
36
+ };
37
+ const getSandboxLivestream = async (roomName, isPublic = false) => {
38
+ const url = new URL(`${managerUrl}/livestream`);
39
+ url.searchParams.set('roomName', roomName);
40
+ url.searchParams.set('public', isPublic.toString());
41
+ console.log({ sanurl: url.toString() });
42
+ const res = await fetch(url);
43
+ if (!res.ok) {
44
+ console.log(await res.json());
45
+ throw new Error(`Failed to retrieve streamer token for '${roomName}' livestream room.`);
46
+ }
47
+ const data = await res.json();
48
+ return data;
49
+ };
50
+ return {
51
+ getSandboxPeerToken,
52
+ getSandboxViewerToken,
53
+ getSandboxLivestream,
54
+ };
55
+ };
56
+ //# sourceMappingURL=useSandbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSandbox.js","sourceRoot":"","sources":["../../src/hooks/useSandbox.ts"],"names":[],"mappings":"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","sourcesContent":["import { FISHJAM_HTTP_CONNECT_URL } from '../consts';\nimport { RoomType } from '../types';\n\ntype BasicInfo = { id: string; name: string };\ntype RoomManagerResponse = {\n peerToken: string;\n url: string;\n room: BasicInfo;\n peer: BasicInfo;\n};\n\nexport type UseSandboxProps =\n | { fishjamId: string; fishjamUrl?: never }\n | { fishjamId?: never; fishjamUrl: string };\n\nexport const useSandbox = ({ fishjamId, fishjamUrl }: UseSandboxProps) => {\n const managerUrl = fishjamUrl\n ? `${fishjamUrl}/room-manager`\n : `${FISHJAM_HTTP_CONNECT_URL}/${fishjamId}/room-manager`;\n\n const getSandboxPeerToken = async (\n roomName: string,\n peerName: string,\n roomType: RoomType = 'conference',\n ) => {\n try {\n const url = new URL(managerUrl);\n url.searchParams.set('roomName', roomName);\n url.searchParams.set('peerName', peerName);\n url.searchParams.set('roomType', roomType);\n\n const res = await fetch(url.toString());\n\n if (!res.ok) {\n throw new Error(\n `Room '${roomName}' or peer '${peerName}' does not exist or cannot retrieve peer token.`,\n );\n }\n const data: RoomManagerResponse = await res.json();\n return data.peerToken;\n } catch (error) {\n throw new Error(\n `Failed to get peer token for room '${roomName}', peer '${peerName}': ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n };\n\n const getSandboxViewerToken = async (roomName: string) => {\n try {\n const url = new URL(`${managerUrl}/${roomName}/livestream-viewer-token`);\n const res = await fetch(url);\n\n if (!res.ok) {\n throw new Error(\n `Room '${roomName}' does not exist or cannot retrieve viewer token.`,\n );\n }\n\n const data: { token: string } = await res.json();\n\n return data.token;\n } catch (error) {\n throw new Error(\n `Failed to get viewer token for room '${roomName}': ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n };\n\n const getSandboxLivestream = async (\n roomName: string,\n isPublic: boolean = false,\n ) => {\n const url = new URL(`${managerUrl}/livestream`);\n url.searchParams.set('roomName', roomName);\n url.searchParams.set('public', isPublic.toString());\n\n console.log({ sanurl: url.toString() });\n const res = await fetch(url);\n if (!res.ok) {\n console.log(await res.json());\n throw new Error(\n `Failed to retrieve streamer token for '${roomName}' livestream room.`,\n );\n }\n\n const data = await res.json();\n return data as {\n streamerToken: string;\n room: { id: string; name: string };\n };\n };\n\n return {\n getSandboxPeerToken,\n getSandboxViewerToken,\n getSandboxLivestream,\n };\n};\n"]}
package/build/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type { SimulcastConfig, VideoLayout, GenericMetadata, TrackMetadata, Brand, } from './types';
1
+ export type { SimulcastConfig, VideoLayout, GenericMetadata, TrackMetadata, Brand, RoomType, } from './types';
2
2
  export type { ConnectionConfig } from './common/client';
3
3
  export { updatePeerMetadata } from './common/metadata';
4
4
  export {
@@ -8,10 +8,11 @@ joinRoom,
8
8
  leaveRoom, } from './common/client';
9
9
  export type { VideoPreviewViewProps } from './components/VideoPreviewView';
10
10
  export type { VideoRendererProps } from './components/VideoRendererView';
11
- export type { LivestreamViewProps, LivestreamViewRef, } from './components/LivestreamView';
11
+ export type { LivestreamViewerProps, LivestreamViewerRef, } from './components/LivestreamViewer';
12
12
  export { VideoPreviewView } from './components/VideoPreviewView';
13
13
  export { VideoRendererView } from './components/VideoRendererView';
14
- export { LivestreamView } from './components/LivestreamView';
14
+ export { LivestreamViewer } from './components/LivestreamViewer';
15
+ export { LivestreamStreamer } from './components/LivestreamStreamer';
15
16
  export type { Peer, PeerId, Track, TrackId, TrackType, VadStatus, EncodingReason, TrackBase, AudioTrack, VideoTrack, UsePeersResult, PeerWithTracks, PeerTrackMetadata, DistinguishedTracks, } from './hooks/usePeers';
16
17
  export type { AudioOutputDevice, AudioOutputDeviceType, AudioSessionMode, } from './hooks/useAudioSettings';
17
18
  export type { CameraId, Camera, CameraConfig, VideoQuality, CameraFacingDirection, CameraConfigBase, } from './hooks/useCamera';
@@ -19,7 +20,11 @@ export type { ScreenShareOptions, ScreenShareQuality, } from './hooks/useScreenS
19
20
  export type { ForegroundServiceConfig } from './hooks/useForegroundService';
20
21
  export type { JoinRoomConfig, ReconnectionStatus, PeerStatus, } from './hooks/useConnection';
21
22
  export type { AppScreenShareData } from './hooks/useAppScreenShare';
22
- export type { UseLivestreamResult } from './hooks/useLivestream';
23
+ export type { useLivestreamViewerResult } from './hooks/useLivestreamViewer';
24
+ export type { useLivestreamStreamerResult } from './hooks/useLivestreamStreamer';
25
+ export type { UseSandboxProps } from './hooks/useSandbox';
26
+ export type { LivestreamStreamerProps } from './components/LivestreamStreamer';
27
+ export type { ConnectViewerConfig } from './hooks/useLivestreamViewer';
23
28
  export { useAudioSettings } from './hooks/useAudioSettings';
24
29
  export { useBandwidthEstimation } from './hooks/useBandwidthEstimation';
25
30
  export { useCamera } from './hooks/useCamera';
@@ -32,7 +37,10 @@ export { usePeers } from './hooks/usePeers';
32
37
  export { useForegroundService } from './hooks/useForegroundService';
33
38
  export { useConnection } from './hooks/useConnection';
34
39
  export { useUpdatePeerMetadata } from './hooks/useUpdatePeerMetadata';
35
- export { useLivestream } from './hooks/useLivestream';
40
+ export { useLivestreamViewer } from './hooks/useLivestreamViewer';
41
+ export { useLivestreamStreamer } from './hooks/useLivestreamStreamer';
42
+ export { useSandbox } from './hooks/useSandbox';
43
+ export { cameras } from 'react-native-whip-whep';
36
44
  export { useCameraPermissions, useMicrophonePermissions, } from './hooks/usePermissions';
37
45
  export type { FishjamRoomProps } from './components/FishjamRoom';
38
46
  export { FishjamRoom } from './components/FishjamRoom';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAGA,YAAY,EACV,eAAe,EACf,WAAW,EACX,eAAe,EACf,aAAa,EACb,KAAK,GACN,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAIxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO;AACL,kBAAkB;AAClB,QAAQ;AACR,kBAAkB;AAClB,SAAS,GACV,MAAM,iBAAiB,CAAC;AAIzB,YAAY,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAC3E,YAAY,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACzE,YAAY,EACV,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAI7D,YAAY,EACV,IAAI,EACJ,MAAM,EACN,KAAK,EACL,OAAO,EACP,SAAS,EACT,SAAS,EACT,cAAc,EACd,SAAS,EACT,UAAU,EACV,UAAU,EACV,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EACV,iBAAiB,EACjB,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,0BAA0B,CAAC;AAElC,YAAY,EACV,QAAQ,EACR,MAAM,EACN,YAAY,EACZ,YAAY,EACZ,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EACV,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAC5E,YAAY,EACV,cAAc,EACd,kBAAkB,EAClB,UAAU,GACX,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,YAAY,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAIjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAGtD,OAAO,EACL,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"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"}
package/build/index.js CHANGED
@@ -9,7 +9,8 @@ joinRoom,
9
9
  leaveRoom, } from './common/client';
10
10
  export { VideoPreviewView } from './components/VideoPreviewView';
11
11
  export { VideoRendererView } from './components/VideoRendererView';
12
- export { LivestreamView } from './components/LivestreamView';
12
+ export { LivestreamViewer } from './components/LivestreamViewer';
13
+ export { LivestreamStreamer } from './components/LivestreamStreamer';
13
14
  // #endregion
14
15
  // #region hooks
15
16
  export { useAudioSettings } from './hooks/useAudioSettings';
@@ -24,7 +25,10 @@ export { usePeers } from './hooks/usePeers';
24
25
  export { useForegroundService } from './hooks/useForegroundService';
25
26
  export { useConnection } from './hooks/useConnection';
26
27
  export { useUpdatePeerMetadata } from './hooks/useUpdatePeerMetadata';
27
- export { useLivestream } from './hooks/useLivestream';
28
+ export { useLivestreamViewer } from './hooks/useLivestreamViewer';
29
+ export { useLivestreamStreamer } from './hooks/useLivestreamStreamer';
30
+ export { useSandbox } from './hooks/useSandbox';
31
+ export { cameras } from 'react-native-whip-whep';
28
32
  // #endregion
29
33
  export { useCameraPermissions, useMicrophonePermissions, } from './hooks/usePermissions';
30
34
  export { FishjamRoom } from './components/FishjamRoom';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAWlE,aAAa;AAEb,kBAAkB;AAClB,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO;AACL,kBAAkB;AAClB,QAAQ;AACR,kBAAkB;AAClB,SAAS,GACV,MAAM,iBAAiB,CAAC;AAWzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAgD7D,aAAa;AAEb,gBAAgB;AAChB,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,aAAa;AAEb,OAAO,EACL,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,yBAAyB,EAAE,CAAC","sourcesContent":["import { initializeWarningListener } from './utils/errorListener';\n\n// #region types\nexport type {\n SimulcastConfig,\n VideoLayout,\n GenericMetadata,\n TrackMetadata,\n Brand,\n} from './types';\nexport type { ConnectionConfig } from './common/client';\n// #endregion\n\n// #region methods\nexport { updatePeerMetadata } from './common/metadata';\nexport {\n /** @deprecated */\n joinRoom,\n /** @deprecated */\n leaveRoom,\n} from './common/client';\n// #endregion\n\n// #region components\nexport type { VideoPreviewViewProps } from './components/VideoPreviewView';\nexport type { VideoRendererProps } from './components/VideoRendererView';\nexport type {\n LivestreamViewProps,\n LivestreamViewRef,\n} from './components/LivestreamView';\n\nexport { VideoPreviewView } from './components/VideoPreviewView';\nexport { VideoRendererView } from './components/VideoRendererView';\nexport { LivestreamView } from './components/LivestreamView';\n// #endregion\n\n// #region types for hooks\nexport type {\n Peer,\n PeerId,\n Track,\n TrackId,\n TrackType,\n VadStatus,\n EncodingReason,\n TrackBase,\n AudioTrack,\n VideoTrack,\n UsePeersResult,\n PeerWithTracks,\n PeerTrackMetadata,\n DistinguishedTracks,\n} from './hooks/usePeers';\n\nexport type {\n AudioOutputDevice,\n AudioOutputDeviceType,\n AudioSessionMode,\n} from './hooks/useAudioSettings';\n\nexport type {\n CameraId,\n Camera,\n CameraConfig,\n VideoQuality,\n CameraFacingDirection,\n CameraConfigBase,\n} from './hooks/useCamera';\n\nexport type {\n ScreenShareOptions,\n ScreenShareQuality,\n} from './hooks/useScreenShare';\nexport type { ForegroundServiceConfig } from './hooks/useForegroundService';\nexport type {\n JoinRoomConfig,\n ReconnectionStatus,\n PeerStatus,\n} from './hooks/useConnection';\nexport type { AppScreenShareData } from './hooks/useAppScreenShare';\nexport type { UseLivestreamResult } from './hooks/useLivestream';\n// #endregion\n\n// #region hooks\nexport { useAudioSettings } from './hooks/useAudioSettings';\nexport { useBandwidthEstimation } from './hooks/useBandwidthEstimation';\nexport { useCamera } from './hooks/useCamera';\nexport { useMicrophone } from './hooks/useMicrophone';\nexport { useScreenShare } from './hooks/useScreenShare';\nexport { useAppScreenShare } from './hooks/useAppScreenShare';\nexport { useReconnection } from './hooks/useReconnection';\nexport { usePeerStatus } from './hooks/usePeerStatus';\nexport { usePeers } from './hooks/usePeers';\nexport { useForegroundService } from './hooks/useForegroundService';\nexport { useConnection } from './hooks/useConnection';\nexport { useUpdatePeerMetadata } from './hooks/useUpdatePeerMetadata';\nexport { useLivestream } from './hooks/useLivestream';\n// #endregion\n\nexport {\n useCameraPermissions,\n useMicrophonePermissions,\n} from './hooks/usePermissions';\n\nexport type { FishjamRoomProps } from './components/FishjamRoom';\nexport { FishjamRoom } from './components/FishjamRoom';\n\ninitializeWarningListener();\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAYlE,aAAa;AAEb,kBAAkB;AAClB,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO;AACL,kBAAkB;AAClB,QAAQ;AACR,kBAAkB;AAClB,SAAS,GACV,MAAM,iBAAiB,CAAC;AAWzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAoDrE,aAAa;AAEb,gBAAgB;AAChB,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,aAAa;AAEb,OAAO,EACL,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,yBAAyB,EAAE,CAAC","sourcesContent":["import { initializeWarningListener } from './utils/errorListener';\n\n// #region types\nexport type {\n SimulcastConfig,\n VideoLayout,\n GenericMetadata,\n TrackMetadata,\n Brand,\n RoomType,\n} from './types';\nexport type { ConnectionConfig } from './common/client';\n// #endregion\n\n// #region methods\nexport { updatePeerMetadata } from './common/metadata';\nexport {\n /** @deprecated */\n joinRoom,\n /** @deprecated */\n leaveRoom,\n} from './common/client';\n// #endregion\n\n// #region components\nexport type { VideoPreviewViewProps } from './components/VideoPreviewView';\nexport type { VideoRendererProps } from './components/VideoRendererView';\nexport type {\n LivestreamViewerProps,\n LivestreamViewerRef,\n} from './components/LivestreamViewer';\n\nexport { VideoPreviewView } from './components/VideoPreviewView';\nexport { VideoRendererView } from './components/VideoRendererView';\nexport { LivestreamViewer } from './components/LivestreamViewer';\nexport { LivestreamStreamer } from './components/LivestreamStreamer';\n// #endregion\n\n// #region types for hooks\nexport type {\n Peer,\n PeerId,\n Track,\n TrackId,\n TrackType,\n VadStatus,\n EncodingReason,\n TrackBase,\n AudioTrack,\n VideoTrack,\n UsePeersResult,\n PeerWithTracks,\n PeerTrackMetadata,\n DistinguishedTracks,\n} from './hooks/usePeers';\n\nexport type {\n AudioOutputDevice,\n AudioOutputDeviceType,\n AudioSessionMode,\n} from './hooks/useAudioSettings';\n\nexport type {\n CameraId,\n Camera,\n CameraConfig,\n VideoQuality,\n CameraFacingDirection,\n CameraConfigBase,\n} from './hooks/useCamera';\n\nexport type {\n ScreenShareOptions,\n ScreenShareQuality,\n} from './hooks/useScreenShare';\nexport type { ForegroundServiceConfig } from './hooks/useForegroundService';\nexport type {\n JoinRoomConfig,\n ReconnectionStatus,\n PeerStatus,\n} from './hooks/useConnection';\nexport type { AppScreenShareData } from './hooks/useAppScreenShare';\nexport type { useLivestreamViewerResult } from './hooks/useLivestreamViewer';\nexport type { useLivestreamStreamerResult } from './hooks/useLivestreamStreamer';\nexport type { UseSandboxProps } from './hooks/useSandbox';\nexport type { LivestreamStreamerProps } from './components/LivestreamStreamer';\nexport type { ConnectViewerConfig } from './hooks/useLivestreamViewer';\n// #endregion\n\n// #region hooks\nexport { useAudioSettings } from './hooks/useAudioSettings';\nexport { useBandwidthEstimation } from './hooks/useBandwidthEstimation';\nexport { useCamera } from './hooks/useCamera';\nexport { useMicrophone } from './hooks/useMicrophone';\nexport { useScreenShare } from './hooks/useScreenShare';\nexport { useAppScreenShare } from './hooks/useAppScreenShare';\nexport { useReconnection } from './hooks/useReconnection';\nexport { usePeerStatus } from './hooks/usePeerStatus';\nexport { usePeers } from './hooks/usePeers';\nexport { useForegroundService } from './hooks/useForegroundService';\nexport { useConnection } from './hooks/useConnection';\nexport { useUpdatePeerMetadata } from './hooks/useUpdatePeerMetadata';\nexport { useLivestreamViewer } from './hooks/useLivestreamViewer';\nexport { useLivestreamStreamer } from './hooks/useLivestreamStreamer';\nexport { useSandbox } from './hooks/useSandbox';\nexport { cameras } from 'react-native-whip-whep';\n// #endregion\n\nexport {\n useCameraPermissions,\n useMicrophonePermissions,\n} from './hooks/usePermissions';\n\nexport type { FishjamRoomProps } from './components/FishjamRoom';\nexport { FishjamRoom } from './components/FishjamRoom';\n\ninitializeWarningListener();\n"]}
package/build/types.d.ts CHANGED
@@ -29,5 +29,6 @@ declare const brand: unique symbol;
29
29
  export type Brand<T, TBrand extends string> = T & {
30
30
  [brand]: TBrand;
31
31
  };
32
+ export type RoomType = 'conference' | 'audio-only' | 'livestream';
32
33
  export {};
33
34
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,KAAK,CAAC;AAEzC;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,YAAY,GAAG,QAAQ,GAAG,kBAAkB,GAAG,kBAAkB,CAAC;CACzE,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAGtD,OAAO,CAAC,MAAM,KAAK,EAAE,OAAO,MAAM,CAAC;AACnC;;GAEG;AACH,MAAM,MAAM,KAAK,CAAC,CAAC,EAAE,MAAM,SAAS,MAAM,IAAI,CAAC,GAAG;IAAE,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,KAAK,CAAC;AAEzC;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,YAAY,GAAG,QAAQ,GAAG,kBAAkB,GAAG,kBAAkB,CAAC;CACzE,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAGtD,OAAO,CAAC,MAAM,KAAK,EAAE,OAAO,MAAM,CAAC;AACnC;;GAEG;AACH,MAAM,MAAM,KAAK,CAAC,CAAC,EAAE,MAAM,SAAS,MAAM,IAAI,CAAC,GAAG;IAAE,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtE,MAAM,MAAM,QAAQ,GAAG,YAAY,GAAG,YAAY,GAAG,YAAY,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * `FILL` or `FIT` - it works just like RN Image component. `FILL` fills the whole view\n * with video and it may cut some parts of the video. `FIT` scales the video so the whole\n * video is visible, but it may leave some empty space in the view.\n */\nexport type VideoLayout = 'FILL' | 'FIT';\n\n/**\n * A type describing simulcast configuration.\n *\n * At the moment, simulcast track is initialized in three versions - low, medium and high.\n * High resolution is the original track resolution, while medium and low resolutions are\n * the original track resolution scaled down by 2 and 4 respectively.\n */\nexport type SimulcastConfig = {\n /**\n * whether to simulcast track or not. By default simulcast is disabled.\n */\n enabled: boolean;\n};\n\nexport type TrackMetadata = {\n active: boolean;\n type: 'microphone' | 'camera' | 'screenShareVideo' | 'screenShareAudio';\n};\n\nexport type GenericMetadata = Record<string, unknown>;\n\n// branded types are useful for restricting where given value can be passed\ndeclare const brand: unique symbol;\n/**\n * Branded type\n */\nexport type Brand<T, TBrand extends string> = T & { [brand]: TBrand };\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * `FILL` or `FIT` - it works just like RN Image component. `FILL` fills the whole view\n * with video and it may cut some parts of the video. `FIT` scales the video so the whole\n * video is visible, but it may leave some empty space in the view.\n */\nexport type VideoLayout = 'FILL' | 'FIT';\n\n/**\n * A type describing simulcast configuration.\n *\n * At the moment, simulcast track is initialized in three versions - low, medium and high.\n * High resolution is the original track resolution, while medium and low resolutions are\n * the original track resolution scaled down by 2 and 4 respectively.\n */\nexport type SimulcastConfig = {\n /**\n * whether to simulcast track or not. By default simulcast is disabled.\n */\n enabled: boolean;\n};\n\nexport type TrackMetadata = {\n active: boolean;\n type: 'microphone' | 'camera' | 'screenShareVideo' | 'screenShareAudio';\n};\n\nexport type GenericMetadata = Record<string, unknown>;\n\n// branded types are useful for restricting where given value can be passed\ndeclare const brand: unique symbol;\n/**\n * Branded type\n */\nexport type Brand<T, TBrand extends string> = T & { [brand]: TBrand };\n\nexport type RoomType = 'conference' | 'audio-only' | 'livestream';\n"]}
@@ -328,40 +328,51 @@ class RNFishjamClient: FishjamClientListener {
328
328
  }
329
329
 
330
330
  func toggleMicrophone() async throws -> Bool {
331
- if let audioTrack = getLocalAudioTrack() {
332
- setMicrophoneTrackState(audioTrack, enabled: !isMicrophoneOn)
331
+ if isMicrophoneOn {
332
+ try stopMicrophone()
333
333
  } else {
334
- try await startMicrophone()
334
+ try await startMicrophone()
335
335
  }
336
336
 
337
- try updateLocalAudioTrackMetadata(metadata: getMicrophoneTrackMetadata())
338
-
339
337
  return isMicrophoneOn
340
338
  }
341
339
 
342
340
  func startMicrophone() async throws {
343
- guard await PermissionUtils.requestMicrophonePermission() else {
344
- emit(event: .warning(message: "Microphone permission not granted."))
345
- return
346
- }
347
- let microphoneTrack = RNFishjamClient.fishjamClient!.createAudioTrack(
348
- metadata: getMicrophoneTrackMetadata().toMetadata())
349
- setAudioSessionMode()
350
- setMicrophoneTrackState(microphoneTrack, enabled: true)
351
- emitEndpoints()
352
- }
353
-
354
- private func getMicrophoneTrackMetadata() -> [String: Any] {
341
+ // If microphone track already exist, just enable it
342
+ if let microphoneTrack = getLocalAudioTrack() {
343
+ try setMicrophoneTrackState(microphoneTrack, enabled: true)
344
+ } else {
345
+ guard await PermissionUtils.requestMicrophonePermission() else {
346
+ emit(event: .warning(message: "Microphone permission not granted."))
347
+ return
348
+ }
349
+ let microphoneTrack = RNFishjamClient.fishjamClient!.createAudioTrack(
350
+ metadata: getMicrophoneTrackMetadata(isEnabled: true).toMetadata())
351
+ setAudioSessionMode()
352
+ try setMicrophoneTrackState(microphoneTrack, enabled: true)
353
+ emitEndpoints()
354
+ }
355
+ }
356
+
357
+ func stopMicrophone() throws {
358
+ guard let microphoneTrack = getLocalAudioTrack() else {
359
+ return
360
+ }
361
+ try setMicrophoneTrackState(microphoneTrack, enabled: false)
362
+ }
363
+
364
+ private func getMicrophoneTrackMetadata(isEnabled: Bool) -> [String: Any] {
355
365
  return [
356
- "active": isMicrophoneOn,
357
- "paused": !isMicrophoneOn, //TODO: FCE-711
366
+ "active": isEnabled,
367
+ "paused": !isEnabled, //TODO: FCE-711
358
368
  "type": "microphone",
359
369
  ]
360
370
  }
361
371
 
362
- private func setMicrophoneTrackState(_ microphoneTrack: LocalAudioTrack, enabled: Bool) {
372
+ private func setMicrophoneTrackState(_ microphoneTrack: LocalAudioTrack, enabled: Bool) throws {
363
373
  microphoneTrack.enabled = enabled
364
374
  isMicrophoneOn = enabled
375
+ try updateLocalAudioTrackMetadata(metadata: getMicrophoneTrackMetadata(isEnabled: enabled))
365
376
  emit(event: .isMicrophoneOn(enabled: enabled))
366
377
  }
367
378
 
@@ -146,6 +146,14 @@ public class RNFishjamClientModule: Module {
146
146
  AsyncFunction("toggleMicrophone") {
147
147
  try await rnFishjamClient.toggleMicrophone()
148
148
  }
149
+
150
+ AsyncFunction("startMicrophone") {
151
+ try await rnFishjamClient.startMicrophone()
152
+ }
153
+
154
+ AsyncFunction("stopMicrophone") {
155
+ try rnFishjamClient.stopMicrophone()
156
+ }
149
157
 
150
158
  AsyncFunction("toggleCamera") {
151
159
  try rnFishjamClient.toggleCamera()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fishjam-cloud/react-native-client",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "description": "A React Native client for Fishjam",
5
5
  "author": "Fishjam Team",
6
6
  "license": "Apache-2.0",
@@ -7,5 +7,8 @@ export type FishjamPluginOptions = {
7
7
  iphoneDeploymentTarget?: string;
8
8
  enableScreensharing?: boolean;
9
9
  supportsPictureInPicture?: boolean;
10
+ appGroupContainerId?: string;
11
+ mainTargetName?: string;
12
+ broadcastExtensionTargetName?: string;
10
13
  };
11
14
  } | undefined;
@@ -1,6 +1,6 @@
1
1
  import { ConfigPlugin } from '@expo/config-plugins';
2
2
  import { FishjamPluginOptions } from './types';
3
- export declare const SBE_PODFILE_SNIPPET = "\ntarget 'FishjamScreenBroadcastExtension' do\n pod 'FishjamCloudClient/Broadcast'\nend";
3
+ export declare function getSbePodfileSnippet(props: FishjamPluginOptions): string;
4
4
  /**
5
5
  * Applies screen sharing plugin if enabled. In order for screensharing to work, we need to copy extension files to your iOS project.
6
6
  * Allows for dynamically changing deploymentTarget.
@@ -33,16 +33,19 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.SBE_PODFILE_SNIPPET = void 0;
36
+ exports.getSbePodfileSnippet = getSbePodfileSnippet;
37
37
  // ios-related code was mostly copied from OneSignal expo plugin: https://github.com/OneSignal/onesignal-expo-plugin/blob/main/onesignal/withOneSignalIos.ts
38
38
  const config_plugins_1 = require("@expo/config-plugins");
39
39
  const fs = __importStar(require("promise-fs"));
40
40
  const path = __importStar(require("path"));
41
- const SBE_TARGET_NAME = 'FishjamScreenBroadcastExtension';
42
- exports.SBE_PODFILE_SNIPPET = `
43
- target '${SBE_TARGET_NAME}' do
44
- pod 'FishjamCloudClient/Broadcast'
45
- end`;
41
+ function getSbeTargetName(props) {
42
+ return (props?.ios?.broadcastExtensionTargetName ||
43
+ 'FishjamScreenBroadcastExtension');
44
+ }
45
+ function getSbePodfileSnippet(props) {
46
+ const targetName = getSbeTargetName(props);
47
+ return `\ntarget '${targetName}' do\n pod 'FishjamCloudClient/Broadcast'\nend`;
48
+ }
46
49
  const TARGETED_DEVICE_FAMILY = `"1,2"`;
47
50
  const IPHONEOS_DEPLOYMENT_TARGET = '15.1';
48
51
  const GROUP_IDENTIFIER_TEMPLATE_REGEX = /{{GROUP_IDENTIFIER}}/gm;
@@ -50,8 +53,9 @@ const BUNDLE_IDENTIFIER_TEMPLATE_REGEX = /{{BUNDLE_IDENTIFIER}}/gm;
50
53
  /**
51
54
  * A helper function for updating a value in a file for given regex
52
55
  */
53
- async function updateFileWithRegex(iosPath, fileName, regex, value) {
54
- const filePath = `${iosPath}/${SBE_TARGET_NAME}/${fileName}`;
56
+ async function updateFileWithRegex(iosPath, fileName, regex, value, props) {
57
+ const targetName = getSbeTargetName(props);
58
+ const filePath = `${iosPath}/${targetName}/${fileName}`;
55
59
  let file = await fs.readFile(filePath, { encoding: 'utf-8' });
56
60
  file = file.replace(regex, value);
57
61
  await fs.writeFile(filePath, file);
@@ -60,23 +64,24 @@ async function updateFileWithRegex(iosPath, fileName, regex, value) {
60
64
  * Inserts a required target to Podfile.
61
65
  * This is needed to provide the dependency of FishjamCloudClient/Broadcast to the extension.
62
66
  */
63
- async function updatePodfile(iosPath) {
67
+ async function updatePodfile(iosPath, props) {
68
+ const podfileSnippet = getSbePodfileSnippet(props);
64
69
  let matches;
65
70
  try {
66
71
  const podfile = await fs.readFile(`${iosPath}/Podfile`, {
67
72
  encoding: 'utf-8',
68
73
  });
69
- matches = podfile.match(exports.SBE_PODFILE_SNIPPET);
74
+ matches = podfile.match(podfileSnippet);
70
75
  }
71
76
  catch (e) {
72
77
  console.error('Error reading from Podfile: ', e);
73
78
  }
74
79
  if (matches) {
75
- console.log(`${SBE_TARGET_NAME} target already added to Podfile. Skipping...`);
80
+ console.log(`${getSbeTargetName(props)} target already added to Podfile. Skipping...`);
76
81
  return;
77
82
  }
78
83
  try {
79
- fs.appendFile(`${iosPath}/Podfile`, exports.SBE_PODFILE_SNIPPET);
84
+ fs.appendFile(`${iosPath}/Podfile`, podfileSnippet);
80
85
  }
81
86
  catch (e) {
82
87
  console.error('Error writing to Podfile: ', e);
@@ -86,10 +91,11 @@ async function updatePodfile(iosPath) {
86
91
  * Adds "App Group" permission
87
92
  * App Group allow your app and the FishjamScreenBroadcastExtension to communicate with each other.
88
93
  */
89
- const withAppGroupPermissions = (config) => {
94
+ const withAppGroupPermissions = (config, props) => {
90
95
  const APP_GROUP_KEY = 'com.apple.security.application-groups';
91
96
  const bundleIdentifier = config.ios?.bundleIdentifier || '';
92
- const groupIdentifier = `group.${bundleIdentifier}`;
97
+ const groupIdentifier = props?.ios?.appGroupContainerId || `group.${bundleIdentifier}`;
98
+ const mainTarget = props?.ios?.mainTargetName || '';
93
99
  config.ios ??= {};
94
100
  config.ios.entitlements ??= {};
95
101
  config.ios.entitlements[APP_GROUP_KEY] ??= [];
@@ -123,11 +129,12 @@ const withAppGroupPermissions = (config) => {
123
129
  projectObj.attributes.TargetAttributes[targetUuid].SystemCapabilities['com.apple.ApplicationGroups.iOS'] = {
124
130
  enabled: 1,
125
131
  };
126
- const entitlementsFilePath = `${props.modRequest.projectName}/${props.modRequest.projectName}.entitlements`;
132
+ const mainTargetName = mainTarget || props.modRequest.projectName;
133
+ const entitlementsFilePath = `${mainTargetName}/${mainTargetName}.entitlements`;
127
134
  const configurations = xcodeProject.pbxXCBuildConfigurationSection();
128
135
  Object.keys(configurations).forEach((key) => {
129
136
  const config = configurations[key];
130
- if (config.buildSettings?.PRODUCT_NAME?.includes(props.modRequest.projectName)) {
137
+ if (config.buildSettings?.PRODUCT_NAME?.includes(mainTargetName)) {
131
138
  if (!config.buildSettings.CODE_SIGN_ENTITLEMENTS) {
132
139
  config.buildSettings.CODE_SIGN_ENTITLEMENTS = entitlementsFilePath;
133
140
  }
@@ -141,11 +148,12 @@ const withAppGroupPermissions = (config) => {
141
148
  * Adds constants to Info.plist
142
149
  * In other to dynamically retreive extension's bundleId and group name we need to store it in Info.plist.
143
150
  */
144
- const withInfoPlistConstants = (config) => (0, config_plugins_1.withInfoPlist)(config, (configuration) => {
151
+ const withInfoPlistConstants = (config, props) => (0, config_plugins_1.withInfoPlist)(config, (configuration) => {
145
152
  const bundleIdentifier = configuration.ios?.bundleIdentifier || '';
146
- configuration.modResults['AppGroupName'] = `group.${bundleIdentifier}`;
153
+ const groupIdentifier = props?.ios?.appGroupContainerId || `group.${bundleIdentifier}`;
154
+ configuration.modResults['AppGroupName'] = groupIdentifier;
147
155
  configuration.modResults['ScreenShareExtensionBundleId'] =
148
- `${bundleIdentifier}.${SBE_TARGET_NAME}`;
156
+ `${bundleIdentifier}.${getSbeTargetName(props)}`;
149
157
  return configuration;
150
158
  });
151
159
  /**
@@ -156,14 +164,22 @@ const withFishjamSBE = (config, options) => (0, config_plugins_1.withXcodeProjec
156
164
  const appName = props.modRequest.projectName || '';
157
165
  const iosPath = props.modRequest.platformProjectRoot;
158
166
  const bundleIdentifier = props.ios?.bundleIdentifier;
167
+ const groupIdentifier = options?.ios?.appGroupContainerId || `group.${bundleIdentifier}`;
159
168
  const xcodeProject = props.modResults;
169
+ const targetName = getSbeTargetName(options);
160
170
  const pluginDir = require.resolve('@fishjam-cloud/react-native-client/package.json');
161
171
  const extensionSourceDir = path.join(pluginDir, '../plugin/broadcastExtensionFiles/');
162
- await updatePodfile(iosPath);
172
+ await updatePodfile(iosPath, options);
163
173
  const projPath = `${iosPath}/${appName}.xcodeproj/project.pbxproj`;
174
+ const templateTargetName = 'FishjamScreenBroadcastExtension';
164
175
  const extFiles = [
165
176
  'FishjamBroadcastSampleHandler.swift',
166
- `${SBE_TARGET_NAME}.entitlements`,
177
+ `${templateTargetName}.entitlements`,
178
+ `Info.plist`,
179
+ ];
180
+ const destFiles = [
181
+ 'FishjamBroadcastSampleHandler.swift',
182
+ `${targetName}.entitlements`,
167
183
  `Info.plist`,
168
184
  ];
169
185
  await xcodeProject.parse(async function (err) {
@@ -171,28 +187,26 @@ const withFishjamSBE = (config, options) => (0, config_plugins_1.withXcodeProjec
171
187
  console.error(`Error parsing iOS project: ${JSON.stringify(err)}`);
172
188
  return;
173
189
  }
174
- if (xcodeProject.pbxTargetByName(SBE_TARGET_NAME)) {
175
- console.log(`${SBE_TARGET_NAME} already exists in project. Skipping...`);
190
+ if (xcodeProject.pbxTargetByName(targetName)) {
191
+ console.log(`${targetName} already exists in project. Skipping...`);
176
192
  return;
177
193
  }
178
194
  try {
179
- // copy extension files
180
- await fs.mkdir(`${iosPath}/${SBE_TARGET_NAME}`, { recursive: true });
195
+ await fs.mkdir(`${iosPath}/${targetName}`, { recursive: true });
181
196
  for (let i = 0; i < extFiles.length; i++) {
182
- const extFile = extFiles[i];
183
- const targetFile = `${iosPath}/${SBE_TARGET_NAME}/${extFile}`;
184
- await fs.copyFile(`${extensionSourceDir}${extFile}`, targetFile);
197
+ const srcFile = `${extensionSourceDir}${extFiles[i]}`;
198
+ const destFile = `${iosPath}/${targetName}/${destFiles[i]}`;
199
+ await fs.copyFile(srcFile, destFile);
185
200
  }
186
201
  }
187
202
  catch (e) {
188
203
  console.error('Error copying extension files: ', e);
189
204
  }
190
- // update extension files
191
- await updateFileWithRegex(iosPath, `${SBE_TARGET_NAME}.entitlements`, GROUP_IDENTIFIER_TEMPLATE_REGEX, `group.${bundleIdentifier}`);
192
- await updateFileWithRegex(iosPath, 'FishjamBroadcastSampleHandler.swift', GROUP_IDENTIFIER_TEMPLATE_REGEX, `group.${bundleIdentifier}`);
193
- await updateFileWithRegex(iosPath, 'FishjamBroadcastSampleHandler.swift', BUNDLE_IDENTIFIER_TEMPLATE_REGEX, bundleIdentifier || '');
205
+ await updateFileWithRegex(iosPath, `${targetName}.entitlements`, GROUP_IDENTIFIER_TEMPLATE_REGEX, groupIdentifier, options);
206
+ await updateFileWithRegex(iosPath, 'FishjamBroadcastSampleHandler.swift', GROUP_IDENTIFIER_TEMPLATE_REGEX, groupIdentifier, options);
207
+ await updateFileWithRegex(iosPath, 'FishjamBroadcastSampleHandler.swift', BUNDLE_IDENTIFIER_TEMPLATE_REGEX, bundleIdentifier || '', options);
194
208
  // Create new PBXGroup for the extension
195
- const extGroup = xcodeProject.addPbxGroup(extFiles, SBE_TARGET_NAME, SBE_TARGET_NAME);
209
+ const extGroup = xcodeProject.addPbxGroup(extFiles, targetName, targetName);
196
210
  // Add the new PBXGroup to the top level group. This makes the
197
211
  // files / folder appear in the file explorer in Xcode.
198
212
  const groups = xcodeProject.hash.project.objects['PBXGroup'];
@@ -212,7 +226,7 @@ const withFishjamSBE = (config, options) => (0, config_plugins_1.withXcodeProjec
212
226
  projObjects['PBXTargetDependency'] || {};
213
227
  // Add the SBE target
214
228
  // This adds PBXTargetDependency and PBXContainerItemProxy for you
215
- const sbeTarget = xcodeProject.addTarget(SBE_TARGET_NAME, 'app_extension', SBE_TARGET_NAME, `${bundleIdentifier}.${SBE_TARGET_NAME}`);
229
+ const sbeTarget = xcodeProject.addTarget(targetName, 'app_extension', targetName, `${bundleIdentifier}.${targetName}`);
216
230
  // Add build phases to the new target
217
231
  xcodeProject.addBuildPhase(['FishjamBroadcastSampleHandler.swift'], 'PBXSourcesBuildPhase', 'Sources', sbeTarget.uuid);
218
232
  xcodeProject.addBuildPhase([], 'PBXResourcesBuildPhase', 'Resources', sbeTarget.uuid);
@@ -225,15 +239,14 @@ const withFishjamSBE = (config, options) => (0, config_plugins_1.withXcodeProjec
225
239
  const configurations = xcodeProject.pbxXCBuildConfigurationSection();
226
240
  for (const key in configurations) {
227
241
  if (typeof configurations[key].buildSettings !== 'undefined' &&
228
- configurations[key].buildSettings.PRODUCT_NAME ===
229
- `"${SBE_TARGET_NAME}"`) {
242
+ configurations[key].buildSettings.PRODUCT_NAME === `"${targetName}"`) {
230
243
  const buildSettingsObj = configurations[key].buildSettings;
231
244
  buildSettingsObj.IPHONEOS_DEPLOYMENT_TARGET =
232
245
  options?.ios?.iphoneDeploymentTarget ?? IPHONEOS_DEPLOYMENT_TARGET;
233
246
  buildSettingsObj.TARGETED_DEVICE_FAMILY = TARGETED_DEVICE_FAMILY;
234
- buildSettingsObj.CODE_SIGN_ENTITLEMENTS = `${SBE_TARGET_NAME}/${SBE_TARGET_NAME}.entitlements`;
247
+ buildSettingsObj.CODE_SIGN_ENTITLEMENTS = `${targetName}/${targetName}.entitlements`;
235
248
  buildSettingsObj.CODE_SIGN_STYLE = 'Automatic';
236
- buildSettingsObj.INFOPLIST_FILE = `${SBE_TARGET_NAME}/Info.plist`;
249
+ buildSettingsObj.INFOPLIST_FILE = `${targetName}/Info.plist`;
237
250
  buildSettingsObj.SWIFT_VERSION = '5.0';
238
251
  buildSettingsObj.MARKETING_VERSION = '1.0.0';
239
252
  buildSettingsObj.CURRENT_PROJECT_VERSION = '1';
@@ -258,8 +271,8 @@ const withFishjamPictureInPicture = (config, props) => (0, config_plugins_1.with
258
271
  */
259
272
  const withFishjamIos = (config, props) => {
260
273
  if (props?.ios?.enableScreensharing) {
261
- config = withAppGroupPermissions(config);
262
- config = withInfoPlistConstants(config);
274
+ config = withAppGroupPermissions(config, props);
275
+ config = withInfoPlistConstants(config, props);
263
276
  config = withFishjamSBE(config, props);
264
277
  }
265
278
  config = (0, config_plugins_1.withPodfileProperties)(config, (configuration) => {
@@ -1 +0,0 @@
1
- {"version":3,"file":"LivestreamView.d.ts","sourceRoot":"","sources":["../../src/components/LivestreamView.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,GAAG,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAkB,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3E,MAAM,MAAM,iBAAiB,GAAG,iBAAiB,CAAC;AAElD;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B;;;OAGG;IACH,WAAW,CAAC,EAAE,WAAW,GAAG,UAAU,CAAC;IACvC;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;OAEG;IACH,OAAO,CAAC,EAAE;QACR,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IAEF,GAAG,CAAC,EAAE,GAAG,CAAC,iBAAiB,CAAC,CAAC;CAC9B,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,8EAQ5B,mBAAmB,gCAUrB,CAAC"}
@@ -1,10 +0,0 @@
1
- import { WhepClientView } from 'react-native-whip-whep';
2
- /**
3
- * Renders a video player playing the livestream set up with {@link useLivestream} hook.
4
- *
5
- * @category Components
6
- * @param {object} props
7
- * @param {object} props.style
8
- */
9
- export const LivestreamView = ({ style, orientation, pipEnabled, autoStartPip, autoStopPip, pipSize, ref, }) => (<WhepClientView ref={ref} style={style} orientation={orientation} pipEnabled={pipEnabled} autoStartPip={autoStartPip} autoStopPip={autoStopPip} pipSize={pipSize}/>);
10
- //# sourceMappingURL=LivestreamView.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"LivestreamView.js","sourceRoot":"","sources":["../../src/components/LivestreamView.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAqB,MAAM,wBAAwB,CAAC;AA4C3E;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,EAC7B,KAAK,EACL,WAAW,EACX,UAAU,EACV,YAAY,EACZ,WAAW,EACX,OAAO,EACP,GAAG,GACiB,EAAE,EAAE,CAAC,CACzB,CAAC,cAAc,CACb,GAAG,CAAC,CAAC,GAAG,CAAC,CACT,KAAK,CAAC,CAAC,KAAsB,CAAC,CAC9B,WAAW,CAAC,CAAC,WAAW,CAAC,CACzB,UAAU,CAAC,CAAC,UAAU,CAAC,CACvB,YAAY,CAAC,CAAC,YAAY,CAAC,CAC3B,WAAW,CAAC,CAAC,WAAW,CAAC,CACzB,OAAO,CAAC,CAAC,OAAO,CAAC,EACjB,CACH,CAAC","sourcesContent":["import { CSSProperties, Ref } from 'react';\nimport { StyleProp, ViewStyle } from 'react-native';\nimport { WhepClientView, WhepClientViewRef } from 'react-native-whip-whep';\n\nexport type LivestreamViewRef = WhepClientViewRef;\n\n/**\n * Props of the LivestreamView component\n */\nexport type LivestreamViewProps = {\n /**\n * Styles of the LivestreamView component\n */\n style?: StyleProp<ViewStyle>;\n /**\n * Used to override the orientation of the video (from metadata).\n * Defaults to \"portrait\".\n */\n orientation?: 'landscape' | 'portrait';\n /**\n * A variable deciding whether the Picture-in-Picture is enabled.\n * Defaults to true.\n */\n pipEnabled?: boolean;\n /**\n * A variable deciding whether the Picture-in-Picture mode should be started automatically after the app is backgrounded.\n * Defaults to false.\n */\n autoStartPip?: boolean;\n /**\n * A variable deciding whether the Picture-in-Picture mode should be stopped automatically on iOS after the app is foregrounded.\n * Always enabled on Android as PiP is not supported in foreground.\n * Defaults to false.\n */\n autoStopPip?: boolean;\n /**\n * A variable deciding the size of the Picture-in-Picture mode.\n */\n pipSize?: {\n width: number;\n height: number;\n };\n\n ref?: Ref<LivestreamViewRef>;\n};\n\n/**\n * Renders a video player playing the livestream set up with {@link useLivestream} hook.\n *\n * @category Components\n * @param {object} props\n * @param {object} props.style\n */\nexport const LivestreamView = ({\n style,\n orientation,\n pipEnabled,\n autoStartPip,\n autoStopPip,\n pipSize,\n ref,\n}: LivestreamViewProps) => (\n <WhepClientView\n ref={ref}\n style={style as CSSProperties}\n orientation={orientation}\n pipEnabled={pipEnabled}\n autoStartPip={autoStartPip}\n autoStopPip={autoStopPip}\n pipSize={pipSize}\n />\n);\n"]}
@@ -1,6 +0,0 @@
1
- export interface UseLivestreamResult {
2
- connect: (url: string, token: string) => Promise<void>;
3
- disconnect: () => void;
4
- }
5
- export declare const useLivestream: () => UseLivestreamResult;
6
- //# sourceMappingURL=useLivestream.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useLivestream.d.ts","sourceRoot":"","sources":["../../src/hooks/useLivestream.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,eAAO,MAAM,aAAa,QAAO,mBAShC,CAAC"}
@@ -1,12 +0,0 @@
1
- import { useCallback } from 'react';
2
- import { connectWhepClient, createWhepClient, disconnectWhepClient, } from 'react-native-whip-whep';
3
- export const useLivestream = () => {
4
- const connect = useCallback(async (url, token) => {
5
- createWhepClient(url, {
6
- authToken: token,
7
- });
8
- await connectWhepClient();
9
- }, []);
10
- return { connect, disconnect: disconnectWhepClient };
11
- };
12
- //# sourceMappingURL=useLivestream.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useLivestream.js","sourceRoot":"","sources":["../../src/hooks/useLivestream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAOhC,MAAM,CAAC,MAAM,aAAa,GAAG,GAAwB,EAAE;IACrD,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,EAAE,GAAW,EAAE,KAAa,EAAE,EAAE;QAC/D,gBAAgB,CAAC,GAAG,EAAE;YACpB,SAAS,EAAE,KAAK;SACjB,CAAC,CAAC;QACH,MAAM,iBAAiB,EAAE,CAAC;IAC5B,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,CAAC;AACvD,CAAC,CAAC","sourcesContent":["import { useCallback } from 'react';\nimport {\n connectWhepClient,\n createWhepClient,\n disconnectWhepClient,\n} from 'react-native-whip-whep';\n\nexport interface UseLivestreamResult {\n connect: (url: string, token: string) => Promise<void>;\n disconnect: () => void;\n}\n\nexport const useLivestream = (): UseLivestreamResult => {\n const connect = useCallback(async (url: string, token: string) => {\n createWhepClient(url, {\n authToken: token,\n });\n await connectWhepClient();\n }, []);\n\n return { connect, disconnect: disconnectWhepClient };\n};\n"]}