




sudo gem install cocoapods
pod init
platform :ios, '8.0'target 'App' do# TRTC Lite版# インストールパッケージのサイズ増加は最小限だが、RTC Engineとライブプレーヤー(TXLivePlayer)の2つの機能のみをサポートします。pod 'TXLiteAVSDK_TRTC', :podspec => 'https://liteav.sdk.qcloud.com/pod/liteavsdkspec/TXLiteAVSDK_TRTC.podspec'# Add the Chat SDKpod '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
pod install
pod update
pod setuppod repo updaterm ~/Library/Caches/CocoaPods/search_index.json
Privacy - Microphone Usage Description, 、そしてマイク使用目的も入力してください。



// ChatコントロールパネルからアプリケーションのSDKAppIDを取得します。// V2TIMSDKListenerのイベントリスナーを追加、selfはid<V2TIMSDKListener>の実装クラス。IM SDKのイベントをリスニングする必要がない場合、このステップは無視できます。[[V2TIMManager sharedInstance] addIMSDKListener:self];// Chat SDKを初期化、このインターフェースを呼び出した後、すぐにログインインターフェースを呼び出すことができます。[[V2TIMManager sharedInstance] initSDK:sdkAppID config:config];// SDK初期化後にはいくつかのイベントが発生します。例えば、接続状態、ログインチケットの有効期限切れなど。- (void)onConnecting {NSLog(@"Chat SDKがTencent Cloudクラウドサーバーに接続中");}- (void)onConnectSuccess {NSLog(@"Chat SDKはすでにTencent Cloudクラウドサーバーに接続しました");}// イベントリスナーを削除// selfはid<V2TIMSDKListener>の実装クラス[[V2TIMManager sharedInstance] removeIMSDKListener:self];// SDKの初期化解除[[V2TIMManager sharedInstance] unInitSDK];
// 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];
// ログイン: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);}];
// ログアウト[[V2TIMManager sharedInstance] logout:^{NSLog(@"success");} fail:^(int code, NSString *desc) {NSLog(@"failure, code:%d, desc:%@", code, desc);}];
// グループを作成[[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}
GROUP_TYPE_AVCHATROOMを選択する必要があります。// グループに参加[[V2TIMManager sharedInstance] joinGroup:groupID msg:message succ:^{// グループへの参加に成功} fail:^(int code, NSString *desc) {// グループへの参加に失敗}];// グループ参加イベントをリスニング[[V2TIMManager sharedInstance] addGroupListener:self];- (void)onMemberEnter:(NSString *)groupID memberList:(NSArray<V2TIMGroupMemberInfo *>*)memberList {// 誰かがグループに参加しました。}
- (void)enterRoomWithRoomId:(NSString *)roomId userID:(NSString *)userId {TRTCParams *params = [[TRTCParams alloc] init];// 文字列のルーム番号を例にしています。Chatのグループ番号と一致させることをお勧めします。params.strRoomId = roomId;params.userId = userId;// 業務バックエンドから取得したUserSigparams.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!"];}}
roomIdと文字列型のstrRoomIdに分かれており、2種類のルームは相互接続されません。ルーム番号のタイプを統一することをお勧めします。TRTCAppSceneVoiceChatRoomがお勧めです。[[V2TIMManager sharedInstance] quitGroup:groupID succ:^{// グループからの退出に成功} fail:^(int code, NSString *desc) {// グループからの退出に失敗}];[[V2TIMManager sharedInstance] addGroupListener:self];- (void)onMemberLeave:(NSString *)groupID member:(V2TIMGroupMemberInfo *)member {// グループメンバー退出コールバック}
dismissGroupを使用してグループを解散することのみが可能です。- (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...");}}
onExitRoomコールバック通知をスローして知らせます。enterRoomを呼び出す場合や他のオーディオ・ビデオSDKに切り替える場合は、onExitRoomのコールバックが返ってくるまで関連操作を行わないでください。そうしないと、カメラやマイクが強制的に使用されるなど、さまざまな異常が発生する可能性があります。[[V2TIMManager sharedInstance] dismissGroup:groupID succ:^{// グループ解散に成功} fail:^(int code, NSString *desc) {// グループ解散に失敗}];[[V2TIMManager sharedInstance] addGroupListener:self];- (void)onGroupDismissed:(NSString *)groupID opUser:(V2TIMGroupMemberInfo *)opUser {// グループ解散コールバック}
DismissRoom(数字ルームIDと文字列ルームIDを区別)を提供しています。このインターフェースを呼び出すことで、ルーム内の全ユーザーを退室させ、ルームを解散することができます。exitRoom インターフェースを通じて、ルーム内の全ての配信者と視聴者の退室を完了させます。RTC Engineのルームライフサイクルルールに従い、ルームは自動的に解散されます。詳細はルーム退室をご参照ください。#import "JSONModel.h"typedef NS_ENUM(NSUInteger, SeatInfoStatus) {SeatInfoStatusUnused = 0,SeatInfoStatusUsed = 1,SeatInfoStatusLocked = 2,};NS_ASSUME_NONNULL_BEGIN@interface SeatInfoModel : JSONModel/// 座席状態、3つの状態に対応@property (nonatomic, assign) SeatInfoStatus status;/// 座席はミュート状態か@property (nonatomic, assign) BOOL mute;/// 座席が埋まっている場合、ユーザー情報を保存@property (nonatomic, copy) NSString *userId;@endNS_ASSUME_NONNULL_END
// 聞き手がマイクオンの申請を送信、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) {// グループ属性の変更に失敗、マイクオン失敗}];}
// ローカルに保存された全部のマイク情報リスト@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]) {// 自身情報のマッチングに成功、TRTCのロールに切り替えてプッシュを開始[self.trtcCloud switchRole:TRTCRoleAnchor];[self.trtcCloud startLocalAudio:TRTCAudioQualityDefault];} else {// ローカルマイクリストを更新し、ローカルマイクのビューをレンダリング}}}}
// ローカルに保存された全部のマイク情報リスト@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:^{// グループ属性の変更に成功、TRTCのロールに切り替えプッシュを停止[self.trtcCloud switchRole:TRTCRoleAudience];[self.trtcCloud stopLocalAudio];} fail:^(int code, NSString *desc) {// グループ属性の変更に失敗、マイクオフに失敗}];}
// ローカルに保存された全部のマイク情報リスト@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]) {// 自身情報のマッチングに成功、TRTCのロールに切り替えプッシュを停止[self.trtcCloud switchRole:TRTCRoleAudience];[self.trtcCloud stopLocalAudio];} else {// ローカルマイクリストを更新し、ローカルマイクのビューをレンダリング}}}}
// ローカルに保存された全部のマイク情報リスト@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 {// ローカルマイクリストを更新し、ローカルマイクのビューをレンダリング}}}}
// ローカルに保存された全部のマイク情報リスト@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) {// マイクをロック}}}
// ローカルに保存された全部のマイク情報リスト@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) {// グループ属性の変更に失敗、マイクポジション移動に失敗}];}
muteRemoteAudio(userId, mute)を追加で呼び出してリモートユーザーのオーディオストリームを購読および再生する必要があります。// 自動購読モード(デフォルト)[self.trtcCloud setDefaultStreamRecvMode:YES video:YES];// 手動購読モード(カスタム)[self.trtcCloud setDefaultStreamRecvMode:NO video:NO];
setDefaultStreamRecvModeは、入室enterRoomする前に呼び出す必要があります。// ローカルオーディオのキャプチャーとパブリッシュを有効にします。[self.trtcCloud startLocalAudio:TRTCAudioQualityDefault];// ローカルオーディオのキャプチャーとパブリッシュを停止する[self.trtcCloud stopLocalAudio];
startLocalAudioはマイクの使用権限を申請し、stopLocalAudioはマイクの使用権限をリリースします。// ローカルオーディオストリームのパブリッシュを一時停止(マイクオフ)[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はソフトウェアレベルでデータフローを一時停止または再開するだけでよいため、効率が高くスムーズで、頻繁にマイクのオンオフが必要なシナリオに適しています。// ローカルオーディオのキャプチャーとパブリッシュ時の音質設定[self.trtcCloud startLocalAudio:TRTCAudioQualityDefault];// オーディオプッシュ中に音質を動的に設定[self.trtcCloud setAudioQuality:TRTCAudioQualityDefault];
// 音量タイプの設定[self.trtcCloud setSystemVolumeType:TRTCSystemVolumeTypeAuto];
// オーディオルーティングの設定[self.trtcCloud setAudioRoute:TRTCAudioModeSpeakerphone];
// パブリックチャットに弾幕メッセージを送信[[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);}
// 音量コールバックを有効にすることをお勧めします。入室に成功した後すぐに開始してください。// 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が空でない場合はリモートユーザーの音量の大きさを表します。// BGM、効果音、およびボイスエフェクトの設定を行うための管理クラスを取得self.audioEffectManager = [self.trtcCloud getAudioEffectManager];TXAudioMusicParam *param = [[TXAudioMusicParam alloc] init];param.ID = musicID;param.path = musicPath;// 音楽をリモートにパブリッシュするか(そうでなければローカルのみで再生)param.publish = YES;// 効果音ファイルかparam.isShortFile = NO;// BGMの再生を開始__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コールバックはトリガーされません。}];// BGMの再生を停止[self.audioEffectManager stopPlayMusic:musicID];// BGMの再生を一時停止[self.audioEffectManager pausePlayMusic:musicID];// BGMの再生を再開[self.audioEffectManager resumePlayMusic:musicID];
musicPath にローカルの絶対パスまたは URL アドレスを渡します。MP3/AAC/M4A/WAV 形式をサポートします。// BGMのローカル再生ボリュームの設定[self.audioEffectManager setMusicPlayoutVolume:musicID volume:volume];// BGMのリモート再生ボリュームの設定[self.audioEffectManager setMusicPublishVolume:musicID volume:volume];// すべてのBGMのローカルとリモート音量の設定[self.audioEffectManager setAllMusicVolume:volume];// ボーカルのキャプチャーボリュームの設定[self.audioEffectManager setVoiceVolume:volume];
muteLocalAudio(true)をsetVoiceVolume(0)で置き換えてください。AudioMusicParamのloopCountパラメータを使用して、ループ再生回数を設定します。- (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];}
onCompleteコールバックはトリガーされません。設定されたループ回数がすべて完了した後にのみ、そのコールバックがトリガーされます。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];}}];}
- (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];}
#pragma mark - TRTCCloudDelegate- (void)onStartPublishMediaStream:(NSString *)taskId code:(int)code message:(NSString *)message extraInfo:(NSDictionary *)extraInfo {// taskId: リクエストが成功した場合、TRTCバックエンドはコールバックでこのタスクの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は成功を意味し、その他の値は失敗を意味します。}
startPublishMediaStream で起動したメディアストリームを更新します。// taskId: onStartPublishMediaStreamでコールバックされたタスクID// target: 例えば、パブリッシュしたCDN URLの追加、削除// params: メディアストリームのエンコード出力パラメータを一貫して保持することがお勧めです。これにより、再生側での中断を避けることができます。// config: ストリームミックストランスコーディングに参加するユーザーリストを更新。例えば、クロスルームPKなど。[self.trtcCloud updatePublishMediaStream:taskId publishTarget:target encoderParam:trtcStreamEncoderParam mixingConfig:trtcStreamMixingConfig];
startPublishMediaStream で起動したメディアストリームを停止します。// taskId: onStartPublishMediaStreamでコールバックされたタスクID[self.trtcCloud stopPublishMediaStream:taskId];
startPublishMediaStreamで開始されたそのユーザーのすべてのメディアストリームが停止します。1つのメディアストリームのみを開始した場合や、自分が開始したすべてのメディアストリームを停止したい場合は、この方法をお勧めします。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(@"現在のネットワークはTRTC最低要件を満たしていない");break;default:break;}}
TRTCParams *params = [[TRTCParams alloc] init];params.sdkAppId = SDKAppID;params.roomId = self.roomId;params.userId = self.userId;// 業務バックエンドから取得したUserSigparams.userSig = [self getUserSig];// 業務バックエンドから取得したPrivateMapKeyparams.privateMapKey = [self getPrivateMapKey];params.role = TRTCRoleAudience;[self.trtcCloud enterRoom:params appScene:TRTCAppSceneVoiceChatRoom];
// 業務バックエンドから最新のPrivateMapKeyを取得し、ロール切り替えインターフェースに渡します。[self.trtcCloud switchRole:TRTCRoleAnchor privateMapKey:[self getPrivateMapKey]];
列挙値 | 取得値 | 説明 |
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がnullかどうか確認してください |
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のルームに連続して入室しようとしていないか確認してください。 |
列挙値 | 取得値 | 説明 |
ERR_MIC_START_FAIL | -1302 | マイクの起動に失敗しました。例えば、WindowsまたはMacデバイスで、マイクの設定プログラム(ドライバー)に異常があります。デバイスを無効にしてから再度有効にするか、マシンを再起動するか、設定プログラムを更新してください。 |
ERR_SPEAKER_START_FAIL | -1321 | スピーカーの起動に失敗しました。例えば、WindowsやMacのデバイスで、スピーカーの設定プログラム(ドライバー)に異常があります。デバイスを無効にしてから再度有効にするか、マシンを再起動するか、設定プログラムを更新してください。 |
ERR_MIC_OCCUPY | -1319 | マイクが使用中です。たとえば、モバイルデバイスが通話中の場合、マイクを開くと失敗します。 |
onConnectionLostコールバック受信後、ローカルのマイクポジションUIにネットワーク切断の警告を表示し、ユーザーに通知します。同時に、ローカルでタイマーを起動し、設定された時間閾値を超えてもonConnectionRecoveryコールバックが受信されない場合、つまりネットワークが継続して切断状態にある場合は、ローカルでマイクオフにし、退室プロセスを開始し、同時にポップアップウィンドウでユーザーにルームからの退出とページの破棄を通知します。ネットワーク切断が90秒(デフォルト)を超えると、タイムアウトによる退房がトリガーされ、RTC Engine サーバーは該当ユーザーをルームから退出させます。もし該当ユーザーが配信者ロールの場合、ルーム内の他のユーザーは onRemoteUserLeaveRoom コールバックを受信します。#pragma mark - TRTCCloudDelegate- (void)onConnectionLost {// SDKクラウドとの接続が切断されました。}- (void)onTryToReconnect {// SDKクラウドに再接続しています。}- (void)onConnectionRecovery {// SDKクラウドとの接続が復旧されました。}
// アンカーがマイクオン聞き手ユーザーの状態を購読[[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]];}}}

subscribeUserStatus を呼び出すとエラーが報告されます。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) {// グループからの退出に失敗}];}}
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(文字列型ルーム番号)を呼び出して RTC Engine ルームを強制的に解散することもできます。
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);}];
onUserAudioAvailable(userId, true) コールバックに基づいて対応する配信者のミュート状態を解除します。- (void)onUserAudioAvailable:(NSString *)userId available:(BOOL)available {if (available) {// 対応するアンカーのミュート状態を解除}}
[[V2TIMManager sharedInstance] getGroupAttributes:groupID keys:nil succ:^(NSMutableDictionary<NSString *,NSString *> *groupAttributeList) {// グループ属性の取得に成功しました。配信者のミュート状態を保存するキーはmuteStatusと仮定しますNSString *muteStatus = groupAttributeList[@"muteStatus"];// muteStatusを分析し、各マイクオンアンカーのミュート状態を取得} fail:^(int code, NSString *desc) {// グループ属性の取得に失敗}];
フィードバック