Skip to content

Commit c94eb05

Browse files
committed
live streaming update
1 parent c540d59 commit c94eb05

3 files changed

Lines changed: 82 additions & 28 deletions

File tree

iOS/APIExample/Common/UITypeAlias.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ extension UIColor {
8383
}
8484

8585
extension UIView {
86-
8786
/// Adds constraints to this `UIView` instances `superview` object to make sure this always has the same size as the superview.
8887
/// Please note that this has no effect if its `superview` is `nil` – add this `UIView` instance as a subview before calling this.
8988
func bindFrameToSuperviewBounds() {

iOS/APIExample/Examples/Advanced/LiveStreaming/Base.lproj/LiveStreaming.storyboard

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097.2" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
3-
<device id="retina6_1" orientation="portrait" appearance="dark"/>
2+
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17506" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
3+
<device id="retina6_1" orientation="portrait" appearance="light"/>
44
<dependencies>
55
<deployment identifier="iOS"/>
6-
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
6+
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17505"/>
77
<capability name="Named colors" minToolsVersion="9.0"/>
88
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
9+
<capability name="System colors in document resources" minToolsVersion="11.0"/>
910
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
1011
</dependencies>
1112
<scenes>
@@ -25,15 +26,15 @@
2526
<fontDescription key="fontDescription" type="system" pointSize="14"/>
2627
<textInputTraits key="textInputTraits"/>
2728
</textField>
28-
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kbN-ZR-nNn" userLabel="joinBtn">
29+
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kbN-ZR-nNn" userLabel="joinBtn">
2930
<rect key="frame" x="172" y="74" width="30" height="30"/>
3031
<state key="normal" title="Join"/>
3132
<connections>
3233
<action selector="doJoinPressedWithSender:" destination="O0d-ef-mTa" eventType="touchUpInside" id="pdy-Tj-ycl"/>
3334
</connections>
3435
</button>
3536
</subviews>
36-
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
37+
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
3738
<constraints>
3839
<constraint firstItem="kbN-ZR-nNn" firstAttribute="top" secondItem="GWc-L5-fZV" secondAttribute="bottom" constant="20" id="LVQ-Cs-yOU"/>
3940
<constraint firstItem="kbN-ZR-nNn" firstAttribute="centerX" secondItem="GWc-L5-fZV" secondAttribute="centerX" id="RUT-ez-nDw"/>
@@ -44,13 +45,13 @@
4445
</constraints>
4546
</view>
4647
</subviews>
47-
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
48+
<viewLayoutGuide key="safeArea" id="wDs-Gr-g1S"/>
49+
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
4850
<constraints>
4951
<constraint firstItem="UzG-zY-iSA" firstAttribute="centerY" secondItem="wDs-Gr-g1S" secondAttribute="centerY" multiplier="0.8" id="8bT-wH-NDK"/>
5052
<constraint firstItem="UzG-zY-iSA" firstAttribute="leading" secondItem="wDs-Gr-g1S" secondAttribute="leading" constant="20" id="BQh-SU-OA6"/>
5153
<constraint firstItem="wDs-Gr-g1S" firstAttribute="trailing" secondItem="UzG-zY-iSA" secondAttribute="trailing" constant="20" id="gHu-5I-6Gb"/>
5254
</constraints>
53-
<viewLayoutGuide key="safeArea" id="wDs-Gr-g1S"/>
5455
</view>
5556
<connections>
5657
<outlet property="channelTextField" destination="GWc-L5-fZV" id="xDy-ai-JdS"/>
@@ -71,14 +72,18 @@
7172
<subviews>
7273
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="q9v-1n-ZYf">
7374
<rect key="frame" x="0.0" y="44" width="414" height="818"/>
74-
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
75+
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
7576
</view>
7677
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XSO-cE-x5n">
7778
<rect key="frame" x="257.5" y="54" width="136.5" height="182"/>
78-
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
79+
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
80+
<gestureRecognizers/>
7981
<constraints>
8082
<constraint firstAttribute="width" secondItem="XSO-cE-x5n" secondAttribute="height" multiplier="3:4" id="Bux-mO-Qgq"/>
8183
</constraints>
84+
<connections>
85+
<outletCollection property="gestureRecognizers" destination="yDz-VT-Yop" appends="YES" id="grI-uM-Mpw"/>
86+
</connections>
8287
</view>
8388
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Uwe-Fi-04a" userLabel="CoHost">
8489
<rect key="frame" x="20" y="783" width="132" height="44"/>
@@ -172,7 +177,8 @@
172177
</constraints>
173178
</view>
174179
</subviews>
175-
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
180+
<viewLayoutGuide key="safeArea" id="CeS-QQ-Djo"/>
181+
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
176182
<constraints>
177183
<constraint firstItem="Uwe-Fi-04a" firstAttribute="leading" secondItem="CeS-QQ-Djo" secondAttribute="leading" constant="20" id="0oI-Iz-1eG"/>
178184
<constraint firstItem="XSO-cE-x5n" firstAttribute="top" secondItem="CeS-QQ-Djo" secondAttribute="top" constant="10" id="1HU-w7-YYi"/>
@@ -186,16 +192,16 @@
186192
<constraint firstItem="CeS-QQ-Djo" firstAttribute="trailing" secondItem="q9v-1n-ZYf" secondAttribute="trailing" id="isT-Rq-5PH"/>
187193
<constraint firstItem="Uwe-Fi-04a" firstAttribute="top" secondItem="Wts-5Z-p7a" secondAttribute="bottom" constant="10" id="wl5-PM-CyG"/>
188194
</constraints>
189-
<viewLayoutGuide key="safeArea" id="CeS-QQ-Djo"/>
190195
</view>
191196
<connections>
197+
<outlet property="backgroundVideoContainer" destination="q9v-1n-ZYf" id="ADa-RX-kZg"/>
192198
<outlet property="clientRoleToggle" destination="7iE-Y0-bQi" id="xF0-48-qAP"/>
193-
<outlet property="localVideoContainer" destination="XSO-cE-x5n" id="1XV-B8-ry9"/>
194-
<outlet property="remoteVideoContainer" destination="q9v-1n-ZYf" id="WST-Vv-Jjj"/>
199+
<outlet property="foregroundVideoContainer" destination="XSO-cE-x5n" id="7GG-yW-hDg"/>
195200
<outlet property="ultraLowLatencyToggle" destination="cbb-WI-53A" id="n3x-pK-MuE"/>
196201
</connections>
197202
</viewController>
198203
<placeholder placeholderIdentifier="IBFirstResponder" id="8dQ-Wz-bG7" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
204+
<tapGestureRecognizer id="yDz-VT-Yop"/>
199205
</objects>
200206
<point key="canvasLocation" x="3130" y="931"/>
201207
</scene>
@@ -207,5 +213,8 @@
207213
<namedColor name="btnPanelForeground">
208214
<color red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
209215
</namedColor>
216+
<systemColor name="systemBackgroundColor">
217+
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
218+
</systemColor>
210219
</resources>
211220
</document>

iOS/APIExample/Examples/Advanced/LiveStreaming/LiveStreaming.swift

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -53,19 +53,31 @@ class LiveStreamingEntry : UIViewController
5353
}
5454

5555
class LiveStreamingMain: BaseViewController {
56-
var localVideo = Bundle.loadView(fromNib: "VideoView", withType: VideoView.self)
57-
var remoteVideo = Bundle.loadView(fromNib: "VideoView", withType: VideoView.self)
58-
@IBOutlet weak var localVideoContainer:UIView!
59-
@IBOutlet weak var remoteVideoContainer:UIView!
56+
var foregroundVideo = Bundle.loadView(fromNib: "VideoView", withType: VideoView.self)
57+
var backgroundVideo = Bundle.loadView(fromNib: "VideoView", withType: VideoView.self)
58+
@IBOutlet weak var foregroundVideoContainer:UIView!
59+
@IBOutlet weak var backgroundVideoContainer:UIView!
6060
@IBOutlet weak var clientRoleToggle:UISwitch!
6161
@IBOutlet weak var ultraLowLatencyToggle:UISwitch!
62+
var remoteUid: UInt?
6263
var agoraKit: AgoraRtcEngineKit!
6364
var role: AgoraClientRole = .broadcaster {
6465
didSet {
65-
localVideoContainer.isHidden = role != .broadcaster
66+
foregroundVideoContainer.isHidden = role != .broadcaster
6667
ultraLowLatencyToggle.isEnabled = role == .audience
6768
}
6869
}
70+
var isLocalVideoForeground = false {
71+
didSet {
72+
if(isLocalVideoForeground) {
73+
foregroundVideo.setPlaceholder(text: "Local Host".localized)
74+
backgroundVideo.setPlaceholder(text: "Remote Host".localized)
75+
} else {
76+
foregroundVideo.setPlaceholder(text: "Remote Host".localized)
77+
backgroundVideo.setPlaceholder(text: "Local Host".localized)
78+
}
79+
}
80+
}
6981
var isUltraLowLatencyOn: Bool = false
7082

7183
// indicate if current instance has joined channel
@@ -75,12 +87,10 @@ class LiveStreamingMain: BaseViewController {
7587
super.viewDidLoad()
7688

7789
// layout render view
78-
localVideoContainer.addSubview(localVideo)
79-
remoteVideoContainer.addSubview(remoteVideo)
80-
localVideo.setPlaceholder(text: "Local Host".localized)
81-
localVideo.bindFrameToSuperviewBounds()
82-
remoteVideo.setPlaceholder(text: "Remote Host".localized)
83-
remoteVideo.bindFrameToSuperviewBounds()
90+
foregroundVideoContainer.addSubview(foregroundVideo)
91+
backgroundVideoContainer.addSubview(backgroundVideo)
92+
foregroundVideo.bindFrameToSuperviewBounds()
93+
backgroundVideo.bindFrameToSuperviewBounds()
8494

8595
// set up agora instance when view loadedlet config = AgoraRtcEngineConfig()
8696
let config = AgoraRtcEngineConfig()
@@ -92,6 +102,9 @@ class LiveStreamingMain: BaseViewController {
92102
guard let channelName = configs["channelName"] as? String,
93103
let role = configs["role"] as? AgoraClientRole else {return}
94104

105+
// for audience put local video in foreground
106+
isLocalVideoForeground = role == .audience
107+
95108
// make this room live broadcasting room
96109
agoraKit.setChannelProfile(.liveBroadcasting)
97110
updateClientRole(role)
@@ -108,7 +121,7 @@ class LiveStreamingMain: BaseViewController {
108121
// 2. If app certificate is turned on at dashboard, token is needed
109122
// when joining channel. The channel name and uid used to calculate
110123
// the token has to match the ones used for channel join
111-
let result = agoraKit.joinChannel(byToken: nil, channelId: channelName, info: nil, uid: SCREEN_SHARE_BROADCASTER_UID) {[unowned self] (channel, uid, elapsed) -> Void in
124+
let result = agoraKit.joinChannel(byToken: nil, channelId: channelName, info: nil, uid: 0) {[unowned self] (channel, uid, elapsed) -> Void in
112125
self.isJoined = true
113126
LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info)
114127
}
@@ -138,7 +151,7 @@ class LiveStreamingMain: BaseViewController {
138151
let videoCanvas = AgoraRtcVideoCanvas()
139152
videoCanvas.uid = 0
140153
// the view to be binded
141-
videoCanvas.view = localVideo.videoView
154+
videoCanvas.view = foregroundVideo.videoView
142155
videoCanvas.renderMode = .hidden
143156
agoraKit.setupLocalVideo(videoCanvas)
144157

@@ -159,6 +172,31 @@ class LiveStreamingMain: BaseViewController {
159172
agoraKit.setClientRole(.audience, options: options)
160173
}
161174

175+
@IBAction func onTapForegroundVideo(_ sender:UIButton) {
176+
isLocalVideoForeground = !isLocalVideoForeground
177+
178+
let localVideoCanvas = AgoraRtcVideoCanvas()
179+
localVideoCanvas.uid = 0
180+
localVideoCanvas.renderMode = .hidden
181+
182+
let remoteVideoCanvas = AgoraRtcVideoCanvas()
183+
remoteVideoCanvas.renderMode = .hidden
184+
185+
if(isLocalVideoForeground) {
186+
localVideoCanvas.view = foregroundVideo.videoView
187+
remoteVideoCanvas.view = backgroundVideo.videoView
188+
} else {
189+
localVideoCanvas.view = foregroundVideo.videoView
190+
remoteVideoCanvas.view = backgroundVideo.videoView
191+
}
192+
193+
agoraKit.setupLocalVideo(localVideoCanvas)
194+
if let uid = remoteUid {
195+
remoteVideoCanvas.uid = uid
196+
agoraKit.setupRemoteVideo(remoteVideoCanvas)
197+
}
198+
}
199+
162200
@IBAction func onToggleClientRole(_ sender:UISwitch) {
163201
let role:AgoraClientRole = sender.isOn ? .broadcaster : .audience
164202
updateClientRole(role)
@@ -227,13 +265,16 @@ extension LiveStreamingMain: AgoraRtcEngineDelegate {
227265
func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int) {
228266
LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info)
229267

268+
//record remote uid
269+
remoteUid = uid
270+
230271
// Only one remote video view is available for this
231272
// tutorial. Here we check if there exists a surface
232273
// view tagged as this uid.
233274
let videoCanvas = AgoraRtcVideoCanvas()
234275
videoCanvas.uid = uid
235276
// the view to be binded
236-
videoCanvas.view = remoteVideo.videoView
277+
videoCanvas.view = backgroundVideo.videoView
237278
videoCanvas.renderMode = .hidden
238279
agoraKit.setupRemoteVideo(videoCanvas)
239280
}
@@ -245,6 +286,11 @@ extension LiveStreamingMain: AgoraRtcEngineDelegate {
245286
func rtcEngine(_ engine: AgoraRtcEngineKit, didOfflineOfUid uid: UInt, reason: AgoraUserOfflineReason) {
246287
LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info)
247288

289+
//clear remote uid
290+
if(remoteUid == uid){
291+
remoteUid = nil
292+
}
293+
248294
// to unlink your view from sdk, so that your view reference will be released
249295
// note the video will stay at its last frame, to completely remove it
250296
// you will need to remove the EAGL sublayer from your binded view

0 commit comments

Comments
 (0)