@stream-io/video-react-native-sdk 1.29.4-beta.0 → 1.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3162 -0
- package/android/src/main/AndroidManifest.xml +1 -8
- package/android/src/main/AndroidManifestNew.xml +0 -11
- package/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.kt +5 -42
- package/android/src/main/java/com/streamvideo/reactnative/audio/utils/WebRtcAudioUtils.kt +6 -70
- package/android/src/main/java/com/streamvideo/reactnative/callmanager/StreamInCallManagerModule.kt +4 -6
- package/android/src/main/java/com/streamvideo/reactnative/util/CallAliveServiceChecker.kt +95 -0
- package/dist/commonjs/components/Call/CallContent/CallContent.js +13 -7
- package/dist/commonjs/components/Call/CallContent/CallContent.js.map +1 -1
- package/dist/commonjs/components/Call/CallContent/RTCViewPipIOS.js +50 -14
- package/dist/commonjs/components/Call/CallContent/RTCViewPipIOS.js.map +1 -1
- package/dist/commonjs/components/Call/CallContent/RTCViewPipNative.js +27 -0
- package/dist/commonjs/components/Call/CallContent/RTCViewPipNative.js.map +1 -1
- package/dist/commonjs/components/Call/CallLayout/CallParticipantsGrid.js +19 -10
- package/dist/commonjs/components/Call/CallLayout/CallParticipantsGrid.js.map +1 -1
- package/dist/commonjs/components/Call/CallLayout/CallParticipantsSpotlight.js +12 -9
- package/dist/commonjs/components/Call/CallLayout/CallParticipantsSpotlight.js.map +1 -1
- package/dist/commonjs/components/Call/CallParticipantsList/CallParticipantsList.js +19 -4
- package/dist/commonjs/components/Call/CallParticipantsList/CallParticipantsList.js.map +1 -1
- package/dist/commonjs/hooks/push/index.js +2 -0
- package/dist/commonjs/hooks/push/index.js.map +1 -1
- package/dist/commonjs/hooks/push/useIosCallkeepWithCallingStateEffect.js +160 -0
- package/dist/commonjs/hooks/push/useIosCallkeepWithCallingStateEffect.js.map +1 -0
- package/dist/commonjs/hooks/push/useIosVoipPushEventsSetupEffect.js +31 -18
- package/dist/commonjs/hooks/push/useIosVoipPushEventsSetupEffect.js.map +1 -1
- package/dist/commonjs/hooks/push/useProcessPushCallEffect.js +67 -0
- package/dist/commonjs/hooks/push/useProcessPushCallEffect.js.map +1 -0
- package/dist/commonjs/hooks/useAndroidKeepCallAliveEffect.js +97 -64
- package/dist/commonjs/hooks/useAndroidKeepCallAliveEffect.js.map +1 -1
- package/dist/commonjs/index.js +0 -1
- package/dist/commonjs/index.js.map +1 -1
- package/dist/commonjs/modules/call-manager/CallManager.js +0 -26
- package/dist/commonjs/modules/call-manager/CallManager.js.map +1 -1
- package/dist/commonjs/providers/StreamCall/index.js +6 -6
- package/dist/commonjs/providers/StreamCall/index.js.map +1 -1
- package/dist/commonjs/utils/StreamVideoRN/index.js +21 -33
- package/dist/commonjs/utils/StreamVideoRN/index.js.map +1 -1
- package/dist/commonjs/utils/hooks/index.js +0 -11
- package/dist/commonjs/utils/hooks/index.js.map +1 -1
- package/dist/commonjs/utils/internal/registerSDKGlobals.js +3 -52
- package/dist/commonjs/utils/internal/registerSDKGlobals.js.map +1 -1
- package/dist/commonjs/utils/push/android.js +202 -151
- package/dist/commonjs/utils/push/android.js.map +1 -1
- package/dist/commonjs/utils/push/internal/ios.js +34 -17
- package/dist/commonjs/utils/push/internal/ios.js.map +1 -1
- package/dist/commonjs/utils/push/internal/rxSubjects.js +45 -1
- package/dist/commonjs/utils/push/internal/rxSubjects.js.map +1 -1
- package/dist/commonjs/utils/push/internal/utils.js +20 -32
- package/dist/commonjs/utils/push/internal/utils.js.map +1 -1
- package/dist/commonjs/utils/push/ios.js.map +1 -1
- package/dist/commonjs/utils/push/libs/callkeep.js +17 -0
- package/dist/commonjs/utils/push/libs/callkeep.js.map +1 -0
- package/dist/commonjs/utils/push/libs/index.js +19 -8
- package/dist/commonjs/utils/push/libs/index.js.map +1 -1
- package/dist/commonjs/utils/push/libs/notifee/index.js +19 -0
- package/dist/commonjs/utils/push/libs/notifee/index.js.map +1 -1
- package/dist/commonjs/utils/push/libs/voipPushNotification.js +17 -0
- package/dist/commonjs/utils/push/libs/voipPushNotification.js.map +1 -0
- package/dist/commonjs/utils/push/setupIosCallKeepEvents.js +205 -0
- package/dist/commonjs/utils/push/setupIosCallKeepEvents.js.map +1 -0
- package/dist/commonjs/utils/push/setupIosVoipPushEvents.js +6 -7
- package/dist/commonjs/utils/push/setupIosVoipPushEvents.js.map +1 -1
- package/dist/commonjs/version.js +1 -1
- package/dist/commonjs/version.js.map +1 -1
- package/dist/module/components/Call/CallContent/CallContent.js +10 -4
- package/dist/module/components/Call/CallContent/CallContent.js.map +1 -1
- package/dist/module/components/Call/CallContent/RTCViewPipIOS.js +52 -16
- package/dist/module/components/Call/CallContent/RTCViewPipIOS.js.map +1 -1
- package/dist/module/components/Call/CallContent/RTCViewPipNative.js +27 -0
- package/dist/module/components/Call/CallContent/RTCViewPipNative.js.map +1 -1
- package/dist/module/components/Call/CallLayout/CallParticipantsGrid.js +19 -10
- package/dist/module/components/Call/CallLayout/CallParticipantsGrid.js.map +1 -1
- package/dist/module/components/Call/CallLayout/CallParticipantsSpotlight.js +15 -12
- package/dist/module/components/Call/CallLayout/CallParticipantsSpotlight.js.map +1 -1
- package/dist/module/components/Call/CallParticipantsList/CallParticipantsList.js +20 -5
- package/dist/module/components/Call/CallParticipantsList/CallParticipantsList.js.map +1 -1
- package/dist/module/hooks/push/index.js +2 -0
- package/dist/module/hooks/push/index.js.map +1 -1
- package/dist/module/hooks/push/useIosCallkeepWithCallingStateEffect.js +153 -0
- package/dist/module/hooks/push/useIosCallkeepWithCallingStateEffect.js.map +1 -0
- package/dist/module/hooks/push/useIosVoipPushEventsSetupEffect.js +31 -18
- package/dist/module/hooks/push/useIosVoipPushEventsSetupEffect.js.map +1 -1
- package/dist/module/hooks/push/useProcessPushCallEffect.js +60 -0
- package/dist/module/hooks/push/useProcessPushCallEffect.js.map +1 -0
- package/dist/module/hooks/useAndroidKeepCallAliveEffect.js +99 -66
- package/dist/module/hooks/useAndroidKeepCallAliveEffect.js.map +1 -1
- package/dist/module/index.js +0 -1
- package/dist/module/index.js.map +1 -1
- package/dist/module/modules/call-manager/CallManager.js +0 -26
- package/dist/module/modules/call-manager/CallManager.js.map +1 -1
- package/dist/module/providers/StreamCall/index.js +6 -6
- package/dist/module/providers/StreamCall/index.js.map +1 -1
- package/dist/module/utils/StreamVideoRN/index.js +21 -33
- package/dist/module/utils/StreamVideoRN/index.js.map +1 -1
- package/dist/module/utils/hooks/index.js +0 -1
- package/dist/module/utils/hooks/index.js.map +1 -1
- package/dist/module/utils/internal/registerSDKGlobals.js +3 -52
- package/dist/module/utils/internal/registerSDKGlobals.js.map +1 -1
- package/dist/module/utils/push/android.js +204 -153
- package/dist/module/utils/push/android.js.map +1 -1
- package/dist/module/utils/push/internal/ios.js +34 -17
- package/dist/module/utils/push/internal/ios.js.map +1 -1
- package/dist/module/utils/push/internal/rxSubjects.js +44 -0
- package/dist/module/utils/push/internal/rxSubjects.js.map +1 -1
- package/dist/module/utils/push/internal/utils.js +19 -29
- package/dist/module/utils/push/internal/utils.js.map +1 -1
- package/dist/module/utils/push/ios.js.map +1 -1
- package/dist/module/utils/push/libs/callkeep.js +11 -0
- package/dist/module/utils/push/libs/callkeep.js.map +1 -0
- package/dist/module/utils/push/libs/index.js +2 -1
- package/dist/module/utils/push/libs/index.js.map +1 -1
- package/dist/module/utils/push/libs/notifee/index.js +18 -0
- package/dist/module/utils/push/libs/notifee/index.js.map +1 -1
- package/dist/module/utils/push/libs/voipPushNotification.js +11 -0
- package/dist/module/utils/push/libs/voipPushNotification.js.map +1 -0
- package/dist/module/utils/push/setupIosCallKeepEvents.js +199 -0
- package/dist/module/utils/push/setupIosCallKeepEvents.js.map +1 -0
- package/dist/module/utils/push/setupIosVoipPushEvents.js +6 -7
- package/dist/module/utils/push/setupIosVoipPushEvents.js.map +1 -1
- package/dist/module/version.js +1 -1
- package/dist/module/version.js.map +1 -1
- package/dist/typescript/components/Call/CallContent/CallContent.d.ts.map +1 -1
- package/dist/typescript/components/Call/CallContent/RTCViewPipIOS.d.ts.map +1 -1
- package/dist/typescript/components/Call/CallContent/RTCViewPipNative.d.ts +18 -0
- package/dist/typescript/components/Call/CallContent/RTCViewPipNative.d.ts.map +1 -1
- package/dist/typescript/components/Call/CallLayout/CallParticipantsGrid.d.ts.map +1 -1
- package/dist/typescript/components/Call/CallLayout/CallParticipantsSpotlight.d.ts.map +1 -1
- package/dist/typescript/components/Call/CallParticipantsList/CallParticipantsList.d.ts.map +1 -1
- package/dist/typescript/hooks/push/index.d.ts.map +1 -1
- package/dist/typescript/hooks/push/useIosCallkeepWithCallingStateEffect.d.ts +5 -0
- package/dist/typescript/hooks/push/useIosCallkeepWithCallingStateEffect.d.ts.map +1 -0
- package/dist/typescript/hooks/push/useIosVoipPushEventsSetupEffect.d.ts.map +1 -1
- package/dist/typescript/hooks/push/useProcessPushCallEffect.d.ts +8 -0
- package/dist/typescript/hooks/push/useProcessPushCallEffect.d.ts.map +1 -0
- package/dist/typescript/hooks/useAndroidKeepCallAliveEffect.d.ts.map +1 -1
- package/dist/typescript/index.d.ts +0 -1
- package/dist/typescript/index.d.ts.map +1 -1
- package/dist/typescript/modules/call-manager/CallManager.d.ts +0 -5
- package/dist/typescript/modules/call-manager/CallManager.d.ts.map +1 -1
- package/dist/typescript/utils/StreamVideoRN/index.d.ts +2 -20
- package/dist/typescript/utils/StreamVideoRN/index.d.ts.map +1 -1
- package/dist/typescript/utils/StreamVideoRN/types.d.ts +29 -54
- package/dist/typescript/utils/StreamVideoRN/types.d.ts.map +1 -1
- package/dist/typescript/utils/hooks/index.d.ts +0 -1
- package/dist/typescript/utils/hooks/index.d.ts.map +1 -1
- package/dist/typescript/utils/internal/registerSDKGlobals.d.ts.map +1 -1
- package/dist/typescript/utils/push/android.d.ts +2 -1
- package/dist/typescript/utils/push/android.d.ts.map +1 -1
- package/dist/typescript/utils/push/internal/ios.d.ts.map +1 -1
- package/dist/typescript/utils/push/internal/rxSubjects.d.ts +33 -0
- package/dist/typescript/utils/push/internal/rxSubjects.d.ts.map +1 -1
- package/dist/typescript/utils/push/internal/utils.d.ts +1 -8
- package/dist/typescript/utils/push/internal/utils.d.ts.map +1 -1
- package/dist/typescript/utils/push/ios.d.ts +2 -1
- package/dist/typescript/utils/push/ios.d.ts.map +1 -1
- package/dist/typescript/utils/push/libs/callkeep.d.ts +3 -0
- package/dist/typescript/utils/push/libs/callkeep.d.ts.map +1 -0
- package/dist/typescript/utils/push/libs/index.d.ts +2 -1
- package/dist/typescript/utils/push/libs/index.d.ts.map +1 -1
- package/dist/typescript/utils/push/libs/notifee/index.d.ts +1 -0
- package/dist/typescript/utils/push/libs/notifee/index.d.ts.map +1 -1
- package/dist/typescript/utils/push/libs/voipPushNotification.d.ts +3 -0
- package/dist/typescript/utils/push/libs/voipPushNotification.d.ts.map +1 -0
- package/dist/typescript/utils/push/setupIosCallKeepEvents.d.ts +6 -0
- package/dist/typescript/utils/push/setupIosCallKeepEvents.d.ts.map +1 -0
- package/dist/typescript/utils/push/setupIosVoipPushEvents.d.ts.map +1 -1
- package/dist/typescript/version.d.ts +1 -1
- package/dist/typescript/version.d.ts.map +1 -1
- package/expo-config-plugin/dist/withAndroidManifest.js +33 -1
- package/expo-config-plugin/dist/withAndroidPermissions.js +7 -2
- package/expo-config-plugin/dist/withAppDelegate.js +197 -19
- package/expo-config-plugin/dist/withMainActivity.js +1 -1
- package/expo-config-plugin/dist/withiOSInfoPlist.js +3 -2
- package/ios/PictureInPicture/PictureInPictureAvatarView.swift +273 -0
- package/ios/PictureInPicture/PictureInPictureConnectionQualityIndicator.swift +162 -0
- package/ios/PictureInPicture/PictureInPictureContent.swift +173 -0
- package/ios/PictureInPicture/PictureInPictureContentState.swift +123 -0
- package/ios/PictureInPicture/PictureInPictureDelegateProxy.swift +89 -0
- package/ios/PictureInPicture/PictureInPictureEnforcedStopAdapter.swift +166 -0
- package/ios/PictureInPicture/PictureInPictureLogger.swift +16 -0
- package/ios/PictureInPicture/PictureInPictureParticipantOverlayView.swift +217 -0
- package/ios/PictureInPicture/PictureInPictureReconnectionView.swift +193 -0
- package/ios/PictureInPicture/StreamAVPictureInPictureVideoCallViewController.swift +125 -7
- package/ios/PictureInPicture/StreamPictureInPictureController.swift +237 -63
- package/ios/PictureInPicture/StreamPictureInPictureControllerProtocol.swift +30 -0
- package/ios/PictureInPicture/StreamPictureInPictureVideoRenderer.swift +384 -12
- package/ios/RTCViewPip.swift +187 -21
- package/ios/RTCViewPipManager.mm +9 -0
- package/ios/RTCViewPipManager.swift +3 -3
- package/ios/StreamInCallManager.m +0 -2
- package/ios/StreamInCallManager.swift +7 -19
- package/ios/StreamVideoReactNative.h +4 -7
- package/ios/StreamVideoReactNative.m +82 -189
- package/package.json +19 -14
- package/src/components/Call/CallContent/CallContent.tsx +16 -8
- package/src/components/Call/CallContent/RTCViewPipIOS.tsx +81 -15
- package/src/components/Call/CallContent/RTCViewPipNative.tsx +36 -0
- package/src/components/Call/CallLayout/CallParticipantsGrid.tsx +28 -14
- package/src/components/Call/CallLayout/CallParticipantsSpotlight.tsx +19 -10
- package/src/components/Call/CallParticipantsList/CallParticipantsList.tsx +20 -5
- package/src/hooks/push/index.ts +2 -0
- package/src/hooks/push/useIosCallkeepWithCallingStateEffect.ts +235 -0
- package/src/hooks/push/useIosVoipPushEventsSetupEffect.ts +34 -21
- package/src/hooks/push/useProcessPushCallEffect.ts +108 -0
- package/src/hooks/useAndroidKeepCallAliveEffect.ts +120 -94
- package/src/index.ts +0 -1
- package/src/modules/call-manager/CallManager.ts +0 -36
- package/src/modules/call-manager/native-module.d.ts +0 -7
- package/src/providers/StreamCall/index.tsx +6 -6
- package/src/utils/StreamVideoRN/index.ts +30 -40
- package/src/utils/StreamVideoRN/types.ts +29 -56
- package/src/utils/hooks/index.ts +0 -1
- package/src/utils/internal/registerSDKGlobals.ts +4 -47
- package/src/utils/push/android.ts +309 -227
- package/src/utils/push/internal/ios.ts +44 -28
- package/src/utils/push/internal/rxSubjects.ts +61 -0
- package/src/utils/push/internal/utils.ts +26 -45
- package/src/utils/push/ios.ts +6 -1
- package/src/utils/push/libs/callkeep.ts +16 -0
- package/src/utils/push/libs/index.ts +2 -1
- package/src/utils/push/libs/notifee/index.ts +27 -0
- package/src/utils/push/libs/voipPushNotification.ts +17 -0
- package/src/utils/push/setupIosCallKeepEvents.ts +252 -0
- package/src/utils/push/setupIosVoipPushEvents.ts +7 -11
- package/src/version.ts +1 -1
- package/android/src/main/java/com/streamvideo/reactnative/keepalive/KeepAliveNotification.kt +0 -83
- package/android/src/main/java/com/streamvideo/reactnative/keepalive/StreamCallKeepAliveHeadlessService.kt +0 -149
- package/dist/commonjs/hooks/push/useCallingExpWithCallingStateEffect.js +0 -121
- package/dist/commonjs/hooks/push/useCallingExpWithCallingStateEffect.js.map +0 -1
- package/dist/commonjs/utils/hooks/useDebouncedValue.js +0 -24
- package/dist/commonjs/utils/hooks/useDebouncedValue.js.map +0 -1
- package/dist/commonjs/utils/internal/callingx/audioSessionPromise.js +0 -58
- package/dist/commonjs/utils/internal/callingx/audioSessionPromise.js.map +0 -1
- package/dist/commonjs/utils/internal/callingx/callingx.js +0 -109
- package/dist/commonjs/utils/internal/callingx/callingx.js.map +0 -1
- package/dist/commonjs/utils/keepCallAliveHeadlessTask.js +0 -48
- package/dist/commonjs/utils/keepCallAliveHeadlessTask.js.map +0 -1
- package/dist/commonjs/utils/push/libs/callingx.js +0 -75
- package/dist/commonjs/utils/push/libs/callingx.js.map +0 -1
- package/dist/commonjs/utils/push/setupCallingExpEvents.js +0 -108
- package/dist/commonjs/utils/push/setupCallingExpEvents.js.map +0 -1
- package/dist/module/hooks/push/useCallingExpWithCallingStateEffect.js +0 -114
- package/dist/module/hooks/push/useCallingExpWithCallingStateEffect.js.map +0 -1
- package/dist/module/utils/hooks/useDebouncedValue.js +0 -19
- package/dist/module/utils/hooks/useDebouncedValue.js.map +0 -1
- package/dist/module/utils/internal/callingx/audioSessionPromise.js +0 -51
- package/dist/module/utils/internal/callingx/audioSessionPromise.js.map +0 -1
- package/dist/module/utils/internal/callingx/callingx.js +0 -100
- package/dist/module/utils/internal/callingx/callingx.js.map +0 -1
- package/dist/module/utils/keepCallAliveHeadlessTask.js +0 -42
- package/dist/module/utils/keepCallAliveHeadlessTask.js.map +0 -1
- package/dist/module/utils/push/libs/callingx.js +0 -67
- package/dist/module/utils/push/libs/callingx.js.map +0 -1
- package/dist/module/utils/push/setupCallingExpEvents.js +0 -102
- package/dist/module/utils/push/setupCallingExpEvents.js.map +0 -1
- package/dist/typescript/hooks/push/useCallingExpWithCallingStateEffect.d.ts +0 -5
- package/dist/typescript/hooks/push/useCallingExpWithCallingStateEffect.d.ts.map +0 -1
- package/dist/typescript/utils/hooks/useDebouncedValue.d.ts +0 -8
- package/dist/typescript/utils/hooks/useDebouncedValue.d.ts.map +0 -1
- package/dist/typescript/utils/internal/callingx/audioSessionPromise.d.ts +0 -16
- package/dist/typescript/utils/internal/callingx/audioSessionPromise.d.ts.map +0 -1
- package/dist/typescript/utils/internal/callingx/callingx.d.ts +0 -14
- package/dist/typescript/utils/internal/callingx/callingx.d.ts.map +0 -1
- package/dist/typescript/utils/keepCallAliveHeadlessTask.d.ts +0 -10
- package/dist/typescript/utils/keepCallAliveHeadlessTask.d.ts.map +0 -1
- package/dist/typescript/utils/push/libs/callingx.d.ts +0 -9
- package/dist/typescript/utils/push/libs/callingx.d.ts.map +0 -1
- package/dist/typescript/utils/push/setupCallingExpEvents.d.ts +0 -8
- package/dist/typescript/utils/push/setupCallingExpEvents.d.ts.map +0 -1
- package/src/hooks/push/useCallingExpWithCallingStateEffect.ts +0 -147
- package/src/utils/hooks/useDebouncedValue.ts +0 -21
- package/src/utils/internal/callingx/audioSessionPromise.ts +0 -53
- package/src/utils/internal/callingx/callingx.ts +0 -146
- package/src/utils/keepCallAliveHeadlessTask.ts +0 -54
- package/src/utils/push/libs/callingx.ts +0 -90
- package/src/utils/push/setupCallingExpEvents.ts +0 -130
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright © 2024 Stream.io Inc. All rights reserved.
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import UIKit
|
|
6
|
+
|
|
7
|
+
/// A view representing a connection quality indicator for Picture-in-Picture.
|
|
8
|
+
/// Displays three vertical bars that indicate connection quality levels:
|
|
9
|
+
/// - Excellent: All 3 bars green
|
|
10
|
+
/// - Good: 2 bars green, 1 bar gray
|
|
11
|
+
/// - Poor: 1 bar red, 2 bars gray
|
|
12
|
+
/// - Unknown: All bars hidden
|
|
13
|
+
/// This aligns with upstream stream-video-swift ConnectionQualityIndicator.
|
|
14
|
+
final class PictureInPictureConnectionQualityIndicator: UIView {
|
|
15
|
+
|
|
16
|
+
// MARK: - Connection Quality Enum
|
|
17
|
+
|
|
18
|
+
/// Connection quality levels matching the stream-video-swift/video-client enum
|
|
19
|
+
enum ConnectionQuality: Int {
|
|
20
|
+
case unspecified = 0 // Unknown
|
|
21
|
+
case poor = 1
|
|
22
|
+
case good = 2
|
|
23
|
+
case excellent = 3
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// MARK: - Properties
|
|
27
|
+
|
|
28
|
+
/// The current connection quality level
|
|
29
|
+
var connectionQuality: ConnectionQuality = .unspecified {
|
|
30
|
+
didSet {
|
|
31
|
+
updateIndicator()
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/// Size of the indicator view
|
|
36
|
+
private let indicatorSize: CGFloat = 24
|
|
37
|
+
|
|
38
|
+
/// Width of each bar
|
|
39
|
+
private let barWidth: CGFloat = 3
|
|
40
|
+
|
|
41
|
+
/// Spacing between bars
|
|
42
|
+
private let barSpacing: CGFloat = 2
|
|
43
|
+
|
|
44
|
+
// MARK: - Colors
|
|
45
|
+
|
|
46
|
+
private let goodColor = UIColor(red: 0.2, green: 0.8, blue: 0.4, alpha: 1.0) // Green
|
|
47
|
+
private let badColor = UIColor(red: 0.9, green: 0.3, blue: 0.3, alpha: 1.0) // Red
|
|
48
|
+
private let inactiveColor = UIColor.white.withAlphaComponent(0.5)
|
|
49
|
+
|
|
50
|
+
// MARK: - UI Components
|
|
51
|
+
|
|
52
|
+
/// Background container with rounded corner
|
|
53
|
+
private lazy var containerView: UIView = {
|
|
54
|
+
let view = UIView()
|
|
55
|
+
view.translatesAutoresizingMaskIntoConstraints = false
|
|
56
|
+
view.backgroundColor = UIColor.black.withAlphaComponent(0.6)
|
|
57
|
+
// Apply rounded corner only to top-left
|
|
58
|
+
view.layer.cornerRadius = 8
|
|
59
|
+
view.layer.maskedCorners = [.layerMinXMinYCorner] // top-left only
|
|
60
|
+
return view
|
|
61
|
+
}()
|
|
62
|
+
|
|
63
|
+
/// Stack view containing the three bars
|
|
64
|
+
private lazy var barsStackView: UIStackView = {
|
|
65
|
+
let stack = UIStackView()
|
|
66
|
+
stack.translatesAutoresizingMaskIntoConstraints = false
|
|
67
|
+
stack.axis = .horizontal
|
|
68
|
+
stack.alignment = .bottom
|
|
69
|
+
stack.spacing = barSpacing
|
|
70
|
+
stack.distribution = .equalSpacing
|
|
71
|
+
return stack
|
|
72
|
+
}()
|
|
73
|
+
|
|
74
|
+
/// First (shortest) bar
|
|
75
|
+
private lazy var bar1: UIView = {
|
|
76
|
+
createBar(height: barWidth * 2)
|
|
77
|
+
}()
|
|
78
|
+
|
|
79
|
+
/// Second (medium) bar
|
|
80
|
+
private lazy var bar2: UIView = {
|
|
81
|
+
createBar(height: barWidth * 3)
|
|
82
|
+
}()
|
|
83
|
+
|
|
84
|
+
/// Third (tallest) bar
|
|
85
|
+
private lazy var bar3: UIView = {
|
|
86
|
+
createBar(height: barWidth * 4)
|
|
87
|
+
}()
|
|
88
|
+
|
|
89
|
+
// MARK: - Initialization
|
|
90
|
+
|
|
91
|
+
override init(frame: CGRect) {
|
|
92
|
+
super.init(frame: frame)
|
|
93
|
+
setUp()
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
required init?(coder: NSCoder) {
|
|
97
|
+
fatalError("init(coder:) has not been implemented")
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// MARK: - Private Methods
|
|
101
|
+
|
|
102
|
+
private func setUp() {
|
|
103
|
+
isUserInteractionEnabled = false
|
|
104
|
+
isHidden = true // Hidden by default (unknown quality)
|
|
105
|
+
|
|
106
|
+
addSubview(containerView)
|
|
107
|
+
containerView.addSubview(barsStackView)
|
|
108
|
+
|
|
109
|
+
barsStackView.addArrangedSubview(bar1)
|
|
110
|
+
barsStackView.addArrangedSubview(bar2)
|
|
111
|
+
barsStackView.addArrangedSubview(bar3)
|
|
112
|
+
|
|
113
|
+
NSLayoutConstraint.activate([
|
|
114
|
+
containerView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
|
115
|
+
containerView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
|
116
|
+
containerView.widthAnchor.constraint(equalToConstant: indicatorSize),
|
|
117
|
+
containerView.heightAnchor.constraint(equalToConstant: indicatorSize),
|
|
118
|
+
|
|
119
|
+
barsStackView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor),
|
|
120
|
+
barsStackView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor)
|
|
121
|
+
])
|
|
122
|
+
|
|
123
|
+
updateIndicator()
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
private func createBar(height: CGFloat) -> UIView {
|
|
127
|
+
let bar = UIView()
|
|
128
|
+
bar.translatesAutoresizingMaskIntoConstraints = false
|
|
129
|
+
bar.backgroundColor = inactiveColor
|
|
130
|
+
bar.layer.cornerRadius = 1
|
|
131
|
+
bar.layer.masksToBounds = true
|
|
132
|
+
|
|
133
|
+
NSLayoutConstraint.activate([
|
|
134
|
+
bar.widthAnchor.constraint(equalToConstant: barWidth),
|
|
135
|
+
bar.heightAnchor.constraint(equalToConstant: height)
|
|
136
|
+
])
|
|
137
|
+
|
|
138
|
+
return bar
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
private func updateIndicator() {
|
|
142
|
+
switch connectionQuality {
|
|
143
|
+
case .excellent:
|
|
144
|
+
isHidden = false
|
|
145
|
+
bar1.backgroundColor = goodColor
|
|
146
|
+
bar2.backgroundColor = goodColor
|
|
147
|
+
bar3.backgroundColor = goodColor
|
|
148
|
+
case .good:
|
|
149
|
+
isHidden = false
|
|
150
|
+
bar1.backgroundColor = goodColor
|
|
151
|
+
bar2.backgroundColor = goodColor
|
|
152
|
+
bar3.backgroundColor = inactiveColor
|
|
153
|
+
case .poor:
|
|
154
|
+
isHidden = false
|
|
155
|
+
bar1.backgroundColor = badColor
|
|
156
|
+
bar2.backgroundColor = inactiveColor
|
|
157
|
+
bar3.backgroundColor = inactiveColor
|
|
158
|
+
case .unspecified:
|
|
159
|
+
isHidden = true
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright © 2024 Stream.io Inc. All rights reserved.
|
|
3
|
+
//
|
|
4
|
+
// Adapted from stream-video-swift for React Native SDK
|
|
5
|
+
// Original: https://github.com/GetStream/stream-video-swift/blob/develop/Sources/StreamVideoSwiftUI/Utils/PictureInPicture/PictureInPictureContent.swift
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import Foundation
|
|
9
|
+
|
|
10
|
+
/// Represents the content state for the Picture-in-Picture window.
|
|
11
|
+
///
|
|
12
|
+
/// This enum defines the different states that the PiP window can display:
|
|
13
|
+
/// - `inactive`: No content is being shown (PiP is not active)
|
|
14
|
+
/// - `video`: Live video from a participant (camera or screen share)
|
|
15
|
+
/// - `avatar`: Participant avatar placeholder (when video is disabled)
|
|
16
|
+
/// - `screenSharing`: Screen share content with indicator overlay
|
|
17
|
+
/// - `reconnecting`: Connection recovery indicator
|
|
18
|
+
///
|
|
19
|
+
/// The React Native SDK receives content state from the JavaScript layer through
|
|
20
|
+
/// the bridge, unlike the upstream Swift SDK which observes call state internally.
|
|
21
|
+
enum PictureInPictureContent: Equatable, CustomStringConvertible {
|
|
22
|
+
/// No content - PiP is inactive or transitioning
|
|
23
|
+
case inactive
|
|
24
|
+
|
|
25
|
+
/// Video content from a participant
|
|
26
|
+
/// - Parameters:
|
|
27
|
+
/// - track: The WebRTC video track to render
|
|
28
|
+
/// - participantName: The participant's display name (for fallback)
|
|
29
|
+
/// - participantImageURL: URL to participant's profile image (for fallback)
|
|
30
|
+
case video(track: RTCVideoTrack?, participantName: String?, participantImageURL: String?)
|
|
31
|
+
|
|
32
|
+
/// Screen sharing content
|
|
33
|
+
/// - Parameters:
|
|
34
|
+
/// - track: The WebRTC video track containing screen share
|
|
35
|
+
/// - participantName: Name of the participant sharing their screen
|
|
36
|
+
case screenSharing(track: RTCVideoTrack?, participantName: String?)
|
|
37
|
+
|
|
38
|
+
/// Avatar placeholder shown when video is disabled
|
|
39
|
+
/// - Parameters:
|
|
40
|
+
/// - participantName: The participant's display name (for initials)
|
|
41
|
+
/// - participantImageURL: URL to participant's profile image
|
|
42
|
+
case avatar(participantName: String?, participantImageURL: String?)
|
|
43
|
+
|
|
44
|
+
/// Connection recovery indicator
|
|
45
|
+
case reconnecting
|
|
46
|
+
|
|
47
|
+
// MARK: - CustomStringConvertible
|
|
48
|
+
|
|
49
|
+
var description: String {
|
|
50
|
+
switch self {
|
|
51
|
+
case .inactive:
|
|
52
|
+
return ".inactive"
|
|
53
|
+
case let .video(track, name, _):
|
|
54
|
+
return ".video(track:\(track?.trackId ?? "nil"), name:\(name ?? "-"))"
|
|
55
|
+
case let .screenSharing(track, name):
|
|
56
|
+
return ".screenSharing(track:\(track?.trackId ?? "nil"), name:\(name ?? "-"))"
|
|
57
|
+
case let .avatar(name, _):
|
|
58
|
+
return ".avatar(name:\(name ?? "-"))"
|
|
59
|
+
case .reconnecting:
|
|
60
|
+
return ".reconnecting"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// MARK: - Equatable
|
|
65
|
+
|
|
66
|
+
static func == (lhs: PictureInPictureContent, rhs: PictureInPictureContent) -> Bool {
|
|
67
|
+
switch (lhs, rhs) {
|
|
68
|
+
case (.inactive, .inactive):
|
|
69
|
+
return true
|
|
70
|
+
case let (.video(lhsTrack, lhsName, lhsImage), .video(rhsTrack, rhsName, rhsImage)):
|
|
71
|
+
return isSameTrackInstance(lhsTrack, rhsTrack)
|
|
72
|
+
&& lhsName == rhsName
|
|
73
|
+
&& lhsImage == rhsImage
|
|
74
|
+
case let (.screenSharing(lhsTrack, lhsName), .screenSharing(rhsTrack, rhsName)):
|
|
75
|
+
return isSameTrackInstance(lhsTrack, rhsTrack)
|
|
76
|
+
&& lhsName == rhsName
|
|
77
|
+
case let (.avatar(lhsName, lhsImage), .avatar(rhsName, rhsImage)):
|
|
78
|
+
return lhsName == rhsName
|
|
79
|
+
&& lhsImage == rhsImage
|
|
80
|
+
case (.reconnecting, .reconnecting):
|
|
81
|
+
return true
|
|
82
|
+
default:
|
|
83
|
+
return false
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/// Track identity must be reference-based so reconnect-created tracks
|
|
88
|
+
/// with reused `trackId` still propagate through content updates.
|
|
89
|
+
private static func isSameTrackInstance(_ lhs: RTCVideoTrack?, _ rhs: RTCVideoTrack?) -> Bool {
|
|
90
|
+
switch (lhs, rhs) {
|
|
91
|
+
case (nil, nil):
|
|
92
|
+
return true
|
|
93
|
+
case let (lhsTrack?, rhsTrack?):
|
|
94
|
+
return lhsTrack === rhsTrack
|
|
95
|
+
default:
|
|
96
|
+
return false
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// MARK: - Convenience Properties
|
|
101
|
+
|
|
102
|
+
/// Returns the video track if this content has one, nil otherwise
|
|
103
|
+
var track: RTCVideoTrack? {
|
|
104
|
+
switch self {
|
|
105
|
+
case let .video(track, _, _):
|
|
106
|
+
return track
|
|
107
|
+
case let .screenSharing(track, _):
|
|
108
|
+
return track
|
|
109
|
+
case .inactive, .avatar, .reconnecting:
|
|
110
|
+
return nil
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/// Returns the participant name if available
|
|
115
|
+
var participantName: String? {
|
|
116
|
+
switch self {
|
|
117
|
+
case let .video(_, name, _):
|
|
118
|
+
return name
|
|
119
|
+
case let .screenSharing(_, name):
|
|
120
|
+
return name
|
|
121
|
+
case let .avatar(name, _):
|
|
122
|
+
return name
|
|
123
|
+
case .inactive, .reconnecting:
|
|
124
|
+
return nil
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/// Returns the participant image URL if available
|
|
129
|
+
var participantImageURL: String? {
|
|
130
|
+
switch self {
|
|
131
|
+
case let .video(_, _, imageURL):
|
|
132
|
+
return imageURL
|
|
133
|
+
case let .avatar(_, imageURL):
|
|
134
|
+
return imageURL
|
|
135
|
+
case .inactive, .screenSharing, .reconnecting:
|
|
136
|
+
return nil
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/// Whether this content represents an active video stream
|
|
141
|
+
var hasActiveVideo: Bool {
|
|
142
|
+
switch self {
|
|
143
|
+
case .video, .screenSharing:
|
|
144
|
+
return true
|
|
145
|
+
case .inactive, .avatar, .reconnecting:
|
|
146
|
+
return false
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/// Whether this content is screen sharing
|
|
151
|
+
var isScreenSharing: Bool {
|
|
152
|
+
if case .screenSharing = self {
|
|
153
|
+
return true
|
|
154
|
+
}
|
|
155
|
+
return false
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/// Whether this content shows an avatar
|
|
159
|
+
var isShowingAvatar: Bool {
|
|
160
|
+
if case .avatar = self {
|
|
161
|
+
return true
|
|
162
|
+
}
|
|
163
|
+
return false
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/// Whether this content shows the reconnection view
|
|
167
|
+
var isReconnecting: Bool {
|
|
168
|
+
if case .reconnecting = self {
|
|
169
|
+
return true
|
|
170
|
+
}
|
|
171
|
+
return false
|
|
172
|
+
}
|
|
173
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright © 2024 Stream.io Inc. All rights reserved.
|
|
3
|
+
//
|
|
4
|
+
// Adapted from stream-video-swift PictureInPictureStore for React Native SDK
|
|
5
|
+
// The React Native SDK receives state from the JavaScript bridge rather than
|
|
6
|
+
// observing call state internally, so this is a simplified state container.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import Combine
|
|
10
|
+
import Foundation
|
|
11
|
+
|
|
12
|
+
/// Manages the content state for the Picture-in-Picture window.
|
|
13
|
+
///
|
|
14
|
+
/// This class provides centralized state management for the PiP content view system.
|
|
15
|
+
/// Unlike the upstream `PictureInPictureStore` which uses a Flux-like action/dispatch pattern,
|
|
16
|
+
/// this implementation is optimized for the React Native bridge where state updates come
|
|
17
|
+
/// from the JavaScript layer.
|
|
18
|
+
///
|
|
19
|
+
/// State changes are published via Combine to allow reactive updates in the view layer.
|
|
20
|
+
///
|
|
21
|
+
/// Concurrency model:
|
|
22
|
+
/// - This state container is main-thread confined.
|
|
23
|
+
/// - `RTCVideoTrack` references are never sent across queues.
|
|
24
|
+
final class PictureInPictureContentState {
|
|
25
|
+
|
|
26
|
+
/// A full state snapshot that can be applied atomically.
|
|
27
|
+
struct Snapshot {
|
|
28
|
+
var track: RTCVideoTrack?
|
|
29
|
+
var participantName: String?
|
|
30
|
+
var participantImageURL: String?
|
|
31
|
+
var isVideoEnabled: Bool
|
|
32
|
+
var isScreenSharing: Bool
|
|
33
|
+
var isReconnecting: Bool
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// MARK: - Published State
|
|
37
|
+
|
|
38
|
+
/// The current content being displayed in the PiP window.
|
|
39
|
+
@Published private(set) var content: PictureInPictureContent = .inactive
|
|
40
|
+
|
|
41
|
+
/// Publisher for observing content changes.
|
|
42
|
+
var contentPublisher: AnyPublisher<PictureInPictureContent, Never> {
|
|
43
|
+
$content.eraseToAnyPublisher()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// MARK: - Private
|
|
47
|
+
|
|
48
|
+
private var snapshot: Snapshot = makeDefaultSnapshot()
|
|
49
|
+
|
|
50
|
+
// MARK: - Initialization
|
|
51
|
+
|
|
52
|
+
init() {}
|
|
53
|
+
|
|
54
|
+
// MARK: - State Update
|
|
55
|
+
|
|
56
|
+
/// Applies all content inputs in one step to avoid parallel update paths.
|
|
57
|
+
func apply(_ snapshot: Snapshot) {
|
|
58
|
+
ensureMainThread()
|
|
59
|
+
self.snapshot = snapshot
|
|
60
|
+
publishIfNeeded(for: snapshot)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/// Resets all state to defaults.
|
|
64
|
+
/// Called when cleaning up after a call ends.
|
|
65
|
+
func reset() {
|
|
66
|
+
ensureMainThread()
|
|
67
|
+
snapshot = Self.makeDefaultSnapshot()
|
|
68
|
+
if content != .inactive {
|
|
69
|
+
content = .inactive
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/// Computes and publishes content based on the latest snapshot.
|
|
74
|
+
private func publishIfNeeded(for snapshot: Snapshot) {
|
|
75
|
+
let newContent: PictureInPictureContent
|
|
76
|
+
|
|
77
|
+
// Priority order: reconnecting > screen sharing > avatar (video disabled) > video > avatar fallback
|
|
78
|
+
if snapshot.isReconnecting {
|
|
79
|
+
newContent = .reconnecting
|
|
80
|
+
} else if snapshot.isScreenSharing {
|
|
81
|
+
newContent = .screenSharing(
|
|
82
|
+
track: snapshot.track,
|
|
83
|
+
participantName: snapshot.participantName
|
|
84
|
+
)
|
|
85
|
+
} else if !snapshot.isVideoEnabled {
|
|
86
|
+
newContent = .avatar(
|
|
87
|
+
participantName: snapshot.participantName,
|
|
88
|
+
participantImageURL: snapshot.participantImageURL
|
|
89
|
+
)
|
|
90
|
+
} else if snapshot.isVideoEnabled, snapshot.track != nil {
|
|
91
|
+
newContent = .video(
|
|
92
|
+
track: snapshot.track,
|
|
93
|
+
participantName: snapshot.participantName,
|
|
94
|
+
participantImageURL: snapshot.participantImageURL
|
|
95
|
+
)
|
|
96
|
+
} else {
|
|
97
|
+
newContent = .avatar(
|
|
98
|
+
participantName: snapshot.participantName,
|
|
99
|
+
participantImageURL: snapshot.participantImageURL
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if content != newContent {
|
|
104
|
+
content = newContent
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/// PiP content state is expected to be mutated on the main thread only.
|
|
109
|
+
private func ensureMainThread() {
|
|
110
|
+
dispatchPrecondition(condition: .onQueue(.main))
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private static func makeDefaultSnapshot() -> Snapshot {
|
|
114
|
+
Snapshot(
|
|
115
|
+
track: nil,
|
|
116
|
+
participantName: nil,
|
|
117
|
+
participantImageURL: nil,
|
|
118
|
+
isVideoEnabled: true,
|
|
119
|
+
isScreenSharing: false,
|
|
120
|
+
isReconnecting: false
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright © 2024 Stream.io Inc. All rights reserved.
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import AVKit
|
|
6
|
+
import Combine
|
|
7
|
+
|
|
8
|
+
/// A wrapper around AVPictureInPictureControllerDelegate that publishes all
|
|
9
|
+
/// delegate method calls via a single Combine publisher.
|
|
10
|
+
///
|
|
11
|
+
/// This proxy enables reactive handling of PiP lifecycle events and allows
|
|
12
|
+
/// multiple subscribers to observe PiP state changes through a unified interface.
|
|
13
|
+
final class PictureInPictureDelegateProxy: NSObject, AVPictureInPictureControllerDelegate {
|
|
14
|
+
|
|
15
|
+
/// Enum representing each AVPictureInPictureControllerDelegate method call
|
|
16
|
+
/// with its respective associated values.
|
|
17
|
+
enum Event: CustomStringConvertible {
|
|
18
|
+
case willStart(AVPictureInPictureController)
|
|
19
|
+
case didStart(AVPictureInPictureController)
|
|
20
|
+
case failedToStart(AVPictureInPictureController, Error)
|
|
21
|
+
case willStop(AVPictureInPictureController)
|
|
22
|
+
case didStop(AVPictureInPictureController)
|
|
23
|
+
case restoreUI(AVPictureInPictureController, (Bool) -> Void)
|
|
24
|
+
|
|
25
|
+
var description: String {
|
|
26
|
+
switch self {
|
|
27
|
+
case .willStart:
|
|
28
|
+
return ".willStart"
|
|
29
|
+
case .didStart:
|
|
30
|
+
return ".didStart"
|
|
31
|
+
case let .failedToStart(_, error):
|
|
32
|
+
return ".failedToStart(error: \(error.localizedDescription))"
|
|
33
|
+
case .willStop:
|
|
34
|
+
return ".willStop"
|
|
35
|
+
case .didStop:
|
|
36
|
+
return ".didStop"
|
|
37
|
+
case .restoreUI:
|
|
38
|
+
return ".restoreUI"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/// The Combine publisher that emits Picture-in-Picture delegate events.
|
|
44
|
+
var publisher: AnyPublisher<Event, Never> {
|
|
45
|
+
eventSubject.eraseToAnyPublisher()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private let eventSubject = PassthroughSubject<Event, Never>()
|
|
49
|
+
|
|
50
|
+
// MARK: - AVPictureInPictureControllerDelegate
|
|
51
|
+
|
|
52
|
+
func pictureInPictureControllerWillStartPictureInPicture(
|
|
53
|
+
_ pictureInPictureController: AVPictureInPictureController
|
|
54
|
+
) {
|
|
55
|
+
eventSubject.send(.willStart(pictureInPictureController))
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
func pictureInPictureControllerDidStartPictureInPicture(
|
|
59
|
+
_ pictureInPictureController: AVPictureInPictureController
|
|
60
|
+
) {
|
|
61
|
+
eventSubject.send(.didStart(pictureInPictureController))
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
func pictureInPictureController(
|
|
65
|
+
_ pictureInPictureController: AVPictureInPictureController,
|
|
66
|
+
failedToStartPictureInPictureWithError error: Error
|
|
67
|
+
) {
|
|
68
|
+
eventSubject.send(.failedToStart(pictureInPictureController, error))
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
func pictureInPictureControllerWillStopPictureInPicture(
|
|
72
|
+
_ pictureInPictureController: AVPictureInPictureController
|
|
73
|
+
) {
|
|
74
|
+
eventSubject.send(.willStop(pictureInPictureController))
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
func pictureInPictureControllerDidStopPictureInPicture(
|
|
78
|
+
_ pictureInPictureController: AVPictureInPictureController
|
|
79
|
+
) {
|
|
80
|
+
eventSubject.send(.didStop(pictureInPictureController))
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
func pictureInPictureController(
|
|
84
|
+
_ pictureInPictureController: AVPictureInPictureController,
|
|
85
|
+
restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void
|
|
86
|
+
) {
|
|
87
|
+
eventSubject.send(.restoreUI(pictureInPictureController, completionHandler))
|
|
88
|
+
}
|
|
89
|
+
}
|