• 서비스
  • 가격
  • 리소스
  • 기술지원

iOS

업무 프로세스

본 섹션에서는 음성 채팅방의 몇 가지 일반적인 업무 프로세스를 요약하여 전체 시나리오 구현 프로세스를 더 잘 이해할 수 있도록 도와줍니다.
방 관리 프로세스
방장 마이크 순위 관리 프로세스
청취자 마이크 순위 관리 프로세스
아래 그림은 방 생성, 입장, 퇴장, 해산 등의 구현 프로세스를 포함한 방 관리 프로세스를 보여줍니다.



아래 그림은 방주인이 마이크를 관리하는 프로세스를 보여줍니다. 마이크 사용 초청, 마이크 사용 강제 끄기, 마이크 금언등의 구현 프로세스를 포함합니다.



아래 그림은 청취자가 마이크를 관리하는 프로세스를 보여줍니다. 마이크 자동 사용, 마이크 자동 끄기, 마이크 순위 이동 등의 구현 프로세스를 포함합니다.




접속 준비

단계1: 서비스 개통

음성 채팅방 시나리오는 일반적으로 ChatRTC Engine 두 가지 유료 PaaS 서비스에 의존하여 구축됩니다.
1. 먼저 콘솔에 로그인하여 애플리케이션을 생성해야 합니다. RTC Engine 애플리케이션을 생성한 후 Chat 애플리케이션을 생성해야 합니다.



설명:
두 개의 애플리케이션을 생성하고 각각 테스트 환경과 프로덕션 환경에 적용할 것을 권장하며 1년 동안 각 계정(UIN)당 매월 10,000분의 무료 사용 시간이 제공합니다.
RTC Engine 월정액 요금제는 체험판(기본), 라이트, 스탠다드, 프로페셔널로 구분되며, 다양한 부가 기능 서비스를 이용할 수 있습니다. 자세한 내용은 버전 기능 및 월정액 요금제 설명를 참조하세요.
2. 애플리케이션 생성이 완료되면 앱 관리-앱 개요 메뉴에서 해당 애플리케이션의 기본 정보를 확인할 수 있습니다. SDKAppIDSDKSecretKey는 향후 사용을 위해 안전하게 보관해야 하며,동시에 키 유출로 인한 트래픽 도용을 방지해야 합니다.




단계2: SDK 임포트하기

RTC Engine SDK와 Chat SDK가 CocoaPods에 이미 게시되었으며, CocoaPods를 통해 SDK를 통합하는 것을 권장합니다.
1. CocoaPods 설치
터미널 창구에 다음 명령을 입력하세요(Mac에 Ruby 환경을 미리서 설치해야 합니다):
sudo gem install cocoapods
2. Podfile 파일 생성
프로젝트 경로로 이동한 후 다음 명령어를 입력하면 프로젝트 경로에 Podfile 파일이 생성됩니다.
pod init
3. Podfile 파일 편집
프로젝트 필요에 따라 적합한 버전을 선택하고 Podfile 파일을 편집하세요.
platform :ios, '8.0'
target 'App' do

# RTC Engine 라이트 버전
# 설치 패키지의 크기 증가가 최소화되어 있어서 RTC Engine 및 라이브방송 플레이어(TXLivePlayer) 두 가지 기능만 지원됩니다.
pod 'TXLiteAVSDK_TRTC', :podspec => 'https://liteav.sdk.qcloud.com/pod/liteavsdkspec/TXLiteAVSDK_TRTC.podspec’
# Add the Chat SDK
pod 'TXIMSDK_Plus_iOS'
# pod 'TXIMSDK_Plus_iOS_XCFramework'
# pod 'TXIMSDK_Plus_Swift_iOS_XCFramework'
# If you need to add the Quic plugin, please uncomment the next line.
# Note: This plugin must be used with the Objective-C edition or XCFramework edition of the Chat SDK, and the plugin version number must match the Chat SDK version number.
# pod 'TXIMSDK_Plus_QuicPlugin'

end
4. SDK 업데이트 및 설치
터미널 창구에 다음 명령을 입력하여 로컬 라이브러리 파일을 업데이트하고 SDK를 설치하세요.
pod install
또는 다음 명령을 사용하여 로컬 라이브러리 버전을 업데이트해도 됩니다.
pod update
pod 명령 실행 후 SDK가 통합된 .xcworkspace 확장자의 프로젝트 파일이 생성되며, 더블 클릭하여 열 수 있습니다.
설명:
pod 검색이 실패할 경우 pod의 로컬 repo 캐시를 업데이트해 볼 것을 권장합니다. 업데이트 명령은 다음과 같습니다.
pod setup
pod repo update
rm ~/Library/Caches/CocoaPods/search_index.json
CocoaPods 통합 방식 외에도 SDK를 다운로드하여 수동으로 임포트할 수도 있습니다. 자세한 내용은 RTC Engine SDK 수동 통합Chat SDK 수동 통합를 참조하세요.
Quic 플러그인은 axp-Quic 멀티플렉싱 전송 프로토콜을 제공하며 약한 네트워크 환경에서도 더 우수한 성능을 발휘합니다. 네트워크 패킷 손실률이 70%에 달하는 조건에서도 서비스를 제공할 수 있습니다. 이 기능은 프로페셔널 에디션, 프로페셔널 에디션 플러스 및 엔터프라이즈 에디션의 사용자에게만 개방되어 있습니다. 프로페셔널 에디션, 프로페셔널 에디션 플러스 또는 엔터프라이즈 에디션를 구매한 후 사용할 수 있습니다. 기능이 정상적으로 작동될 수 있도록 하려면 터미널 SDK를 7.7.5282및 그의 이상 버전으로 업데이트하세요.

단계 3: 엔지니어링 구성

1. 음성 채팅 시나리오에서 RTC Engine SDK 및 Chat SDK는 앱의 마이크 권한을 요구하며, 앱의 Info.plist에 다음 내용을 추가해야 합니다. 시스템에 나타난 권한 부여 다이얼로 박스에 마이크에 대한 안내가 있습니다.
Privacy - Microphone Usage Description,마이크 사용 목적 안내문을 함께 입력하세요



2. 앱이 백그라운드에서도 관련 기능을 계속 실행하려면 Xcode에서 현재 프로젝트를 선택하고 Capabilities에서 Background Modes 설정을 ON으로 설정한 후 Audio, AirPlay and Picture in Picture를 선택하세요. 아래 그림과 같습니다:




접속 과정

단계1: 인증 자격 증명의 생성

UserSig는 텐센트 실시간 통신 서비스에서 설계한 보안 서명이고 악의적인 공격자가 클라우드 서비스 사용 권한을 도용하는 것을 방지하기 위한 목적입니다. RTC Engine 및 Chat 서비스는 모두 이 보안 메커니즘을 채택하고 있으며 RTC Engine은 방 입장 시 인증을 수행하고 Chat은 로그인 시 인증을 수행합니다.
디버깅 및 테스트 단계: 클라이언트 예시 코드콘솔에서 가져오기 두 가지 방법으로 UserSig를 계산 및 생성할 수 있으며, 디버깅 및 테스트 용도로만 사용됩니다.
정식 운영 단계: 클라이언트가 역공학으로 키가 유출되는 것을 방지하기 위해 보안 등급이 더 높은 서버 UserSig 계산 방식의 사용을 권장합니다.
구체적인 구현 프로세스는 다음과 같습니다.
1. 손님의 App은 SDK 초기화 함수를 호출하기 전에 먼저 서버에 UserSig를 요청해야 합니다.
2. 손님의 서버는 SDKAppID와 UserID에 따라 UserSig를 계산합니다.
3. 서버는 계산된 UserSig를 손님의 App에 반환합니다.
4. 손님의 App은 가져온 UserSig를 특정 API를 통해 SDK에 전달합니다.
5. SDK는 SDKAppID + UserID + UserSig를 텐센트 클라우드 서버에 제출하여 검증합니다.
6. 텐센트 클라우드는 UserSig를 검증하여 합법성을 확인합니다.
7. 검증이 통과되면 Chat SDK에 인스턴트 메시징 서비스를 제공하고 RTC Engine SDK에 실시간 음성/영상 서비스를 제공합니다.



주의:
디버깅 단계의 로컬 UserSig 계산 방식은 온라인 환경에 적용하는 것을 권장하지 않으며, 역공학으로 인해 키가 유출될 수 있기 때문입니다.
여러 언어 버전(Java/Go/PHP/Nodejs/Python/C#/C++)의 UserSig 서버 계산원 코드를 제공하며 자세한 내용은 서버에서 UserSig 계산을 참조하십시오.

단계 2: 초기화 및 리스닝

시퀀스 다이어그램




1. Chat SDK 초기화 및 이벤트 리스너의 추가
// Chat IM 콘솔에서 애플리케이션 SDKAppID를 획득합니다.
// V2TIMSDKListener의 이벤트 리스너를 추가합니다. self는 id<V2TIMSDKListener>의 구현 클래스이고 Chat SDK의 이벤트를 감지할 필요가 없는 경우 이 단계는 생략할 수 있습니다.
[[V2TIMManager sharedInstance] addIMSDKListener:self];
// Chat SDK를 초기화합니다. 이 인터페이스를 호출한 후 즉시 로그인 인터페이스를 호출할 수 있습니다.
[[V2TIMManager sharedInstance] initSDK:sdkAppID config:config];

// SDK 초기화 후 연결 상태, 로그인 티켓 만료 등 일부 이벤트가 발생할 수 있습니다
- (void)onConnecting {
NSLog(@"Chat SDK가 텐센트 클라우드 서버에 연결 중입니다");
}

- (void)onConnectSuccess {
NSLog(@"Chat SDK가 텐센트 클라우드 서버에 성공적으로 연결되었습니다");
}

// 이벤트 리스너의 제거
// self는 id<V2TIMSDKListener>의 구현 클래스입니다
[[V2TIMManager sharedInstance] removeIMSDKListener:self];
// SDK 초기화의 해제
[[V2TIMManager sharedInstance] unInitSDK];
설명:
앱의 라이프사이클이 SDK 라이프사이클과 일치하는 경우, 앱을 종료하기 전에 초기화 해제를 수행하지 않아도 됩니다. 특정 화면에 진입한 후에만 SDK를 초기화하고 화면을 나간 후 더 이상 사용하지 않는 경우, SDK를 초기화 해제할 수 있습니다.
2. RTC Engine SDK 인스턴스의 생성 및 이벤트 리스너의 설정.
// RTC Engine SDK 인스턴스의 생성(싱글톤 모드)
_trtcCloud = [TRTCCloud sharedInstance];
// 이벤트 리스너의 설정
_trtcCloud.delegate = self;

// SDK의 다양한 이벤트 알림(예: 오류 코드, 경고 코드, 오디오/비디오 상태 매개변수 등)
- (void)onError:(TXLiteAVError)errCode errMsg:(nullable NSString *)errMsg extInfo:(nullable NSDictionary *)extInfo {
NSLog(@"%d: %@", errCode, errMsg);
}

- (void)onWarning:(TXLiteAVWarning)warningCode warningMsg:(nullable NSString *)warningMsg extInfo:(nullable NSDictionary *)extInfo {
NSLog(@"%d: %@", warningCode, warningMsg);
}

// 이벤트 리스너의 제거
_trtcCloud.delegate = nil;
// RTC Engine SDK 인스턴스(싱글톤 모드)를 파기합니다.
[TRTCCloud destroySharedIntance];
설명:
SDK 이벤트 알림을 모니터링하고 일반적인 오류에 대한 로그 출력 및 처리를 권장합니다. 자세한 내용은 오류 코드 표를 참조하세요.

단계3: 로그인 및 로그아웃

Chat SDK 초기화 후, 계정 인증 및 기능 사용 권한을 얻기 위해 SDK 로그인 인터페이스를 호출해야 합니다. 따라서 다른 기능을 사용하기 전에 반드시 로그인이 성공했는지 확인하세요. 그렇지 않으면 기능이 비정상적으로 작동하거나 사용할 수 없을 수 있습니다. RTC Engine 오디오/비디오 서비스만 필요한 경우 이 단계를 무시해도 됩니다.

시퀀스 다이어그램




1. 로그인.
// 로그인: userID는 사용자 자체 정의 가능하고 userSig는 단계1 참조하여 생성 및 획득합니다
[[V2TIMManager sharedInstance] login:userID userSig:userSig succ:^{
NSLog(@"success");
} fail:^(int code, NSString *desc) {
// 다음 오류 코드가 반환되면 UserSig가 만료되었음을 의미하므로 새로 발급된 UserSig를 사용하여 다시 로그인하십시오.
// 1. ERR_USER_SIG_EXPIRED(6206)
// 2. ERR_SVR_ACCOUNT_USERSIG_EXPIRED(70001)
// 주의: 다른 오류 코드의 경우 여기에서 로그인 인터페이스를 호출하지 마십시오. Chat SDK 로그인이 무한 루프에 빠지는 것을 방지하기 위한 것입니다.
NSLog(@"failure, code:%d, desc:%@", code, desc);
}];
2. 로그아웃
// 로그아웃
[[V2TIMManager sharedInstance] logout:^{
NSLog(@"success");
} fail:^(int code, NSString *desc) {
NSLog(@"failure, code:%d, desc:%@", code, desc);
}];
설명:
Chat SDK의 라이프사이클이 애플리케이션의 라이프사이클과 일치하는 경우, 애플리케이션을 종료하기 전에 로그아웃하지 않아도 됩니다. 특정 화면에 진입한 후에만 Chat SDK를 사용하고 화면을 나간 후에는 더 이상 사용하지 않는 경우, 로그아웃을 수행하고 Chat SDK를 초기화 해제할 수 있습니다.

단계4: 방 관리

시퀀스 다이어그램




1. 방 생성.
스트리머(방주인)이 라이브방송을 시작할 때 방을 생성해야 하며, 여기서 "방"의 개념은 Chat의 "그룹"에 해당합니다. 이 예시는 클라이언트에서 Chat 그룹을 생성하는 방식만 보여주며, 실제로는 서버에서도 그룹를 생성할 수 있습니다.
// 그룹 생성
[[V2TIMManager sharedInstance] createGroup:GroupType_AVChatRoom groupID:groupID groupName:groupName succ:^(NSString *groupID) {
// 그룹 생성 성공
} fail:^(int code, NSString *desc) {
// 그룹 생성 실패
}];


// 그룹 생성 알림을 감시합니다
[[V2TIMManager sharedInstance] addGroupListener:self];
- (void)onGroupCreated:(NSString *)groupID {
// 그룹 생성 콜백하고 groupID는 새로 생성된 그룹의 ID입니다
}
주의:
음성 채팅방 시나리오에서 Chat 그룹 생성은 라이브 방송 그룹 유형을 선택해야 합니다. GroupType_AVChatRoom.
RTC Engine에는 방 생성 API가 없으며 사용자가 입장하려는 방이 존재하지 않을 경우 백엔드에서 자동으로 방을 생성합니다.
2. 방 입장.
Chat 그룹 입장.
// 그룹 입장
[[V2TIMManager sharedInstance] joinGroup:groupID msg:message succ:^{
// 그룹 가입 성공
} fail:^(int code, NSString *desc) {
// 그룹 가입 실패
}];

// 그룹 가입 이벤트의 감시
[[V2TIMManager sharedInstance] addGroupListener:self];
- (void)onMemberEnter:(NSString *)groupID memberList:(NSArray<V2TIMGroupMemberInfo *>*)memberList {
// 누군가 그룹에 가입했습니다
}
RTC Engine 방에 가입합니다.
- (void)enterRoomWithRoomId:(NSString *)roomId userID:(NSString *)userId {
TRTCParams *params = [[TRTCParams alloc] init];
// 문자열 방 번호를 예로 들면 IM 그룹 번호와 일치하는 것이 좋습니다
params.strRoomId = roomId;
params.userId = userId;
// 업무 백엔드에서 가져온 UserSig
params.userSig = getUserSig(userId);
// 손임의 SDKAppID로 교체합니다
params.sdkAppId = SDKAppID;
// 음성 채팅 상호 작용 시나리오에서 방에 들어가려면 사용자 역할을 지정해야 합니다
params.role = TRTCRoleAudience;
// 음성 채팅 인터랙티브 방 입장 시나리오를 예로 들어,
[self.trtcCloud enterRoom:params appScene:TRTCAppSceneVoiceChatRoom];
}

// 방 입장 결과 이벤트의 콜백
- (void)onEnterRoom:(NSInteger)result {
if (result > 0) {
// result는 방에 임장하는 데 소요된 시간(밀리초)을 나타냅니다.
[self toastTip:@"Enter room succeed!"];
} else {
// result는 방 입장 실패의 오류 코드를 나타냅니다.
[self toastTip:@"Enter room failed!"];
}
}
주의:
RTC Engine 방 번호는 정수형 roomId와 문자열 형식 strRoomId로 나뉘며 두 유형의 방은 서로 통하지 않으므로 방 번호 유형을 통일하는 것을 권장합니다.
음성 채팅 인터랙티브 시나리오에서 방에 입장 시 사용자 역할(스트리머/시청자)을 지정해야 하며 스트리머만 스트리밍 권한이 있습니다. 지정하지 않으면 기본적으로 스트리머 역할로 설정됩니다.
음성 채팅 인터랙티브 방 입장 시나리오에서는 TRTCAppSceneVoiceChatRoom을 사용하는 것이 좋습니다.
3. 방에서 나가기.
Chat 그룹 나가기.
[[V2TIMManager sharedInstance] quitGroup:groupID succ:^{
// 그룹 나가기 성공
} fail:^(int code, NSString *desc) {
// 그룹 나가기 실패
}];

[[V2TIMManager sharedInstance] addGroupListener:self];
- (void)onMemberLeave:(NSString *)groupID member:(V2TIMGroupMemberInfo *)member {
// 그룹 멤버 나가기의 콜백
}
주의:
라이브 방송 그룹(AVChatRoom)에서는 그룹 주인이 그룹에서 나갈 수 없으며 dismissGroup을 호출하여 그룹을 해산할 수만 있습니다.
RTC Engine 방에서 나가기.
- (void)exitTrtcRoom {
self.trtcCloud = [TRTCCloud sharedInstance];
[self.trtcCloud stopLocalAudio];
[self.trtcCloud exitRoom];
}

// onExitRoom 콜백을 수신하여 자신의 퇴장 사유를 확인할 수 있습니다.
- (void)onExitRoom:(NSInteger)reason {
if (reason == 0) {
// exitRoom을 호출하여 방에서 나가기.
NSLog(@"Exit current room by calling the 'exitRoom' api of sdk ...");
} else if (reason == 1) {
//서버에 의해 현재 방에서 나가게 됩니다
NSLog(@"Kicked out of the current room by server through the restful api...");
} else if (reason == 2) {
// 현재 방 전체가 해체됩니다
NSLog(@"Current room is dissolved by server through the restful api...");
}
}
주의:
SDK가 점유한 모든 리소스가 릴리스된 후, SDK는 onExitRoom 콜백을 통해 알려줍니다.
enterRoom을 다시 호출하거나 다른 음성/영상 SDK로 전환하려면 onExitRoom 콜백이 발생한 후 관련 작업을 수행하십시오. 그렇지 않으면 카메라, 마이크등 장치의 점유됨과 같은 다양한 이상 현상이 발생할 수 있습니다.
4. 방 해산하기.
Chat 그룹 해산.
본 예시는 클라이언트에서 Chat 그룹 해산하는 방법만 보여주고 실제로는 서버에서 그룹 해산할 수도 있습니다.
[[V2TIMManager sharedInstance] dismissGroup:groupID succ:^{
// 그룹 해산 성공
} fail:^(int code, NSString *desc) {
// 그룹 해산 실패
}];

[[V2TIMManager sharedInstance] addGroupListener:self];
- (void)onGroupDismissed:(NSString *)groupID opUser:(V2TIMGroupMemberInfo *)opUser {
// 그룹 해산 콜백
}
RTC Engine 방을 해산합니다.
서버측 해산: RTC Engine 서버 측 방 해산 API DismissRoom(숫자 방 ID와 문자열 방 ID 구분)를 제공합니다. 이 인터페이스를 호출하여 방의 모든 사용자를 방에서 제거하고 방을 해산할 수 있습니다.
클라이언트 측 해산: 각 클라이언트의 방 나가기 exitRoom 인터페이스를 통해 방 내의 모든 스트리머와 청취자를 방에서 완전히 나가게 할 수 있습니다. 방을 나간 후, RTC Engine 방의 생명주기 규칙에 따라 방은 자동으로 해산됩니다. 자세한 내용은 방 나가기를 참조하세요.
경고:
라이브 방송 작업이 종료되면 방 해산 API를 호출하여 방이 해산되도록 하여 청취자가 의외로 방에 들어가서 원치 않는 비용이 발생하는 것을 방지하는 것을 권장합니다.

단계5: 마이크 순위 관리

시퀀스 다이어그램




먼저, 마이크 순위 정보를 저장하기 위한 모델을 생성할 수 있습니다.
#import "JSONModel.h"

typedef NS_ENUM(NSUInteger, SeatInfoStatus) {
SeatInfoStatusUnused = 0,
SeatInfoStatusUsed = 1,
SeatInfoStatusLocked = 2,
};

NS_ASSUME_NONNULL_BEGIN

@interface SeatInfoModel : JSONModel

/// 좌석 상태는 세 가지 상태에 대응합니다
@property (nonatomic, assign) SeatInfoStatus status;
/// 죄석 금언 여부
@property (nonatomic, assign) BOOL mute;
/// 좌석이 점유됐을 때, 사용자 정보 저장합니다
@property (nonatomic, copy) NSString *userId;

@end

NS_ASSUME_NONNULL_END
1. 자동으로 마이크 사용.
자동으로 마이크의 사용을 켜는 것은 방송실에 있는 청취자가 방주인 또는 관리자에게 마이크의 사용 켜기 신청을 보내고 동의한다는 시그널링을 받은 후 마이크를 켜서 사용하는 것을 의미합니다. 자유 마이크 모드인 경우 시그널링 요청 부분은 무시할 수 있습니다.
청취자가 마이크 사용의 요청을 보냅니다
// 청취자가 마이크 요청을 보내며 userId는 스트리머 Id이고 data는 시그널링 식별을 위한 json을 전달할 수 있습니다
- (void)sendInvitationWithUserId:(NSString *)userId data:(NSString *)data {
[[V2TIMManager sharedInstance] invite:userId data:data onlineUserOnly:YES offlinePushInfo:nil timeout:0 succ:^{
NSLog(@"sendInvitation success");
} fail:^(int code, NSString *desc) {
NSLog(@"sendInvitation error %d", code);
}];
}

// 스트리머가 마이크 사용의 요청을 수신하며 inviteID는 해당 요청 Id이고 inviter는 요청자 ID입니다
[[V2TIMManager sharedInstance] addSignalingListener:self];
- (void)onReceiveNewInvitation:(NSString *)inviteID inviter:(NSString *)inviter groupID:(NSString *)groupID inviteeList:(NSArray<NSString *> *)inviteeList data:(NSString * __nullable)data {
NSLog(@"received invitation: %@ from %@", inviteID, inviter);
}
스트리머가 마이크 사용의 요청을 처리합니다
// 마이크 사용의 요청을 동의합니다
- (void)acceptInvitationWithInviteID:(NSString *)inviteID data:(NSString *)data {
[[V2TIMManager sharedInstance] accept:inviteID data:data succ:^{
NSLog(@"acceptInvitation success");
} fail:^(int code, NSString *desc) {
NSLog(@"acceptInvitation error %d", code);
}];
}

// 마이크 사용의 요청 거절합니다
- (void)rejectInvitationWithInviteID:(NSString *)inviteID data:(NSString *)data {
[[V2TIMManager sharedInstance] reject:inviteID data:data succ:^{
NSLog(@"rejectInvitation success");
} fail:^(int code, NSString *desc) {
NSLog(@"rejectInvitation error %d", code);
}];
}
청취자가 마이크 사용합니다
스트리머가 청취자의 마이크 사용 요청을 동의하면 청취자는 그룹 속성을 수정하는 방식으로 마이크 정보를 추가할 수 있으며,다른 사용자는 그룹 속성 변경 콜백을 수신하고 로컬 마이크 정보가 업데이트됩니다.
// 로컬에 저장된 전체 마이크 순위 정보의 목록
@property (nonatomic, copy) NSArray<SeatInfoModel *> *seatInfoArray;

// 마이크 요청 동의의 콜백
- (void)onInviteeAccepted:(NSString *)inviteID invitee:(NSString *)invitee data:(NSString * __nullable)data {
NSLog(@"received accept invitation: %@ from %@", inviteID, invitee);
NSInteger seatIndex = [self findSeatIndex:inviteID];
[self takeSeatWithIndex:seatIndex];
}

// 청취자가 마이크를 켜서 사용하기 시작합니다
- (void)takeSeatWithIndex:(NSInteger)seatIndex {
// 마이크 순위 정보 인스턴스 생성하며 수정된 마이크 순위 정보를 저장합니다
SeatInfoModel *localInfo = self.seatInfoArray[seatIndex];
SeatInfoModel *seatInfo = [[SeatInfoModel alloc] init];
seatInfo.status = SeatInfoStatusUsed;
seatInfo.mute = localInfo.mute;
seatInfo.userId = self.userId;
// 마이크 순위 정보 객체를 JSON 형식으로 직렬화합니다
NSString *jsonStr = seatInfo.toJSONString;
NSDictionary *dict = @{ [NSString stringWithFormat:@"seat%ld", seatIndex]: jsonStr };
// 그룹 속성을 설정하고 해당 그룹 속성이 이미 있으면 value 값을 업데이트하고, 없으면 해당 속성을 추가합니다.
[[V2TIMManager sharedInstance] setGroupAttributes:self.groupId attributes:dict succ:^{
// 그룹 속성의 수정이 성공되고 TRTC 역할의 전환 및 스트리밍 시작합니다
[self.trtcCloud switchRole:TRTCRoleAnchor];
[self.trtcCloud startLocalAudio:TRTCAudioQualityDefault];
} fail:^(int code, NSString *desc) {
// 그룹 속성의 수정이 실패되고 마이크 연결이 실패됩니다
}];
}
2. 마이크의 사용을 초대합니다.
스트리머가 마이크의 사용을 초대합니다(청취자의 동의 필요없이).직접 그룹 속성을 수정하여 저장된 마이크 순위 정보를 변경하며, 해당 청취자는 그룹 속성 변경 콜백을 수신한 후 userId 매칭에 성공하면 RTC Engine 역할을 전환하고 스트리밍을 시작할 수 있습니다. 마이크 사용 초대 모드인 경우, 자동으로 마이크를 켜기 구현 로직을 참조하고 시그널링의 발신자와 수신자를 바꾸기만 하면 됩니다.
// 로컬에 저장된 전체 마이크 순위 정보의 목록
@property (nonatomic, copy) NSArray<SeatInfoModel *> *seatInfoArray;

// 스트리머 측에서 해당 인터페이스를 호출하여 그룹 속성에 저장된 마이크 순위 정보를 수정합니다.
- (void)pickSeatWithUserId:(NSString *)userId seatIndex:(NSInteger)seatIndex {
// 마이크 순위 정보 인스턴스 생성하며 수정된 마이크 순위 정보를 저장합니다
SeatInfoModel *localInfo = self.seatInfoArray[seatIndex];
SeatInfoModel *seatInfo = [[SeatInfoModel alloc] init];
seatInfo.status = SeatInfoStatusUsed;
seatInfo.mute = localInfo.mute;
seatInfo.userId = self.userId;
// 마이크 순위 정보 객체를 JSON 형식으로 직렬화합니다
NSString *jsonStr = seatInfo.toJSONString;
NSDictionary *dict = @{ [NSString stringWithFormat:@"seat%ld", seatIndex]: jsonStr };
// 그룹 속성 설정합니다.해당 그룹 속성이 이미 있으면 value 값을 업데이트하고 없으면 해당 속성을 추가합니다
[[V2TIMManager sharedInstance] setGroupAttributes:self.groupId attributes:dict succ:^{
// 그룹 속성의 수정이 성공되고 onGroupAttributeChanged 콜백 트리거됩니다
} fail:^(int code, NSString *desc) {
// 그룹 속성의 수정이 실패되며 마이크 연결이 실패됩니다
}];
}

// 청취자 측에서 그룹 속성 변경 콜백을 수신하여 자체 정보에 매칭 성공 후 스트리밍 시작합니다
[[V2TIMManager sharedInstance] addGroupListener:self];
- (void)onGroupAttributeChanged:(NSString *)groupID attributes:(NSMutableDictionary<NSString *,NSString *> *)attributes {
// 로컬에 저장된 기존의 전체 마이크 순위 정보 리스트
NSArray *oldSeatArray = self.seatInfoArray;
// groupAttributeMap에서 파싱한 최신 전체 마이크 순위 정보 리스트
NSArray *newSeatArray = [self getSeatListFromAttr:attributes seatSize:self.seatSize];
// 전체 마이크 순위 정보 리스트를 순회하며 새/구 마이크 정보를 비교합니다.
for (int i = 0; i < self.seatSize; i++) {
SeatInfoModel *oldInfo = oldSeatArray[i];
SeatInfoModel *newInfo = newSeatArray[i];
if (oldInfo.status != newInfo.status && newInfo.status == SeatInfoStatusUsed) {
if ([newInfo.userId isEqualToString:self.userId]) {
// 자신의 정보에 매칭 성공 후, RTC Engine 역할 전환 및 스트리밍 시작합니다
[self.trtcCloud switchRole:TRTCRoleAnchor];
[self.trtcCloud startLocalAudio:TRTCAudioQualityDefault];
} else {
// 로컬 마이크 순위 목록을 업데이트하고 로컬 마이크 순위 뷰 렌더링합니다
}
}
}
}
3. 자동으로 마이크 끄기.
연결된 청취자는 그룹 속성을 수정하는 방식으로 마이크 순위 정보를 재설정할 수 있으며 다른 사용자는 그룹 속성 변경 콜백을 받고 로컬 마이크 정보가 업데이트됩니다.
// 로컬에 저장된 전체 마이크 순위 정보의 목록
@property (nonatomic, copy) NSArray<SeatInfoModel *> *seatInfoArray;

- (void)leaveSeatWithIndex:(NSInteger)seatIndex {
// 마이크 순위 정보 인스턴스 생성하며 수정된 마이크 순위 정보를 저장합니다
SeatInfoModel *localInfo = self.seatInfoArray[seatIndex];
SeatInfoModel *seatInfo = [[SeatInfoModel alloc] init];
seatInfo.status = SeatInfoStatusUnused;
seatInfo.mute = localInfo.mute;
seatInfo.userId = @"";
// 마이크 순위 정보 객체를 JSON 형식으로 직렬화합니다
NSString *jsonStr = seatInfo.toJSONString;
NSDictionary *dict = @{ [NSString stringWithFormat:@"seat%ld", seatIndex]: jsonStr };
// 그룹 속성 설정합니다.해당 그룹 속성이 이미 있으면 value 값을 업데이트하고 없으면 해당 속성을 추가합니다
[[V2TIMManager sharedInstance] setGroupAttributes:self.groupId attributes:dict succ:^{
// 그룹 속성의 수정이 성공되고 RTC Engine 역할 전환 및 스트리밍 중지합니다
[self.trtcCloud switchRole:TRTCRoleAudience];
[self.trtcCloud stopLocalAudio];
} fail:^(int code, NSString *desc) {
// 그룹 속성의 수정이 실패되고 마이크 끄기가 실패됩니다
}];
}
4. 강제로 마이크 끄기.
스트리머가 사용자의 마이크 사용을 끄게 합니다. 그룹 속성에 저장된 마이크 순위 정보를 직접 수정하여 저장하고 해당 연결된 청취자는 그룹 속성 변경 콜백을 받은 후 userId와 일치하면 RTC Engine 역할을 전환하고 스트리밍을 중지합니다.
// 로컬에 저장된 전체 마이크 순위 정보의 목록
@property (nonatomic, copy) NSArray<SeatInfoModel *> *seatInfoArray;

// 스트리머 측에서 해당 인터페이스를 호출하여 그룹 속성에 저장된 마이크 순위 정보를 수정합니다.
- (void)kickSeatWithIndex:(NSInteger)seatIndex {
// 마이크 순위 정보 인스턴스 생성하며 수정된 마이크 순위 정보를 저장합니다
SeatInfoModel *localInfo = self.seatInfoArray[seatIndex];
SeatInfoModel *seatInfo = [[SeatInfoModel alloc] init];
seatInfo.status = SeatInfoStatusUnused;
seatInfo.mute = localInfo.mute;
seatInfo.userId = @"";
// 마이크 순위 정보 객체를 JSON 형식으로 직렬화합니다
NSString *jsonStr = seatInfo.toJSONString;
NSDictionary *dict = @{ [NSString stringWithFormat:@"seat%ld", seatIndex]: jsonStr };
// 그룹 속성 설정합니다.해당 그룹 속성이 이미 있으면 value 값을 업데이트하고 없으면 해당 속성을 추가합니다
[[V2TIMManager sharedInstance] setGroupAttributes:self.groupId attributes:dict succ:^{
// 그룹 속성의 수정이 성공되고 onGroupAttributeChanged 콜백 트리거됩니다
} fail:^(int code, NSString *desc) {
// 그룹 속성의 수정이 실패되고 마이크 끄기 실패됩니다
}];
}

// 연결된 청취자 측에서 그룹 속성 변경 콜백을 수신하여 자체 정보에 매칭 성공 후 스트리밍 중지합니다
[[V2TIMManager sharedInstance] addGroupListener:self];
- (void)onGroupAttributeChanged:(NSString *)groupID attributes:(NSMutableDictionary<NSString *,NSString *> *)attributes {
// 로컬에 저장된 기존의 전체 마이크 순위 정보 리스트
NSArray *oldSeatArray = self.seatInfoArray;
// groupAttributeMap에서 파싱한 최신 전체 마이크 순위 정보 리스트
NSArray *newSeatArray = [self getSeatListFromAttr:attributes seatSize:self.seatSize];
// 전체 마이크 순위 정보 리스트를 순회하며 새/구 마이크 정보를 비교합니다.
for (int i = 0; i < self.seatSize; i++) {
SeatInfoModel *oldInfo = oldSeatArray[i];
SeatInfoModel *newInfo = newSeatArray[i];
if (oldInfo.status != newInfo.status && newInfo.status == SeatInfoStatusUnused) {
if ([newInfo.userId isEqualToString:self.userId]) {
// 자신의 정보에 매칭 성공 후 RTC Engine 역할을 전환하고 스트리밍을 중지합니다.
[self.trtcCloud switchRole:TRTCRoleAudience];
[self.trtcCloud stopLocalAudio];
} else {
// 로컬 마이크 순위 목록을 업데이트하고 로컬 마이크 순위 뷰 렌더링합니다
}
}
}
}
5. 마이크 금언.
스트리머가 특정 마이크 순위를 금언/해제하고 그룹 속성에 저장된 마이크 순위 정보를 직접 수정하며 해당 연결된 청취자는 그룹 속성 변경 콜백을 수신한 후 userId 매칭에 성공하면 로컬 스트리밍을 일시 중지/재개합니다.
// 로컬에 저장된 전체 마이크 순위 정보의 목록
@property (nonatomic, copy) NSArray<SeatInfoModel *> *seatInfoArray;

// 스트리머 측에서 해당 인터페이스를 호출하여 그룹 속성에 저장된 마이크 순위 정보를 수정합니다.
- (void)muteSeatWithIndex:(NSInteger)seatIndex mute:(BOOL)mute {
// 마이크 순위 정보 인스턴스 생성하며 수정된 마이크 순위 정보를 저장합니다
SeatInfoModel *localInfo = self.seatInfoArray[seatIndex];
SeatInfoModel *seatInfo = [[SeatInfoModel alloc] init];
seatInfo.status = localInfo.status;
seatInfo.mute = mute;
seatInfo.userId = localInfo.userId;
// 마이크 순위 정보 객체를 JSON 형식으로 직렬화합니다
NSString *jsonStr = seatInfo.toJSONString;
NSDictionary *dict = @{ [NSString stringWithFormat:@"seat%ld", seatIndex]: jsonStr };
// 그룹 속성 설정합니다. 해당 그룹 속성이 이미 있으면 value 값을 업데이트하고 없으면 해당 속성을 추가합니다
[[V2TIMManager sharedInstance] setGroupAttributes:self.groupId attributes:dict succ:^{
// 그룹 속성의 수정이 성공되고 onGroupAttributeChanged 콜백 트리거됩니다
} fail:^(int code, NSString *desc) {
// 그룹 속성의 수정이 실패되고 마이크 금언 실패됩니다
}];
}

// 연결된 청취자 측에서 그룹 속성 변경 콜백을 수신하여 자체 정보에 매칭 성공 후 스트리밍 일시 중지/재개합니다
[[V2TIMManager sharedInstance] addGroupListener:self];
- (void)onGroupAttributeChanged:(NSString *)groupID attributes:(NSMutableDictionary<NSString *,NSString *> *)attributes {
// 로컬에 저장된 기존의 전체 마이크 순위 정보 리스트
NSArray *oldSeatArray = self.seatInfoArray;
// groupAttributeMap에서 파싱한 최신 전체 마이크 순위 정보 리스트
NSArray *newSeatArray = [self getSeatListFromAttr:attributes seatSize:self.seatSize];
// 전체 마이크 순위 정보 리스트를 순회하며 새/구 마이크 정보를 비교합니다.
for (int i = 0; i < self.seatSize; i++) {
SeatInfoModel *oldInfo = oldSeatArray[i];
SeatInfoModel *newInfo = newSeatArray[i];
if (oldInfo.mute != newInfo.mute) {
if ([newInfo.userId isEqualToString:self.userId]) {
// 자신의 정보에 매칭 성공 후 로컬 스트리밍을 일시 중지/재개합니다.
[self.trtcCloud muteLocalAudio:newInfo.mute];
} else {
// 로컬 마이크 순위 목록을 업데이트하고 로컬 마이크 순위 뷰 렌더링합니다
}
}
}
}
6. 마이크 순위 잠그기.
스트리머가 특정 마이크를 잠그거나 잠금 해제합니다. 그룹 속성에 저장된 마이크 순위 정보를 직접 수정하며 청취자는 그룹 속성 변경 콜백을 수신한 후 해당 마이크 뷰가 업데이트됩니다.
// 로컬에 저장된 전체 마이크 순위 정보의 목록
@property (nonatomic, copy) NSArray<SeatInfoModel *> *seatInfoArray;

// 스트리머 측에서 해당 인터페이스를 호출하여 그룹 속성에 저장된 마이크 순위 정보를 수정합니다.
- (void)lockSeatWithIndex:(NSInteger)seatIndex isLock:(BOOL)isLock {
// 마이크 순위 정보 인스턴스 생성하며 수정된 마이크 순위 정보를 저장합니다
SeatInfoModel *localInfo = self.seatInfoArray[seatIndex];
SeatInfoModel *seatInfo = [[SeatInfoModel alloc] init];
seatInfo.status = isLock? SeatInfoStatusLocked : SeatInfoStatusUnused;
seatInfo.mute = localInfo.mute;
seatInfo.userId = @"";
// 마이크 순위 정보 객체를 JSON 형식으로 직렬화합니다
NSString *jsonStr = seatInfo.toJSONString;
NSDictionary *dict = @{ [NSString stringWithFormat:@"seat%ld", seatIndex]: jsonStr };
// 그룹 속성 설정합니다. 해당 그룹 속성이 이미 있으면 value 값을 업데이트하고 없으면 해당 속성을 추가합니다
[[V2TIMManager sharedInstance] setGroupAttributes:self.groupId attributes:dict succ:^{
// 그룹 속성의 수정이 성공되고 onGroupAttributeChanged 콜백 트리거됩니다
} fail:^(int code, NSString *desc) {
// 그룹 속성의 수정이 실패되고 마이크 잠금이 실패됩니다
}];
}

// 청취자 측에서 그룹 속성 변경 콜백을 수신하여 해당 마이크 뷰가 업데이트됩니다
[[V2TIMManager sharedInstance] addGroupListener:self];
- (void)onGroupAttributeChanged:(NSString *)groupID attributes:(NSMutableDictionary<NSString *,NSString *> *)attributes {
// 로컬에 저장된 기존의 전체 마이크 순위 정보 리스트
NSArray *oldSeatArray = self.seatInfoArray;
// groupAttributeMap에서 파싱한 최신 전체 마이크 순위 정보 리스트
NSArray *newSeatArray = [self getSeatListFromAttr:attributes seatSize:self.seatSize];
// 전체 마이크 순위 정보 리스트를 순회하며 새/구 마이크 정보를 비교합니다.
for (int i = 0; i < self.seatSize; i++) {
SeatInfoModel *oldInfo = oldSeatArray[i];
SeatInfoModel *newInfo = newSeatArray[i];
if (oldInfo.status == SeatInfoStatusLocked && newInfo.status == SeatInfoStatusUnused) {
// 마이크 잠금의 해제
} else if (oldInfo.status != newInfo.status && newInfo.status == SeatInfoStatusLocked) {
// 마이크 순위 잠그기
}
}
}
7. 마이크 순위의 이동.
마이크 사용중의 스트리머가 마이크 순위를 이동하면 그룹 속성에 저장된 소스 및 대상 마이크 정보를 각각 수정해야 하며 청취자는 그룹 속성 변경 콜백을 수신한 후 해당 마이크 뷰가 업데이트됩니다.
// 로컬에 저장된 전체 마이크 순위 정보의 목록
@property (nonatomic, copy) NSArray<SeatInfoModel *> *seatInfoArray;

// 마이크 사용중의 스트리머가 해당 인터페이스를 호출하여 그룹 속성에 저장된 마이크 정보를 수정합니다.
- (void)moveSeatToIndex:(NSInteger)dstIndex {
// userId로 소스 마이크 번호를 받습니다
__block NSInteger srcIndex = -1;
[self.seatInfoArray enumerateObjectsUsingBlock:^(SeatInfoModel * _Nonnull seatInfo, NSUInteger idx, BOOL * _Nonnull stop) {
if ([seatInfo.userId isEqualToString:self.userId]) {
srcIndex = idx;
*stop = YES;
}
}];
if (srcIndex < 0 || dstIndex < 0 || dstIndex >= self.seatInfoArray.count) {
return;
}
// 마이크 번호로 해당 마이크 순위를 받습니다
SeatInfoModel *srcSeatInfo = self.seatInfoArray[srcIndex];
SeatInfoModel *dstSeatInfo = self.seatInfoArray[dstIndex];
// 마이크 위치 정보 인스턴스를 생성하고 수정된 소스 마이크 순위 정보를 저장합니다
SeatInfoModel *srcChangeInfo = [[SeatInfoModel alloc] init];
srcChangeInfo.status = SeatInfoStatusUnused;
srcChangeInfo.mute = srcSeatInfo.mute;
srcChangeInfo.userId = @"";
// 마이크 순위 정보 인스턴스를 생성하고 수정된 대상 마이크 순위 정보를 저장합니다
SeatInfoModel *dstChangeInfo = [[SeatInfoModel alloc] init];
dstChangeInfo.status = SeatInfoStatusUsed;
dstChangeInfo.mute = dstSeatInfo.mute;
dstChangeInfo.userId = self.userId;
// 마이크 순위 정보 객체를 JSON 형식으로 직렬화합니다
NSString *srcJsonStr = srcChangeInfo.toJSONString;
NSString *dstJsonStr = dstChangeInfo.toJSONString;
NSDictionary *dict = @{ [NSString stringWithFormat:@"seat%ld", srcIndex]: srcJsonStr,
[NSString stringWithFormat:@"seat%ld", dstIndex]: dstJsonStr
};
// 그룹 속성을 설정하고 해당 그룹 속성이 이미 있으면 value 값을 업데이트하고, 없으면 해당 속성을 추가합니다.
[[V2TIMManager sharedInstance] setGroupAttributes:self.groupId attributes:dict succ:^{
// 그룹 속성의 수정이 성공되며 마이크 이동이 성공됩니다
} fail:^(int code, NSString *desc) {
// 그룹 속성의 수정이 실패되고 마이크 이동이 실패됩니다
}];
}

단계6: 오디오 관리

시퀀스 다이어그램




1. 구독 모드.
RTC Engine SDK는 기본적으로 오디오 스트림을 자동으로 구독하는 로직으로 설정되어 있으며 사용자가 방에 입장하면 원격 사용자의 음성이 자동으로 재생됩니다. 수동으로 오디오 스트림을 구독하는 경우, muteRemoteAudio(userId, mute)를 추가로 호출하여 원격 사용자의 오디오 스트림을 구독하고 재생해야 합니다.
// 자동 구독 모드(기본값)
[self.trtcCloud setDefaultStreamRecvMode:YES video:YES];

// 수동 구독 모드(자체 정의)
[self.trtcCloud setDefaultStreamRecvMode:NO video:NO];
주의:
구독 모드인 setDefaultStreamRecvMode을 설정하려면 방 입장 enterRoom 전에 호출해야만 적용시켜야 합니다.
2. 수집 및 게시.
// 로컬 오디오의 수집 및 게시를 활성화합니다
[self.trtcCloud startLocalAudio:TRTCAudioQualityDefault];

// 로컬 오디오의 수집 및 게시를 중지합니다
[self.trtcCloud stopLocalAudio];
설명:
startLocalAudio는 마이크 사용 권한을 요청하며, stopLocalAudio는 마이크 사용 권한을 릴리스합니다.
3. 마이크 끄기와 켜기.
// 로컬 오디오 스트림 게시를 일시 중지합니다(마이크 끄기)
[self.trtcCloud muteLocalAudio:YES];
// 로컬 오디오 스트림 게시를 재개합니다(마이크 켜기)
[self.trtcCloud muteLocalAudio:NO];

// 특정 원격 사용자의 오디오 스트림 구독 및 재생을 일시 중지합니다
[self.trtcCloud muteRemoteAudio:userId mute:YES];
// 특정 원격 사용자의 오디오 스트림 구독 및 재생을 재개합니다
[self.trtcCloud muteRemoteAudio:userId mute:NO];

// 모든 원격 사용자의 오디오 스트림 구독 및 재생을 일시 중지합니다
[self.trtcCloud muteAllRemoteAudio:YES];
// 모든 원격 사용자의 오디오 스트림 구독 및 재생을 재개합니다
[self.trtcCloud muteAllRemoteAudio:NO];
설명:
반면에, muteLocalAudio는 소프트웨어 측면에서 데이터 스트림을 일시 중지하거나 허용하기만 하면 되므로 효율적이고 원활합니다.자주 마이크를 켜고 끄는 시나리오에 더 적합합니다.
4. 음질 및 음량 유형.
음질의 설정
// 로컬 오디오 수집 및 게시 시 음질을 설정합니다
[self.trtcCloud startLocalAudio:TRTCAudioQualityDefault];

// 오디오 스트리밍 중 종적으로 음질을 설정합니다
[self.trtcCloud setAudioQuality:TRTCAudioQualityDefault];
설명:
RTC Engine 사전 설정된 음질은 세 가지 등급(Speech/Default/Music)으로 나뉘며 각각 다른 오디오 매개변수에 해당합니다. 자세한 내용은 TRTCAudioQuality을 참조하세요.
음량 유형의 설정
RTC Engine 각 음질 등급에는 기본 음량 유형이 설정되어 있으며 음량 유형을 강제로 지정하려면 다음 인터페이스를 사용할 수 있습니다.
// 음량 유형의 설정
[self.trtcCloud setSystemVolumeType:TRTCSystemVolumeTypeAuto];
설명:
RTC Engine 음량 유형은 세 가지 등급(VOIP/Auto/Media)으로 나뉘며 각각 다른 음량 채널에 해당합니다. 자세한 내용은 TRTCSystemVolumeType을 참조하세요.
오디오 라우팅의 설정
휴대폰과 같은 모바일 장치에는 일반적으로 스피커와 수화기 두 가지 재생 위치가 있습니다. 오디오 라우팅을 강제로 지정하려면 다음 인터페이스를 사용할 수 있습니다.
// 오디오 라우팅의 설정
[self.trtcCloud setAudioRoute:TRTCAudioModeSpeakerphone];
설명:
RTC Engine 오디오 라우팅은 두 가지 유형(Speaker/Earpiece)으로 나뉘며, 각각 다른 발음 위치에 해당합니다. 자세한 내용은 TRTCAudioRoute을 참조하세요.

고급 기능

탄막 메시지 인터랙티브

음성 채팅 라이브 방송에는 일반적으로 텍스트 형태의 탄막 메시지 인터랙티브가 있으며, 여기서는 Chat을 통해 그룹 채팅 일반 텍스트 메시지를 보내고 받는 방식으로 구현할 수 있습니다.
// 공개 탄막 메시지의 전송
[[V2TIMManager sharedInstance] sendGroupTextMessage:text to:groupID priority:V2TIM_PRIORITY_NORMAL succ:^{
// 탄막 메시지의 전송이 성공됩니다
} fail:^(int code, NSString *desc) {
// 탄막 메시지의 전송이 실패됩니다
}];

// 공개 탄막 메시지의 수신
[[V2TIMManager sharedInstance] addSimpleMsgListener:self];
- (void)onRecvGroupTextMessage:(NSString *)msgID groupID:(NSString *)groupID sender:(V2TIMGroupMemberInfo *)info text:(NSString *)text {
NSLog(@"%@: %@", info.nickName, text);
}

볼륨 크기 콜백

RTC Engine 고정된 주기로 마이크 사용중의 스트리머의 볼륨 크기를 콜백할 수 있으며 일반적으로 음파나 음량을 표시하거나 발언 중인 스트리머를 알리는 데 사용됩니다.
// 볼륨 크기 콜백 활성화하고 방 입장 성공 후 즉시 활성화하는 것을 권장합니다
// interval: 콜백 간격(ms); enable_vad: 인간 음성 검사의 활성화 여부
[self.trtcCloud enableAudioVolumeEvaluation:interval enable_vad:enable_vad];
self.trtcCloud.delegate = self;

- (void)onUserVoiceVolume:(NSArray<TRTCVolumeInfo *> *)userVolumes totalVolume:(NSInteger)totalVolume {
// userVolumes는 로컬 사용자와 원격 스트리밍 사용자를 포함한 모든 말하고 있는 사용자의 볼륨 크기를 관리합니다
// totalVolume는 원격 스트리밍 사용자 중 최대 볼륨 값을 피드백하는 데 사용됩니다
...
// 볼륨 크기에 따라 UI에 해당하는 음파 디스플레이를 표시합니다.
...
}
주의:
인간 음성 검사는 로컬 음성 검사 결과만 피드백하며 자신의 역할은 반드시 스트리머여야 하여 사용자에게 마이크 켜기를 알리기 편리합니다.
userVolumes는 배열이며 배열의 각 요소에서 userId가 비어 있으면 로컬 마이크에서 수집한 볼륨 크기가 너무 적다는 것을 나타내고, userId가 비어 있지 않으면 원격 사용자의 볼륨 크기가 너무 적다는 것을 나타냅니다.

음악 및 음향 효과의 재생

배경 음악및 음향 효과의 재생은 음성 채팅방 시나리오에서 자주 사용되는 것입니다.아래에서는 일반적으로 사용되는 배경 음악 관련 인터페이스의 사용 방법과 주의 사항에 대해 설명합니다.
1. 재생 시작/중지/일시 정지/재개.
// 배경 음악, 짧은 음향 효과 및 인간음성 이펙트를 설정하는 데 사용되는 관리 클래스 얻습니다
self.audioEffectManager = [self.trtcCloud getAudioEffectManager];

TXAudioMusicParam *param = [[TXAudioMusicParam alloc] init];
param.ID = musicID;
param.path = musicPath;
// 음악을 원격으로 게시할지?(그렇지 않으면 로컬에서만 재생됨)
param.publish = YES;
// 재생 중인 파일이 짧은 음향 효과 파일인지?
param.isShortFile = NO;

// 배경 음악의 재생 시작합니다
__weak typeof(self) weakSelf = self;
[self.audioEffectManager startPlayMusic:param onStart:^(NSInteger errCode) {
__strong typeof(weakSelf) strongSelf = weakSelf;
// 재생 시작 콜백
// -4001: 경로 열기 실패
// -4002: 디코딩 실패
// -4003: URL 주소 무효
// -4004: 재생 중지되지 않음
if (errCode < 0) {
// 재생 실패 후 다시 재생하기 전에 현재 음악 재생을 먼저 중지해야 합니다.
[strongSelf.audioEffectManager stopPlayMusic:musicID];
}
} onProgress:^(NSInteger progressMs, NSInteger durationMs) {
// 재생 진도 콜백
// progressMs 현재 재생 시간(밀리초)
// durationMs 현재 음악의 총 시간(밀리초)
} onComplete:^(NSInteger errCode) {
// 재생 종료 콜백
// 약한 네트워크 상태로 인해 재생 중간에 실패한 경우에도 이 콜백이 발생하며 이때 errCode < 0입니다
// 재생 중간에 일시 정지하거나 중지해도 onComplete 콜백이 발생하지 않습니다
}];
// 배경 음악의 재생 중지합니다
[self.audioEffectManager stopPlayMusic:musicID];
// 배경 음악의 재생을 일시 정지합니다
[self.audioEffectManager pausePlayMusic:musicID];
// 배경 음악의 재생 재개합니다
[self.audioEffectManager resumePlayMusic:musicID];
주의:
RTC Engine 여러 음악을 동시에 재생할 수 있으며 musicID로 고유하게 식별됩니다. 어느 기간에 한 곡만 재생하려면 새 음악 재생 전에 다른 음악을 중지하거나 동일한 musicID를 사용하여 다른 음악을 재생할 수 있습니다. 이 경우에 SDK는 기존 음악을 먼저 중지한 후 새 음악을 재생합니다.
RTC Engine 로컬 및 네트워크 오디오 파일의 재생을 지원하며 musicPath를 통해 로컬 절대 경로 또는 URL 주소를 전달할 수 있습니다. MP3/AAC/M4A/WAV 형식을 지원합니다.
2. 음악 및 인간 음성의 볼륨 비율을 조정합니다.
// 특정 배경 음악의 로컬 재생 음량 크기를 설정합니다
[self.audioEffectManager setMusicPlayoutVolume:musicID volume:volume];
// 특정 배경 음악의 원격 재생 음량 크기를 설정합니다
[self.audioEffectManager setMusicPublishVolume:musicID volume:volume];
// 모든 배경 음악의 로컬 음량 및 원격 음량 크기를 설정합니다
[self.audioEffectManager setAllMusicVolume:volume];
// 인간 음성을 수집하는 음량 크기를 설정합니다
[self.audioEffectManager setVoiceVolume:volume];
주의:
음량 값 volume의 정상 범위는 0-100이며 기본값은 60입니다. 최대 150까지 설정할 수 있지만 폭음 위험이 있습니다.
인간 음성이 배경 음악에 묻히는 경우, 음악의 재생 음량을 적절히 낮추고 인간 음성을 수집하는 음량을 높여야 합니다.
마이크 끄고 배경 음악은 끄지 않는 경우: muteLocalAudio(true) 아니고 setVoiceVolume(0)를 사용합니다.
3. 배경 음악 및 음향 효과를 반복 재생합니다.
방안 1: AudioMusicParamloopCount 매개변수를 사용하여 반복 재생 횟수를 설정합니다.
값의 범위는 0 - 임의의 양의 정수이며, 기본값은 0입니다. 0은 음악을 한 번 재생함을 나타내고, 1은 음악을 두 번 재생함을 나타내며, 이와 같이 반복됩니다.
- (void)startPlayMusicWithId:(int32_t)musicId path:(NSString *)path loopCount:(NSInteger)loopCount {
TXAudioMusicParam *param = [[TXAudioMusicParam alloc] init];
param.ID = musicId;
param.path = path;
param.publish = YES;
// 재생 중인 파일이 짧은 음향 효과 파일인지?
param.isShortFile = YES;
// 반복 재생 횟수를 설정합니다. 음수는 무한 반복을 의미합니다
param.loopCount = loopCount < 0 ? NSIntegerMax : loopCount;
[self.audioEffectManager startPlayMusic:param onStart:nil onProgress:nil onComplete:nil];
}
설명:
방안 1은 매번 반복 재생이 끝나도 onComplete 콜백이 트리거되지 않으며 설정된 반복 횟수가 모두 완료된 후에야 해당 콜백이 트리거됩니다.
방안 2: "배경 음악이 재생 완료됨" 이벤트 콜백 onComplete을 통해 반복 재생을 구현하며 일반적으로 리스트 반복 또는 단곡 반복에 사용됩니다.
- (void)repeatPlayMusicWithParam:(TXAudioMusicParam *)param {
__weak typeof(self) weakSelf = self;
[self.audioEffectManager startPlayMusic:param onStart:nil onProgress:nil onComplete:^(NSInteger errCode) {
__strong typeof(weakSelf) strongSelf = weakSelf;
// 여기서 재생 인터페이스를 다시 호출하여 음악을 반복 재생할 수 있습니다.
if (errCode >= 0) {
[strongSelf repeatPlayMusicWithParam:param];
}
}];
}

혼합 스트림 전송 및 리턴 전송

1. 혼합 스트림을 RTC Engine 방으로 리턴 전송합니다.
- (void)startPublishMediaToRoom:(NSString *)roomId userID:(NSString *)userId {
// 미디어 스트림 발행의 목적지 주소
TRTCPublishTarget *target = [[TRTCPublishTarget alloc] init];
// 혼합 스트림 후 방으로 리턴 전송
target.mode = TRTCPublishMixStreamToRoom;
target.mixStreamIdentity.strRoomId = roomId;
// 혼합 스트림 로봇의 userid는 방 내 다른 사용자의 userid와 중복되면 안됩니다
target.mixStreamIdentity.userId = [NSString stringWithFormat:@"%@%@", userId, MIX_ROBOT];
TRTCStreamEncoderParam* encoderParam = [[TRTCStreamEncoderParam alloc] init];
// 트랜스코딩된 오디오 스트림의 인코딩 매개변수를 설정합니다(사용자 자체 정의 가능)
encoderParam.audioEncodedSampleRate = 48000;
encoderParam.audioEncodedChannelNum = 2;
encoderParam.audioEncodedKbps = 64;
encoderParam.audioEncodedCodecType = 2;
// 트랜스코팅된 비디오 스트림의 인코딩 매개변수를 설정합니다(순수 오디오및 믹싱혼합 스트림의 경우는 무시해도 됩니다)
encoderParam.videoEncodedWidth = 64;
encoderParam.videoEncodedHeight = 64;
encoderParam.videoEncodedFPS = 15;
encoderParam.videoEncodedGOP = 3;
encoderParam.videoEncodedKbps = 30;
// 오디오/비디오 혼합 스트리밍 매개변수를 설정합니다
TRTCStreamMixingConfig *config = [[TRTCStreamMixingConfig alloc] init];
// 기본적으로 빈 값을 입력하면 되고 방의 모든 오디오가 믹싱됨을 의미합니다
config.audioMixUserList = nil;
// 비디오 혼합 스트림 템플릿을 설정합니다(순수 오디오및 믹싱혼합 스트림의 경우는 무시해도 됩니다)
TRTCVideoLayout *layout = [[TRTCVideoLayout alloc] init];
config.videoLayoutList = @[layout];
// 혼합 스트림의 전송이 시작됩니다
[self.trtcCloud startPublishMediaStream:target encoderParam:encoderParam mixingConfig:config];
}
2. 이벤트 콜백 및 업데이트 작업 중지합니다.
작업 결과 이벤트의 콜백
#pragma mark - TRTCCloudDelegate

- (void)onStartPublishMediaStream:(NSString *)taskId code:(int)code message:(NSString *)message extraInfo:(NSDictionary *)extraInfo {
// taskId: 요청이 성공하면 RTC Engine 백엔드는 콜백에서 이 작업의 taskId를 제공합니다. 다음에 이 taskId를 updatePublishMediaStream 및 stopPublishMediaStream과 함께 사용하여 업데이트 및 중지할 수 있습니다.
// code: 콜백 결과.0은 성공을 나타내며 그 외의 값은 실패를 나타냅니다.
}

- (void)onUpdatePublishMediaStream:(NSString *)taskId code:(int)code message:(NSString *)message extraInfo:(NSDictionary *)extraInfo {
// 미디어 스트림 발생 인터페이스(updatePublishMediaStream)를 호출할 때 전달한 taskId는 이 콜백을 통해 다시 전달되며 이 콜백이 어떤 업데이트 요청에 속하는지 식별하는 데 사용됩니다.
// code: 콜백 결과.0은 성공을 나타내며 그 외의 값은 실패를 나타냅니다.
}

- (void)onStopPublishMediaStream:(NSString *)taskId code:(int)code message:(NSString *)message extraInfo:(NSDictionary *)extraInfo {
// 미디어 스트림 중지 인터페이스(stopPublishMediaStream)를 호출할 때 전달한 taskId는 이 콜백을 통해 다시 전달되며 이 콜백이 어떤 중지 요청에 속하는지 식별하는 데 사용됩니다.
// code: 콜백 결과. 0은 성공을 나타내며, 그 외의 값은 실패를 나타냅니다.
}
미디어 발생 스트림의업데이트
이 인터페이스는 RTC Engine 서버에 명령을 보내고 startPublishMediaStream로 시작된 미디어 스트림을 업데이트합니다.
// taskId: onStartPublishMediaStream 콜백의 작업 ID
// target: 예를 들어 발행된 CDN URL 추가 또는 삭제
// params: 재생 측의 스트림 중단을 방지하기 위해 미디어 스트림 인코딩 출력 매개변수를 일치하게 유지하세요.
// config: 예를 들어 크로스 룸 PK와 같은혼합 스트림 트랜스코딩에 참여하는 사용자 목록 업데이트합니다
[self.trtcCloud updatePublishMediaStream:taskId publishTarget:target encoderParam:trtcStreamEncoderParam mixingConfig:trtcStreamMixingConfig];
주의:
동일한 작업은 순수 오디오, 오디오/비디오, 순수 비디오 간의 전환을 지원하지 않습니다.
미디어 스트림의 발생을 중지합니다.
이 인터페이스는 RTC Engine 서버에 명령을 보내고 startPublishMediaStream로 시작된 미디어 스트림을 중지합니다.
// taskId: onStartPublishMediaStream 콜백의 작업 ID
[self.trtcCloud stopPublishMediaStream:taskId];
주의:
taskId가 빈 문자열이면 startPublishMediaStream로 시작된 해당 사용자의 모든 미디어 스트림을 중지합니다. 하나의 미디어 스트림만 시작했거나 손님을 통해 시작된 모든 미디어 스트림을 중지하려는 경우 이 방법을 사용하는 것이 좋습니다.

네트워크 상태의 실시간 콜백

onNetworkQuality를 통해 로컬 및 원격 사용자의 네트워크 상태를 실시간으로 모니터링할 수 있으며 이 콜백은 2초마다 한 번씩 발생합니다.
#pragma mark - TRTCCloudDelegate

- (void)onNetworkQuality:(TRTCQualityInfo *)localQuality remoteQuality:(NSArray<TRTCQualityInfo *> *)remoteQuality {
// localQuality userId가 비어 있으면 로컬 사용자의 네트워크 상태에 대한 평가 결과를 나타냅니다.
// remoteQuality는 원격 사용자의 네트워크 상태에 대한 평가 결과를 나타내며 그 결과는 원격 및 로컬 양쪽의 영향을 다 받습니다.
switch(localQuality.quality) {
case TRTCQuality_Unknown:
NSLog(@"정의되지 않음");
break;
case TRTCQuality_Excellent:
NSLog(@"현재 네트워크 상태가 매우 좋음");
break;
case TRTCQuality_Good:
NSLog(@"현재 네트워크 상태가 비교적 좋음");
break;
case TRTCQuality_Poor:
NSLog(@"현재 네트워크 상태가 보통임");
break;
case TRTCQuality_Bad:
NSLog(@"현재 네트워크 상태가 나쁨");
break;
case TRTCQuality_Vbad:
NSLog(@"현재 네트워크 상태가 매우 나쁨");
break;
case TRTCQuality_Down:
NSLog(@"현재 네트워크가 RTC Engine 최소 요구 사항을 충족하지 못함");
break;
default:
break;
}
}

고급 권한의 관리

RTC Engine 고급 권한 관리는 다양한 방에 대해 서로 다른 입장 권한을 설정하는 데 사용할 수 있습니다(예: 고급 VIP 방). 또한 청취자의 마이크 권한을 관리하는 데도 사용할 수 있습니다(예: 유령 마이크 처리). 구체적인 조작 단계는 다음과 같습니다.
1. RTC Engine 콘솔의 기능 구성 페이지에서 고급 권한 관리 스위치를 켭니다.
2. 업무 백엔드에서 PrivateMapKey를 생성하고 코드 예시는 PrivateMapKey 계산원 코드를 참조하세요.
3. 입장 검증 & 마이크 연결 검증 PrivateMapKey.
입장 검증
TRTCParams *params = [[TRTCParams alloc] init];
params.sdkAppId = SDKAppID;
params.roomId = self.roomId;
params.userId = self.userId;
// 업무 백엔드에서 가져온 UserSig
params.userSig = [self getUserSig];
// 업무 백엔드에서 얻은 PrivateMapKey입니다
params.privateMapKey = [self getPrivateMapKey];
params.role = TRTCRoleAudience;
[self.trtcCloud enterRoom:params appScene:TRTCAppSceneVoiceChatRoom];
마이크 연결 검증
// 업무 백엔드에서 얻은 최신 PrivateMapKey를 역할 전환 인터페이스에 전달합니다
[self.trtcCloud switchRole:TRTCRoleAnchor privateMapKey:[self getPrivateMapKey]];

이상 처리

고장및 오류 처리

RTC Engine SDK에서 복구할 수 없는 오류가 발생하면 onError 콜백에서 나오며, 자세한 내용은 오류 코드표을 참조하십시오.
UserSig 관련.
UserSig 검증 실패로 인해 방 입장에 실패할 수 있으며, UserSig 도구을 사용하여 검증할 수 있습니다.
열거형
설명
ERR_TRTC_INVALID_USER_SIG
-3320
방 입장 매개변수 userSig가 올바르지 않습니다. TRTCParams.userSig이 비어 있는지 확인하세요.
ERR_TRTC_USER_SIG_CHECK_FAILED
-100018
UserSig 검증에 실패했습니다. 매개변수 TRTCParams.userSig이 올바르게 입력되었는지 또는 만료되지 않았는지 확인하세요.
입장 및 퇴장 관련.
방 입장 실패 시 먼저 입장 매개변수가 올바른지 확인하고 입장 및 퇴장 인터페이스는 반드시 쌍으로 호출해야 합니다. 입장에 실패한 경우에도 퇴장 인터페이스를 호출해야 합니다.
열거형
설명
ERR_TRTC_CONNECT_SERVER_TIMEOUT
-3308
방 입장 요청이 시간 초과하는 경우, 네트워크 연결이 끊겼는지 또는 VPN이 켜져 있는지 확인하세요. 4G로 전환하여 테스트할 수도 있습니다.
ERR_TRTC_INVALID_SDK_APPID
-3317
입장 매개변수 sdkAppId가 잘못되었습니다. TRTCParams.sdkAppId이 비어 있는지 확인하세요.
ERR_TRTC_INVALID_ROOM_ID
-3318
입장 매개변수 roomId가 잘못되었습니다. TRTCParams.roomId 또는 TRTCParams.strRoomId이 비어 있는지 확인하세요. roomId와 strRoomId는 혼용할 수 없습니다.
ERR_TRTC_INVALID_USER_ID
-3319
입장 매개변수 userId가 올바르지 않습니다. TRTCParams.userId이 비어 있는지 확인하세요.
ERR_TRTC_ENTER_ROOM_REFUSED
-3340
입장 요청이 거부되었습니다. enterRoom을 연속적으로 호출하여 동일한 ID의 방에 입장했는지 확인하세요.
장치 관련.
장치 관련 오류를 감지할 수 있으며 관련 오류 발생 시 UI에서 사용자에게 알립니다.
열거형
설명
ERR_MIC_START_FAIL
-1302
Windows 또는 Mac 장치에서 마이크 구성 프로그램(드라이버)이 비정상일 경우, 마이크 열 수가 없습니다. 장치를 비활성화한 후 다시 활성화하거나, 기기를 재시작하거나, 구성 프로그램을 업데이트하세요.
ERR_SPEAKER_START_FAIL
-1321
스피커 열기가 실패됩니다. 예를 들어 Windows 또는 Mac 장치에서 스피커 구성 프로그램(드라이버)이 비정상일 경우, 장치를 비활성화한 후 다시 활성화하거나 기기를 재시작하거나 구성 프로그램을 업데이트하세요.
ERR_MIC_OCCUPY
-1319
마이크가 사용 중입니다. 예를 들어 모바일 장치에서 통화 중일 때 마이크를 열 수가 없습니다.

오류 종료 처리

1. 네트워크 연결 감지 및 퇴장 타임아웃.
다음 콜백을 통해 RTC Engine 연결 끊김 및 재연결 이벤트 알림을 모니터링할 수 있습니다.
onConnectionLost 콜백을 수신한 후 로컬 마이크 순위 UI에서 네트워크 연결 끊김을 표시하여 사용자에게 알려줍니다. 동시에 로컬에서 타이머를 시작하고 설정된 시간 임계값을 초과한 후에도 onConnectionRecovery 콜백을 수신하지 못하면 네트워크가 계속 끊긴 상태입니다. 이때 로컬에서 마이크 종료 및 방 나가기 프로세스를 시작하고 사용자에게 방을 나갔음을 알리는 팝업을 보낸 후 페이지를 파기합니다. 네트워크 연결이 90초(기본값) 이상 끊어지면 타임아웃으로 인한 방 나가기가 트리거되며 RTC Engine 서버는 해당 사용자를 방에서 강제 퇴장시킵니다. 해당 사용자가 스트리머 역할인 경우 방 내 다른 사용자는 onRemoteUserLeaveRoom 콜백을 받게 됩니다.
#pragma mark - TRTCCloudDelegate

- (void)onConnectionLost {
// SDK와 클라우드 간의 연결이 끊어졌습니다.
}

- (void)onTryToReconnect {
// SDK가 클라우드에 다시 연결을 시도 중입니다.
}

- (void)onConnectionRecovery {
// SDK와 클라우드 간의 연결이 복구되었습니다.
}
2. 오프라인 상태에서 자동으로 마이크의 사용을 끕니다.
Chat 사용자의 일반 상태는 온라인(ONLINE), 오프라인(OFFLINE), 미로그인(UNLOGINED)으로 구분됩니다.오프라인 상태는 일반적으로 사용자가 프로세스를 강제 종료하거나 네트워크가 비정상적으로 중단된 경우 발생합니다. 스트리머 구독을 통해 오프라인 상태의 마이크 사용자를 감지하여 마이크의 사용을 끄게 시킬 수 있습니다.
// 스트리머 구독을 통해 마이크 사용자의 상태를 감지합니다
[[V2TIMManager sharedInstance] subscribeUserStatus:userList succ:^{
// 스트리머 구독 사용자의 상태가 성공합니다
} fail:^(int code, NSString *desc) {
// 스트리머 구독 사용자의 상태가 실패합니다
}];

// 스트리머 구독을 통해 마이크 사용자의 상태 취소합니다
[[V2TIMManager sharedInstance] unsubscribeUserStatus:userList succ:^{
// 스트리머 구독 사용자의 상태룰 취소하는 것이 성공합니다
} fail:^(int code, NSString *desc) {
// 스트리머 구독 사용자의 상태를 취소하는 것이 실패합니다.
}];

// 사용자 상태 변경의 알림 및 처리
[[V2TIMManager sharedInstance] addIMSDKListener:self];

- (void)onUserStatusChanged:(NSArray<V2TIMUserStatus *> *)userStatusList {
for (V2TIMUserStatus *userStatus in userStatusList) {
NSString *userId = userStatus.userID;
V2TIMUserStatusType status = userStatus.statusType;
if (status == V2TIM_USER_STATUS_OFFLINE) {
// 오프라인 상태에서 마이크 사용 끄게 시킵니다
[self kickSeatWithIndex:[self getSeatIndexWithUserId:userId]];
}
}
}

주의:
스트리머 구독 사용자의 상태는 프로페셔널 버전 패키지로 업그레이드해야 합니다. 자세한 내용은 기본 서비스 내역를 참조하세요.
스트리머 구독 사용자의 상태는 사전에 Chat 콘솔에서 사용자 상태 조회 및 상태 변경 알림 구성을 활성화해야 합니다. 활성화하지 않으면 subscribeUserStatus 호출 시 오류가 발생합니다.

서버에서 사용자를 강제 퇴장 시키고 방 해산시킵니다

1. 서버에서 사용자를 강제 퇴장시킵니다.
먼저 RTC Engine 서버에서 사용자 강제 퇴장 인터페이스 RemoveUser(정수형 방 번호) 또는 RemoveUserByStrRoomId(문자열 방 번호)를 호출하여 대상 사용자를 RTC Engine 방에서 퇴장시킵니다. 입력 예시는 다음과 같습니다.
https://trtc.tencentcloudapi.com/?Action=RemoveUser
&SdkAppId=1400000001
&RoomId=1234
&UserIds.0=test1
&UserIds.1=test2
&<공통 요청 매개변수>
사용자 강제 퇴장이 성공적으로 실행되면 대상 사용자는 클라이언트에서 onExitRoom() 콜백을 수신하며 reason 값은 1입니다. 이때 해당 콜백에서 마이크 사용 종료및 Chat 그룹 퇴장 등의 작업을 처리할 수 있습니다.
// RTC Engine 방 이탈 이벤트의 콜백
- (void)onExitRoom:(NSInteger)reason {
if (reason == 0) {
// exitRoom을 호출하여 방에서 나가기.
NSLog(@"Exit current room by calling the 'exitRoom' api of sdk ...");
} else {
// reason 1: 서버에 의해 현재 방에서 나가게 됩니다
// reason 2: 현재 방 전체가 해산됩니다
NSLog(@"Kicked out of the current room by server or current room is dissolved ...");
// 마이크 사용 종료
[self leaveSeatWithIndex:seatIndex];
// Chat 그룹에서 나가기
[[V2TIMManager sharedInstance] quitGroup:groupID succ:^{
//그룹 나가기 성공
} fail:^(int code, NSString *desc) {
// 그룹 나가기 실패
}];
}
}
2. 서버에서 방을 해산시킵니다.
먼저 Chat 서버의 그룹 해산 인터페이스 destroy_group을 호출하여 대상 그룹을 해산합니다.요청 URL 예시는 다음과 같습니다.
https://xxxxxx/v4/group_open_http_svc/destroy_group?sdkappid=88888888&identifier=admin&usersig=xxx&random=99999999&contenttype=json
그룹 해산이 성공적으로 실행되면 대상 그룹의 모든 멤버는 클라이언트에서 onGroupDismissed() 콜백을 받게 됩니다. 이때 해당 콜백에서 RTC Engine 방 나가기 등의 작업을 처리할 수 있습니다.
// 그룹 해산 콜백
[[V2TIMManager sharedInstance] addGroupListener:self];
- (void)onGroupDismissed:(NSString *)groupID opUser:(V2TIMGroupMemberInfo *)opUser {
// RTC Engine 방 나가기
[self.trtcCloud stopLocalAudio];
[self.trtcCloud exitRoom];
}
설명:
방 내 모든 사용자가 exitRoom()을 호출하여 방 나가기를 완료하면 RTC Engine 방이 자동으로 해산됩니다. 물론 서버 측의 인터페이스 DismissRoom(정수형 방 번호) 또는 DismissRoomByStrRoomId(문자열 방 ID)를 호출하여 RTC Engine 방을 강제로 해산시킬 수도 있습니다.

방에 입장해서 라이브 방송 기록을 확인합니다

AVChatRoom은 기본적으로 라이브 방송실의 이전 메시지를 저장하지 않습니다.새 사용자가 방송실에 입장하면 입장 후의 사용자가 보낸 메시지만 볼 수 있습니다. 새로 입장한 사용자의 체험을 개선하기 위해 콘솔에서 라이브방송 그룹 사용자가 입장 전의 메시지 수량을 구성할 수 있습니다. 하기 그림과 같습니다.

라이브방송 그룹 사용자가 입장 전의 이전 메시지는 다른 그룹의 이전 메시지와 동일합니다.코드 예시는 하기와 같습니다.
V2TIMMessageListGetOption *option = [[V2TIMMessageListGetOption alloc] init];
option.getType = V2TIM_GET_CLOUD_OLDER_MSG; // 클라우드의 이전 메시지 가져오기
option.getTimeBegin = 1640966400; // 2022-01-01 00:00:00부터 시작
option.getTimePeriod = 1 * 24 * 60 * 60; // 하루 종일의 메시지 가져오기
option.count = INT_MAX; // 시간 범위 내 모든 메시지로 반환하기
option.groupID = #your group id#; // 그룹 채팅 메시지 가져오기
[V2TIMManager.sharedInstance getHistoryMessageList:option succ:^(NSArray<V2TIMMessage *> *msgs) {
NSLog(@"success");
} fail:^(int code, NSString *desc) {
NSLog(@"failure, code:%d, desc:%@", code, desc);
}];
주의:
이 기능은 프리미엄 버전 사용자만 이용할 수 있으며 그룹 생성 후 24시간 이내에 최대 20개의 이전 메시지만 지원합니다.

방 입장 시 마이크 사용중의 스트리머의 무음 상태를 감지합니다

방안 1: 방 입장 시 모든 스트리머를 기본적으로 무음 상태로 설정한 후, onUserAudioAvailable(userId, true) 콜백을 통해 해당 스트리머의 무음상태를 해제합니다.
- (void)onUserAudioAvailable:(NSString *)userId available:(BOOL)available {
if (available) {
// 해당 스트리머의 무음 상태를 해제합니다
}
}
방안 2: 스트리머의 무음상태를 Chat 그룹 속성에 저장하고 청취자가 방에 입장하면 전체 그룹 속성을 받아서 마이크 사용중의 스트리머의 무음 상태를 확인할 수 있습니다.
[[V2TIMManager sharedInstance] getGroupAttributes:groupID keys:nil succ:^(NSMutableDictionary<NSString *,NSString *> *groupAttributeList) {
// 그룹 속성 가져오기가 성공되며 스트리머 무음 상태를 저장하는 키를 muteStatus로 가정합니다
NSString *muteStatus = groupAttributeList[@"muteStatus"];
// muteStatus를 분석하여 각 마이크를 사용하는 스트리머의 무음 상태를 가져옵니다
} fail:^(int code, NSString *desc) {
// 그룹 속성 가져오기가 실패됩니다
}];