@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.
- package/android/src/main/java/com/reactnativehmssdk/HMSManager.kt +28 -6
- package/ios/HMSConstants.swift +1 -0
- package/ios/HMSManager.m +39 -0
- package/ios/HMSManager.swift +116 -1
- package/ios/HMSRNSDK.swift +270 -1
- package/ios/PIPMode/HMSPipModel.swift +18 -0
- package/ios/PIPMode/HMSPipView.swift +36 -0
- package/ios/PIPMode/HMSSampleBufferSwiftUIView.swift +45 -0
- package/lib/commonjs/classes/HMSPIPConfig.js +4 -0
- package/lib/commonjs/classes/HMSPIPConfig.js.map +1 -1
- package/lib/commonjs/classes/HMSSDK.js +52 -10
- package/lib/commonjs/classes/HMSSDK.js.map +1 -1
- package/lib/module/classes/HMSPIPConfig.js +1 -1
- package/lib/module/classes/HMSPIPConfig.js.map +1 -1
- package/lib/module/classes/HMSSDK.js +52 -10
- package/lib/module/classes/HMSSDK.js.map +1 -1
- package/lib/typescript/classes/HMSPIPConfig.d.ts +3 -0
- package/lib/typescript/classes/HMSSDK.d.ts +3 -0
- package/package.json +1 -1
- package/sdk-versions.json +2 -2
- package/src/classes/HMSPIPConfig.ts +30 -0
- package/src/classes/HMSSDK.tsx +58 -21
|
@@ -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
|
-
|
|
1521
|
-
|
|
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.
|
|
1546
|
-
|
|
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.
|
|
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.
|
|
1618
|
+
val availability: AvailabilityStatus = hmsSdk.isNoiseCancellationSupported()
|
|
1597
1619
|
val isAvailable =
|
|
1598
1620
|
if (availability == AvailabilityStatus.Available) {
|
|
1599
1621
|
true
|
package/ios/HMSConstants.swift
CHANGED
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
|
package/ios/HMSManager.swift
CHANGED
|
@@ -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
|
}
|
package/ios/HMSRNSDK.swift
CHANGED
|
@@ -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 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["HMSPIPConfig.ts"],"sourcesContent":["
|
|
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":[]}
|