Skip to content

Commit 6396bfb

Browse files
authored
Update voice-video-calling-cte-ios.md
1 parent 5e5523c commit 6396bfb

File tree

1 file changed

+26
-204
lines changed

1 file changed

+26
-204
lines changed

articles/communication-services/quickstarts/voice-video-calling/includes/custom-teams-endpoint/voice-video-calling-cte-ios.md

Lines changed: 26 additions & 204 deletions
Original file line numberDiff line numberDiff line change
@@ -289,88 +289,6 @@ AVAudioSession.sharedInstance().requestRecordPermission { (granted) in
289289
}
290290
```
291291

292-
## Display local video
293-
294-
Before starting a call, you can manage settings related to video. In this quickstart, we introduce the implementation of toggling local video before or during a call.
295-
296-
First we need to access local cameras with `deviceManager`. Once the desired camera is selected, we can construct `LocalVideoStream` and create a `VideoStreamRenderer`, and then attach it to `previewView`. During the call, we can use `startVideo` or `stopVideo` to start or stop sending `LocalVideoStream` to remote participants. This function also works with handling incoming calls.
297-
298-
```Swift
299-
func toggleLocalVideo() {
300-
// toggling video before call starts
301-
if (call == nil)
302-
{
303-
if(!sendingVideo)
304-
{
305-
self.callClient = CallClient()
306-
self.callClient.getDeviceManager { (deviceManager, error) in
307-
if (error == nil) {
308-
print("Got device manager instance")
309-
self.deviceManager = deviceManager
310-
} else {
311-
print("Failed to get device manager instance")
312-
}
313-
}
314-
guard let deviceManager = deviceManager else {
315-
return
316-
}
317-
let camera = deviceManager.cameras.first
318-
let scalingMode = ScalingMode.fit
319-
if (self.localVideoStream == nil) {
320-
self.localVideoStream = [LocalVideoStream]()
321-
}
322-
localVideoStream!.append(LocalVideoStream(camera: camera!))
323-
previewRenderer = try! VideoStreamRenderer(localVideoStream: localVideoStream!.first!)
324-
previewView = try! previewRenderer!.createView(withOptions: CreateViewOptions(scalingMode:scalingMode))
325-
self.sendingVideo = true
326-
}
327-
else{
328-
self.sendingVideo = false
329-
self.previewView = nil
330-
self.previewRenderer!.dispose()
331-
self.previewRenderer = nil
332-
}
333-
}
334-
// toggle local video during the call
335-
else{
336-
if (sendingVideo) {
337-
teamsCall!.stopVideo(stream: localVideoStream!.first!) { (error) in
338-
if (error != nil) {
339-
print("cannot stop video")
340-
}
341-
else {
342-
self.sendingVideo = false
343-
self.previewView = nil
344-
self.previewRenderer!.dispose()
345-
self.previewRenderer = nil
346-
}
347-
}
348-
}
349-
else {
350-
guard let deviceManager = deviceManager else {
351-
return
352-
}
353-
let camera = deviceManager.cameras.first
354-
let scalingMode = ScalingMode.fit
355-
if (self.localVideoStream == nil) {
356-
self.localVideoStream = [LocalVideoStream]()
357-
}
358-
localVideoStream!.append(LocalVideoStream(camera: camera!))
359-
previewRenderer = try! VideoStreamRenderer(localVideoStream: localVideoStream!.first!)
360-
previewView = try! previewRenderer!.createView(withOptions: CreateViewOptions(scalingMode:scalingMode))
361-
teamsCall!.startVideo(stream:(localVideoStream?.first)!) { (error) in
362-
if (error != nil) {
363-
print("cannot start video")
364-
}
365-
else {
366-
self.sendingVideo = true
367-
}
368-
}
369-
}
370-
}
371-
}
372-
```
373-
374292
## Place an outgoing call
375293

376294
The `startCall` method is set as the action that is performed when the Start Call button is tapped. In this quickstart, outgoing calls are audio only by default. To start a call with video, we need to set `VideoOptions` with `LocalVideoStream` and pass it with `startCallOptions` to set initial options for the call.
@@ -428,6 +346,7 @@ func setTeamsCallAndObserver(call:TeamsCall, error:Error?) {
428346
self.teamsCall = call
429347
self.teamsCallObserver = TeamsCallObserver(self)
430348
self.teamsCall!.delegate = self.teamsCallObserver
349+
// Attach a RemoteParticipant observer
431350
self.remoteParticipantObserver = RemoteParticipantObserver(self)
432351
} else {
433352
print("Failed to get teams call object")
@@ -472,11 +391,6 @@ final class TeamsIncomingCallHandler: NSObject, TeamsCallAgentDelegate, TeamsInc
472391

473392
We need to create an instance of `TeamsIncomingCallHandler` by adding the following code to the `onAppear` callback in `ContentView.swift`:
474393

475-
```Swift
476-
let teamsIncomingCallHandler = TeamsIncomingCallHandler.getOrCreateInstance()
477-
teamsIncomingCallHandler.contentView = self
478-
```
479-
480394
Set a delegate to the `TeamsCallAgent` after the `TeamsCallAgent` being successfully created:
481395

482396
```Swift
@@ -487,7 +401,6 @@ Once there's an incoming call, the `TeamsIncomingCallHandler` calls the function
487401

488402
```Swift
489403
func showIncomingCallBanner(_ incomingCall: TeamsIncomingCall) {
490-
isIncomingCall = true
491404
self.teamsIncomingCall = incomingCall
492405
}
493406
```
@@ -496,65 +409,37 @@ The actions attached to `answer` and `decline` are implemented as the following
496409

497410
```Swift
498411
func answerIncomingCall() {
499-
isIncomingCall = false
500412
let options = AcceptTeamsCallOptions()
501-
if (self.incomingCall != nil) {
502-
guard let deviceManager = deviceManager else {
503-
return
504-
}
505-
if (self.localVideoStream == nil) {
506-
self.localVideoStream = [LocalVideoStream]()
507-
}
508-
if(sendingVideo)
509-
{
510-
let camera = deviceManager.cameras.first
511-
localVideoStream!.append(LocalVideoStream(camera: camera!))
512-
let videoOptions = VideoOptions(localVideoStreams: localVideoStream!)
513-
options.videoOptions = videoOptions
514-
}
515-
self.incomingCall!.accept(options: options) { (call, error) in
516-
setCallAndObersever(call: call, error: error)
517-
}
413+
guard let teamsIncomingCall = self.teamsIncomingCall else {
414+
print("No active incoming call")
415+
return
518416
}
519-
}
520-
521-
func declineIncomingCall(){
522-
self.incomingCall!.reject { (error) in }
523-
isIncomingCall = false
524-
}
525-
```
526-
527-
## Remote participant video streams
528417

529-
We can create a `RemoteVideoStreamData` class to handle rendering video streams of remote participant.
530-
531-
```Swift
532-
public class RemoteVideoStreamData : NSObject, RendererDelegate {
533-
public func videoStreamRenderer(didFailToStart renderer: VideoStreamRenderer) {
534-
owner.errorMessage = "Renderer failed to start"
418+
guard let deviceManager = deviceManager else {
419+
print("No device manager instance")
420+
return
535421
}
536-
537-
private var owner:ContentView
538-
let stream:RemoteVideoStream
539-
var renderer:VideoStreamRenderer? {
540-
didSet {
541-
if renderer != nil {
542-
renderer!.delegate = self
543-
}
544-
}
422+
423+
if localVideoStream == nil {
424+
localVideoStream = [LocalVideoStream]()
545425
}
546-
547-
var views:[RendererView] = []
548-
init(view:ContentView, stream:RemoteVideoStream) {
549-
owner = view
550-
self.stream = stream
426+
427+
if sendingVideo
428+
{
429+
let camera = deviceManager.cameras.first
430+
localVideoStream!.append(LocalVideoStream(camera: camera!))
431+
let videoOptions = VideoOptions(localVideoStreams: localVideoStream!)
432+
options.videoOptions = videoOptions
551433
}
552-
553-
public func videoStreamRenderer(didRenderFirstFrame renderer: VideoStreamRenderer) {
554-
let size:StreamSize = renderer.size
555-
owner.remoteVideoSize = String(size.width) + " X " + String(size.height)
434+
435+
teamsIncomingCall.accept(options: options) { (call, error) in
436+
setTeamsCallAndObserver(call: call, error: error)
556437
}
557438
}
439+
440+
func declineIncomingCall(){
441+
self.teamsIncomingCall?.reject { (error) in }
442+
}
558443
```
559444

560445
## Subscribe to events
@@ -577,83 +462,20 @@ public class TeamsCallObserver: NSObject, TeamsCallDelegate, TeamsIncomingCallDe
577462
// render remote video streams when remote participant changes
578463
public func teamsCall(_ teamsCall: TeamsCall, didUpdateRemoteParticipant args: ParticipantsUpdatedEventArgs) {
579464
for participant in args.addedParticipants {
580-
participant.delegate = owner.remoteParticipantObserver
581-
for stream in participant.videoStreams {
582-
if !owner.remoteVideoStreamData.isEmpty {
583-
return
584-
}
585-
let data:RemoteVideoStreamData = RemoteVideoStreamData(view: owner, stream: stream)
586-
let scalingMode = ScalingMode.fit
587-
data.renderer = try! VideoStreamRenderer(remoteVideoStream: stream)
588-
let view:RendererView = try! data.renderer!.createView(withOptions: CreateViewOptions(scalingMode:scalingMode))
589-
data.views.append(view)
590-
self.owner.remoteViews.append(view)
591-
owner.remoteVideoStreamData[stream.id] = data
592-
}
593-
owner.remoteParticipant = participant
465+
participant.delegate = self.remoteParticipantObserver
594466
}
595467
}
596468

597469
// Handle remote video streams when the call is connected
598470
public func initialCallParticipant() {
599471
for participant in owner.teamsCall.remoteParticipants {
600-
participant.delegate = owner.remoteParticipantObserver
472+
participant.delegate = self.remoteParticipantObserver
601473
for stream in participant.videoStreams {
602474
renderRemoteStream(stream)
603475
}
604476
owner.remoteParticipant = participant
605477
}
606478
}
607-
608-
//create render for RemoteVideoStream and attach it to view
609-
public func renderRemoteStream(_ stream: RemoteVideoStream!) {
610-
if !owner.remoteVideoStreamData.isEmpty {
611-
return
612-
}
613-
let data:RemoteVideoStreamData = RemoteVideoStreamData(view: owner, stream: stream)
614-
let scalingMode = ScalingMode.fit
615-
data.renderer = try! VideoStreamRenderer(remoteVideoStream: stream)
616-
let view:RendererView = try! data.renderer!.createView(withOptions: CreateViewOptions(scalingMode:scalingMode))
617-
self.owner.remoteViews.append(view)
618-
owner.remoteVideoStreamData[stream.id] = data
619-
}
620-
}
621-
```
622-
623-
## Remote participant Management
624-
625-
All remote participants are represented with the `RemoteParticipant` type and are available through the `remoteParticipants` collection on a call instance.
626-
627-
We can implement a `RemoteParticipantObserver` class to subscribe to the updates on remote video streams of remote participants.
628-
629-
```Swift
630-
public class RemoteParticipantObserver : NSObject, RemoteParticipantDelegate {
631-
private var owner:ContentView
632-
init(_ view:ContentView) {
633-
owner = view
634-
}
635-
636-
public func renderRemoteStream(_ stream: RemoteVideoStream!) {
637-
let data:RemoteVideoStreamData = RemoteVideoStreamData(view: owner, stream: stream)
638-
let scalingMode = ScalingMode.fit
639-
data.renderer = try! VideoStreamRenderer(remoteVideoStream: stream)
640-
let view:RendererView = try! data.renderer!.createView(withOptions: CreateViewOptions(scalingMode:scalingMode))
641-
self.owner.remoteViews.append(view)
642-
owner.remoteVideoStreamData[stream.id] = data
643-
}
644-
645-
// render RemoteVideoStream when remote participant turns on the video, dispose the renderer when remote video is off
646-
public func remoteParticipant(_ remoteParticipant: RemoteParticipant, didUpdateVideoStreams args: RemoteVideoStreamsEventArgs) {
647-
for stream in args.addedRemoteVideoStreams {
648-
renderRemoteStream(stream)
649-
}
650-
for stream in args.removedRemoteVideoStreams {
651-
for data in owner.remoteVideoStreamData.values {
652-
data.renderer?.dispose()
653-
}
654-
owner.remoteViews.removeAll()
655-
}
656-
}
657479
}
658480
```
659481

0 commit comments

Comments
 (0)