@stream-io/video-react-native-sdk 1.22.2 → 1.23.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 (43) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/android/src/main/java/com/streamvideo/reactnative/callmanager/ProximityManager.kt +183 -0
  3. package/android/src/main/java/com/streamvideo/reactnative/callmanager/StreamInCallManagerModule.kt +12 -1
  4. package/dist/commonjs/components/Livestream/LivestreamPlayer/LivestreamPlayer.js +3 -2
  5. package/dist/commonjs/components/Livestream/LivestreamPlayer/LivestreamPlayer.js.map +1 -1
  6. package/dist/commonjs/components/Participant/FloatingParticipantView/index.js +13 -6
  7. package/dist/commonjs/components/Participant/FloatingParticipantView/index.js.map +1 -1
  8. package/dist/commonjs/components/Participant/FloatingParticipantView/useFloatingVideoDimensions.js +30 -0
  9. package/dist/commonjs/components/Participant/FloatingParticipantView/useFloatingVideoDimensions.js.map +1 -0
  10. package/dist/commonjs/constants/index.js +1 -6
  11. package/dist/commonjs/constants/index.js.map +1 -1
  12. package/dist/commonjs/hooks/useTrackDimensions.js +1 -1
  13. package/dist/commonjs/hooks/useTrackDimensions.js.map +1 -1
  14. package/dist/commonjs/version.js +1 -1
  15. package/dist/module/components/Livestream/LivestreamPlayer/LivestreamPlayer.js +3 -2
  16. package/dist/module/components/Livestream/LivestreamPlayer/LivestreamPlayer.js.map +1 -1
  17. package/dist/module/components/Participant/FloatingParticipantView/index.js +14 -7
  18. package/dist/module/components/Participant/FloatingParticipantView/index.js.map +1 -1
  19. package/dist/module/components/Participant/FloatingParticipantView/useFloatingVideoDimensions.js +23 -0
  20. package/dist/module/components/Participant/FloatingParticipantView/useFloatingVideoDimensions.js.map +1 -0
  21. package/dist/module/constants/index.js +0 -5
  22. package/dist/module/constants/index.js.map +1 -1
  23. package/dist/module/hooks/useTrackDimensions.js +1 -1
  24. package/dist/module/hooks/useTrackDimensions.js.map +1 -1
  25. package/dist/module/version.js +1 -1
  26. package/dist/typescript/components/Livestream/LivestreamPlayer/LivestreamPlayer.d.ts +3 -3
  27. package/dist/typescript/components/Livestream/LivestreamPlayer/LivestreamPlayer.d.ts.map +1 -1
  28. package/dist/typescript/components/Participant/FloatingParticipantView/index.d.ts.map +1 -1
  29. package/dist/typescript/components/Participant/FloatingParticipantView/useFloatingVideoDimensions.d.ts +9 -0
  30. package/dist/typescript/components/Participant/FloatingParticipantView/useFloatingVideoDimensions.d.ts.map +1 -0
  31. package/dist/typescript/constants/index.d.ts +0 -5
  32. package/dist/typescript/constants/index.d.ts.map +1 -1
  33. package/dist/typescript/hooks/useTrackDimensions.d.ts +1 -1
  34. package/dist/typescript/hooks/useTrackDimensions.d.ts.map +1 -1
  35. package/dist/typescript/version.d.ts +1 -1
  36. package/ios/StreamInCallManager.swift +105 -38
  37. package/package.json +3 -3
  38. package/src/components/Livestream/LivestreamPlayer/LivestreamPlayer.tsx +5 -3
  39. package/src/components/Participant/FloatingParticipantView/index.tsx +20 -6
  40. package/src/components/Participant/FloatingParticipantView/useFloatingVideoDimensions.tsx +36 -0
  41. package/src/constants/index.ts +0 -6
  42. package/src/hooks/useTrackDimensions.ts +2 -2
  43. package/src/version.ts +1 -1
@@ -0,0 +1,23 @@
1
+ import { useTrackDimensions } from '../../../hooks/useTrackDimensions';
2
+ export const useFloatingVideoDimensions = (containerDimensions, participant, trackType) => {
3
+ const containerWidth = containerDimensions?.width ?? 0;
4
+ const {
5
+ width,
6
+ height
7
+ } = useTrackDimensions(participant, trackType);
8
+ if (width === 0 || height === 0 || containerWidth === 0) {
9
+ return undefined;
10
+ }
11
+ const aspectRatio = width / height;
12
+
13
+ // based on Android AOSP PiP mode default dimensions algorithm
14
+ // 23% of the container width
15
+ const floatingVideoWidth = containerWidth * 0.23;
16
+ // the height is calculated based on the aspect ratio
17
+ const floatingVideoHeight = floatingVideoWidth / aspectRatio;
18
+ return {
19
+ width: floatingVideoWidth,
20
+ height: floatingVideoHeight
21
+ };
22
+ };
23
+ //# sourceMappingURL=useFloatingVideoDimensions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useTrackDimensions","useFloatingVideoDimensions","containerDimensions","participant","trackType","containerWidth","width","height","undefined","aspectRatio","floatingVideoWidth","floatingVideoHeight"],"sourceRoot":"../../../../../src","sources":["components/Participant/FloatingParticipantView/useFloatingVideoDimensions.tsx"],"mappings":"AAIA,SAASA,kBAAkB,QAAQ,mCAAmC;AAEtE,OAAO,MAAMC,0BAA0B,GAAGA,CACxCC,mBAKa,EACbC,WAA+C,EAC/CC,SAAyB,KACtB;EACH,MAAMC,cAAc,GAAGH,mBAAmB,EAAEI,KAAK,IAAI,CAAC;EACtD,MAAM;IAAEA,KAAK;IAAEC;EAAO,CAAC,GAAGP,kBAAkB,CAACG,WAAW,EAAEC,SAAS,CAAC;EAEpE,IAAIE,KAAK,KAAK,CAAC,IAAIC,MAAM,KAAK,CAAC,IAAIF,cAAc,KAAK,CAAC,EAAE;IACvD,OAAOG,SAAS;EAClB;EAEA,MAAMC,WAAW,GAAGH,KAAK,GAAGC,MAAM;;EAElC;EACA;EACA,MAAMG,kBAAkB,GAAGL,cAAc,GAAG,IAAI;EAChD;EACA,MAAMM,mBAAmB,GAAGD,kBAAkB,GAAGD,WAAW;EAE5D,OAAO;IACLH,KAAK,EAAEI,kBAAkB;IACzBH,MAAM,EAAEI;EACV,CAAC;AACH,CAAC","ignoreList":[]}
@@ -1,8 +1,3 @@
1
- export const FLOATING_VIDEO_VIEW_STYLE = {
2
- height: 140,
3
- width: 80,
4
- borderRadius: 10
5
- };
6
1
  export const defaultEmojiReactions = [{
7
2
  type: 'reaction',
8
3
  emoji_code: ':rolling_on_the_floor_laughing:',
@@ -1 +1 @@
1
- {"version":3,"names":["FLOATING_VIDEO_VIEW_STYLE","height","width","borderRadius","defaultEmojiReactions","type","emoji_code","custom","icon","Z_INDEX","IN_BACK","IN_MIDDLE","IN_FRONT"],"sourceRoot":"../../../src","sources":["constants/index.ts"],"mappings":"AAEA,OAAO,MAAMA,yBAAyB,GAAG;EACvCC,MAAM,EAAE,GAAG;EACXC,KAAK,EAAE,EAAE;EACTC,YAAY,EAAE;AAChB,CAAC;AAED,OAAO,MAAMC,qBAA2C,GAAG,CACzD;EACEC,IAAI,EAAE,UAAU;EAChBC,UAAU,EAAE,iCAAiC;EAC7CC,MAAM,EAAE,CAAC,CAAC;EACVC,IAAI,EAAE;AACR,CAAC,EACD;EACEH,IAAI,EAAE,UAAU;EAChBC,UAAU,EAAE,QAAQ;EACpBC,MAAM,EAAE,CAAC,CAAC;EACVC,IAAI,EAAE;AACR,CAAC,EACD;EACEH,IAAI,EAAE,UAAU;EAChBC,UAAU,EAAE,UAAU;EACtBC,MAAM,EAAE,CAAC,CAAC;EACVC,IAAI,EAAE;AACR,CAAC,EACD;EACEH,IAAI,EAAE,UAAU;EAChBC,UAAU,EAAE,WAAW;EACvBC,MAAM,EAAE,CAAC,CAAC;EACVC,IAAI,EAAE;AACR,CAAC,EACD;EACEH,IAAI,EAAE,UAAU;EAChBC,UAAU,EAAE,aAAa;EACzBC,MAAM,EAAE,CAAC,CAAC;EACVC,IAAI,EAAE;AACR,CAAC,EACD;EACEH,IAAI,EAAE,UAAU;EAChBC,UAAU,EAAE,gBAAgB;EAC5BC,MAAM,EAAE,CAAC,CAAC;EACVC,IAAI,EAAE;AACR,CAAC,EACD;EACEH,IAAI,EAAE,aAAa;EACnBC,UAAU,EAAE,eAAe;EAC3BC,MAAM,EAAE,CAAC,CAAC;EACVC,IAAI,EAAE;AACR,CAAC,CACF;AAED,OAAO,MAAMC,OAAO,GAAG;EACrBC,OAAO,EAAE,CAAC;EACVC,SAAS,EAAE,CAAC;EACZC,QAAQ,EAAE;AACZ,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["defaultEmojiReactions","type","emoji_code","custom","icon","Z_INDEX","IN_BACK","IN_MIDDLE","IN_FRONT"],"sourceRoot":"../../../src","sources":["constants/index.ts"],"mappings":"AAEA,OAAO,MAAMA,qBAA2C,GAAG,CACzD;EACEC,IAAI,EAAE,UAAU;EAChBC,UAAU,EAAE,iCAAiC;EAC7CC,MAAM,EAAE,CAAC,CAAC;EACVC,IAAI,EAAE;AACR,CAAC,EACD;EACEH,IAAI,EAAE,UAAU;EAChBC,UAAU,EAAE,QAAQ;EACpBC,MAAM,EAAE,CAAC,CAAC;EACVC,IAAI,EAAE;AACR,CAAC,EACD;EACEH,IAAI,EAAE,UAAU;EAChBC,UAAU,EAAE,UAAU;EACtBC,MAAM,EAAE,CAAC,CAAC;EACVC,IAAI,EAAE;AACR,CAAC,EACD;EACEH,IAAI,EAAE,UAAU;EAChBC,UAAU,EAAE,WAAW;EACvBC,MAAM,EAAE,CAAC,CAAC;EACVC,IAAI,EAAE;AACR,CAAC,EACD;EACEH,IAAI,EAAE,UAAU;EAChBC,UAAU,EAAE,aAAa;EACzBC,MAAM,EAAE,CAAC,CAAC;EACVC,IAAI,EAAE;AACR,CAAC,EACD;EACEH,IAAI,EAAE,UAAU;EAChBC,UAAU,EAAE,gBAAgB;EAC5BC,MAAM,EAAE,CAAC,CAAC;EACVC,IAAI,EAAE;AACR,CAAC,EACD;EACEH,IAAI,EAAE,aAAa;EACnBC,UAAU,EAAE,eAAe;EAC3BC,MAAM,EAAE,CAAC,CAAC;EACVC,IAAI,EAAE;AACR,CAAC,CACF;AAED,OAAO,MAAMC,OAAO,GAAG;EACrBC,OAAO,EAAE,CAAC;EACVC,SAAS,EAAE,CAAC;EACZC,QAAQ,EAAE;AACZ,CAAC","ignoreList":[]}
@@ -10,7 +10,7 @@ export function useTrackDimensions(participant, trackType) {
10
10
  const {
11
11
  videoStream,
12
12
  screenShareStream
13
- } = participant;
13
+ } = participant || {};
14
14
  const stream = trackType === 'screenShareTrack' ? screenShareStream : videoStream;
15
15
  const [track] = stream?.getVideoTracks() ?? [];
16
16
  const trackId = track?.id;
@@ -1 +1 @@
1
- {"version":3,"names":["useEffect","useState","NativeEventEmitter","NativeModules","useTrackDimensions","participant","trackType","videoStream","screenShareStream","stream","track","getVideoTracks","trackId","id","trackDimensions","setTrackDimensions","settings","getSettings","width","height","handleVideoTrackDimensionChanged","eventData","prev","webRTCEventEmitter","WebRTCModule","subscription","addListener","remove"],"sourceRoot":"../../../src","sources":["hooks/useTrackDimensions.ts"],"mappings":"AAIA,SAASA,SAAS,EAAEC,QAAQ,QAAQ,OAAO;AAC3C,SAASC,kBAAkB,EAAEC,aAAa,QAAQ,cAAc;;AAEhE;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,kBAAkBA,CAChCC,WAAmC,EACnCC,SAAyB,EACzB;EACA,MAAM;IAAEC,WAAW;IAAEC;EAAkB,CAAC,GAAGH,WAAW;EACtD,MAAMI,MAAM,GACVH,SAAS,KAAK,kBAAkB,GAAGE,iBAAiB,GAAGD,WAAW;EACpE,MAAM,CAACG,KAAK,CAAC,GAAGD,MAAM,EAAEE,cAAc,CAAC,CAAC,IAAI,EAAE;EAC9C,MAAMC,OAAO,GAAGF,KAAK,EAAEG,EAAE;EAEzB,MAAM,CAACC,eAAe,EAAEC,kBAAkB,CAAC,GAAGd,QAAQ,CAAC,MAAM;IAC3D,MAAMe,QAAQ,GAAGN,KAAK,EAAEO,WAAW,CAAC,CAAC;IACrC,MAAMC,KAAK,GAAGF,QAAQ,EAAEE,KAAK,IAAI,CAAC;IAClC,MAAMC,MAAM,GAAGH,QAAQ,EAAEG,MAAM,IAAI,CAAC;IACpC,OAAO;MACLD,KAAK;MACLC;IACF,CAAC;EACH,CAAC,CAAC;;EAEF;EACAnB,SAAS,CAAC,MAAM;IACd,IAAI,CAACY,OAAO,IAAI,CAACF,KAAK,EAAE;IAExB,MAAMU,gCAAgC,GAAIC,SAKzC,IAAK;MACJ;MACA,IAAIA,SAAS,CAACT,OAAO,KAAKA,OAAO,EAAE;QACjCG,kBAAkB,CAAEO,IAAI,IAAK;UAC3B,IACEA,IAAI,CAACJ,KAAK,KAAKG,SAAS,CAACH,KAAK,IAC9BI,IAAI,CAACH,MAAM,KAAKE,SAAS,CAACF,MAAM,EAChC;YACA,OAAOG,IAAI;UACb;UACA,OAAO;YAAEJ,KAAK,EAAEG,SAAS,CAACH,KAAK;YAAEC,MAAM,EAAEE,SAAS,CAACF;UAAO,CAAC;QAC7D,CAAC,CAAC;MACJ;IACF,CAAC;IAED,MAAM;MAAED,KAAK;MAAEC;IAAO,CAAC,GAAGT,KAAK,CAACO,WAAW,CAAC,CAAC;IAC7CF,kBAAkB,CAAEO,IAAI,IAAK;MAC3B,IAAIA,IAAI,CAACJ,KAAK,KAAKA,KAAK,IAAII,IAAI,CAACH,MAAM,KAAKA,MAAM,EAAE;QAClD,OAAOG,IAAI;MACb;MACA,OAAO;QACLJ,KAAK,EAAEA,KAAK,IAAI,CAAC;QACjBC,MAAM,EAAEA,MAAM,IAAI;MACpB,CAAC;IACH,CAAC,CAAC;IAEF,MAAMI,kBAAkB,GAAG,IAAIrB,kBAAkB,CAC/CC,aAAa,CAACqB,YAChB,CAAC;IACD,MAAMC,YAAY,GAAGF,kBAAkB,CAACG,WAAW,CACjD,4BAA4B,EAC5BN,gCACF,CAAC;IAED,OAAO,MAAM;MACXK,YAAY,CAACE,MAAM,CAAC,CAAC;IACvB,CAAC;EACH,CAAC,EAAE,CAACf,OAAO,EAAEF,KAAK,CAAC,CAAC;EAEpB,OAAOI,eAAe;AACxB","ignoreList":[]}
1
+ {"version":3,"names":["useEffect","useState","NativeEventEmitter","NativeModules","useTrackDimensions","participant","trackType","videoStream","screenShareStream","stream","track","getVideoTracks","trackId","id","trackDimensions","setTrackDimensions","settings","getSettings","width","height","handleVideoTrackDimensionChanged","eventData","prev","webRTCEventEmitter","WebRTCModule","subscription","addListener","remove"],"sourceRoot":"../../../src","sources":["hooks/useTrackDimensions.ts"],"mappings":"AAIA,SAASA,SAAS,EAAEC,QAAQ,QAAQ,OAAO;AAC3C,SAASC,kBAAkB,EAAEC,aAAa,QAAQ,cAAc;;AAEhE;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,kBAAkBA,CAChCC,WAA+C,EAC/CC,SAAyB,EACzB;EACA,MAAM;IAAEC,WAAW;IAAEC;EAAkB,CAAC,GAAGH,WAAW,IAAI,CAAC,CAAC;EAC5D,MAAMI,MAAM,GACVH,SAAS,KAAK,kBAAkB,GAAGE,iBAAiB,GAAGD,WAAW;EACpE,MAAM,CAACG,KAAK,CAAC,GAAGD,MAAM,EAAEE,cAAc,CAAC,CAAC,IAAI,EAAE;EAC9C,MAAMC,OAAO,GAAGF,KAAK,EAAEG,EAAE;EAEzB,MAAM,CAACC,eAAe,EAAEC,kBAAkB,CAAC,GAAGd,QAAQ,CAAC,MAAM;IAC3D,MAAMe,QAAQ,GAAGN,KAAK,EAAEO,WAAW,CAAC,CAAC;IACrC,MAAMC,KAAK,GAAGF,QAAQ,EAAEE,KAAK,IAAI,CAAC;IAClC,MAAMC,MAAM,GAAGH,QAAQ,EAAEG,MAAM,IAAI,CAAC;IACpC,OAAO;MACLD,KAAK;MACLC;IACF,CAAC;EACH,CAAC,CAAC;;EAEF;EACAnB,SAAS,CAAC,MAAM;IACd,IAAI,CAACY,OAAO,IAAI,CAACF,KAAK,EAAE;IAExB,MAAMU,gCAAgC,GAAIC,SAKzC,IAAK;MACJ;MACA,IAAIA,SAAS,CAACT,OAAO,KAAKA,OAAO,EAAE;QACjCG,kBAAkB,CAAEO,IAAI,IAAK;UAC3B,IACEA,IAAI,CAACJ,KAAK,KAAKG,SAAS,CAACH,KAAK,IAC9BI,IAAI,CAACH,MAAM,KAAKE,SAAS,CAACF,MAAM,EAChC;YACA,OAAOG,IAAI;UACb;UACA,OAAO;YAAEJ,KAAK,EAAEG,SAAS,CAACH,KAAK;YAAEC,MAAM,EAAEE,SAAS,CAACF;UAAO,CAAC;QAC7D,CAAC,CAAC;MACJ;IACF,CAAC;IAED,MAAM;MAAED,KAAK;MAAEC;IAAO,CAAC,GAAGT,KAAK,CAACO,WAAW,CAAC,CAAC;IAC7CF,kBAAkB,CAAEO,IAAI,IAAK;MAC3B,IAAIA,IAAI,CAACJ,KAAK,KAAKA,KAAK,IAAII,IAAI,CAACH,MAAM,KAAKA,MAAM,EAAE;QAClD,OAAOG,IAAI;MACb;MACA,OAAO;QACLJ,KAAK,EAAEA,KAAK,IAAI,CAAC;QACjBC,MAAM,EAAEA,MAAM,IAAI;MACpB,CAAC;IACH,CAAC,CAAC;IAEF,MAAMI,kBAAkB,GAAG,IAAIrB,kBAAkB,CAC/CC,aAAa,CAACqB,YAChB,CAAC;IACD,MAAMC,YAAY,GAAGF,kBAAkB,CAACG,WAAW,CACjD,4BAA4B,EAC5BN,gCACF,CAAC;IAED,OAAO,MAAM;MACXK,YAAY,CAACE,MAAM,CAAC,CAAC;IACvB,CAAC;EACH,CAAC,EAAE,CAACf,OAAO,EAAEF,KAAK,CAAC,CAAC;EAEpB,OAAOI,eAAe;AACxB","ignoreList":[]}
@@ -1,2 +1,2 @@
1
- export const version = '1.22.2';
1
+ export const version = '1.23.0';
2
2
  //# sourceMappingURL=version.js.map
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { PropsWithChildren } from 'react';
2
2
  import { type ViewerLivestreamProps } from '../ViewerLivestream';
3
3
  export type LivestreamPlayerProps = {
4
4
  /**
@@ -19,7 +19,7 @@ export type LivestreamPlayerProps = {
19
19
  *
20
20
  * `"asap"` behavior means joining the call as soon as it is possible
21
21
  * (either the `join_ahead_time_seconds` setting allows it, or the user
22
- * has a the capability to join backstage).
22
+ * has the capability to join backstage).
23
23
  *
24
24
  * `"live"` behavior means joining the call when it goes live.
25
25
  *
@@ -27,5 +27,5 @@ export type LivestreamPlayerProps = {
27
27
  */
28
28
  joinBehavior?: 'asap' | 'live';
29
29
  };
30
- export declare const LivestreamPlayer: ({ callType, callId, ViewerLivestream, joinBehavior, }: LivestreamPlayerProps) => React.JSX.Element | null;
30
+ export declare const LivestreamPlayer: ({ callType, callId, ViewerLivestream, joinBehavior, children, }: PropsWithChildren<LivestreamPlayerProps>) => React.JSX.Element | null;
31
31
  //# sourceMappingURL=LivestreamPlayer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LivestreamPlayer.d.ts","sourceRoot":"","sources":["../../../../../src/components/Livestream/LivestreamPlayer/LivestreamPlayer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AACnD,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,qBAAqB,CAAC;AAK7B,MAAM,MAAM,qBAAqB,GAAG;IAClC;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,gBAAgB,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC;IAE9D;;;;;;;;;;OAUG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAChC,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,uDAK9B,qBAAqB,6BA2CvB,CAAC"}
1
+ {"version":3,"file":"LivestreamPlayer.d.ts","sourceRoot":"","sources":["../../../../../src/components/Livestream/LivestreamPlayer/LivestreamPlayer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,iBAAiB,EAAuB,MAAM,OAAO,CAAC;AACtE,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,qBAAqB,CAAC;AAK7B,MAAM,MAAM,qBAAqB,GAAG;IAClC;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,gBAAgB,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC;IAE9D;;;;;;;;;;OAUG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAChC,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,iEAM9B,iBAAiB,CAAC,qBAAqB,CAAC,6BA4C1C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/Participant/FloatingParticipantView/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAEL,KAAK,SAAS,EAGd,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAKtB,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,kCAAkC,EACxC,MAAM,YAAY,CAAC;AAEpB,OAAO,EAEL,KAAK,6BAA6B,EAClC,KAAK,oBAAoB,EAC1B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAEtE,MAAM,MAAM,gCAAgC,GACxC,UAAU,GACV,WAAW,GACX,aAAa,GACb,cAAc,CAAC;AAEnB;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG,6BAA6B,GACtE,IAAI,CAAC,kCAAkC,EAAE,iBAAiB,CAAC,GAC3D,IAAI,CAAC,gBAAgB,EAAE,oBAAoB,CAAC,GAC5C,IAAI,CAAC,oBAAoB,EAAE,WAAW,GAAG,aAAa,CAAC,GAAG;IACxD;;OAEG;IACH,SAAS,CAAC,EAAE,gCAAgC,CAAC;IAC7C;;OAEG;IACH,WAAW,CAAC,EAAE,sBAAsB,CAAC;IACrC;;OAEG;IACH,oBAAoB,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC5C;;;OAGG;IACH,uBAAuB,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC/C;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B,CAAC;AA2BJ;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAAI,2PAcrC,4BAA4B,6BAsF9B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/Participant/FloatingParticipantView/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAEL,KAAK,SAAS,EAGd,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAKtB,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,kCAAkC,EACxC,MAAM,YAAY,CAAC;AAEpB,OAAO,EAEL,KAAK,6BAA6B,EAClC,KAAK,oBAAoB,EAC1B,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAEtE,MAAM,MAAM,gCAAgC,GACxC,UAAU,GACV,WAAW,GACX,aAAa,GACb,cAAc,CAAC;AAEnB;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG,6BAA6B,GACtE,IAAI,CAAC,kCAAkC,EAAE,iBAAiB,CAAC,GAC3D,IAAI,CAAC,gBAAgB,EAAE,oBAAoB,CAAC,GAC5C,IAAI,CAAC,oBAAoB,EAAE,WAAW,GAAG,aAAa,CAAC,GAAG;IACxD;;OAEG;IACH,SAAS,CAAC,EAAE,gCAAgC,CAAC;IAC7C;;OAEG;IACH,WAAW,CAAC,EAAE,sBAAsB,CAAC;IACrC;;OAEG;IACH,oBAAoB,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC5C;;;OAGG;IACH,uBAAuB,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC/C;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B,CAAC;AA2BJ;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAAI,2PAcrC,4BAA4B,6BAsG9B,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { StreamVideoParticipant, VideoTrackType } from '@stream-io/video-client';
2
+ export declare const useFloatingVideoDimensions: (containerDimensions: {
3
+ width: number;
4
+ height: number;
5
+ } | undefined, participant: StreamVideoParticipant | undefined, trackType: VideoTrackType) => {
6
+ width: number;
7
+ height: number;
8
+ } | undefined;
9
+ //# sourceMappingURL=useFloatingVideoDimensions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFloatingVideoDimensions.d.ts","sourceRoot":"","sources":["../../../../../src/components/Participant/FloatingParticipantView/useFloatingVideoDimensions.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,cAAc,EACf,MAAM,yBAAyB,CAAC;AAGjC,eAAO,MAAM,0BAA0B,GACrC,qBACI;IACE,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GACD,SAAS,EACb,aAAa,sBAAsB,GAAG,SAAS,EAC/C,WAAW,cAAc;;;aAqB1B,CAAC"}
@@ -1,9 +1,4 @@
1
1
  import { type StreamReactionType } from '../components';
2
- export declare const FLOATING_VIDEO_VIEW_STYLE: {
3
- height: number;
4
- width: number;
5
- borderRadius: number;
6
- };
7
2
  export declare const defaultEmojiReactions: StreamReactionType[];
8
3
  export declare const Z_INDEX: {
9
4
  IN_BACK: number;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/constants/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,eAAO,MAAM,yBAAyB;;;;CAIrC,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,kBAAkB,EA2CrD,CAAC;AAEF,eAAO,MAAM,OAAO;;;;CAInB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/constants/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,eAAO,MAAM,qBAAqB,EAAE,kBAAkB,EA2CrD,CAAC;AAEF,eAAO,MAAM,OAAO;;;;CAInB,CAAC"}
@@ -4,7 +4,7 @@ import { type StreamVideoParticipant, type VideoTrackType } from '@stream-io/vid
4
4
  * Note: the `tracktype` is used only for local participants.
5
5
  * `tracktype` should be 'videoTrack' for video track and 'screenShareTrack' for screen share track.
6
6
  */
7
- export declare function useTrackDimensions(participant: StreamVideoParticipant, trackType: VideoTrackType): {
7
+ export declare function useTrackDimensions(participant: StreamVideoParticipant | undefined, trackType: VideoTrackType): {
8
8
  width: number;
9
9
  height: number;
10
10
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useTrackDimensions.d.ts","sourceRoot":"","sources":["../../../src/hooks/useTrackDimensions.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,cAAc,EACpB,MAAM,yBAAyB,CAAC;AAIjC;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,sBAAsB,EACnC,SAAS,EAAE,cAAc;;;EAmE1B"}
1
+ {"version":3,"file":"useTrackDimensions.d.ts","sourceRoot":"","sources":["../../../src/hooks/useTrackDimensions.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,cAAc,EACpB,MAAM,yBAAyB,CAAC;AAIjC;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,sBAAsB,GAAG,SAAS,EAC/C,SAAS,EAAE,cAAc;;;EAmE1B"}
@@ -1,2 +1,2 @@
1
- export declare const version = "1.22.2";
1
+ export declare const version = "1.23.0";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -18,32 +18,32 @@ enum DefaultAudioDevice {
18
18
 
19
19
  @objc(StreamInCallManager)
20
20
  class StreamInCallManager: RCTEventEmitter {
21
-
21
+
22
22
  private let audioSessionQueue = DispatchQueue(label: "io.getstream.rn.audioSessionQueue")
23
-
23
+
24
24
  private var audioManagerActivated = false
25
25
  private var callAudioRole: CallAudioRole = .communicator
26
26
  private var defaultAudioDevice: DefaultAudioDevice = .speaker
27
27
  private var previousVolume: Float = 0.75
28
-
28
+
29
29
  private struct AudioSessionState {
30
30
  let category: AVAudioSession.Category
31
31
  let mode: AVAudioSession.Mode
32
32
  let options: AVAudioSession.CategoryOptions
33
33
  }
34
-
34
+
35
35
  private var previousAudioSessionState: AudioSessionState?
36
-
36
+ private var hasRegisteredRouteObserver = false
37
+
37
38
  override func invalidate() {
38
39
  stop()
39
40
  super.invalidate()
40
41
  }
41
-
42
+
42
43
  override static func requiresMainQueueSetup() -> Bool {
43
44
  return false
44
45
  }
45
-
46
-
46
+
47
47
  @objc(setAudioRole:)
48
48
  func setAudioRole(audioRole: String) {
49
49
  audioSessionQueue.async { [self] in
@@ -54,7 +54,7 @@ class StreamInCallManager: RCTEventEmitter {
54
54
  self.callAudioRole = audioRole.lowercased() == "listener" ? .listener : .communicator
55
55
  }
56
56
  }
57
-
57
+
58
58
  @objc(setDefaultAudioDeviceEndpointType:)
59
59
  func setDefaultAudioDeviceEndpointType(endpointType: String) {
60
60
  audioSessionQueue.async { [self] in
@@ -65,7 +65,7 @@ class StreamInCallManager: RCTEventEmitter {
65
65
  self.defaultAudioDevice = endpointType.lowercased() == "earpiece" ? .earpiece : .speaker
66
66
  }
67
67
  }
68
-
68
+
69
69
  @objc
70
70
  func start() {
71
71
  audioSessionQueue.async { [self] in
@@ -79,10 +79,17 @@ class StreamInCallManager: RCTEventEmitter {
79
79
  options: session.categoryOptions
80
80
  )
81
81
  configureAudioSession()
82
+ // Enable wake lock to prevent the screen from dimming/locking during a call
83
+ DispatchQueue.main.async {
84
+ UIApplication.shared.isIdleTimerDisabled = true
85
+ self.registerAudioRouteObserver()
86
+ self.updateProximityMonitoring()
87
+ self.log("Wake lock enabled (idle timer disabled)")
88
+ }
82
89
  audioManagerActivated = true
83
90
  }
84
91
  }
85
-
92
+
86
93
  @objc
87
94
  func stop() {
88
95
  audioSessionQueue.async { [self] in
@@ -100,13 +107,20 @@ class StreamInCallManager: RCTEventEmitter {
100
107
  }
101
108
  audioManagerActivated = false
102
109
  }
110
+ // Disable wake lock and proximity when call manager stops so the device can sleep again
111
+ DispatchQueue.main.async {
112
+ self.setProximityMonitoringEnabled(false)
113
+ self.unregisterAudioRouteObserver()
114
+ UIApplication.shared.isIdleTimerDisabled = false
115
+ self.log("Wake lock disabled (idle timer enabled)")
116
+ }
103
117
  }
104
-
118
+
105
119
  private func configureAudioSession() {
106
120
  let intendedCategory: AVAudioSession.Category!
107
121
  let intendedMode: AVAudioSession.Mode!
108
122
  let intendedOptions: AVAudioSession.CategoryOptions!
109
-
123
+
110
124
  if (callAudioRole == .listener) {
111
125
  // enables high quality audio playback but disables microphone
112
126
  intendedCategory = .playback
@@ -115,16 +129,16 @@ class StreamInCallManager: RCTEventEmitter {
115
129
  } else {
116
130
  intendedCategory = .playAndRecord
117
131
  intendedMode = .voiceChat
118
-
132
+
119
133
  if (defaultAudioDevice == .speaker) {
120
134
  // defaultToSpeaker will route to speaker if nothing else is connected
121
- intendedOptions = [.allowBluetooth, .defaultToSpeaker]
135
+ intendedOptions = [.allowBluetoothHFP, .defaultToSpeaker]
122
136
  } else {
123
137
  // having no defaultToSpeaker makes sure audio goes to earpiece if nothing is connected
124
- intendedOptions = [.allowBluetooth]
138
+ intendedOptions = [.allowBluetoothHFP]
125
139
  }
126
140
  }
127
-
141
+
128
142
  // START: set the config that webrtc must use when it takes control
129
143
  let rtcConfig = RTCAudioSessionConfiguration.webRTC()
130
144
  rtcConfig.category = intendedCategory.rawValue
@@ -132,14 +146,14 @@ class StreamInCallManager: RCTEventEmitter {
132
146
  rtcConfig.categoryOptions = intendedOptions
133
147
  RTCAudioSessionConfiguration.setWebRTC(rtcConfig)
134
148
  // END
135
-
149
+
136
150
  // START: compare current audio session with intended, and update if different
137
151
  let session = RTCAudioSession.sharedInstance()
138
152
  let currentCategory = session.category
139
153
  let currentMode = session.mode
140
154
  let currentOptions = session.categoryOptions
141
155
  let currentIsActive = session.isActive
142
-
156
+
143
157
  if currentCategory != intendedCategory.rawValue || currentMode != intendedMode.rawValue || currentOptions != intendedOptions || !currentIsActive {
144
158
  session.lockForConfiguration()
145
159
  do {
@@ -162,7 +176,7 @@ class StreamInCallManager: RCTEventEmitter {
162
176
  }
163
177
  // END
164
178
  }
165
-
179
+
166
180
  @objc(showAudioRoutePicker)
167
181
  public func showAudioRoutePicker() {
168
182
  guard #available(iOS 11.0, tvOS 11.0, macOS 10.15, *) else {
@@ -177,7 +191,7 @@ class StreamInCallManager: RCTEventEmitter {
177
191
  .sendActions(for: .touchUpInside)
178
192
  }
179
193
  }
180
-
194
+
181
195
  @objc(setForceSpeakerphoneOn:)
182
196
  func setForceSpeakerphoneOn(enable: Bool) {
183
197
  let session = AVAudioSession.sharedInstance()
@@ -188,12 +202,12 @@ class StreamInCallManager: RCTEventEmitter {
188
202
  log("Error setting speakerphone: \(error)")
189
203
  }
190
204
  }
191
-
205
+
192
206
  @objc(setMicrophoneMute:)
193
207
  func setMicrophoneMute(enable: Bool) {
194
208
  log("iOS does not support setMicrophoneMute()")
195
209
  }
196
-
210
+
197
211
  @objc
198
212
  func logAudioState() {
199
213
  let session = AVAudioSession.sharedInstance()
@@ -209,17 +223,17 @@ class StreamInCallManager: RCTEventEmitter {
209
223
  """
210
224
  log(logString)
211
225
  }
212
-
226
+
213
227
  @objc(muteAudioOutput)
214
228
  func muteAudioOutput() {
215
229
  DispatchQueue.main.async { [self] in
216
230
  let volumeView = MPVolumeView()
217
-
231
+
218
232
  // Add to a temporary view hierarchy to make it functional
219
233
  if let window = getCurrentWindow() {
220
234
  volumeView.frame = CGRect(x: -1000, y: -1000, width: 1, height: 1)
221
235
  window.addSubview(volumeView)
222
-
236
+
223
237
  // Give it a moment to initialize
224
238
  DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
225
239
  if let slider = volumeView.subviews.first(where: { $0 is UISlider }) as? UISlider {
@@ -230,24 +244,24 @@ class StreamInCallManager: RCTEventEmitter {
230
244
  } else {
231
245
  self.log("Could not find volume slider")
232
246
  }
233
-
247
+
234
248
  // Remove from view hierarchy after use
235
249
  volumeView.removeFromSuperview()
236
250
  }
237
251
  }
238
252
  }
239
253
  }
240
-
254
+
241
255
  @objc(unmuteAudioOutput)
242
256
  func unmuteAudioOutput() {
243
257
  DispatchQueue.main.async { [self] in
244
258
  let volumeView = MPVolumeView()
245
-
259
+
246
260
  // Add to a temporary view hierarchy to make it functional
247
261
  if let window = getCurrentWindow() {
248
262
  volumeView.frame = CGRect(x: -1000, y: -1000, width: 1, height: 1)
249
263
  window.addSubview(volumeView)
250
-
264
+
251
265
  // Give it a moment to initialize
252
266
  DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
253
267
  if let slider = volumeView.subviews.first(where: { $0 is UISlider }) as? UISlider {
@@ -258,31 +272,84 @@ class StreamInCallManager: RCTEventEmitter {
258
272
  } else {
259
273
  self.log("Could not find volume slider")
260
274
  }
261
-
275
+
262
276
  // Remove from view hierarchy after use
263
277
  volumeView.removeFromSuperview()
264
278
  }
265
279
  }
266
280
  }
267
281
  }
268
-
282
+
283
+ // MARK: - Proximity Handling
284
+ private func registerAudioRouteObserver() {
285
+ if hasRegisteredRouteObserver { return }
286
+ NotificationCenter.default.addObserver(
287
+ self,
288
+ selector: #selector(handleAudioRouteChange(_:)),
289
+ name: AVAudioSession.routeChangeNotification,
290
+ object: nil
291
+ )
292
+ hasRegisteredRouteObserver = true
293
+ log("Registered AVAudioSession.routeChangeNotification observer")
294
+ }
295
+
296
+ private func unregisterAudioRouteObserver() {
297
+ if !hasRegisteredRouteObserver { return }
298
+ NotificationCenter.default.removeObserver(self, name: AVAudioSession.routeChangeNotification, object: nil)
299
+ hasRegisteredRouteObserver = false
300
+ log("Unregistered AVAudioSession.routeChangeNotification observer")
301
+ }
302
+
303
+ @objc private func handleAudioRouteChange(_ notification: Notification) {
304
+ // Route changes can arrive on arbitrary queues; ensure UI-safe work on main
305
+ DispatchQueue.main.async { [weak self] in
306
+ self?.updateProximityMonitoring()
307
+ }
308
+ }
309
+
310
+ private func updateProximityMonitoring() {
311
+ // Proximity is only meaningful while a call is active
312
+ guard audioManagerActivated else {
313
+ setProximityMonitoringEnabled(false)
314
+ return
315
+ }
316
+ let session = AVAudioSession.sharedInstance()
317
+ let port = session.currentRoute.outputs.first?.portType
318
+ let isEarpiece = (port == .builtInReceiver)
319
+ setProximityMonitoringEnabled(isEarpiece)
320
+ }
321
+
322
+ private func setProximityMonitoringEnabled(_ enabled: Bool) {
323
+ // Always toggle on the main thread
324
+ if Thread.isMainThread {
325
+ if UIDevice.current.isProximityMonitoringEnabled != enabled {
326
+ UIDevice.current.isProximityMonitoringEnabled = enabled
327
+ log("Proximity monitoring \(enabled ? "ENABLED" : "DISABLED")")
328
+ }
329
+ } else {
330
+ DispatchQueue.main.async { [weak self] in
331
+ self?.setProximityMonitoringEnabled(enabled)
332
+ }
333
+ }
334
+ }
335
+
269
336
  // MARK: - RCTEventEmitter
270
-
337
+
271
338
  override func supportedEvents() -> [String]! {
272
339
  // TODO: list events that can be sent to JS
273
340
  return []
274
341
  }
275
-
342
+
276
343
  @objc
277
344
  override func addListener(_ eventName: String!) {
278
345
  super.addListener(eventName)
279
346
  }
280
-
347
+
281
348
  @objc
282
349
  override func removeListeners(_ count: Double) {
283
350
  super.removeListeners(count)
284
351
  }
285
-
352
+
286
353
  // MARK: - Helper Methods
287
354
  private func getCurrentWindow() -> UIWindow? {
288
355
  if #available(iOS 13.0, *) {
@@ -294,10 +361,10 @@ class StreamInCallManager: RCTEventEmitter {
294
361
  return UIApplication.shared.keyWindow
295
362
  }
296
363
  }
297
-
364
+
298
365
  // MARK: - Logging Helper
299
366
  private func log(_ message: String) {
300
367
  NSLog("InCallManager: %@", message)
301
368
  }
302
-
369
+
303
370
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stream-io/video-react-native-sdk",
3
- "version": "1.22.2",
3
+ "version": "1.23.0",
4
4
  "description": "Stream Video SDK for React Native",
5
5
  "author": "https://getstream.io",
6
6
  "homepage": "https://getstream.io/video/docs/react-native/",
@@ -45,8 +45,8 @@
45
45
  "!**/.*"
46
46
  ],
47
47
  "dependencies": {
48
- "@stream-io/video-client": "1.34.1",
49
- "@stream-io/video-react-bindings": "1.10.1",
48
+ "@stream-io/video-client": "1.35.1",
49
+ "@stream-io/video-react-bindings": "1.10.3",
50
50
  "intl-pluralrules": "2.0.1",
51
51
  "lodash.merge": "^4.6.2",
52
52
  "react-native-url-polyfill": "^3.0.0",
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useState } from 'react';
1
+ import React, { PropsWithChildren, useEffect, useState } from 'react';
2
2
  import {
3
3
  ViewerLivestream as DefaultViewerLivestream,
4
4
  type ViewerLivestreamProps,
@@ -27,7 +27,7 @@ export type LivestreamPlayerProps = {
27
27
  *
28
28
  * `"asap"` behavior means joining the call as soon as it is possible
29
29
  * (either the `join_ahead_time_seconds` setting allows it, or the user
30
- * has a the capability to join backstage).
30
+ * has the capability to join backstage).
31
31
  *
32
32
  * `"live"` behavior means joining the call when it goes live.
33
33
  *
@@ -41,7 +41,8 @@ export const LivestreamPlayer = ({
41
41
  callId,
42
42
  ViewerLivestream = DefaultViewerLivestream,
43
43
  joinBehavior = 'asap',
44
- }: LivestreamPlayerProps) => {
44
+ children,
45
+ }: PropsWithChildren<LivestreamPlayerProps>) => {
45
46
  const client = useStreamVideoClient();
46
47
 
47
48
  const [call, setCall] = useState<Call>();
@@ -82,6 +83,7 @@ export const LivestreamPlayer = ({
82
83
  return (
83
84
  <StreamCall call={call}>
84
85
  <ViewerLivestream joinBehavior={joinBehavior} />
86
+ {children}
85
87
  </StreamCall>
86
88
  );
87
89
  };
@@ -6,7 +6,7 @@ import {
6
6
  View,
7
7
  type ViewStyle,
8
8
  } from 'react-native';
9
- import { FLOATING_VIDEO_VIEW_STYLE, Z_INDEX } from '../../../constants';
9
+ import { Z_INDEX } from '../../../constants';
10
10
  import { ComponentTestIds } from '../../../constants/TestIds';
11
11
  import { VideoSlash } from '../../../icons';
12
12
  import FloatingView from './FloatingView';
@@ -21,6 +21,7 @@ import {
21
21
  type ParticipantViewProps,
22
22
  } from '../ParticipantView';
23
23
  import { useTheme } from '../../../contexts/ThemeContext';
24
+ import { useFloatingVideoDimensions } from './useFloatingVideoDimensions';
24
25
  import { type StreamVideoParticipant } from '@stream-io/video-client';
25
26
 
26
27
  export type FloatingParticipantViewAlignment =
@@ -104,7 +105,11 @@ export const FloatingParticipantView = ({
104
105
  objectFit,
105
106
  }: FloatingParticipantViewProps) => {
106
107
  const {
107
- theme: { colors, floatingParticipantsView },
108
+ theme: {
109
+ colors,
110
+ floatingParticipantsView,
111
+ variants: { spacingSizes },
112
+ },
108
113
  } = useTheme();
109
114
 
110
115
  const floatingAlignmentMap: Record<
@@ -122,6 +127,12 @@ export const FloatingParticipantView = ({
122
127
  height: number;
123
128
  }>();
124
129
 
130
+ const floatingVideoDimensions = useFloatingVideoDimensions(
131
+ containerDimensions,
132
+ participant,
133
+ 'videoTrack',
134
+ );
135
+
125
136
  const participantViewProps: ParticipantViewComponentProps = {
126
137
  ParticipantLabel: null,
127
138
  ParticipantNetworkQualityIndicator,
@@ -158,7 +169,7 @@ export const FloatingParticipantView = ({
158
169
  });
159
170
  }}
160
171
  >
161
- {containerDimensions && (
172
+ {containerDimensions && floatingVideoDimensions && (
162
173
  <FloatingView
163
174
  containerHeight={containerDimensions.height}
164
175
  containerWidth={containerDimensions.width}
@@ -171,6 +182,12 @@ export const FloatingParticipantView = ({
171
182
  trackType="videoTrack"
172
183
  style={[
173
184
  styles.participantViewContainer,
185
+ {
186
+ width: floatingVideoDimensions.width,
187
+ height: floatingVideoDimensions.height,
188
+ borderRadius: floatingVideoDimensions.width * 0.1,
189
+ marginHorizontal: spacingSizes.md,
190
+ },
174
191
  participantViewStyle,
175
192
  { shadowColor: colors.sheetPrimary },
176
193
  floatingParticipantsView.participantViewContainer,
@@ -197,9 +214,6 @@ const styles = StyleSheet.create({
197
214
  flex: 1,
198
215
  },
199
216
  participantViewContainer: {
200
- height: FLOATING_VIDEO_VIEW_STYLE.height,
201
- width: FLOATING_VIDEO_VIEW_STYLE.width,
202
- borderRadius: FLOATING_VIDEO_VIEW_STYLE.borderRadius,
203
217
  shadowOffset: {
204
218
  width: 0,
205
219
  height: 2,
@@ -0,0 +1,36 @@
1
+ import {
2
+ StreamVideoParticipant,
3
+ VideoTrackType,
4
+ } from '@stream-io/video-client';
5
+ import { useTrackDimensions } from '../../../hooks/useTrackDimensions';
6
+
7
+ export const useFloatingVideoDimensions = (
8
+ containerDimensions:
9
+ | {
10
+ width: number;
11
+ height: number;
12
+ }
13
+ | undefined,
14
+ participant: StreamVideoParticipant | undefined,
15
+ trackType: VideoTrackType,
16
+ ) => {
17
+ const containerWidth = containerDimensions?.width ?? 0;
18
+ const { width, height } = useTrackDimensions(participant, trackType);
19
+
20
+ if (width === 0 || height === 0 || containerWidth === 0) {
21
+ return undefined;
22
+ }
23
+
24
+ const aspectRatio = width / height;
25
+
26
+ // based on Android AOSP PiP mode default dimensions algorithm
27
+ // 23% of the container width
28
+ const floatingVideoWidth = containerWidth * 0.23;
29
+ // the height is calculated based on the aspect ratio
30
+ const floatingVideoHeight = floatingVideoWidth / aspectRatio;
31
+
32
+ return {
33
+ width: floatingVideoWidth,
34
+ height: floatingVideoHeight,
35
+ };
36
+ };