IVS iOS Broadcast SDK를 사용한 게시 및 구독 | 실시간 스트리밍 - Amazon IVS

IVS iOS Broadcast SDK를 사용한 게시 및 구독 | 실시간 스트리밍

이 문서에서는 IVS Real-Time Streaming iOS Broadcast SDK를 사용하여 스테이지에 게시하고 구독하는 단계를 안내합니다.

개념

실시간 기능의 3가지 핵심 개념은 스테이지, 전략렌더러입니다. 설계 목표는 작동하는 제품을 구축하는 데 필요한 클라이언트 측 로직의 수를 최소화하는 것입니다.

단계

IVSStage 클래스는 호스트 애플리케이션과 SDK 사이의 주요 상호 작용 지점입니다. 클래스는 스테이지 자체를 나타내며 스테이지에 참가하고 나가는 데 사용됩니다. 스테이지를 만들거나 참가하려면 제어 플레인에서 유효하고 만료되지 않은 토큰 문자열(token으로 표시됨)이 필요합니다. 스테이지 참가 및 나가기는 간단합니다.

let stage = try IVSStage(token: token, strategy: self) try stage.join() stage.leave()

IVSStage 클래스는 IVSStageRendererIVSErrorDelegate가 첨부될 수 있는 위치이기도 합니다.

let stage = try IVSStage(token: token, strategy: self) stage.errorDelegate = self stage.addRenderer(self) // multiple renderers can be added

Strategy

IVSStageStrategy 프로토콜은 호스트 애플리케이션이 원하는 스테이지 상태를 SDK에 전달하는 방법을 제공합니다. shouldSubscribeToParticipant, shouldPublishParticipantstreamsToPublishForParticipant 함수를 구현해야 합니다. 모든 함수를 아래에서 설명합니다.

참가자 구독

func stage(_ stage: IVSStage, shouldSubscribeToParticipant participant: IVSParticipantInfo) -> IVSStageSubscribeType

원격 참가자가 스테이지에 참가하면 SDK는 호스트 애플리케이션에 해당 참가자의 원하는 구독 상태를 쿼리합니다. 옵션은 .none, .audioOnly.audioVideo입니다. 이 함수의 값을 반환할 때 호스트 애플리케이션은 게시 상태, 현재 구독 상태 또는 스테이지 연결 상태에 대해 걱정할 필요가 없습니다. .audioVideo가 반환되는 경우 SDK는 구독 전에 원격 참가자가 게시할 때까지 기다리고, 프로세스 전반에 걸쳐 렌더러를 통해 호스트 애플리케이션을 업데이트합니다.

다음은 샘플 구현입니다.

func stage(_ stage: IVSStage, shouldSubscribeToParticipant participant: IVSParticipantInfo) -> IVSStageSubscribeType { return .audioVideo }

항상 모든 참가자가 서로 보기를 원하는 호스트 애플리케이션(예: 비디오 채팅 애플리케이션)을 위한 이 기능의 전체 구현입니다.

고급 구현도 가능합니다. IVSParticipantInfoattributes 속성을 사용하여 서버에서 제공하는 특성을 기반으로 참가자를 선택적으로 구독합니다.

func stage(_ stage: IVSStage, shouldSubscribeToParticipant participant: IVSParticipantInfo) -> IVSStageSubscribeType { switch participant.attributes["role"] { case "moderator": return .none case "guest": return .audioVideo default: return .none } }

이를 통해 중재자가 직접 보거나 듣지 않고 모든 게스트를 모니터링할 수 있는 스테이지를 만들 수 있습니다. 호스트 애플리케이션은 추가 비즈니스 로직을 사용하여 중재자가 서로를 볼 수는 있지만 게스트에게는 보이지 않도록 할 수 있습니다.

참가자 구독 구성

func stage(_ stage: IVSStage, subscribeConfigurationForParticipant participant: IVSParticipantInfo) -> IVSSubscribeConfiguration

원격 참가자를 구독 중인 경우(참가자 구독 참조) SDK에서는 해당 참가자의 사용자 지정 구독 구성에 대한 호스트 애플리케이션을 쿼리합니다. 이 구성은 선택 사항이며, 호스트 애플리케이션에서 구독자 동작의 특정 측면을 제어할 수 있습니다. 구성할 수 있는 항목에 대한 내용은 SDK 참조 설명서의 SubscribeConfiguration을 참조하세요.

다음은 샘플 구현입니다.

func stage(_ stage: IVSStage, subscribeConfigurationForParticipant participant: IVSParticipantInfo) -> IVSSubscribeConfiguration { let config = IVSSubscribeConfiguration() try! config.jitterBuffer.setMinDelay(.medium()) return config }

구독한 모든 참가자의 지터-버퍼 최소 지연이 이 구현을 통해 MEDIUM 사전 설정으로 업데이트됩니다.

shouldSubscribeToParticipant와 마찬가지로 고급 구현도 가능합니다. 주어진 ParticipantInfo를 사용하여 특정 참가자에 대한 구독 구성을 선택적으로 업데이트할 수 있습니다.

기본 동작을 사용하는 것이 좋습니다. 변경하려는 특정 동작이 있는 경우에만 사용자 지정 구성을 지정합니다.

게시

func stage(_ stage: IVSStage, shouldPublishParticipant participant: IVSParticipantInfo) -> Bool

스테이지에 연결되면 SDK는 호스트 애플리케이션을 쿼리하여 특정 참가자가 게시해야 하는지 여부를 확인합니다. 이는 제공된 토큰을 기반으로 게시할 권한이 있는 로컬 참가자에게만 호출됩니다.

다음은 샘플 구현입니다.

func stage(_ stage: IVSStage, shouldPublishParticipant participant: IVSParticipantInfo) -> Bool { return true }

이는 사용자가 항상 게시하기를 원하는 표준 비디오 채팅 애플리케이션에 대한 구현입니다. 오디오 및 비디오를 음소거 또는 음소거 해제하여 즉시 숨기거나 보기/듣기가 가능하도록 할 수 있습니다. (게시/게시 취소를 사용할 수도 있지만 속도가 훨씬 느립니다. 음소거/음소거 해제는 가시성을 자주 변경하는 것이 바람직한 사용 사례에 적합합니다.)

게시할 스트림 선택

func stage(_ stage: IVSStage, streamsToPublishForParticipant participant: IVSParticipantInfo) -> [IVSLocalStageStream]

게시할 때 이를 사용하여 게시해야 하는 오디오 및 비디오 스트림을 결정합니다. 이에 대해서는 미디어 스트림 게시에서 자세히 설명합니다.

전략 업데이트

전략은 동적이어야 합니다. 위 함수 중에서 반환되는 값은 언제든지 변경될 수 있습니다. 예를 들어 호스트 애플리케이션이 최종 사용자가 버튼을 탭할 때까지 게시하지 않으려는 경우, shouldPublishParticipant에서 변수를 반환할 수 있습니다(예: hasUserTappedPublishButton). 최종 사용자의 상호 작용에 따라 변수가 변경되면 stage.refreshStrategy()를 호출하여 SDK에 최신 값에 대한 전략을 쿼리하고 변경된 사항만 적용하도록 신호를 보냅니다. SDK에서 shouldPublishParticipant 값이 변경된 것을 관찰하면 게시 프로세스가 시작됩니다. SDK 쿼리와 모든 함수가 이전과 동일한 값을 반환하는 경우 refreshStrategy 호출 시 스테이지가 수정되지 않습니다.

shouldSubscribeToParticipant의 반환 값이 .audioVideo에서 .audioOnly로 변경된 경우 이전에 비디오 스트림이 존재했다면 반환된 값이 변경된 모든 참가자에 대한 비디오 스트림이 제거됩니다.

일반적으로 스테이지는 전략을 사용하여 이전 전략과 현재 전략 간의 차이를 가장 효율적으로 적용하므로 호스트 애플리케이션에서 이를 올바르게 관리하는 데 필요한 모든 상태에 대해 걱정할 필요가 없습니다. 이로 인해 stage.refreshStrategy() 호출은 전략이 변경되지 않는 한 아무 소용도 없으므로 소모량이 적은 작업이라고 생각하면 됩니다.

렌더러

IVSStageRenderer 프로토콜은 호스트 애플리케이션에 스테이지 상태를 전달하는 방법을 제공합니다. 호스트 애플리케이션의 UI 업데이트는 대체로 렌더러에서 제공하는 이벤트에 의해 전적으로 이루어질 수 있습니다. 렌더러는 다음과 같은 함수를 제공합니다.

func stage(_ stage: IVSStage, participantDidJoin participant: IVSParticipantInfo) func stage(_ stage: IVSStage, participantDidLeave participant: IVSParticipantInfo) func stage(_ stage: IVSStage, participant: IVSParticipantInfo, didChange publishState: IVSParticipantPublishState) func stage(_ stage: IVSStage, participant: IVSParticipantInfo, didChange subscribeState: IVSParticipantSubscribeState) func stage(_ stage: IVSStage, participant: IVSParticipantInfo, didAdd streams: [IVSStageStream]) func stage(_ stage: IVSStage, participant: IVSParticipantInfo, didRemove streams: [IVSStageStream]) func stage(_ stage: IVSStage, participant: IVSParticipantInfo, didChangeMutedStreams streams: [IVSStageStream]) func stage(_ stage: IVSStage, didChange connectionState: IVSStageConnectionState, withError error: Error?)

렌더러에서 제공하는 정보가 전략의 반환 값에 영향을 미칠 것으로 예상되지는 않습니다. 예를 들어, shouldSubscribeToParticipant의 반환 값은 participant:didChangePublishState가 호출될 때 변경되지 않을 것으로 예상됩니다. 호스트 애플리케이션이 특정 참가자를 구독하려는 경우 해당 참가자의 게시 상태와 무관하게 원하는 구독 유형을 반환해야 합니다. SDK는 원하는 전략 상태가 스테이지 상태를 기반을 정확한 시간에 실행되도록 하는 역할을 합니다.

게시 참가자만 participantDidJoin를 트리거하고, 참가자가 게시를 중단하거나 스테이지 세션에서 나갈 때마다 participantDidLeave가 트리거됩니다.

미디어 스트림 게시

내장 마이크 및 카메라와 같은 로컬 디바이스는 IVSDeviceDiscovery를 통해 검색됩니다. 다음은 전면 카메라와 기본 마이크를 선택한 다음 SDK에 게시될 IVSLocalStageStreams로 반환하는 예제입니다.

let devices = IVSDeviceDiscovery().listLocalDevices() // Find the camera virtual device, choose the front source, and create a stream let camera = devices.compactMap({ $0 as? IVSCamera }).first! let frontSource = camera.listAvailableInputSources().first(where: { $0.position == .front })! camera.setPreferredInputSource(frontSource) let cameraStream = IVSLocalStageStream(device: camera) // Find the microphone virtual device and create a stream let microphone = devices.compactMap({ $0 as? IVSMicrophone }).first! let microphoneStream = IVSLocalStageStream(device: microphone) // Configure the audio manager to use the videoChat preset, which is optimized for bi-directional communication, including echo cancellation. IVSStageAudioManager.sharedInstance().setPreset(.videoChat) // This is a function on IVSStageStrategy func stage(_ stage: IVSStage, streamsToPublishForParticipant participant: IVSParticipantInfo) -> [IVSLocalStageStream] { return [cameraStream, microphoneStream] }

참가자 표시 및 제거

구독이 완료되면 렌더러의 didAddStreams 함수를 통해 IVSStageStream 객체 배열을 받게 됩니다. 이 참가자에 대한 오디오 수준 통계를 미리 보거나 수신하려면 스트림에서 기본IVSDevice 객체에 액세스할 수 있습니다.

if let imageDevice = stream.device as? IVSImageDevice { let preview = imageDevice.previewView() /* attach this UIView subclass to your view */ } else if let audioDevice = stream.device as? IVSAudioDevice { audioDevice.setStatsCallback( { stats in /* process stats.peak and stats.rms */ }) }

참가자가 게시를 중단하거나 참가자 구독이 취소되면 제거된 스트림과 함께 didRemoveStreams 함수가 호출됩니다. 호스트 애플리케이션은 이를 신호로 사용하여 보기 계층 구조에서 참가자의 비디오 스트림을 제거해야 합니다.

didRemoveStreams는 다음을 포함하여 스트림이 제거될 수 있는 모든 시나리오에서 호출됩니다.

  • 원격 참가자가 게시를 중단합니다.

  • 로컬 디바이스가 구독을 취소하거나 구독을 .audioVideo에서 .audioOnly로 변경합니다.

  • 원격 참가자가 스테이지를 나갑니다.

  • 로컬 참가자가 스테이지를 나갑니다.

모든 시나리오에서 didRemoveStreams가 호출되므로 원격 또는 로컬 나가기 작업 중에 UI에서 참가자를 제거하는 사용자 지정 비즈니스 로직이 필요하지 않습니다.

미디어 스트림 음소거 및 음소거 해제

IVSLocalStageStream 객체에는 스트림의 음소거 여부를 제어하는 setMuted 함수가 있습니다. 이 함수는 streamsToPublishForParticipant 전략 함수에서 반환되기 전이나 후에 스트림에서 호출할 수 있습니다.

중요: refreshStrategy 호출 이후 streamsToPublishForParticipant에 의해 새 IVSLocalStageStream 객체 인스턴스가 반환되면 새 스트림 객체의 음소거 상태가 스테이지에 적용됩니다. 새 IVSLocalStageStream 인스턴스를 만들 때는 예상되는 음소거 상태가 유지되도록 주의해야 합니다.

원격 참가자 미디어 음소거 상태 모니터링

참가자가 비디오 또는 오디오 스트림의 음소거 상태를 변경할 때 변경된 스트림 배열과 함께 렌더러 didChangeMutedStreams 함수가 호출됩니다. IVSStageStreamisMuted 속성을 사용하여 UI를 적절히 업데이트합니다.

func stage(_ stage: IVSStage, participant: IVSParticipantInfo, didChangeMutedStreams streams: [IVSStageStream]) { streams.forEach { stream in /* stream.isMuted */ } }

스테이지 구성 생성

스테이지의 비디오 구성 값을 사용자 지정하려면 IVSLocalStageStreamVideoConfiguration을 사용합니다.

let config = IVSLocalStageStreamVideoConfiguration() try config.setMaxBitrate(900_000) try config.setMinBitrate(100_000) try config.setTargetFramerate(30) try config.setSize(CGSize(width: 360, height: 640)) config.degradationPreference = .balanced

WebRTC 통계 가져오기

게시 스트림 또는 구독 스트림에 대한 최신 WebRTC 통계를 가져오려면 IVSStageStream에서 requestRTCStats를 사용합니다. 수집이 완료되면 IVSStageStream에서 설정할 수 있는 IVSStageStreamDelegate를 통해 통계를 받습니다. WebRTC 통계를 지속적으로 수집하려면 Timer에서 이 함수를 호출합니다.

func stream(_ stream: IVSStageStream, didGenerateRTCStats stats: [String : [String : String]]) { for stat in stats { for member in stat.value { print("stat \(stat.key) has member \(member.key) with value \(member.value)") } } }

참가자 특성 가져오기

CreateParticipantToken 엔드포인트 요청에서 특성을 지정하는 경우 IVSParticipantInfo 속성에서 특성을 볼 수 있습니다.

func stage(_ stage: IVSStage, participantDidJoin participant: IVSParticipantInfo) { print("ID: \(participant.participantId)") for attribute in participant.attributes { print("attribute: \(attribute.key)=\(attribute.value)") } }

백그라운드에서 세션 계속하기

앱이 백그라운드로 전환될 때 원격 오디오를 들으면서 스테이지에 계속 있을 수 있지만, 본인이 이미지와 오디오를 계속 전송할 수는 없습니다. IVSStrategy 구현을 업데이트하여 게시를 중단하고 .audioOnly를 구독해야 합니다(또는 해당하는 경우 .none).

func stage(_ stage: IVSStage, shouldPublishParticipant participant: IVSParticipantInfo) -> Bool { return false } func stage(_ stage: IVSStage, shouldSubscribeToParticipant participant: IVSParticipantInfo) -> IVSStageSubscribeType { return .audioOnly }

그런 다음 stage.refreshStrategy()를 호출합니다.

동시 방송을 사용한 계층화된 인코딩 활성화/비활성화

미디어 스트림을 게시할 때 SDK는 고품질 및 저품질 비디오 스트림을 전송하므로 원격 참가자는 다운링크 대역폭이 제한되어 있어도 스트림을 구독할 수 있습니다. 동시 방송을 사용한 계층화된 인코딩이 기본적으로 켜져 있습니다. IVSSimulcastConfiguration으로 이를 비활성화할 수 있습니다.

// Disable Simulcast let config = IVSLocalStageStreamVideoConfiguration() config.simulcast.enabled = false let cameraStream = IVSLocalStageStream(device: camera, configuration: config) // Other Stage implementation code

IVS 채널로 스테이지 브로드캐스트

스테이지를 브로드캐스트하려면 별도의 IVSBroadcastSession을 만든 다음 위에서 설명한 대로 SDK로 브로드캐스트하기 위한 일반적인 지침을 따릅니다. IVSStageStreamdevice 속성은 위 코드 조각에 표시된 대로 IVSImageDevice 또는 IVSAudioDevice입니다. IVSBroadcastSession.mixer에 연결하여 전체 스테이지를 사용자 지정 가능한 레이아웃으로 브로드캐스트할 수 있습니다.

필요에 따라 스테이지를 합성하고 IVS 지연 시간이 짧은 채널로 브로드캐스트하여 더 많은 청중에게 다가갈 수 있습니다. IVS 지연 시간이 짧은 스트리밍 사용 설명서의 Amazon IVS 스트림에서 여러 호스트 활성화를 참조하세요.