expo-realtime-ivs-broadcast 0.1.9 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +261 -4
- package/android/build/.transforms/10a4d332fad050fdaf4ee2d7badc1ee4/transformed/classes/classes_dex/classes.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/ExpoIVSRemoteStreamView.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/ExpoIVSStagePreviewView$attachStreamWithRetry$4.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/ExpoIVSStagePreviewView.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$1$16$1.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$1$10$2.dex → ExpoRealtimeIvsBroadcastModule$definition$1$16$2.dex} +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$1$11$1.dex → ExpoRealtimeIvsBroadcastModule$definition$1$17$1.dex} +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$2.dex → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$1.dex} +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$10.dex → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$10.dex} +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$14.dex → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$11.dex} +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$12.dex → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$12.dex} +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$13.dex → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$13.dex} +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$11.dex → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$14.dex} +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$15.dex → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$15.dex} +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$16.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$17.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$18.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$4.dex → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$2.dex} +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$3.dex → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$3.dex} +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$5.dex → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$4.dex} +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$1.dex → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$5.dex} +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$6.dex → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$6.dex} +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$7.dex → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$7.dex} +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$8.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$9.dex → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$9.dex} +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunctionWithoutArgs$1.dex → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$1.dex} +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunctionWithoutArgs$2.dex → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$2.dex} +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunctionWithoutArgs$3.dex → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$3.dex} +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$4.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$5.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$6.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$7.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$8.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$OnCreate$1.dex → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$OnCreate$1.dex} +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$View$1.dex → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$View$1.dex} +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$View$2.dex → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$View$2.dex} +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$lambda$22$$inlined$Prop$1.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$lambda$10$$inlined$Prop$1.dex → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$lambda$22$$inlined$Prop$2.dex} +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$lambda$23$$inlined$Prop$1.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/IVSStageManager.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/PiPOptions$PiPSourceView.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/PiPOptions.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/PiPStateListener.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/PictureInPictureDelegate.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/PictureInPictureManager$Companion.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/PictureInPictureManager.dex +0 -0
- package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +5 -0
- package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
- package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +12 -1
- package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +5 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoIVSRemoteStreamView.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoIVSStagePreviewView$attachStreamWithRetry$4.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoIVSStagePreviewView.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$1$10$1.class → ExpoRealtimeIvsBroadcastModule$definition$1$16$1.class} +0 -0
- package/android/build/{tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$1$10$2.class → intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$1$16$2.class} +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$1$11$1.class → ExpoRealtimeIvsBroadcastModule$definition$1$17$1.class} +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$4.class → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$1.class} +0 -0
- package/android/build/{tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$10.class → intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$10.class} +0 -0
- package/android/build/{tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$14.class → intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$11.class} +0 -0
- package/android/build/{tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$12.class → intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$12.class} +0 -0
- package/android/build/{tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$13.class → intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$13.class} +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$11.class → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$14.class} +0 -0
- package/android/build/{tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$15.class → intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$15.class} +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$16.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$17.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$18.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$5.class → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$2.class} +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$3.class → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$3.class} +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$2.class → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$4.class} +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$1.class → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$5.class} +0 -0
- package/android/build/{tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$6.class → intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$6.class} +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$7.class → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$7.class} +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$8.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$9.class → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$9.class} +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunctionWithoutArgs$1.class → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$1.class} +0 -0
- package/android/build/{tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunctionWithoutArgs$2.class → intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$2.class} +0 -0
- package/android/build/{tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunctionWithoutArgs$3.class → intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$3.class} +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$4.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$5.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$6.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$7.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$8.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$OnCreate$1.class → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$OnCreate$1.class} +0 -0
- package/android/build/{tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$View$1.class → intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$View$1.class} +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$View$2.class → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$View$2.class} +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$lambda$22$$inlined$Prop$1.class +0 -0
- package/android/build/{tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$lambda$10$$inlined$Prop$1.class → intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$lambda$22$$inlined$Prop$2.class} +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$lambda$10$$inlined$Prop$1.class → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$lambda$23$$inlined$Prop$1.class} +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/IVSStageManager.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/PiPOptions$PiPSourceView.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/PiPOptions.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/PiPStateListener.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/PictureInPictureDelegate.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/PictureInPictureManager$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/PictureInPictureManager.class +0 -0
- package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.s +1 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.s +1 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/counters.tab +1 -1
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.s +1 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
- package/android/build/outputs/logs/manifest-merger-debug-report.txt +14 -2
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoIVSRemoteStreamView.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoIVSStagePreviewView$attachStreamWithRetry$4.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoIVSStagePreviewView.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$1$10$1.class → ExpoRealtimeIvsBroadcastModule$definition$1$16$1.class} +0 -0
- package/android/build/{intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$1$10$2.class → tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$1$16$2.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$1$11$1.class → ExpoRealtimeIvsBroadcastModule$definition$1$17$1.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$1.class +0 -0
- package/android/build/{intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$10.class → tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$10.class} +0 -0
- package/android/build/{intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$14.class → tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$11.class} +0 -0
- package/android/build/{intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$12.class → tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$12.class} +0 -0
- package/android/build/{intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$13.class → tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$13.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$11.class → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$14.class} +0 -0
- package/android/build/{intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$15.class → tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$15.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$16.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$17.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$18.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$2.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$3.class → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$3.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$4.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$5.class +0 -0
- package/android/build/{intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$6.class → tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$6.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$7.class → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$7.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$8.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$9.class → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunction$9.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunctionWithoutArgs$1.class → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$1.class} +0 -0
- package/android/build/{intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunctionWithoutArgs$2.class → tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$2.class} +0 -0
- package/android/build/{intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunctionWithoutArgs$3.class → tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$3.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$4.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$5.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$6.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$7.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$AsyncFunctionWithoutArgs$8.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$OnCreate$1.class → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$OnCreate$1.class} +0 -0
- package/android/build/{intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$View$1.class → tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$View$1.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$View$2.class → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$$inlined$View$2.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$lambda$22$$inlined$Prop$1.class +0 -0
- package/android/build/{intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$lambda$9$$inlined$Prop$2.class → tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$24$lambda$22$$inlined$Prop$2.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/{ExpoRealtimeIvsBroadcastModule$definition$lambda$11$lambda$9$$inlined$Prop$2.class → ExpoRealtimeIvsBroadcastModule$definition$lambda$24$lambda$23$$inlined$Prop$1.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/IVSStageManager.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/PiPOptions$PiPSourceView.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/PiPOptions.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/PiPStateListener.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/PictureInPictureDelegate.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/PictureInPictureManager$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/PictureInPictureManager.class +0 -0
- package/android/src/main/AndroidManifest.xml +5 -0
- package/android/src/main/java/expo/modules/realtimeivsbroadcast/ExpoIVSRemoteStreamView.kt +172 -23
- package/android/src/main/java/expo/modules/realtimeivsbroadcast/ExpoIVSStagePreviewView.kt +68 -9
- package/android/src/main/java/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule.kt +92 -2
- package/android/src/main/java/expo/modules/realtimeivsbroadcast/IVSStageManager.kt +9 -2
- package/android/src/main/java/expo/modules/realtimeivsbroadcast/PictureInPictureManager.kt +431 -0
- package/build/ExpoRealtimeIvsBroadcast.types.d.ts +45 -0
- package/build/ExpoRealtimeIvsBroadcast.types.d.ts.map +1 -1
- package/build/ExpoRealtimeIvsBroadcast.types.js.map +1 -1
- package/build/ExpoRealtimeIvsBroadcastModule.d.ts +7 -1
- package/build/ExpoRealtimeIvsBroadcastModule.d.ts.map +1 -1
- package/build/ExpoRealtimeIvsBroadcastModule.js.map +1 -1
- package/build/ExpoRealtimeIvsBroadcastModule.web.d.ts +7 -1
- package/build/ExpoRealtimeIvsBroadcastModule.web.d.ts.map +1 -1
- package/build/ExpoRealtimeIvsBroadcastModule.web.js +20 -0
- package/build/ExpoRealtimeIvsBroadcastModule.web.js.map +1 -1
- package/build/index.d.ts +60 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +77 -0
- package/build/index.js.map +1 -1
- package/ios/ExpoIVSRemoteStreamView.swift +17 -0
- package/ios/ExpoIVSStagePreviewView.swift +18 -0
- package/ios/ExpoRealtimeIvsBroadcast.podspec +2 -1
- package/ios/ExpoRealtimeIvsBroadcastModule.swift +46 -1
- package/ios/IVSPictureInPictureController.swift +1070 -0
- package/ios/IVSStageManager.swift +419 -1
- package/package.json +1 -1
- package/src/ExpoRealtimeIvsBroadcast.types.ts +53 -0
- package/src/ExpoRealtimeIvsBroadcastModule.ts +9 -1
- package/src/ExpoRealtimeIvsBroadcastModule.web.ts +26 -8
- package/src/index.ts +94 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$1$10$1.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$8.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$lambda$9$$inlined$Prop$1.dex +0 -0
- package/android/build/.transforms/9f2f591934de19590757f5a4b0b59398/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$lambda$9$$inlined$Prop$2.dex +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$8.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$lambda$9$$inlined$Prop$1.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$1.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$2.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$4.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$5.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$$inlined$AsyncFunction$8.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/expo/modules/realtimeivsbroadcast/ExpoRealtimeIvsBroadcastModule$definition$lambda$11$lambda$9$$inlined$Prop$1.class +0 -0
|
@@ -0,0 +1,1070 @@
|
|
|
1
|
+
// IVSPictureInPictureController.swift
|
|
2
|
+
// Picture-in-Picture support for IVS Stages
|
|
3
|
+
|
|
4
|
+
import AVKit
|
|
5
|
+
import AVFoundation
|
|
6
|
+
import UIKit
|
|
7
|
+
import AmazonIVSBroadcast
|
|
8
|
+
|
|
9
|
+
// MARK: - PiP Types (Available to all iOS versions for type compatibility)
|
|
10
|
+
|
|
11
|
+
/// Options for configuring PiP behavior
|
|
12
|
+
public struct PiPOptions {
|
|
13
|
+
public var autoEnterOnBackground: Bool = true
|
|
14
|
+
public var sourceView: PiPSourceView = .remote
|
|
15
|
+
public var preferredAspectRatio: CGSize = CGSize(width: 9, height: 16)
|
|
16
|
+
|
|
17
|
+
public enum PiPSourceView: String {
|
|
18
|
+
case local
|
|
19
|
+
case remote
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public init() {}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/// Delegate protocol for PiP state changes
|
|
26
|
+
public protocol IVSPictureInPictureControllerDelegate: AnyObject {
|
|
27
|
+
func pictureInPictureDidStart()
|
|
28
|
+
func pictureInPictureDidStop()
|
|
29
|
+
func pictureInPictureWillRestore()
|
|
30
|
+
func pictureInPictureDidFail(with error: String)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// MARK: - View Frame Capture
|
|
34
|
+
/// Captures frames from any UIView using CADisplayLink for PiP
|
|
35
|
+
/// This is the workaround for IVS SDK not exposing frame callbacks
|
|
36
|
+
/// ALL operations happen on the main thread to avoid threading issues
|
|
37
|
+
|
|
38
|
+
public class ViewFrameCapture {
|
|
39
|
+
private var displayLink: CADisplayLink?
|
|
40
|
+
private weak var targetView: UIView?
|
|
41
|
+
private var frameCallback: ((CVPixelBuffer) -> Void)?
|
|
42
|
+
|
|
43
|
+
// Throttle frame capture to 30fps
|
|
44
|
+
private var lastCaptureTime: CFTimeInterval = 0
|
|
45
|
+
private let targetFrameInterval: CFTimeInterval = 1.0 / 30.0
|
|
46
|
+
|
|
47
|
+
// Fixed output size to prevent jittering - 9:16 portrait
|
|
48
|
+
private let fixedOutputWidth: Int = 540
|
|
49
|
+
private let fixedOutputHeight: Int = 960
|
|
50
|
+
|
|
51
|
+
// Reusable pixel buffer pool for efficiency
|
|
52
|
+
private var pixelBufferPool: CVPixelBufferPool?
|
|
53
|
+
private var lastWidth: Int = 0
|
|
54
|
+
private var lastHeight: Int = 0
|
|
55
|
+
|
|
56
|
+
private var isCapturing: Bool = false
|
|
57
|
+
|
|
58
|
+
public init() {}
|
|
59
|
+
|
|
60
|
+
deinit {
|
|
61
|
+
stop()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/// Start capturing frames from the target view
|
|
65
|
+
public func start(view: UIView, callback: @escaping (CVPixelBuffer) -> Void) {
|
|
66
|
+
// Ensure we're on main thread
|
|
67
|
+
guard Thread.isMainThread else {
|
|
68
|
+
DispatchQueue.main.async { [weak self] in
|
|
69
|
+
self?.start(view: view, callback: callback)
|
|
70
|
+
}
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
stop() // Clean up any existing capture
|
|
75
|
+
|
|
76
|
+
self.targetView = view
|
|
77
|
+
self.frameCallback = callback
|
|
78
|
+
self.isCapturing = true
|
|
79
|
+
|
|
80
|
+
let displayLink = CADisplayLink(target: self, selector: #selector(self.captureFrame))
|
|
81
|
+
displayLink.preferredFrameRateRange = CAFrameRateRange(minimum: 24, maximum: 30, preferred: 30)
|
|
82
|
+
displayLink.add(to: .main, forMode: .common)
|
|
83
|
+
self.displayLink = displayLink
|
|
84
|
+
|
|
85
|
+
print("🖼️ [ViewCapture] Started capturing frames from view")
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/// Stop capturing frames
|
|
89
|
+
public func stop() {
|
|
90
|
+
// Ensure we're on main thread
|
|
91
|
+
guard Thread.isMainThread else {
|
|
92
|
+
DispatchQueue.main.async { [weak self] in
|
|
93
|
+
self?.stop()
|
|
94
|
+
}
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
isCapturing = false
|
|
99
|
+
displayLink?.invalidate()
|
|
100
|
+
displayLink = nil
|
|
101
|
+
targetView = nil
|
|
102
|
+
frameCallback = nil
|
|
103
|
+
pixelBufferPool = nil
|
|
104
|
+
lastWidth = 0
|
|
105
|
+
lastHeight = 0
|
|
106
|
+
frameCount = 0
|
|
107
|
+
print("🖼️ [ViewCapture] Stopped capturing frames")
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@objc private func captureFrame(_ displayLink: CADisplayLink) {
|
|
111
|
+
// All of this runs on main thread (CADisplayLink callback)
|
|
112
|
+
guard isCapturing else { return }
|
|
113
|
+
|
|
114
|
+
// Throttle to target frame rate
|
|
115
|
+
let currentTime = displayLink.timestamp
|
|
116
|
+
guard currentTime - lastCaptureTime >= targetFrameInterval else { return }
|
|
117
|
+
lastCaptureTime = currentTime
|
|
118
|
+
|
|
119
|
+
guard let view = targetView, let callback = frameCallback else { return }
|
|
120
|
+
|
|
121
|
+
let bounds = view.bounds
|
|
122
|
+
guard bounds.width > 0 && bounds.height > 0 else { return }
|
|
123
|
+
|
|
124
|
+
// Check if view has a window - if not, try to get superview bounds
|
|
125
|
+
// IVS preview might not have window when app is in background
|
|
126
|
+
let captureView: UIView
|
|
127
|
+
let captureBounds: CGRect
|
|
128
|
+
|
|
129
|
+
if view.window != nil {
|
|
130
|
+
captureView = view
|
|
131
|
+
captureBounds = bounds
|
|
132
|
+
} else if let superview = view.superview, superview.window != nil {
|
|
133
|
+
// Try capturing from superview instead
|
|
134
|
+
captureView = superview
|
|
135
|
+
captureBounds = superview.bounds
|
|
136
|
+
} else {
|
|
137
|
+
// Last resort: capture the view anyway with afterScreenUpdates
|
|
138
|
+
captureView = view
|
|
139
|
+
captureBounds = bounds
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Use UIGraphicsImageRenderer with drawHierarchy for Metal/OpenGL views
|
|
143
|
+
// This is the only reliable way to capture IVS preview views
|
|
144
|
+
// NOTE: afterScreenUpdates must be true when view is not in visible window (e.g., during PiP)
|
|
145
|
+
let renderer = UIGraphicsImageRenderer(size: captureBounds.size)
|
|
146
|
+
let image = renderer.image { rendererContext in
|
|
147
|
+
// drawHierarchy captures Metal/OpenGL content unlike layer.render
|
|
148
|
+
// afterScreenUpdates: true is required when view may not be visible
|
|
149
|
+
captureView.drawHierarchy(in: captureBounds, afterScreenUpdates: true)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
guard let cgImage = image.cgImage else { return }
|
|
153
|
+
|
|
154
|
+
// Use FIXED output size to prevent jittering
|
|
155
|
+
let width = fixedOutputWidth
|
|
156
|
+
let height = fixedOutputHeight
|
|
157
|
+
|
|
158
|
+
// Get pixel buffer from pool with fixed size
|
|
159
|
+
guard let pixelBuffer = getPixelBuffer(width: width, height: height) else {
|
|
160
|
+
return
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
CVPixelBufferLockBaseAddress(pixelBuffer, [])
|
|
164
|
+
defer { CVPixelBufferUnlockBaseAddress(pixelBuffer, []) }
|
|
165
|
+
|
|
166
|
+
guard let context = CGContext(
|
|
167
|
+
data: CVPixelBufferGetBaseAddress(pixelBuffer),
|
|
168
|
+
width: width,
|
|
169
|
+
height: height,
|
|
170
|
+
bitsPerComponent: 8,
|
|
171
|
+
bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer),
|
|
172
|
+
space: CGColorSpaceCreateDeviceRGB(),
|
|
173
|
+
bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue | CGBitmapInfo.byteOrder32Little.rawValue
|
|
174
|
+
) else {
|
|
175
|
+
return
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Calculate scaling to fit the captured image into fixed output size
|
|
179
|
+
// while maintaining aspect ratio (aspect fill)
|
|
180
|
+
let sourceWidth = CGFloat(cgImage.width)
|
|
181
|
+
let sourceHeight = CGFloat(cgImage.height)
|
|
182
|
+
let targetWidth = CGFloat(width)
|
|
183
|
+
let targetHeight = CGFloat(height)
|
|
184
|
+
|
|
185
|
+
let sourceAspect = sourceWidth / sourceHeight
|
|
186
|
+
let targetAspect = targetWidth / targetHeight
|
|
187
|
+
|
|
188
|
+
var drawRect: CGRect
|
|
189
|
+
if sourceAspect > targetAspect {
|
|
190
|
+
// Source is wider - fit to height, crop sides
|
|
191
|
+
let scaledWidth = targetHeight * sourceAspect
|
|
192
|
+
let xOffset = (scaledWidth - targetWidth) / 2
|
|
193
|
+
drawRect = CGRect(x: -xOffset, y: 0, width: scaledWidth, height: targetHeight)
|
|
194
|
+
} else {
|
|
195
|
+
// Source is taller - fit to width, crop top/bottom
|
|
196
|
+
let scaledHeight = targetWidth / sourceAspect
|
|
197
|
+
let yOffset = (scaledHeight - targetHeight) / 2
|
|
198
|
+
drawRect = CGRect(x: 0, y: -yOffset, width: targetWidth, height: scaledHeight)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// CGContext has origin at bottom-left, so we need to flip
|
|
202
|
+
context.translateBy(x: 0, y: CGFloat(height))
|
|
203
|
+
context.scaleBy(x: 1, y: -1)
|
|
204
|
+
|
|
205
|
+
// Draw the image scaled to fit the fixed output size (aspect fill)
|
|
206
|
+
context.draw(cgImage, in: drawRect)
|
|
207
|
+
|
|
208
|
+
// Log first frame capture for debugging
|
|
209
|
+
if frameCount == 0 {
|
|
210
|
+
print("🖼️ [ViewCapture] First frame captured: \(width)x\(height)")
|
|
211
|
+
}
|
|
212
|
+
frameCount += 1
|
|
213
|
+
|
|
214
|
+
// Call the callback with the captured frame
|
|
215
|
+
callback(pixelBuffer)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
private var frameCount: Int = 0
|
|
219
|
+
|
|
220
|
+
private func getPixelBuffer(width: Int, height: Int) -> CVPixelBuffer? {
|
|
221
|
+
// Create new pool if size changed
|
|
222
|
+
if width != lastWidth || height != lastHeight || pixelBufferPool == nil {
|
|
223
|
+
lastWidth = width
|
|
224
|
+
lastHeight = height
|
|
225
|
+
|
|
226
|
+
let attributes: [String: Any] = [
|
|
227
|
+
kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA,
|
|
228
|
+
kCVPixelBufferWidthKey as String: width,
|
|
229
|
+
kCVPixelBufferHeightKey as String: height,
|
|
230
|
+
kCVPixelBufferIOSurfacePropertiesKey as String: [:],
|
|
231
|
+
kCVPixelBufferCGImageCompatibilityKey as String: true,
|
|
232
|
+
kCVPixelBufferCGBitmapContextCompatibilityKey as String: true
|
|
233
|
+
]
|
|
234
|
+
|
|
235
|
+
var pool: CVPixelBufferPool?
|
|
236
|
+
CVPixelBufferPoolCreate(kCFAllocatorDefault, nil, attributes as CFDictionary, &pool)
|
|
237
|
+
pixelBufferPool = pool
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
guard let pool = pixelBufferPool else { return nil }
|
|
241
|
+
|
|
242
|
+
var pixelBuffer: CVPixelBuffer?
|
|
243
|
+
CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, pool, &pixelBuffer)
|
|
244
|
+
return pixelBuffer
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// MARK: - SampleBufferVideoCallView
|
|
249
|
+
/// A UIView that uses AVSampleBufferDisplayLayer as its layer class
|
|
250
|
+
/// This is required for Video Call PiP
|
|
251
|
+
|
|
252
|
+
@available(iOS 15.0, *)
|
|
253
|
+
class SampleBufferVideoCallView: UIView {
|
|
254
|
+
override class var layerClass: AnyClass {
|
|
255
|
+
return AVSampleBufferDisplayLayer.self
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
var sampleBufferDisplayLayer: AVSampleBufferDisplayLayer {
|
|
259
|
+
return layer as! AVSampleBufferDisplayLayer
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// MARK: - IVSPictureInPictureController
|
|
264
|
+
|
|
265
|
+
/// Controller for managing Picture-in-Picture functionality with IVS streams
|
|
266
|
+
/// Uses the Video Call PiP API for real-time video
|
|
267
|
+
@available(iOS 15.0, *)
|
|
268
|
+
public class IVSPictureInPictureController: NSObject {
|
|
269
|
+
|
|
270
|
+
// MARK: - Properties
|
|
271
|
+
|
|
272
|
+
private var pipController: AVPictureInPictureController?
|
|
273
|
+
private var sampleBufferDisplayLayer: AVSampleBufferDisplayLayer?
|
|
274
|
+
private var pipContentSource: AVPictureInPictureController.ContentSource?
|
|
275
|
+
|
|
276
|
+
// Video Call PiP components
|
|
277
|
+
private var pipVideoCallViewController: AVPictureInPictureVideoCallViewController?
|
|
278
|
+
private var sampleBufferVideoCallView: SampleBufferVideoCallView?
|
|
279
|
+
|
|
280
|
+
// Container/source view for PiP - this should be the ACTUAL visible view showing video
|
|
281
|
+
private var pipContainerView: UIView?
|
|
282
|
+
private weak var activeSourceView: UIView?
|
|
283
|
+
|
|
284
|
+
// Configuration
|
|
285
|
+
private var options: PiPOptions = PiPOptions()
|
|
286
|
+
|
|
287
|
+
// State
|
|
288
|
+
public private(set) var isActive: Bool = false
|
|
289
|
+
public private(set) var isEnabled: Bool = false
|
|
290
|
+
|
|
291
|
+
// Delegate
|
|
292
|
+
public weak var delegate: IVSPictureInPictureControllerDelegate?
|
|
293
|
+
|
|
294
|
+
// Frame timing for sample buffer creation
|
|
295
|
+
private var frameCount: Int64 = 0
|
|
296
|
+
private let timeScale: Int32 = 600
|
|
297
|
+
|
|
298
|
+
// Queue for sample buffer operations
|
|
299
|
+
private let sampleBufferQueue = DispatchQueue(label: "com.ivs.pip.sampleBuffer")
|
|
300
|
+
|
|
301
|
+
// View frame capture for remote streams
|
|
302
|
+
private var viewFrameCapture: ViewFrameCapture?
|
|
303
|
+
private weak var captureTargetView: UIView?
|
|
304
|
+
|
|
305
|
+
// Placeholder frame generator for broadcaster PiP (when camera is unavailable in background)
|
|
306
|
+
private var placeholderTimer: Timer?
|
|
307
|
+
private var placeholderPixelBuffer: CVPixelBuffer?
|
|
308
|
+
private var isUsingPlaceholder: Bool = false
|
|
309
|
+
private var lastRealFrameTime: CFAbsoluteTime = 0
|
|
310
|
+
private let placeholderTimeout: CFTimeInterval = 0.5 // Switch to placeholder after 0.5s without frames
|
|
311
|
+
|
|
312
|
+
// MARK: - Initialization
|
|
313
|
+
|
|
314
|
+
public override init() {
|
|
315
|
+
super.init()
|
|
316
|
+
setupNotifications()
|
|
317
|
+
createPlaceholderPixelBuffer()
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
deinit {
|
|
321
|
+
NotificationCenter.default.removeObserver(self)
|
|
322
|
+
cleanup()
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// MARK: - Setup
|
|
326
|
+
|
|
327
|
+
private func setupNotifications() {
|
|
328
|
+
NotificationCenter.default.addObserver(
|
|
329
|
+
self,
|
|
330
|
+
selector: #selector(applicationWillResignActive),
|
|
331
|
+
name: UIApplication.willResignActiveNotification,
|
|
332
|
+
object: nil
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
NotificationCenter.default.addObserver(
|
|
336
|
+
self,
|
|
337
|
+
selector: #selector(applicationDidBecomeActive),
|
|
338
|
+
name: UIApplication.didBecomeActiveNotification,
|
|
339
|
+
object: nil
|
|
340
|
+
)
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/// Enable PiP with the given options
|
|
344
|
+
/// Uses the Video Call PiP API which is designed for real-time video
|
|
345
|
+
public func enable(options: PiPOptions) -> Bool {
|
|
346
|
+
guard AVPictureInPictureController.isPictureInPictureSupported() else {
|
|
347
|
+
print("🖼️ [PiP] Picture-in-Picture is not supported on this device (simulator?)")
|
|
348
|
+
delegate?.pictureInPictureDidFail(with: "PiP not supported on this device")
|
|
349
|
+
return false
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Ensure we're on the main thread for all UI operations
|
|
353
|
+
guard Thread.isMainThread else {
|
|
354
|
+
var result = false
|
|
355
|
+
DispatchQueue.main.sync {
|
|
356
|
+
result = self.enable(options: options)
|
|
357
|
+
}
|
|
358
|
+
return result
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// If already enabled, clean up first to allow re-enabling
|
|
362
|
+
if isEnabled {
|
|
363
|
+
print("🖼️ [PiP] Already enabled, resetting state for re-enable")
|
|
364
|
+
cleanupForReEnable()
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
self.options = options
|
|
368
|
+
|
|
369
|
+
// Use fixed frame size matching our capture output (9:16 portrait)
|
|
370
|
+
let frameWidth: CGFloat = 540
|
|
371
|
+
let frameHeight: CGFloat = 960
|
|
372
|
+
|
|
373
|
+
// Create SampleBufferVideoCallView - a UIView with AVSampleBufferDisplayLayer as its layer
|
|
374
|
+
let sampleBufferView = SampleBufferVideoCallView(frame: CGRect(x: 0, y: 0, width: frameWidth, height: frameHeight))
|
|
375
|
+
sampleBufferView.sampleBufferDisplayLayer.videoGravity = .resizeAspectFill
|
|
376
|
+
self.sampleBufferDisplayLayer = sampleBufferView.sampleBufferDisplayLayer
|
|
377
|
+
self.sampleBufferVideoCallView = sampleBufferView
|
|
378
|
+
|
|
379
|
+
// Create the PiP Video Call View Controller
|
|
380
|
+
let pipVideoCallVC = AVPictureInPictureVideoCallViewController()
|
|
381
|
+
pipVideoCallVC.preferredContentSize = CGSize(width: frameWidth, height: frameHeight)
|
|
382
|
+
pipVideoCallVC.view.addSubview(sampleBufferView)
|
|
383
|
+
self.pipVideoCallViewController = pipVideoCallVC
|
|
384
|
+
|
|
385
|
+
// Set up constraints for the sample buffer view
|
|
386
|
+
sampleBufferView.translatesAutoresizingMaskIntoConstraints = false
|
|
387
|
+
NSLayoutConstraint.activate([
|
|
388
|
+
sampleBufferView.leadingAnchor.constraint(equalTo: pipVideoCallVC.view.leadingAnchor),
|
|
389
|
+
sampleBufferView.trailingAnchor.constraint(equalTo: pipVideoCallVC.view.trailingAnchor),
|
|
390
|
+
sampleBufferView.topAnchor.constraint(equalTo: pipVideoCallVC.view.topAnchor),
|
|
391
|
+
sampleBufferView.bottomAnchor.constraint(equalTo: pipVideoCallVC.view.bottomAnchor)
|
|
392
|
+
])
|
|
393
|
+
|
|
394
|
+
// NOTE: We'll set the activeSourceView later when setupWithSourceView is called
|
|
395
|
+
// The activeVideoCallSourceView MUST be the actual visible view showing video
|
|
396
|
+
self.isEnabled = true
|
|
397
|
+
|
|
398
|
+
print("🖼️ [PiP] Enabled with Video Call API: autoEnter=\(options.autoEnterOnBackground), source=\(options.sourceView.rawValue)")
|
|
399
|
+
print("🖼️ [PiP] Call setupWithSourceView() with the actual video view to complete setup")
|
|
400
|
+
|
|
401
|
+
return true
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/// Clean up state for re-enabling (without fully disabling)
|
|
405
|
+
private func cleanupForReEnable() {
|
|
406
|
+
// Stop any active PiP
|
|
407
|
+
pipController?.stopPictureInPicture()
|
|
408
|
+
pipController = nil
|
|
409
|
+
pipContentSource = nil
|
|
410
|
+
|
|
411
|
+
// Clean up Video Call components
|
|
412
|
+
sampleBufferVideoCallView?.removeFromSuperview()
|
|
413
|
+
sampleBufferVideoCallView = nil
|
|
414
|
+
pipVideoCallViewController = nil
|
|
415
|
+
|
|
416
|
+
sampleBufferDisplayLayer?.flush()
|
|
417
|
+
sampleBufferDisplayLayer = nil
|
|
418
|
+
|
|
419
|
+
// Reset state but keep isEnabled true (will be set again)
|
|
420
|
+
frameCount = 0
|
|
421
|
+
enqueuedFrameCount = 0
|
|
422
|
+
startTime = nil
|
|
423
|
+
isActive = false
|
|
424
|
+
|
|
425
|
+
// Don't nil out activeSourceView - it might still be valid
|
|
426
|
+
print("🖼️ [PiP] Cleaned up for re-enable")
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/// Complete PiP setup with the actual source view
|
|
430
|
+
/// This MUST be called with the visible view showing video content
|
|
431
|
+
public func setupWithSourceView(_ sourceView: UIView) {
|
|
432
|
+
guard Thread.isMainThread else {
|
|
433
|
+
DispatchQueue.main.async { [weak self] in
|
|
434
|
+
self?.setupWithSourceView(sourceView)
|
|
435
|
+
}
|
|
436
|
+
return
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
guard let pipVideoCallVC = pipVideoCallViewController else {
|
|
440
|
+
print("🖼️ [PiP] Error: Must call enable() before setupWithSourceView()")
|
|
441
|
+
return
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
self.activeSourceView = sourceView
|
|
445
|
+
self.pipContainerView = sourceView
|
|
446
|
+
|
|
447
|
+
// Create PiP content source using Video Call API
|
|
448
|
+
// The activeVideoCallSourceView is the ACTUAL view showing video in the app
|
|
449
|
+
let contentSource = AVPictureInPictureController.ContentSource(
|
|
450
|
+
activeVideoCallSourceView: sourceView,
|
|
451
|
+
contentViewController: pipVideoCallVC
|
|
452
|
+
)
|
|
453
|
+
self.pipContentSource = contentSource
|
|
454
|
+
|
|
455
|
+
// Create PiP controller
|
|
456
|
+
let controller = AVPictureInPictureController(contentSource: contentSource)
|
|
457
|
+
controller.delegate = self
|
|
458
|
+
controller.canStartPictureInPictureAutomaticallyFromInline = options.autoEnterOnBackground
|
|
459
|
+
|
|
460
|
+
self.pipController = controller
|
|
461
|
+
|
|
462
|
+
// Pre-warm with placeholder frames so PiP is possible immediately
|
|
463
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) { [weak self] in
|
|
464
|
+
for _ in 0..<3 {
|
|
465
|
+
self?.enqueuePlaceholderFrame()
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
print("🖼️ [PiP] Setup complete with source view: \(sourceView)")
|
|
470
|
+
print("🖼️ [PiP] isPictureInPicturePossible: \(controller.isPictureInPicturePossible)")
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/// Disable PiP
|
|
474
|
+
public func disable() {
|
|
475
|
+
// Ensure we're on the main thread
|
|
476
|
+
guard Thread.isMainThread else {
|
|
477
|
+
DispatchQueue.main.async { [weak self] in
|
|
478
|
+
self?.disable()
|
|
479
|
+
}
|
|
480
|
+
return
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if isActive {
|
|
484
|
+
stop()
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
stopViewCapture()
|
|
488
|
+
cleanup()
|
|
489
|
+
isEnabled = false
|
|
490
|
+
|
|
491
|
+
print("🖼️ [PiP] Disabled")
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/// Start PiP manually
|
|
495
|
+
public func start() {
|
|
496
|
+
// Ensure we're on the main thread
|
|
497
|
+
guard Thread.isMainThread else {
|
|
498
|
+
DispatchQueue.main.async { [weak self] in
|
|
499
|
+
self?.start()
|
|
500
|
+
}
|
|
501
|
+
return
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
guard isEnabled else {
|
|
505
|
+
print("🖼️ [PiP] Cannot start - PiP is not enabled")
|
|
506
|
+
delegate?.pictureInPictureDidFail(with: "PiP is not enabled")
|
|
507
|
+
return
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
guard let controller = pipController else {
|
|
511
|
+
print("🖼️ [PiP] Cannot start - no PiP controller")
|
|
512
|
+
delegate?.pictureInPictureDidFail(with: "PiP controller not initialized")
|
|
513
|
+
return
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// If PiP is not possible, try pre-warming with placeholder frames
|
|
517
|
+
if !controller.isPictureInPicturePossible {
|
|
518
|
+
print("🖼️ [PiP] PiP not possible, pre-warming with placeholder frames...")
|
|
519
|
+
preWarmWithPlaceholder { [weak self, weak controller] success in
|
|
520
|
+
guard let self = self, let controller = controller else { return }
|
|
521
|
+
|
|
522
|
+
if success && controller.isPictureInPicturePossible {
|
|
523
|
+
controller.startPictureInPicture()
|
|
524
|
+
print("🖼️ [PiP] Start requested after pre-warming")
|
|
525
|
+
} else {
|
|
526
|
+
print("🖼️ [PiP] Cannot start - PiP still not possible after pre-warming")
|
|
527
|
+
self.delegate?.pictureInPictureDidFail(with: "PiP is not possible at this time. Make sure video frames are being fed.")
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
return
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
controller.startPictureInPicture()
|
|
534
|
+
print("🖼️ [PiP] Start requested")
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/// Pre-warm the display layer with placeholder frames to make PiP possible
|
|
538
|
+
private func preWarmWithPlaceholder(completion: @escaping (Bool) -> Void) {
|
|
539
|
+
guard let pixelBuffer = placeholderPixelBuffer else {
|
|
540
|
+
completion(false)
|
|
541
|
+
return
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Enqueue several placeholder frames to prime the display layer
|
|
545
|
+
for _ in 0..<5 {
|
|
546
|
+
enqueuePlaceholderFrame()
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// Wait a moment for frames to be processed, then check if PiP is possible
|
|
550
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
|
|
551
|
+
let isPossible = self?.pipController?.isPictureInPicturePossible ?? false
|
|
552
|
+
print("🖼️ [PiP] Pre-warm complete, isPictureInPicturePossible: \(isPossible)")
|
|
553
|
+
completion(isPossible)
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/// Stop PiP manually
|
|
558
|
+
public func stop() {
|
|
559
|
+
// Ensure we're on the main thread
|
|
560
|
+
guard Thread.isMainThread else {
|
|
561
|
+
DispatchQueue.main.async { [weak self] in
|
|
562
|
+
self?.stop()
|
|
563
|
+
}
|
|
564
|
+
return
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
guard let controller = pipController, isActive else {
|
|
568
|
+
print("🖼️ [PiP] Cannot stop - PiP is not active")
|
|
569
|
+
return
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
controller.stopPictureInPicture()
|
|
573
|
+
print("🖼️ [PiP] Stop requested")
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// MARK: - View Capture for Remote Streams (Fallback Method)
|
|
577
|
+
|
|
578
|
+
/// Start capturing frames from a UIView (fallback method when IVSImageDevice is not available)
|
|
579
|
+
/// This also sets up the Video Call API with the source view
|
|
580
|
+
/// NOTE: For IVSImageDevice frame capture, the IVSStageManager handles the callback setup
|
|
581
|
+
/// and calls enqueueFrame() directly. This method is kept as a fallback.
|
|
582
|
+
public func startViewCapture(from view: UIView) {
|
|
583
|
+
// Ensure we're on the main thread
|
|
584
|
+
guard Thread.isMainThread else {
|
|
585
|
+
DispatchQueue.main.async { [weak self] in
|
|
586
|
+
self?.startViewCapture(from: view)
|
|
587
|
+
}
|
|
588
|
+
return
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
stopViewCapture()
|
|
592
|
+
|
|
593
|
+
// IMPORTANT: Set up the Video Call API with this view as the source
|
|
594
|
+
// This must be the actual visible view showing video content
|
|
595
|
+
if let parentView = view.superview {
|
|
596
|
+
// Use the parent container view (ExpoIVSRemoteStreamView) as the source
|
|
597
|
+
setupWithSourceView(parentView)
|
|
598
|
+
} else {
|
|
599
|
+
// Use the view directly
|
|
600
|
+
setupWithSourceView(view)
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
captureTargetView = view
|
|
604
|
+
viewFrameCapture = ViewFrameCapture()
|
|
605
|
+
viewFrameCapture?.start(view: view) { [weak self] pixelBuffer in
|
|
606
|
+
self?.enqueueFrame(pixelBuffer)
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
print("🖼️ [PiP] Started view capture for remote stream (fallback method)")
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/// Stop capturing frames from view
|
|
613
|
+
public func stopViewCapture() {
|
|
614
|
+
// Ensure we're on the main thread
|
|
615
|
+
guard Thread.isMainThread else {
|
|
616
|
+
DispatchQueue.main.async { [weak self] in
|
|
617
|
+
self?.stopViewCapture()
|
|
618
|
+
}
|
|
619
|
+
return
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
viewFrameCapture?.stop()
|
|
623
|
+
viewFrameCapture = nil
|
|
624
|
+
captureTargetView = nil
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
// MARK: - Frame Handling
|
|
628
|
+
|
|
629
|
+
/// Feed a video frame (CVPixelBuffer) to the PiP display
|
|
630
|
+
public func enqueueFrame(_ pixelBuffer: CVPixelBuffer) {
|
|
631
|
+
guard isEnabled, let displayLayer = sampleBufferDisplayLayer else {
|
|
632
|
+
return
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// Track that we received a real frame
|
|
636
|
+
lastRealFrameTime = CFAbsoluteTimeGetCurrent()
|
|
637
|
+
|
|
638
|
+
// If we were using placeholder, switch back to real frames
|
|
639
|
+
if isUsingPlaceholder {
|
|
640
|
+
print("🖼️ [PiP] Real frames resumed, stopping placeholder")
|
|
641
|
+
stopPlaceholderFrameGeneration()
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
// Log first few frames and periodically for debugging
|
|
645
|
+
let shouldLog = enqueuedFrameCount < 3 || (enqueuedFrameCount % 300 == 0) // Log every 10 seconds at 30fps
|
|
646
|
+
if shouldLog {
|
|
647
|
+
let width = CVPixelBufferGetWidth(pixelBuffer)
|
|
648
|
+
let height = CVPixelBufferGetHeight(pixelBuffer)
|
|
649
|
+
print("🖼️ [PiP] Frame #\(enqueuedFrameCount): \(width)x\(height), layer status: \(displayLayer.status.rawValue), isActive: \(isActive)")
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// Create CMSampleBuffer from CVPixelBuffer - do this synchronously
|
|
653
|
+
// to ensure the pixel buffer is not released before we use it
|
|
654
|
+
guard let sampleBuffer = self.createSampleBuffer(from: pixelBuffer) else {
|
|
655
|
+
if enqueuedFrameCount < 3 {
|
|
656
|
+
print("🖼️ [PiP] Failed to create sample buffer")
|
|
657
|
+
}
|
|
658
|
+
return
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
enqueuedFrameCount += 1
|
|
662
|
+
|
|
663
|
+
// Enqueue on background queue for performance
|
|
664
|
+
sampleBufferQueue.async { [weak displayLayer, weak self] in
|
|
665
|
+
guard let displayLayer = displayLayer else { return }
|
|
666
|
+
|
|
667
|
+
// Handle failed display layer
|
|
668
|
+
if displayLayer.status == .failed {
|
|
669
|
+
print("🖼️ [PiP] Display layer failed, flushing...")
|
|
670
|
+
displayLayer.flush()
|
|
671
|
+
// Reset start time for fresh timing after flush
|
|
672
|
+
self?.startTime = nil
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
displayLayer.enqueue(sampleBuffer)
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// Log first successful enqueue
|
|
679
|
+
if enqueuedFrameCount == 1 {
|
|
680
|
+
print("🖼️ [PiP] First frame enqueued successfully")
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
private var enqueuedFrameCount: Int = 0
|
|
685
|
+
|
|
686
|
+
/// Feed a CMSampleBuffer directly to the PiP display
|
|
687
|
+
/// This extracts the pixel buffer and re-creates with proper timing for AVSampleBufferDisplayLayer
|
|
688
|
+
public func enqueueSampleBuffer(_ sampleBuffer: CMSampleBuffer) {
|
|
689
|
+
guard isEnabled, let displayLayer = sampleBufferDisplayLayer else {
|
|
690
|
+
return
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
// Extract pixel buffer from sample buffer and use our timing
|
|
694
|
+
guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
|
|
695
|
+
return
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// Use enqueueFrame which has proper timing handling
|
|
699
|
+
enqueueFrame(pixelBuffer)
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// MARK: - Private Helpers
|
|
703
|
+
|
|
704
|
+
private var startTime: CMTime?
|
|
705
|
+
|
|
706
|
+
private func createSampleBuffer(from pixelBuffer: CVPixelBuffer) -> CMSampleBuffer? {
|
|
707
|
+
var formatDescription: CMVideoFormatDescription?
|
|
708
|
+
let status = CMVideoFormatDescriptionCreateForImageBuffer(
|
|
709
|
+
allocator: kCFAllocatorDefault,
|
|
710
|
+
imageBuffer: pixelBuffer,
|
|
711
|
+
formatDescriptionOut: &formatDescription
|
|
712
|
+
)
|
|
713
|
+
|
|
714
|
+
guard status == noErr, let format = formatDescription else {
|
|
715
|
+
print("🖼️ [PiP] Failed to create format description")
|
|
716
|
+
return nil
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
// Use host time for live streaming - this ensures proper synchronization
|
|
720
|
+
let currentTime = CMClockGetTime(CMClockGetHostTimeClock())
|
|
721
|
+
|
|
722
|
+
// Initialize start time on first frame
|
|
723
|
+
if startTime == nil {
|
|
724
|
+
startTime = currentTime
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// Calculate presentation time relative to start
|
|
728
|
+
let presentationTime = CMTimeSubtract(currentTime, startTime!)
|
|
729
|
+
|
|
730
|
+
var timingInfo = CMSampleTimingInfo(
|
|
731
|
+
duration: CMTime(value: 1, timescale: 30), // 1/30th second duration
|
|
732
|
+
presentationTimeStamp: presentationTime,
|
|
733
|
+
decodeTimeStamp: .invalid
|
|
734
|
+
)
|
|
735
|
+
|
|
736
|
+
var sampleBuffer: CMSampleBuffer?
|
|
737
|
+
let createStatus = CMSampleBufferCreateForImageBuffer(
|
|
738
|
+
allocator: kCFAllocatorDefault,
|
|
739
|
+
imageBuffer: pixelBuffer,
|
|
740
|
+
dataReady: true,
|
|
741
|
+
makeDataReadyCallback: nil,
|
|
742
|
+
refcon: nil,
|
|
743
|
+
formatDescription: format,
|
|
744
|
+
sampleTiming: &timingInfo,
|
|
745
|
+
sampleBufferOut: &sampleBuffer
|
|
746
|
+
)
|
|
747
|
+
|
|
748
|
+
guard createStatus == noErr else {
|
|
749
|
+
print("🖼️ [PiP] Failed to create sample buffer: \(createStatus)")
|
|
750
|
+
return nil
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
// Increment frame count
|
|
754
|
+
frameCount += 1
|
|
755
|
+
|
|
756
|
+
return sampleBuffer
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// MARK: - Placeholder Frame Generation
|
|
760
|
+
|
|
761
|
+
/// Create a placeholder pixel buffer with "Broadcasting" text
|
|
762
|
+
private func createPlaceholderPixelBuffer() {
|
|
763
|
+
let width = 540
|
|
764
|
+
let height = 960
|
|
765
|
+
|
|
766
|
+
let attributes: [String: Any] = [
|
|
767
|
+
kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA,
|
|
768
|
+
kCVPixelBufferWidthKey as String: width,
|
|
769
|
+
kCVPixelBufferHeightKey as String: height,
|
|
770
|
+
kCVPixelBufferIOSurfacePropertiesKey as String: [:],
|
|
771
|
+
kCVPixelBufferCGImageCompatibilityKey as String: true,
|
|
772
|
+
kCVPixelBufferCGBitmapContextCompatibilityKey as String: true
|
|
773
|
+
]
|
|
774
|
+
|
|
775
|
+
var pixelBuffer: CVPixelBuffer?
|
|
776
|
+
CVPixelBufferCreate(kCFAllocatorDefault, width, height, kCVPixelFormatType_32BGRA, attributes as CFDictionary, &pixelBuffer)
|
|
777
|
+
|
|
778
|
+
guard let buffer = pixelBuffer else {
|
|
779
|
+
print("🖼️ [PiP] Failed to create placeholder pixel buffer")
|
|
780
|
+
return
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
CVPixelBufferLockBaseAddress(buffer, [])
|
|
784
|
+
defer { CVPixelBufferUnlockBaseAddress(buffer, []) }
|
|
785
|
+
|
|
786
|
+
guard let context = CGContext(
|
|
787
|
+
data: CVPixelBufferGetBaseAddress(buffer),
|
|
788
|
+
width: width,
|
|
789
|
+
height: height,
|
|
790
|
+
bitsPerComponent: 8,
|
|
791
|
+
bytesPerRow: CVPixelBufferGetBytesPerRow(buffer),
|
|
792
|
+
space: CGColorSpaceCreateDeviceRGB(),
|
|
793
|
+
bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue | CGBitmapInfo.byteOrder32Little.rawValue
|
|
794
|
+
) else {
|
|
795
|
+
return
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
// Fill with dark background
|
|
799
|
+
context.setFillColor(UIColor(red: 0.1, green: 0.1, blue: 0.15, alpha: 1.0).cgColor)
|
|
800
|
+
context.fill(CGRect(x: 0, y: 0, width: width, height: height))
|
|
801
|
+
|
|
802
|
+
// Draw "Broadcasting" text
|
|
803
|
+
UIGraphicsPushContext(context)
|
|
804
|
+
|
|
805
|
+
// Flip context for proper text rendering
|
|
806
|
+
context.translateBy(x: 0, y: CGFloat(height))
|
|
807
|
+
context.scaleBy(x: 1, y: -1)
|
|
808
|
+
|
|
809
|
+
let paragraphStyle = NSMutableParagraphStyle()
|
|
810
|
+
paragraphStyle.alignment = .center
|
|
811
|
+
|
|
812
|
+
// Draw large red recording dot
|
|
813
|
+
let circleSize: CGFloat = 50
|
|
814
|
+
let circleRect = CGRect(x: (CGFloat(width) - circleSize) / 2, y: CGFloat(height) / 2 - 120, width: circleSize, height: circleSize)
|
|
815
|
+
context.setFillColor(UIColor.red.cgColor)
|
|
816
|
+
context.fillEllipse(in: circleRect)
|
|
817
|
+
|
|
818
|
+
// Draw "LIVE" text - large and bold
|
|
819
|
+
let liveText = "LIVE"
|
|
820
|
+
let liveAttributes: [NSAttributedString.Key: Any] = [
|
|
821
|
+
.font: UIFont.boldSystemFont(ofSize: 72),
|
|
822
|
+
.foregroundColor: UIColor.white,
|
|
823
|
+
.paragraphStyle: paragraphStyle
|
|
824
|
+
]
|
|
825
|
+
let liveRect = CGRect(x: 0, y: CGFloat(height) / 2 - 40, width: CGFloat(width), height: 90)
|
|
826
|
+
liveText.draw(in: liveRect, withAttributes: liveAttributes)
|
|
827
|
+
|
|
828
|
+
// Draw "Broadcasting in progress" text
|
|
829
|
+
let subText = "Broadcasting in progress"
|
|
830
|
+
let subAttributes: [NSAttributedString.Key: Any] = [
|
|
831
|
+
.font: UIFont.systemFont(ofSize: 28),
|
|
832
|
+
.foregroundColor: UIColor.lightGray,
|
|
833
|
+
.paragraphStyle: paragraphStyle
|
|
834
|
+
]
|
|
835
|
+
let subRect = CGRect(x: 0, y: CGFloat(height) / 2 + 60, width: CGFloat(width), height: 40)
|
|
836
|
+
subText.draw(in: subRect, withAttributes: subAttributes)
|
|
837
|
+
|
|
838
|
+
UIGraphicsPopContext()
|
|
839
|
+
|
|
840
|
+
self.placeholderPixelBuffer = buffer
|
|
841
|
+
print("🖼️ [PiP] Placeholder pixel buffer created")
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
/// Start generating placeholder frames to keep PiP alive
|
|
845
|
+
private func startPlaceholderFrameGeneration() {
|
|
846
|
+
guard placeholderTimer == nil else { return }
|
|
847
|
+
|
|
848
|
+
isUsingPlaceholder = true
|
|
849
|
+
print("🖼️ [PiP] Starting placeholder frame generation")
|
|
850
|
+
|
|
851
|
+
// Generate placeholder frames at 10fps to keep PiP alive
|
|
852
|
+
placeholderTimer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { [weak self] _ in
|
|
853
|
+
self?.enqueuePlaceholderFrame()
|
|
854
|
+
}
|
|
855
|
+
RunLoop.main.add(placeholderTimer!, forMode: .common)
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
/// Stop generating placeholder frames
|
|
859
|
+
private func stopPlaceholderFrameGeneration() {
|
|
860
|
+
placeholderTimer?.invalidate()
|
|
861
|
+
placeholderTimer = nil
|
|
862
|
+
isUsingPlaceholder = false
|
|
863
|
+
print("🖼️ [PiP] Stopped placeholder frame generation")
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
/// Enqueue a placeholder frame
|
|
867
|
+
private func enqueuePlaceholderFrame() {
|
|
868
|
+
guard isEnabled, let pixelBuffer = placeholderPixelBuffer, let displayLayer = sampleBufferDisplayLayer else {
|
|
869
|
+
return
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
guard let sampleBuffer = createSampleBuffer(from: pixelBuffer) else {
|
|
873
|
+
return
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
sampleBufferQueue.async { [weak displayLayer] in
|
|
877
|
+
guard let displayLayer = displayLayer else { return }
|
|
878
|
+
|
|
879
|
+
if displayLayer.status == .failed {
|
|
880
|
+
displayLayer.flush()
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
displayLayer.enqueue(sampleBuffer)
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
/// Check if we should switch to placeholder (called when real frames stop coming)
|
|
888
|
+
private func checkForPlaceholderSwitch() {
|
|
889
|
+
let timeSinceLastFrame = CFAbsoluteTimeGetCurrent() - lastRealFrameTime
|
|
890
|
+
|
|
891
|
+
if timeSinceLastFrame > placeholderTimeout && !isUsingPlaceholder && isActive {
|
|
892
|
+
print("🖼️ [PiP] No real frames for \(timeSinceLastFrame)s, switching to placeholder")
|
|
893
|
+
startPlaceholderFrameGeneration()
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
private func cleanup() {
|
|
898
|
+
// Ensure we're on the main thread for UI operations
|
|
899
|
+
guard Thread.isMainThread else {
|
|
900
|
+
DispatchQueue.main.sync { [weak self] in
|
|
901
|
+
self?.cleanup()
|
|
902
|
+
}
|
|
903
|
+
return
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
// Stop placeholder frame generation
|
|
907
|
+
stopPlaceholderFrameGeneration()
|
|
908
|
+
|
|
909
|
+
pipController?.stopPictureInPicture()
|
|
910
|
+
pipController = nil
|
|
911
|
+
pipContentSource = nil
|
|
912
|
+
|
|
913
|
+
// Clean up Video Call components
|
|
914
|
+
sampleBufferVideoCallView?.removeFromSuperview()
|
|
915
|
+
sampleBufferVideoCallView = nil
|
|
916
|
+
pipVideoCallViewController = nil
|
|
917
|
+
|
|
918
|
+
sampleBufferDisplayLayer?.flush()
|
|
919
|
+
sampleBufferDisplayLayer = nil
|
|
920
|
+
|
|
921
|
+
// Don't remove pipContainerView if it's the actual source view (not owned by us)
|
|
922
|
+
if pipContainerView != activeSourceView {
|
|
923
|
+
pipContainerView?.removeFromSuperview()
|
|
924
|
+
}
|
|
925
|
+
pipContainerView = nil
|
|
926
|
+
activeSourceView = nil
|
|
927
|
+
|
|
928
|
+
frameCount = 0
|
|
929
|
+
enqueuedFrameCount = 0
|
|
930
|
+
startTime = nil
|
|
931
|
+
isActive = false
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
// MARK: - App Lifecycle
|
|
935
|
+
|
|
936
|
+
@objc private func applicationWillResignActive() {
|
|
937
|
+
// NOTE: We no longer manually trigger PiP here because
|
|
938
|
+
// AVPictureInPictureController.canStartPictureInPictureAutomaticallyFromInline = true
|
|
939
|
+
// handles auto-entering PiP automatically when the app goes to background.
|
|
940
|
+
// Manual triggering was causing "Failed to start" errors due to race conditions
|
|
941
|
+
// with the system's built-in auto-enter mechanism.
|
|
942
|
+
print("🖼️ [PiP] App going to background (system handles auto-enter)")
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
@objc private func applicationDidBecomeActive() {
|
|
946
|
+
// Could be used for cleanup or state updates when app returns
|
|
947
|
+
print("🖼️ [PiP] App became active")
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
// MARK: - Public Getters
|
|
951
|
+
|
|
952
|
+
public var isPictureInPicturePossible: Bool {
|
|
953
|
+
return pipController?.isPictureInPicturePossible ?? false
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
public var currentSourceView: PiPOptions.PiPSourceView {
|
|
957
|
+
return options.sourceView
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
// MARK: - AVPictureInPictureControllerDelegate
|
|
962
|
+
|
|
963
|
+
@available(iOS 15.0, *)
|
|
964
|
+
extension IVSPictureInPictureController: AVPictureInPictureControllerDelegate {
|
|
965
|
+
|
|
966
|
+
public func pictureInPictureControllerWillStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
|
|
967
|
+
print("🖼️ [PiP] Will start")
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
public func pictureInPictureControllerDidStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
|
|
971
|
+
isActive = true
|
|
972
|
+
lastRealFrameTime = CFAbsoluteTimeGetCurrent() // Reset timer
|
|
973
|
+
|
|
974
|
+
// Start monitoring for frame timeout to switch to placeholder
|
|
975
|
+
startFrameMonitoring()
|
|
976
|
+
|
|
977
|
+
print("🖼️ [PiP] Did start")
|
|
978
|
+
delegate?.pictureInPictureDidStart()
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
/// Start monitoring for frame timeout
|
|
982
|
+
private func startFrameMonitoring() {
|
|
983
|
+
// Check every 0.5 seconds if we should switch to placeholder
|
|
984
|
+
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { [weak self] timer in
|
|
985
|
+
guard let self = self else {
|
|
986
|
+
timer.invalidate()
|
|
987
|
+
return
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
// Stop monitoring if PiP is no longer active
|
|
991
|
+
if !self.isActive {
|
|
992
|
+
timer.invalidate()
|
|
993
|
+
return
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
self.checkForPlaceholderSwitch()
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
public func pictureInPictureControllerWillStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
|
|
1001
|
+
print("🖼️ [PiP] Will stop")
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
public func pictureInPictureControllerDidStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
|
|
1005
|
+
isActive = false
|
|
1006
|
+
|
|
1007
|
+
// Stop placeholder frame generation
|
|
1008
|
+
stopPlaceholderFrameGeneration()
|
|
1009
|
+
|
|
1010
|
+
// Reset timing for next PiP session - this is crucial for re-enabling PiP
|
|
1011
|
+
startTime = nil
|
|
1012
|
+
frameCount = 0
|
|
1013
|
+
enqueuedFrameCount = 0
|
|
1014
|
+
|
|
1015
|
+
// Flush the display layer to prepare for fresh frames
|
|
1016
|
+
sampleBufferDisplayLayer?.flush()
|
|
1017
|
+
|
|
1018
|
+
// Pre-warm with a few placeholder frames so PiP can start again immediately
|
|
1019
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
|
|
1020
|
+
self?.enqueuePlaceholderFrame()
|
|
1021
|
+
self?.enqueuePlaceholderFrame()
|
|
1022
|
+
self?.enqueuePlaceholderFrame()
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
print("🖼️ [PiP] Did stop - state reset for next session")
|
|
1026
|
+
delegate?.pictureInPictureDidStop()
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
public func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, failedToStartPictureInPictureWithError error: Error) {
|
|
1030
|
+
isActive = false
|
|
1031
|
+
print("🖼️ [PiP] Failed to start: \(error.localizedDescription)")
|
|
1032
|
+
delegate?.pictureInPictureDidFail(with: error.localizedDescription)
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
public func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void) {
|
|
1036
|
+
print("🖼️ [PiP] Restore user interface requested")
|
|
1037
|
+
delegate?.pictureInPictureWillRestore()
|
|
1038
|
+
completionHandler(true)
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
// MARK: - AVPictureInPictureSampleBufferPlaybackDelegate
|
|
1043
|
+
|
|
1044
|
+
@available(iOS 15.0, *)
|
|
1045
|
+
extension IVSPictureInPictureController: AVPictureInPictureSampleBufferPlaybackDelegate {
|
|
1046
|
+
|
|
1047
|
+
public func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, setPlaying playing: Bool) {
|
|
1048
|
+
// For live streaming, we ignore play/pause requests - always playing
|
|
1049
|
+
print("🖼️ [PiP] setPlaying: \(playing) (ignored - live stream)")
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
public func pictureInPictureControllerTimeRangeForPlayback(_ pictureInPictureController: AVPictureInPictureController) -> CMTimeRange {
|
|
1053
|
+
// Return .invalid to indicate live streaming (no seek bar, no time display)
|
|
1054
|
+
// This tells the system there's no seekable content
|
|
1055
|
+
return .invalid
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
public func pictureInPictureControllerIsPlaybackPaused(_ pictureInPictureController: AVPictureInPictureController) -> Bool {
|
|
1059
|
+
// Live streaming is never paused - always return false
|
|
1060
|
+
return false
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
public func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, didTransitionToRenderSize newRenderSize: CMVideoDimensions) {
|
|
1064
|
+
print("🖼️ [PiP] Transitioned to render size: \(newRenderSize.width)x\(newRenderSize.height)")
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
public func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, skipByInterval skipInterval: CMTime) async {
|
|
1068
|
+
// No seeking in live streams - this is a no-op for live content
|
|
1069
|
+
}
|
|
1070
|
+
}
|