@100mslive/react-native-hms 1.10.7 → 1.10.8

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.
@@ -21,6 +21,7 @@ import com.facebook.react.modules.core.DeviceEventManagerModule
21
21
  import com.reactnativehmssdk.HMSManager.Companion.REACT_CLASS
22
22
  import live.hms.video.error.HMSException
23
23
  import live.hms.video.factories.noisecancellation.AvailabilityStatus
24
+ import live.hms.video.sdk.HMSActionResultListener
24
25
  import java.util.UUID
25
26
 
26
27
  @ReactModule(name = REACT_CLASS)
@@ -1517,8 +1518,19 @@ class HMSManager(
1517
1518
  )
1518
1519
  return
1519
1520
  }
1520
- hmsSdk.setNoiseCancellationEnabled(true)
1521
- promise?.resolve(true)
1521
+
1522
+ hmsSdk.enableNoiseCancellation(
1523
+ true,
1524
+ object : HMSActionResultListener {
1525
+ override fun onError(error: HMSException) {
1526
+ promise?.reject(error.code.toString(), error.message)
1527
+ }
1528
+
1529
+ override fun onSuccess() {
1530
+ promise?.resolve(true)
1531
+ }
1532
+ },
1533
+ )
1522
1534
  }
1523
1535
 
1524
1536
  @ReactMethod
@@ -1542,8 +1554,18 @@ class HMSManager(
1542
1554
  )
1543
1555
  return
1544
1556
  }
1545
- hmsSdk.setNoiseCancellationEnabled(false)
1546
- promise?.resolve(true)
1557
+ hmsSdk.enableNoiseCancellation(
1558
+ false,
1559
+ object : HMSActionResultListener {
1560
+ override fun onError(error: HMSException) {
1561
+ promise?.reject(error.code.toString(), error.message)
1562
+ }
1563
+
1564
+ override fun onSuccess() {
1565
+ promise?.resolve(true)
1566
+ }
1567
+ },
1568
+ )
1547
1569
  }
1548
1570
 
1549
1571
  @ReactMethod
@@ -1567,7 +1589,7 @@ class HMSManager(
1567
1589
  )
1568
1590
  return
1569
1591
  }
1570
- val isEnabled = hmsSdk.getNoiseCancellationEnabled()
1592
+ val isEnabled = hmsSdk.isNoiseCancellationEnabled()
1571
1593
  promise?.resolve(isEnabled)
1572
1594
  }
1573
1595
 
@@ -1593,7 +1615,7 @@ class HMSManager(
1593
1615
  return
1594
1616
  }
1595
1617
 
1596
- val availability: AvailabilityStatus = hmsSdk.isNoiseCancellationAvailable()
1618
+ val availability: AvailabilityStatus = hmsSdk.isNoiseCancellationSupported()
1597
1619
  val isAvailable =
1598
1620
  if (availability == AvailabilityStatus.Available) {
1599
1621
  true
@@ -34,4 +34,5 @@ struct HMSConstants {
34
34
  static let ON_POLL_UPDATE = "ON_POLL_UPDATE"
35
35
  static let ON_WHITEBOARD_UPDATE = "ON_WHITEBOARD_UPDATE"
36
36
  static let ON_TRANSCRIPTS = "ON_TRANSCRIPTS"
37
+ static let ON_PIP_MODE_CHANGED = "ON_PIP_MODE_CHANGED"
37
38
  }
package/ios/HMSManager.m CHANGED
@@ -393,4 +393,43 @@ RCT_EXTERN_METHOD(handleRealTimeTranscription
393
393
  : (NSDictionary)data
394
394
  : (RCTPromiseResolveBlock)resolve
395
395
  : (RCTPromiseRejectBlock)reject)
396
+
397
+ #pragma mark - PIP Mode Support
398
+
399
+ RCT_EXTERN_METHOD(handlePipActions
400
+ : (NSString)action
401
+ : (NSDictionary)data
402
+ : (RCTPromiseResolveBlock)resolve
403
+ : (RCTPromiseRejectBlock)reject)
404
+
405
+ RCT_EXTERN_METHOD(setupPIP
406
+ : (NSDictionary)data
407
+ : (RCTPromiseResolveBlock)resolve
408
+ : (RCTPromiseRejectBlock)reject)
409
+
410
+ RCT_EXTERN_METHOD(stopPIP
411
+ : (NSDictionary)data
412
+ : (RCTPromiseResolveBlock)resolve
413
+ : (RCTPromiseRejectBlock)reject)
414
+
415
+ RCT_EXTERN_METHOD(disposePIP
416
+ : (NSDictionary)data
417
+ : (RCTPromiseResolveBlock)resolve
418
+ : (RCTPromiseRejectBlock)reject)
419
+
420
+ RCT_EXTERN_METHOD(isPIPActive
421
+ : (NSDictionary)data
422
+ : (RCTPromiseResolveBlock)resolve
423
+ : (RCTPromiseRejectBlock)reject)
424
+
425
+ RCT_EXTERN_METHOD(changeIOSPIPVideoTrack
426
+ : (NSDictionary)data
427
+ : (RCTPromiseResolveBlock)resolve
428
+ : (RCTPromiseRejectBlock)reject)
429
+
430
+ RCT_EXTERN_METHOD(setActiveSpeakerInIOSPIP
431
+ : (NSDictionary)data
432
+ : (RCTPromiseResolveBlock)resolve
433
+ : (RCTPromiseRejectBlock)reject)
434
+
396
435
  @end
@@ -37,7 +37,7 @@ class HMSManager: RCTEventEmitter {
37
37
  }
38
38
 
39
39
  override func supportedEvents() -> [String]! {
40
- return [ON_JOIN, ON_PREVIEW, ON_ROOM_UPDATE, ON_PEER_UPDATE, ON_TRACK_UPDATE, ON_ERROR, ON_MESSAGE, ON_SPEAKER, RECONNECTING, RECONNECTED, ON_ROLE_CHANGE_REQUEST, ON_CHANGE_TRACK_STATE_REQUEST, ON_REMOVED_FROM_ROOM, ON_RTC_STATS, ON_LOCAL_AUDIO_STATS, ON_LOCAL_VIDEO_STATS, ON_REMOTE_AUDIO_STATS, ON_REMOTE_VIDEO_STATS, ON_AUDIO_DEVICE_CHANGED, HMSConstants.ON_SESSION_STORE_AVAILABLE, HMSConstants.ON_SESSION_STORE_CHANGED, HMSConstants.ON_PEER_LIST_UPDATED, HMSConstants.ON_POLL_UPDATE, HMSConstants.ON_WHITEBOARD_UPDATE, HMSConstants.ON_TRANSCRIPTS]
40
+ return [ON_JOIN, ON_PREVIEW, ON_ROOM_UPDATE, ON_PEER_UPDATE, ON_TRACK_UPDATE, ON_ERROR, ON_MESSAGE, ON_SPEAKER, RECONNECTING, RECONNECTED, ON_ROLE_CHANGE_REQUEST, ON_CHANGE_TRACK_STATE_REQUEST, ON_REMOVED_FROM_ROOM, ON_RTC_STATS, ON_LOCAL_AUDIO_STATS, ON_LOCAL_VIDEO_STATS, ON_REMOTE_AUDIO_STATS, ON_REMOTE_VIDEO_STATS, ON_AUDIO_DEVICE_CHANGED, HMSConstants.ON_SESSION_STORE_AVAILABLE, HMSConstants.ON_SESSION_STORE_CHANGED, HMSConstants.ON_PEER_LIST_UPDATED, HMSConstants.ON_POLL_UPDATE, HMSConstants.ON_WHITEBOARD_UPDATE, HMSConstants.ON_TRANSCRIPTS, HMSConstants.ON_PIP_MODE_CHANGED]
41
41
  }
42
42
 
43
43
  // MARK: - HMS SDK Delegate Callbacks
@@ -837,4 +837,119 @@ class HMSManager: RCTEventEmitter {
837
837
  }
838
838
  rnsdk.handleRealTimeTranscription(data, resolve, reject)
839
839
  }
840
+
841
+ // MARK: - PIP Mode Support
842
+
843
+ @objc
844
+ func handlePipActions(_ action: String,
845
+ _ data: NSDictionary,
846
+ _ resolve: RCTPromiseResolveBlock?,
847
+ _ reject: RCTPromiseRejectBlock?) {
848
+
849
+ guard let rnsdk = HMSHelper.getHms(data, hmsCollection) else {
850
+ reject?("6004", "HMSRNSDK instance not found!", nil)
851
+ return
852
+ }
853
+
854
+ DispatchQueue.main.async { [weak self] in
855
+ switch action {
856
+ case "isPipModeSupported":
857
+ self?.isPipModeSupported(resolve, reject)
858
+ case "enterPipMode":
859
+ rnsdk.enterPipMode(resolve, reject)
860
+ case "setPictureInPictureParams":
861
+ if #available(iOS 15.0, *) {
862
+ rnsdk.setPictureInPictureParams(data, resolve, reject)
863
+ } else {
864
+ reject?("6004", "setPictureInPictureParams should be invoked for iOS 15 & above versions", nil)
865
+ }
866
+ default:
867
+ reject?("6004", "Unknown action type received", nil)
868
+ }
869
+ }
870
+ }
871
+
872
+ @objc
873
+ func stopPIP(_ data: NSDictionary,
874
+ _ resolve: RCTPromiseResolveBlock?,
875
+ _ reject: RCTPromiseRejectBlock?) {
876
+
877
+ guard let rnsdk = HMSHelper.getHms(data, hmsCollection) else {
878
+ reject?("6004", "HMSRNSDK instance not found!", nil)
879
+ return
880
+ }
881
+
882
+ DispatchQueue.main.async {
883
+ rnsdk.stopPIP(resolve, reject)
884
+ }
885
+ }
886
+
887
+ @objc
888
+ func disposePIP(_ data: NSDictionary,
889
+ _ resolve: RCTPromiseResolveBlock?,
890
+ _ reject: RCTPromiseRejectBlock?) {
891
+
892
+ guard let rnsdk = HMSHelper.getHms(data, hmsCollection) else {
893
+ reject?("6004", "HMSRNSDK instance not found!", nil)
894
+ return
895
+ }
896
+
897
+ DispatchQueue.main.async {
898
+ rnsdk.disposePIP(resolve, reject)
899
+ }
900
+ }
901
+
902
+ @objc
903
+ func isPipModeSupported(_ resolve: RCTPromiseResolveBlock?,
904
+ _ reject: RCTPromiseRejectBlock?) {
905
+
906
+ resolve?(AVPictureInPictureController.isPictureInPictureSupported())
907
+ }
908
+
909
+ @objc
910
+ func isPIPActive(_ data: NSDictionary,
911
+ _ resolve: RCTPromiseResolveBlock?,
912
+ _ reject: RCTPromiseRejectBlock?) {
913
+
914
+ guard let rnsdk = HMSHelper.getHms(data, hmsCollection) else {
915
+ reject?("6004", "HMSRNSDK instance not found!", nil)
916
+ return
917
+ }
918
+
919
+ DispatchQueue.main.async {
920
+ rnsdk.isPIPActive(resolve, reject)
921
+ }
922
+ }
923
+
924
+ @objc
925
+ func changeIOSPIPVideoTrack(_ data: NSDictionary,
926
+ _ resolve: RCTPromiseResolveBlock?,
927
+ _ reject: RCTPromiseRejectBlock?) {
928
+
929
+ guard let rnsdk = HMSHelper.getHms(data, hmsCollection) else {
930
+ reject?("6004", "HMSRNSDK instance not found!", nil)
931
+ return
932
+ }
933
+ DispatchQueue.main.async {
934
+ if #available(iOS 15.0, *) {
935
+ rnsdk.changeIOSPIPVideoTrack(data, resolve, reject)
936
+ } else {
937
+ reject?("6004", "changeIOSPIPVideoTrack is not supported on iOS version lower than 15.0", nil)
938
+ }
939
+ }
940
+ }
941
+
942
+ @objc
943
+ func setActiveSpeakerInIOSPIP(_ data: NSDictionary,
944
+ _ resolve: RCTPromiseResolveBlock?,
945
+ _ reject: RCTPromiseRejectBlock?) {
946
+
947
+ guard let rnsdk = HMSHelper.getHms(data, hmsCollection) else {
948
+ reject?("6004", "HMSRNSDK instance not found!", nil)
949
+ return
950
+ }
951
+ DispatchQueue.main.async {
952
+ rnsdk.setActiveSpeakerInIOSPIP(data, resolve, reject)
953
+ }
954
+ }
840
955
  }
@@ -8,8 +8,10 @@
8
8
  import Foundation
9
9
  import HMSSDK
10
10
  import ReplayKit
11
+ import AVKit
12
+ import SwiftUI
11
13
 
12
- class HMSRNSDK: HMSUpdateListener, HMSPreviewListener {
14
+ class HMSRNSDK: NSObject, HMSUpdateListener, HMSPreviewListener {
13
15
 
14
16
  var hms: HMSSDK?
15
17
  var interactivity: HMSRNInteractivityCenter?
@@ -38,6 +40,7 @@ class HMSRNSDK: HMSUpdateListener, HMSPreviewListener {
38
40
 
39
41
  // MARK: - Setup
40
42
  init(data: NSDictionary?, delegate manager: HMSManager?, uid id: String) {
43
+ super.init()
41
44
  preferredExtension = data?.value(forKey: "preferredExtension") as? String
42
45
  self.delegate = manager
43
46
  self.id = id
@@ -1534,6 +1537,18 @@ class HMSRNSDK: HMSUpdateListener, HMSPreviewListener {
1534
1537
  }
1535
1538
  }
1536
1539
  }
1540
+
1541
+ if #available(iOS 15.0, *),
1542
+ useActiveSpeakerInPIP,
1543
+ let controller = pipController,
1544
+ controller.isPictureInPictureActive,
1545
+ track.kind == .video,
1546
+ update == .trackRemoved,
1547
+ pipModel?.track == track {
1548
+
1549
+ pipModel?.text = hms?.localPeer?.name
1550
+ pipModel?.track = nil
1551
+ }
1537
1552
 
1538
1553
  if eventsEnableStatus[HMSConstants.ON_TRACK_UPDATE] != true {
1539
1554
  return
@@ -1562,6 +1577,35 @@ class HMSRNSDK: HMSUpdateListener, HMSPreviewListener {
1562
1577
  }
1563
1578
 
1564
1579
  func on(updated speakers: [HMSSpeaker]) {
1580
+
1581
+ if #available(iOS 15.0, *),
1582
+ useActiveSpeakerInPIP,
1583
+ let controller = pipController,
1584
+ controller.isPictureInPictureActive,
1585
+ let peer = speakers.first?.peer,
1586
+ let track = peer.videoTrack {
1587
+
1588
+ if track.isMute() {
1589
+ pipModel?.text = peer.name
1590
+ pipModel?.track = nil
1591
+ } else {
1592
+ if peer.isLocal {
1593
+ if #available(iOS 16.0, *) {
1594
+ if AVCaptureSession().isMultitaskingCameraAccessSupported {
1595
+ pipModel?.text = nil
1596
+ pipModel?.track = track
1597
+ return
1598
+ }
1599
+ }
1600
+ pipModel?.text = peer.name
1601
+ pipModel?.track = nil
1602
+ } else {
1603
+ pipModel?.text = nil
1604
+ pipModel?.track = track
1605
+ }
1606
+ }
1607
+ }
1608
+
1565
1609
  if eventsEnableStatus[HMSConstants.ON_SPEAKER] != true {
1566
1610
  return
1567
1611
  }
@@ -2414,6 +2458,158 @@ class HMSRNSDK: HMSUpdateListener, HMSPreviewListener {
2414
2458
  }
2415
2459
  }
2416
2460
 
2461
+ // MARK: - PIP Mode Support
2462
+
2463
+ internal var _pipVideoCallViewController: Any?
2464
+
2465
+ @available(iOS 15.0, *)
2466
+ internal var pipVideoCallViewController: AVPictureInPictureVideoCallViewController? {
2467
+ if _pipVideoCallViewController == nil {
2468
+ _pipVideoCallViewController = AVPictureInPictureVideoCallViewController()
2469
+ }
2470
+ return _pipVideoCallViewController as? AVPictureInPictureVideoCallViewController
2471
+ }
2472
+
2473
+ internal var _pipModel: Any?
2474
+
2475
+ @available(iOS 15.0, *)
2476
+ internal var pipModel: HMSPipModel? {
2477
+ if _pipModel == nil {
2478
+ _pipModel = HMSPipModel()
2479
+ }
2480
+ return _pipModel as? HMSPipModel
2481
+ }
2482
+
2483
+ internal var pipController: AVPictureInPictureController?
2484
+
2485
+ private var useActiveSpeakerInPIP: Bool = true
2486
+
2487
+ @available(iOS 15.0, *)
2488
+ func setPictureInPictureParams(_ data: NSDictionary,
2489
+ _ resolve: RCTPromiseResolveBlock?,
2490
+ _ reject: RCTPromiseRejectBlock?) {
2491
+
2492
+ guard AVPictureInPictureController.isPictureInPictureSupported() else {
2493
+ let errorMessage = "\(#function) PIP is not supported on this device"
2494
+ reject?("6004", errorMessage, nil)
2495
+ return
2496
+ }
2497
+
2498
+ guard let uiView = UIApplication.shared.keyWindow?.rootViewController?.view else {
2499
+ let errorMessage = "\(#function) Failed to setup PIP"
2500
+ reject?("6004", errorMessage, nil)
2501
+ return
2502
+ }
2503
+
2504
+ pipModel?.pipViewEnabled = true
2505
+
2506
+ if let scaleType = data["scaleType"] as? String {
2507
+ pipModel?.scaleType = getViewContentMode(scaleType)
2508
+ } else {
2509
+ pipModel?.scaleType = .scaleAspectFill
2510
+ }
2511
+
2512
+ pipModel?.color = .black
2513
+ pipModel?.text = hms?.localPeer?.name
2514
+
2515
+ let controller = UIHostingController(rootView: HMSPipView(model: pipModel!))
2516
+
2517
+ pipVideoCallViewController?.view.addConstrained(subview: controller.view)
2518
+
2519
+ if let ratio = data["aspectRatio"] as? [Int], ratio.count == 2 {
2520
+ pipVideoCallViewController?.preferredContentSize = CGSize(width: ratio[0], height: ratio[1])
2521
+ } else {
2522
+ pipVideoCallViewController?.preferredContentSize = CGSize(width: uiView.frame.size.width, height: uiView.frame.size.height)
2523
+ }
2524
+
2525
+ guard let pipVideoCallViewController = pipVideoCallViewController else {
2526
+ let errorMessage = "\(#function) Failed to setup PIP"
2527
+ reject?("6004", errorMessage, nil)
2528
+ return
2529
+ }
2530
+
2531
+ let pipContentSource = AVPictureInPictureController.ContentSource(activeVideoCallSourceView: uiView, contentViewController: pipVideoCallViewController)
2532
+
2533
+ pipController = AVPictureInPictureController(contentSource: pipContentSource)
2534
+
2535
+ pipController?.delegate = self
2536
+
2537
+ pipController?.canStartPictureInPictureAutomaticallyFromInline = true
2538
+
2539
+ if let autoEnterPIP = data["autoEnterPipMode"] as? Bool {
2540
+ pipController?.canStartPictureInPictureAutomaticallyFromInline = autoEnterPIP
2541
+ }
2542
+
2543
+ NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification,
2544
+ object: nil, queue: .main) { [weak self] _ in
2545
+ self?.stopPIP(nil, nil)
2546
+ }
2547
+
2548
+ resolve?(nil)
2549
+ }
2550
+
2551
+ func enterPipMode(_ resolve: RCTPromiseResolveBlock?,
2552
+ _ reject: RCTPromiseRejectBlock?) {
2553
+ pipController?.startPictureInPicture()
2554
+ resolve?(nil)
2555
+ }
2556
+
2557
+ func stopPIP(_ resolve: RCTPromiseResolveBlock?,
2558
+ _ reject: RCTPromiseRejectBlock?) {
2559
+ pipController?.stopPictureInPicture()
2560
+ resolve?(nil)
2561
+ }
2562
+
2563
+ func disposePIP(_ resolve: RCTPromiseResolveBlock?,
2564
+ _ reject: RCTPromiseRejectBlock?) {
2565
+ pipController = nil
2566
+ _pipModel = nil
2567
+ _pipVideoCallViewController = nil
2568
+ NotificationCenter.default.removeObserver(UIApplication.didBecomeActiveNotification)
2569
+ resolve?(nil)
2570
+ }
2571
+
2572
+ func isPIPActive(_ resolve: RCTPromiseResolveBlock?,
2573
+ _ reject: RCTPromiseRejectBlock?) {
2574
+ if pipController != nil && pipController!.isPictureInPictureActive {
2575
+ resolve?(true)
2576
+ } else {
2577
+ resolve?(false)
2578
+ }
2579
+ }
2580
+
2581
+ @available(iOS 15.0, *)
2582
+ func changeIOSPIPVideoTrack(_ data: NSDictionary,
2583
+ _ resolve: RCTPromiseResolveBlock?,
2584
+ _ reject: RCTPromiseRejectBlock?) {
2585
+
2586
+ guard let trackID = data["trackId"] as? String,
2587
+ let room = hms?.room,
2588
+ let track = HMSUtilities.getVideoTrack(for: trackID, in: room)
2589
+ else {
2590
+ let errorMessage = "\(#function) Incorrect data passed for changing track in PIP Mode"
2591
+ reject?("6004", errorMessage, nil)
2592
+ return
2593
+ }
2594
+
2595
+ useActiveSpeakerInPIP = false
2596
+ pipModel?.track = track
2597
+ resolve?(nil)
2598
+ }
2599
+
2600
+ func setActiveSpeakerInIOSPIP(_ data: NSDictionary,
2601
+ _ resolve: RCTPromiseResolveBlock?,
2602
+ _ reject: RCTPromiseRejectBlock?) {
2603
+ guard let enabled = data["enable"] as? Bool else {
2604
+ let errorMessage = "\(#function) Incorrect data passed for setActiveSpeakerInIOSPIP in PIP Mode"
2605
+ reject?("6004", errorMessage, nil)
2606
+ return
2607
+ }
2608
+
2609
+ useActiveSpeakerInPIP = enabled
2610
+ resolve?(nil)
2611
+ }
2612
+
2417
2613
  // MARK: - Helper Functions
2418
2614
 
2419
2615
  // Handle resetting states and data cleanup
@@ -2514,6 +2710,19 @@ class HMSRNSDK: HMSUpdateListener, HMSPreviewListener {
2514
2710
  static private func getTimeStamp() -> String {
2515
2711
  "\(Date().timeIntervalSince1970)"
2516
2712
  }
2713
+
2714
+ private func getViewContentMode(_ type: String?) -> UIView.ContentMode {
2715
+ switch type {
2716
+ case "ASPECT_FILL":
2717
+ return .scaleAspectFill
2718
+ case "ASPECT_FIT":
2719
+ return .scaleAspectFit
2720
+ case "ASPECT_BALANCED":
2721
+ return .center
2722
+ default:
2723
+ return .scaleAspectFill
2724
+ }
2725
+ }
2517
2726
  }
2518
2727
 
2519
2728
  extension UIImage {
@@ -2529,3 +2738,63 @@ extension UIImage {
2529
2738
  return normalizedImage
2530
2739
  }
2531
2740
  }
2741
+
2742
+ extension HMSRNSDK: AVPictureInPictureControllerDelegate {
2743
+
2744
+ public func pictureInPictureControllerWillStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
2745
+ print(#function)
2746
+ }
2747
+
2748
+ public func pictureInPictureControllerDidStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
2749
+
2750
+ if eventsEnableStatus[HMSConstants.ON_PIP_MODE_CHANGED] != true {
2751
+ return
2752
+ }
2753
+
2754
+ self.delegate?.emitEvent(HMSConstants.ON_PIP_MODE_CHANGED,
2755
+ ["event": HMSConstants.ON_PIP_MODE_CHANGED,
2756
+ "id": self.id,
2757
+ "isInPictureInPictureMode": true])
2758
+ }
2759
+
2760
+ public func pictureInPictureControllerWillStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
2761
+ print(#function)
2762
+ }
2763
+
2764
+ public func pictureInPictureControllerDidStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
2765
+ if eventsEnableStatus[HMSConstants.ON_PIP_MODE_CHANGED] != true {
2766
+ return
2767
+ }
2768
+
2769
+ self.delegate?.emitEvent(HMSConstants.ON_PIP_MODE_CHANGED,
2770
+ ["event": HMSConstants.ON_PIP_MODE_CHANGED,
2771
+ "id": self.id,
2772
+ "isInPictureInPictureMode": false])
2773
+ }
2774
+
2775
+ public func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, failedToStartPictureInPictureWithError error: Error) {
2776
+ if eventsEnableStatus[HMSConstants.ON_PIP_MODE_CHANGED] != true {
2777
+ return
2778
+ }
2779
+
2780
+ self.delegate?.emitEvent(HMSConstants.ON_PIP_MODE_CHANGED,
2781
+ ["event": HMSConstants.ON_PIP_MODE_CHANGED,
2782
+ "id": self.id,
2783
+ "isInPictureInPictureMode": false])
2784
+ }
2785
+
2786
+ public func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void) {
2787
+ print(#function)
2788
+ }
2789
+ }
2790
+
2791
+ extension UIView {
2792
+ func addConstrained(subview: UIView) {
2793
+ addSubview(subview)
2794
+ subview.translatesAutoresizingMaskIntoConstraints = false
2795
+ subview.topAnchor.constraint(equalTo: topAnchor).isActive = true
2796
+ subview.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
2797
+ subview.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
2798
+ subview.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
2799
+ }
2800
+ }
@@ -0,0 +1,18 @@
1
+ //
2
+ // HMSPipModel.swift
3
+ // react-native-hms
4
+ //
5
+ // Created by Yogesh Singh on 21/06/24.
6
+ //
7
+
8
+ import SwiftUI
9
+ import HMSSDK
10
+
11
+ @available(iOS 15.0, *)
12
+ class HMSPipModel: ObservableObject {
13
+ @Published var track: HMSVideoTrack?
14
+ @Published var pipViewEnabled = false
15
+ @Published var scaleType: UIView.ContentMode?
16
+ @Published var text: String?
17
+ @Published var color: Color = Color.black
18
+ }
@@ -0,0 +1,36 @@
1
+ //
2
+ // HMSPipView.swift
3
+ // react-native-hms
4
+ //
5
+ // Created by Yogesh Singh on 21/06/24.
6
+ //
7
+
8
+ import SwiftUI
9
+ import HMSSDK
10
+
11
+ @available(iOS 15.0, *)
12
+ struct HMSPipView: View {
13
+
14
+ @ObservedObject var model: HMSPipModel
15
+
16
+ var body: some View {
17
+ if model.pipViewEnabled {
18
+ VStack {
19
+ if let track = model.track, !(track.isMute()) {
20
+ GeometryReader { geo in
21
+ HMSSampleBufferSwiftUIView(track: track,
22
+ contentMode: .scaleAspectFill,
23
+ preferredSize: geo.size,
24
+ model: model)
25
+ .frame(width: geo.size.width, height: geo.size.height)
26
+ }
27
+ } else if let text = model.text {
28
+ Text(text)
29
+ }
30
+ }
31
+ .foregroundColor(.white)
32
+ .frame(maxWidth: .infinity, maxHeight: .infinity)
33
+ .background(model.color)
34
+ }
35
+ }
36
+ }
@@ -0,0 +1,45 @@
1
+ //
2
+ // HMSSampleBufferSwiftUIView.swift
3
+ // react-native-hms
4
+ //
5
+ // Created by Yogesh Singh on 21/06/24.
6
+ //
7
+
8
+ import SwiftUI
9
+ import HMSSDK
10
+
11
+ @available(iOS 15.0, *)
12
+ public struct HMSSampleBufferSwiftUIView: UIViewRepresentable {
13
+ weak var track: HMSVideoTrack?
14
+ var contentMode: UIView.ContentMode
15
+ var preferredSize: CGSize?
16
+
17
+ @ObservedObject var model: HMSPipModel
18
+
19
+ public func makeUIView(context: UIViewRepresentableContext<HMSSampleBufferSwiftUIView>) -> HMSSampleBufferDisplayView {
20
+
21
+ let sampleBufferView = HMSSampleBufferDisplayView(frame: .zero)
22
+ sampleBufferView.track = track
23
+
24
+ if let preferredSize = preferredSize {
25
+ sampleBufferView.preferredSize = preferredSize
26
+ }
27
+ sampleBufferView.contentMode = contentMode
28
+ sampleBufferView.isEnabled = true
29
+
30
+ return sampleBufferView
31
+ }
32
+
33
+ public func updateUIView(_ sampleBufferView: HMSSampleBufferDisplayView, context: UIViewRepresentableContext<HMSSampleBufferSwiftUIView>) {
34
+
35
+ if track != sampleBufferView.track {
36
+ sampleBufferView.track = track
37
+ }
38
+ sampleBufferView.isEnabled = model.pipViewEnabled
39
+ }
40
+
41
+ public static func dismantleUIView(_ uiView: HMSSampleBufferDisplayView, coordinator: ()) {
42
+ uiView.isEnabled = false
43
+ uiView.track = nil
44
+ }
45
+ }
@@ -1,2 +1,6 @@
1
1
  "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
2
6
  //# sourceMappingURL=HMSPIPConfig.js.map
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["HMSPIPConfig.ts"],"sourcesContent":["export interface HMSPIPConfig {\n autoEnterPipMode?: boolean;\n aspectRatio?: [number, number];\n endButton?: boolean;\n audioButton?: boolean;\n videoButton?: boolean;\n}\n"],"mappings":"","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["HMSPIPConfig.ts"],"sourcesContent":["import type { HMSVideoViewMode } from './HMSVideoViewMode';\n\nexport interface HMSPIPConfig {\n /*\n * Whether to automatically enter PIP mode when app enters background.\n */\n autoEnterPipMode?: boolean;\n\n /*\n * The aspect ratio of the PIP window. Default is [9, 16]. Other values can be [3, 4], [1, 1], [4, 3], [16, 9].\n */\n aspectRatio?: [number, number];\n\n /*\n * The scale type of the PIP window. Default is ASPECT_FILL. Other values can be ASPECT_FIT, ASPECT_BALANCED. iOS Only.\n */\n scaleType?: HMSVideoViewMode;\n\n /*\n * Whether to show the Active Speaker in the PIP window. Default is true. iOS only.\n */\n useActiveSpeaker?: boolean;\n /*\n * Whether to show the end button in the PIP window. Default is true. Android only.\n */\n endButton?: boolean;\n\n /*\n * Whether to show the audio mute/unmute button in the PIP window. Default is true. Android only.\n */\n audioButton?: boolean;\n\n /*\n * Whether to show the video mute/unmute button in the PIP window. Default is true. Android only.\n */\n videoButton?: boolean;\n}\n"],"mappings":"","ignoreList":[]}