製品概要
製品の利点
応用シナリオ







curl -X POST \\http://service-mqk0mc83-1257411467.bj.apigw.tencentcs.com/release/register \\-H 'Content-Type: application/json' \\-H 'Cache-control: no-cache' \\-d '{"requestId": "test-regisiter-service","action": "Register","registerRequest": {"operateUin": <operateUin>,"userName": <customedName>,"cosConfig": {"secretId": <CosConfig.secretId>,"secretKey": <CosConfig.secretKey>,"bucket": <CosConfig.bucket>,"region": <CosConfig.region>}}}'
{"requestId": "test-regisiter-service","registerInfo": {"tmpContentId": <tmpContentId>,"tmpSecretId": <tmpSecretId>,"tmpSecretKey": <tmpSecretKey>,"apiGateSecretId": <apiGateSecretId>,"apiGateSecretKey": <apiGateSecretKey>,"demoCosPath": "UIN_demo/run_musicBeat.py","usageDescription": "COSバケット[CosConfig.bucket]からpythonのdemoファイル[UIN_demo/run_musicBeat.py]をダウンロードし、demoの入力ファイルを置き換えた後、python run_musicBeat.pyを実行してください","message": "登録が成功しました、登録していただきありがとうございます","createdAt": <createdAt>,"updatedAt": <updatedAt>}}
demoCosPathディレクトリーに音楽のビート認識機能をサンプルとするpythonで実行可能なdemoが生成されます。ネットワーク環境がある場合に、コマンドpython run_musicBeat.pyを実行して確認してください。sudo gem install cocoapods
pod init
platform :ios, '8.0'target 'App' do# TRTC Lite版# インストールパッケージのサイズ増加は最小限ですが、Real-Time Communication(TRTC)とライブプレーヤー(TXLivePlayer)の2つの機能のみをサポートしています。pod 'TXLiteAVSDK_TRTC', :podspec => 'https://liteav.sdk.qcloud.com/pod/liteavsdkspec/TXLiteAVSDK_TRTC.podspec'# Professional版# Real-Time Communication(TRTC)、ライブストリーミングプレーヤー(TXLivePlayer)、RTMPプッシュ(TXLivePusher)、オンデマンドプレーヤー(TXVodPlayer)およびショートビデオの録画と編集(UGSV)など、多くの機能が含まれています。# pod 'TXLiteAVSDK_Professional', :podspec => 'https://liteav.sdk.qcloud.com/pod/liteavsdkspec/TXLiteAVSDK_Professional.podspec'end
pod install
pod update
pod setuppod repo updaterm ~/Library/Caches/CocoaPods/search_index.json
Privacy - Microphone Usage Description、そしてマイク使用目的も入力してください



// TRTC SDKのインスタンスを作成する(シングルトンパターン)self.trtcCloud = [TRTCCloud sharedInstance];// イベントリスナーを設定するself.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);}// イベントリスナーを削除self.trtcCloud.delegate = nil;// TRTC SDKインスタンスを破棄する(シングルトンパターン)[TRTCCloud destroySharedIntance];
- (void)enterRoomWithRoomId:(NSString *)roomId userID:(NSString *)userId {TRTCParams *params = [[TRTCParams alloc] init];// 文字列のルーム番号を例にparams.strRoomId = roomId;params.userId = userId;// 業務バックエンドから取得したUserSigparams.userSig = [self generateUserSig:userId];// 自分のSDKAppIDに置き換えるparams.sdkAppId = SDKAppID;// すべて視聴者ロールで入室する事がお勧めparams.role = TRTCRoleAudience;// 入室シナリオはLIVEを選択[self.trtcCloud enterRoom:params appScene:TRTCAppSceneLIVE];}
TRTCAppSceneLIVEを選択することをお勧めします。// 入室結果イベントコールバック- (void)onEnterRoom:(NSInteger)result {if (result > 0) {// resultは入室にかかった時間(ミリ秒)NSLog(@"Enter room succeed!");// ブラックフレーム挿入の実験的インターフェースを有効にする[self.trtcCloud callExperimentalAPI:@"{\\"api\\":\\"enableBlackStream\\",\\"params\\": {\\"enable\\":true}}"];} else {// result入室失敗のエラーコードNSLog(@"Enter room failed!");}}
// アンカーロールに切り替え[self.trtcCloud switchRole:TRTCRoleAnchor];// ロール切り替えイベントコールバック- (void)onSwitchRole:(TXLiteAVError)errCode errMsg:(NSString *)errMsg {if (errCode == ERR_NULL) {// メディア音量タイプの設定[self.trtcCloud setSystemVolumeType:TRTCSystemVolumeTypeMedia];// ローカルオーディオストリームを配布し、音質を設定する[self.trtcCloud startLocalAudio:TRTCAudioQualityMusic];}}
// オーディオエフェクト管理クラスを取得self.audioEffectManager = [self.trtcCloud getAudioEffectManager];// originMusicId: カスタム原曲識別子。originMusicUrl: 原曲リソースアドレスTXAudioMusicParam *originMusicParam = [[TXAudioMusicParam alloc] init];originMusicParam.ID = originMusicId;originMusicParam.path = originMusicUrl;// 原曲をリモートにパブリッシュ(またはローカルのみで再生)originMusicParam.publish = YES;// accompMusicId: カスタム伴奏識別子。accompMusicUrl: 伴奏リソースアドレスTXAudioMusicParam *accompMusicParam = [[TXAudioMusicParam alloc] init];accompMusicParam.ID = accompMusicId;accompMusicParam.path = accompMusicUrl;// 伴奏をリモートにパブリッシュ(またはローカルのみで再生)accompMusicParam.publish = YES;// 原曲の再生を開始[self.audioEffectManager startPlayMusic:originMusicParam onStart:^(NSInteger errCode) {// onStart} onProgress:^(NSInteger progressMs, NSInteger durationMs) {// onProgress} onComplete:^(NSInteger errCode) {// onComplete}];// 伴奏の再生を開始[self.audioEffectManager startPlayMusic:originMusicParam onStart:^(NSInteger errCode) {// onStart} onProgress:^(NSInteger progressMs, NSInteger durationMs) {// onProgress} onComplete:^(NSInteger errCode) {// onComplete}];// 原曲に切り替える[self.audioEffectManager setMusicPlayoutVolume:originMusicId volume:100];[self.audioEffectManager setMusicPublishVolume:originMusicId volume:100];[self.audioEffectManager setMusicPlayoutVolume:accompMusicId volume:0];[self.audioEffectManager setMusicPublishVolume:accompMusicId volume:0];// 伴奏に切り替える[self.audioEffectManager setMusicPlayoutVolume:originMusicId volume:0];[self.audioEffectManager setMusicPublishVolume:originMusicId volume:0];[self.audioEffectManager setMusicPlayoutVolume:accompMusicId volume:100];[self.audioEffectManager setMusicPublishVolume:accompMusicId volume:100];
[self.audioEffectManager startPlayMusic:musicParam onStart:^(NSInteger errCode) {// 音楽再生を開始} onProgress:^(NSInteger progressMs, NSInteger durationMs) {// 最新の進行状況とローカルの歌詞の進行状況の誤差に基づいて、seekが必要かどうかを判断する// SEIメッセージを送信して曲の進行状況を伝えるNSDictionary *dic = @{@"musicId": @(self.musicId),@"progress": @(progressMs),@"duration": @(durationMs),};JSONModel *json = [[JSONModel alloc] initWithDictionary:dic error:nil];[self.trtcCloud sendSEIMsg:json.toJSONData repeatCount:1];} onComplete:^(NSInteger errCode) {// 音楽再生完了}];
// 視聴者ロールに切り替える[self.trtcCloud switchRole:TRTCRoleAudience];// ロール切り替えイベントコールバック- (void)onSwitchRole:(TXLiteAVError)errCode errMsg:(NSString *)errMsg {if (errCode == ERR_NULL) {// 伴奏の再生を停止[[self.trtcCloud getAudioEffectManager] stopPlayMusic:self.musicId];// ローカルオーディオのキャプチャーとパブリッシュを停止する[self.trtcCloud stopLocalAudio];}}// ルームから退出[self.trtcCloud exitRoom];// 退室イベントコールバック- (void)onExitRoom:(NSInteger)reason {if (reason == 0) {NSLog(@"exitRoomアクティブコールでルーム退出します");} else if (reason == 1) {NSLog(@"現在のルームからサーバーによってキックされました");} else if (reason == 2) {NSLog(@"現在のルームは解散されました");}}
onExitRoomコールバック通知をスローして知らせます。enterRoomを呼び出す場合や他のオーディオ・ビデオSDKに切り替える場合は、onExitRoomのコールバックが返ってくるまで関連操作を行わないでください。そうしないと、カメラやマイクが強制的に使用されるなど、さまざまな異常が発生する可能性があります。// 部屋に入る- (void)enterRoomWithRoomId:(NSString *)roomId userID:(NSString *)userId {TRTCParams *params = [[TRTCParams alloc] init];// 文字列のルーム番号を例にparams.strRoomId = roomId;params.userId = userId;// 業務バックエンドから取得したUserSigparams.userSig = [self generateUserSig:userId];// 自分のSDKAppIDに置き換えるparams.sdkAppId = SDKAppID;// すべて視聴者ロールで入室する事がお勧めparams.role = TRTCRoleAudience;// 入室シナリオはLIVEを選択[self.trtcCloud enterRoom:params appScene:TRTCAppSceneLIVE];}// 入室結果イベントコールバック- (void)onEnterRoom:(NSInteger)result {if (result > 0) {// resultは入室にかかった時間(ミリ秒)NSLog(@"Enter room succeed!");} else {// result入室失敗のエラーコードNSLog(@"Enter room failed!");}}
TRTCAppSceneLIVEを選択することをお勧めします。- (void)onUserVideoAvailable:(NSString *)userId available:(BOOL)available {if (available) {[self.trtcCloud startRemoteView:userId view:nil];} else {[self.trtcCloud stopRemoteView:userId];}}- (void)onRecvSEIMsg:(NSString *)userId message:(NSData *)message {JSONModel *json = [[JSONModel alloc] initWithData:message error:nil];NSDictionary *dic = json.toDictionary;int32_t musicId = [dic[@"musicId"] intValue];NSInteger progress = [dic[@"progress"] integerValue];NSInteger duration = [dic[@"duration"] integerValue];// ......// TODO歌詞コントロールロジックの更新:// 受信した最新の進行状況とローカルの歌詞進行の誤差に基づいて、歌詞コントロールがseekする必要があるかどうかを判断します。// ......}
// ルームから退出[self.trtcCloud exitRoom];// 退室イベントコールバック- (void)onExitRoom:(NSInteger)reason {if (reason == 0) {NSLog(@"exitRoomアクティブコールでルーム退出します");} else if (reason == 1) {NSLog(@"現在のルームからサーバーによってキックされました");} else if (reason == 2) {NSLog(@"現在のルームは解散されました");}}
- (void)enterRoomWithRoomId:(NSString *)roomId userID:(NSString *)userId {// TRTCCloudマスターインスタンス(ボーカルインスタンス)を作成TRTCCloud *mainCloud = [TRTCCloud sharedInstance];// TRTCCloudサブインスタンス(インストゥルメンタルインスタンス)を作成TRTCCloud *subCloud = [mainCloud createSubCloud];// マスターインスタンス(ボーカルインスタンス)が入室TRTCParams *params = [[TRTCParams alloc] init];params.strRoomId = roomId;params.userId = userId;params.userSig = userSig;params.sdkAppId = SDKAppID;params.role = TRTCRoleAnchor;[mainCloud enterRoom:params appScene:TRTCAppSceneLIVE];// サブインスタンスが手動購読モードを開始し、デフォルトではリモートストリームを購読しない[subCloud setDefaultStreamRecvMode:NO video:NO];// サブインスタンス(インストゥルメンタルインスタンス)が入室TRTCParams *bgmParams = [[TRTCParams alloc] init];bgmParams.strRoomId = roomId;// サブインスタンスのユーザー名は、ルーム内の他のユーザーと重複してはいけません。bgmParams.userId = [userId stringByAppendingString:@"_bgm"];bgmParams.userSig = userSig;bgmParams.sdkAppId = SDKAppID;bgmParams.role = TRTCRoleAnchor;[subCloud enterRoom:bgmParams appScene:TRTCAppSceneLIVE];}
// マスターインスタンスの入室結果イベントコールバック- (void)onEnterRoom:(NSInteger)result {if (result > 0) {// マスターインスタンスがサブインスタンスがパブリッシュした音楽ストリームの購読をキャンセル[self.trtcCloud muteRemoteAudio:[self.userId stringByAppendingString:@"_bgm"] mute:YES];// マスターインスタンスがブラックフレーム挿入の実験的インターフェースを開始[self.trtcCloud callExperimentalAPI:@"{\\"api\\":\\"enableBlackStream\\",\\"params\\": {\\"enable\\":true}}"];// マスターインスタンスが合唱モードの実験的インターフェースを開始[self.trtcCloud callExperimentalAPI:@"{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":true,\\"audioSource\\":0}}"];// マスターインスタンスが低遅延モードの実験的インターフェースを開始[self.trtcCloud callExperimentalAPI:@"{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":true}}"];// マスターインスタンスが音量コールバックを有効にするTRTCAudioVolumeEvaluateParams *aveParams = [[TRTCAudioVolumeEvaluateParams alloc] init];aveParams.interval = 300;[self.trtcCloud enableAudioVolumeEvaluation:YES withParams:aveParams];// マスターインスタンス全過程のメディア音量タイプを設定[self.trtcCloud setSystemVolumeType:TRTCSystemVolumeTypeMedia];// マスターインスタンスがローカルオーディオをキャプチャー・パブリッシュし、同時に音質を設定[self.trtcCloud startLocalAudio:TRTCAudioQualityMusic];} else {// result入室失敗のエラーコードNSLog(@"Enter room failed");}}// サブインスタンスの入室結果イベントコールバック- (void)onEnterRoom:(NSInteger)result {if (result > 0) {// サブインスタンスで合唱モードの実験的インターフェースを有効にする[self.subCloud callExperimentalAPI:@"{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":true,\\"audioSource\\":1}}"];// サブインスタンスが低遅延モードの実験的インターフェースを開始[self.subCloud callExperimentalAPI:@"{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":true}}"];// サブインスタンスの全過程のメディア音量タイプを設定[self.subCloud setSystemVolumeType:TRTCSystemVolumeTypeMedia];// サブインスタンスの音質設定[self.subCloud setAudioQuality:TRTCAudioQualityMusic];} else {// result入室失敗のエラーコードNSLog(@"Enter room failed");}}
audioSourceパラメータの違いに注意する必要があります。- (void)startPublishMediaToRoomWithRoomId:(NSString *)roomId userId:(NSString *)userId {// TRTCPublishTargetオブジェクトを作成TRTCPublishTarget *target = [[TRTCPublishTarget alloc] init];// ミキシング後にルームにプッシュバックtarget.mode = TRTCPublishMixStreamToRoom;TRTCUser *mixStreamIdentity = [[TRTCUser alloc] init];mixStreamIdentity.strRoomId = roomId;// ミキシングロボットのユーザー名は、ルーム内の他のユーザーと重複してはいけません。mixStreamIdentity.userId = [userId stringByAppendingString:@"_robot"];target.mixStreamIdentity = mixStreamIdentity;// トランスコード後のオーディオストリームのエンコードパラメータを設定する(カスタマイズ可能)TRTCStreamEncoderParam *encoderParam = [[TRTCStreamEncoderParam alloc] init];encoderParam.audioEncodedChannelNum = 2;encoderParam.audioEncodedKbps = 64;encoderParam.audioEncodedCodecType = 2;encoderParam.audioEncodedSampleRate = 48000;// トランスコード後のビデオストリームのエンコードパラメータを設定する(ブラックフレームの挿入が必要)encoderParam.videoEncodedFPS = 15;encoderParam.videoEncodedGOP = 3;encoderParam.videoEncodedKbps = 30;encoderParam.videoEncodedWidth = 64;encoderParam.videoEncodedHeight = 64;// オーディオストリームミックスのパラメータを設定TRTCStreamMixingConfig *mixingConfig = [[TRTCStreamMixingConfig alloc] init];// デフォルトでは空欄のままで大丈夫です。これは、ルーム内のすべてのオーディオがミキシングされることを意味します。mixingConfig.audioMixUserList = nil;// ビデオストリームミックステンプレートの配置(ブラックフレームを挿入する場合は必須)TRTCVideoLayout *layout = [[TRTCVideoLayout alloc] init];mixingConfig.videoLayoutList = @[layout];// オーディオ・ビデオストリームプッシュバックを開始[self.trtcCloud startPublishMediaStream:target encoderParam:encoderParam mixingConfig:mixingConfig];}
- (void)updateNetworkTimeExample {[TXLiveBase sharedInstance].delegate = self;[TXLiveBase updateNetworkTime];}- (void)onUpdateNetworkTime:(int)errCode message:(NSString *)errMsg {// errCode 0: 時刻同期成功、偏差は30ms以内;1: 時刻同期成功、しかし偏差は30ms以上の可能性あり;-1: 時刻同期失敗if (errCode == 0) {// 時刻同期成功、NTPタイムスタンプを取得NSInteger ntpTime = [TXLiveBase getNetworkTimestamp];} else {NSLog(@"時刻同期に失敗しました。時刻同期を再試行してください");}}
- (void)sendChorusSignalExample {__weak typeof(self) weakSelf = self;NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {__strong typeof(weakSelf) strongSelf = weakSelf;NSDictionary *dic = @{@"cmd": @"startChorus",// 合唱開始時間を設定: 現在のNTP時間+遅延再生時間(例:3秒)@"startPlayMusicTS": @([TXLiveBase getNetworkTimestamp] + 3000),@"musicId": @(self.musicId),@"musicDuration": @([[strongSelf.subCloud getAudioEffectManager] getMusicDurationInMS:strongSelf.originMusicUri]),};JSONModel *json = [[JSONModel alloc] initWithDictionary:dic error:nil];[strongSelf.trtcCloud sendCustomCmdMsg:1 data:json.toJSONData reliable:NO ordered:NO];}];[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];}
// オーディオエフェクト管理クラスを取得TXAudioEffectManager *audioEffectManager = [self.subCloud getAudioEffectManager];// originMusicId: カスタム原曲識別子。originMusicUrl: 原曲リソースアドレスTXAudioMusicParam *originMusicParam = [[TXAudioMusicParam alloc] init];originMusicParam.ID = originMusicId;originMusicParam.path = originMusicUrl;// 原曲をリモートにパブリッシュ(またはローカルのみで再生)originMusicParam.publish = YES;// 音楽再生を開始するタイムスタンプ(ミリ秒)originMusicParam.startTimeMS = 0;// accompMusicId: カスタム伴奏識別子。accompMusicUrl: 伴奏リソースアドレスTXAudioMusicParam *accompMusicParam = [[TXAudioMusicParam alloc] init];accompMusicParam.ID = accompMusicId;accompMusicParam.path = accompMusicUrl;// 伴奏をリモートにパブリッシュ(またはローカルのみで再生)accompMusicParam.publish = YES;// 音楽再生を開始するタイムスタンプ(ミリ秒)accompMusicParam.startTimeMS = 0;// 原曲のプリロード[audioEffectManager preloadMusic:originMusicParam onProgress:nil onError:nil];// 伴奏をプリロード[audioEffectManager preloadMusic:accompMusicParam onProgress:nil onError:nil];// 遅延再生時間(例えば3秒)後に原曲を再生開始[self.audioEffectManager startPlayMusic:originMusicParam onStart:^(NSInteger errCode) {// onStart} onProgress:^(NSInteger progressMs, NSInteger durationMs) {// onProgress} onComplete:^(NSInteger errCode) {// onComplete}];// 遅延再生時間(例えば3秒)後に伴奏を再生開始[self.audioEffectManager startPlayMusic:originMusicParam onStart:^(NSInteger errCode) {// onStart} onProgress:^(NSInteger progressMs, NSInteger durationMs) {// onProgress} onComplete:^(NSInteger errCode) {// onComplete}];// 原曲に切り替える[self.audioEffectManager setMusicPlayoutVolume:originMusicId volume:100];[self.audioEffectManager setMusicPublishVolume:originMusicId volume:100];[self.audioEffectManager setMusicPlayoutVolume:accompMusicId volume:0];[self.audioEffectManager setMusicPublishVolume:accompMusicId volume:0];// 伴奏に切り替える[self.audioEffectManager setMusicPlayoutVolume:originMusicId volume:0];[self.audioEffectManager setMusicPublishVolume:originMusicId volume:0];[self.audioEffectManager setMusicPlayoutVolume:accompMusicId volume:100];[self.audioEffectManager setMusicPublishVolume:accompMusicId volume:100];
// 約束の合唱開始時間@property (nonatomic, assign) NSInteger startPlayMusicTS;- (void)syncBgmExample {// 現在伴奏の実際の再生進行状況NSInteger currentProgress = [[self.subCloud getAudioEffectManager] getMusicCurrentPosInMS:self.musicId];// 現在伴奏の理想的な再生進行状況NSInteger estimatedProgress = [TXLiveBase getNetworkTimestamp] - self.startPlayMusicTS;// 進捗差が50msを超えた場合、修正を行うif (estimatedProgress >= 0 && labs(currentProgress - estimatedProgress) > 50) {[[self.subCloud getAudioEffectManager] seekMusicToPosInMS:self.musicId pts:estimatedProgress];}}
[[self.subCloud getAudioEffectManager] startPlayMusic:musicParam onStart:^(NSInteger errCode) {// 音楽再生を開始} onProgress:^(NSInteger progressMs, NSInteger durationMs) {// 最新の進行状況とローカルの歌詞の進行状況の誤差に基づいて、seekが必要かどうかを判断する// SEIメッセージを送信して曲の進行状況を伝えるNSDictionary *dic = @{@"musicId": @(self.musicId),@"progress": @(progressMs),@"duration": @(durationMs),};JSONModel *json = [[JSONModel alloc] initWithDictionary:dic error:nil];[self.trtcCloud sendSEIMsg:json.toJSONData repeatCount:1];} onComplete:^(NSInteger errCode) {// 音楽再生完了}];
- (void)exitRoomExample {// サブインスタンスが合唱モードの実験的インターフェースを停止[self.subCloud callExperimentalAPI:@"{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":false,\\"audioSource\\":1}}"];// サブインスタンスが低遅延モードの実験的インターフェースを停止[self.subCloud callExperimentalAPI:@"{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":false}}"];// サブインスタンスが視聴者ロールに切り替わる[self.subCloud switchRole:TRTCRoleAudience];// サブインスタンスが伴奏の再生を停止[[self.subCloud getAudioEffectManager] stopPlayMusic:self.musicId];// サブインスタンスがルームから退出[self.subCloud exitRoom];// マスターインスタンスがブラックフレーム挿入の実験的インターフェースを停止[self.trtcCloud callExperimentalAPI:@"{\\"api\\":\\"enableBlackStream\\",\\"params\\": {\\"enable\\":false}}"];// マスターインスタンスが合唱モードの実験的インターフェースを停止[self.trtcCloud callExperimentalAPI:@"{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":false,\\"audioSource\\":0}}"];// マスターインスタンスが低遅延モードの実験的インターフェイスを停止[self.trtcCloud callExperimentalAPI:@"{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":false}}"];// マスターインスタンスが視聴者ロールに切り替わる[self.trtcCloud switchRole:TRTCRoleAudience];// マスターインスタンスがローカルオーディオのキャプチャーとパブリッシュを停止[self.trtcCloud stopLocalAudio];// マスターインスタンスがルームから退出[self.trtcCloud exitRoom];}
- (void)enterRoomWithRoomId:(NSString *)roomId userID:(NSString *)userId {TRTCParams *params = [[TRTCParams alloc] init];// 文字列のルーム番号を例にparams.strRoomId = roomId;params.userId = userId;// 業務バックエンドから取得したUserSigparams.userSig = [self generateUserSig:userId];// 自分のSDKAppIDに置き換えるparams.sdkAppId = SDKAppID;// サンプルは視聴者ロールとして入室params.role = TRTCRoleAudience;// 入室シナリオはLIVEを選択[self.trtcCloud enterRoom:params appScene:TRTCAppSceneLIVE];}// 入室結果イベントコールバック- (void)onEnterRoom:(NSInteger)result {if (result > 0) {// resultは入室にかかった時間(ミリ秒)NSLog(@"Enter room succeed!");} else {// result入室失敗のエラーコードNSLog(@"Enter room failed!");}}
// アンカーロールに切り替え[self.trtcCloud switchRole:TRTCRoleAnchor];// ロール切り替えイベントコールバック- (void)onSwitchRole:(TXLiteAVError)errCode errMsg:(NSString *)errMsg {if (errCode == ERR_NULL) {// リードシンガーのサブインスタンスがパブリッシュする音楽ストリームの購読を解除[self.trtcCloud muteRemoteAudio:self.bgmUserId mute:YES];// 合唱モードの実験的インターフェースを開始[self.trtcCloud callExperimentalAPI:@"{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":true,\\"audioSource\\":0}}"];// 低遅延モードの実験的インターフェースを開始[self.trtcCloud callExperimentalAPI:@"{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":true}}"];// メディア音量タイプの設定[self.trtcCloud setSystemVolumeType:TRTCSystemVolumeTypeMedia];// ローカルオーディオストリームを配布し、音質を設定する[self.trtcCloud startLocalAudio:TRTCAudioQualityMusic];}}
- (void)updateNetworkTimeExample {[TXLiveBase sharedInstance].delegate = self;[TXLiveBase updateNetworkTime];}- (void)onUpdateNetworkTime:(int)errCode message:(NSString *)errMsg {// errCode 0: 時刻同期成功、偏差は30ms以内;1: 時刻同期成功、しかし偏差は30ms以上の可能性あり;-1: 時刻同期失敗if (errCode == 0) {// 時刻同期成功、NTPタイムスタンプを取得NSInteger ntpTime = [TXLiveBase getNetworkTimestamp];} else {NSLog(@"時刻同期に失敗しました。時刻同期を再試行してください");}}
- (void)onRecvCustomCmdMsgUserId:(NSString *)userId cmdID:(NSInteger)cmdID seq:(UInt32)seq message:(NSData *)message {JSONModel *json = [[JSONModel alloc] initWithData:message error:nil];NSDictionary *dic = json.toDictionary;// 合唱シグナルのマッチングif ([dic[@"cmd"] isEqualToString:@"startChorus"]) {self.startPlayMusicTS = [dic[@"startPlayMusicTS"] integerValue];self.musicId = [dic[@"musicId"] intValue];self.musicDuration = [dic[@"musicDuration"] intValue];// 約束合唱時間と現在の時間との差self.delayMs = self.startPlayMusicTS - [TXLiveBase getNetworkTimestamp];}}
- (void)playBmgExample {// 合唱未開始if (self.delayMs > 0) {// 音楽のプリロードを開始[self preloadMusicWithStartTimeMS:0];// delayMs遅延後に音楽の再生を開始[self startPlayMusicWithStartTimeMS:0];} else if (labs(self.delayMs) < self.musicDuration) {// 合唱進行中// 再生開始時間: 時間差の絶対値+プリロード遅延(例:400ms)NSInteger startTimeMS = labs(self.delayMs) + 400;// 音楽のプリロードを開始[self preloadMusicWithStartTimeMS:startTimeMS];// プリロード遅延(例:400ms)後に音楽の再生を開始[self startPlayMusicWithStartTimeMS:startTimeMS];} else {// 合唱終了// 合唱への参加は許可されない}}// 音楽をプリロードする- (void)preloadMusicWithStartTimeMS:(NSInteger)startTimeMS {// musicId: 合唱シグナルから取得。musicUrl: 対応する音楽リソースのアドレスTXAudioMusicParam *musicParam = [[TXAudioMusicParam alloc] init];musicParam.ID = self.musicId;musicParam.path = self.musicUrl;// 音楽をローカルでのみ再生musicParam.publish = NO;musicParam.startTimeMS = startTimeMS;[self.audioEffectManager preloadMusic:musicParam onProgress:nil onError:nil];}// 音楽の再生を開始- (void)startPlayMusicWithStartTimeMS:(NSInteger)startTimeMS {// musicId: 合唱シグナルから取得。musicUrl: 対応する音楽リソースのアドレスTXAudioMusicParam *musicParam = [[TXAudioMusicParam alloc] init];musicParam.ID = self.musicId;musicParam.path = self.musicUrl;// 音楽をローカルでのみ再生musicParam.publish = NO;musicParam.startTimeMS = startTimeMS;[self.audioEffectManager startPlayMusic:musicParam onStart:nil onProgress:nil onComplete:nil];}
delayMsに基づいて、現在の合唱状態を判断できます。異なる状態のstartPlayMusic遅延呼び出しは、開発者が自分で実装する必要があります。// 約束の合唱開始時間@property (nonatomic, assign) NSInteger startPlayMusicTS;- (void)syncBgmExample {// 現在伴奏の実際の再生進行状況NSInteger currentProgress = [[self.trtcCloud getAudioEffectManager] getMusicCurrentPosInMS:self.musicId];// 現在伴奏の理想的な再生進行状況NSInteger estimatedProgress = [TXLiveBase getNetworkTimestamp] - self.startPlayMusicTS;// 進捗差が50msを超えた場合、修正を行うif (estimatedProgress >= 0 && labs(currentProgress - estimatedProgress) > 50) {[[self.trtcCloud getAudioEffectManager] seekMusicToPosInMS:self.musicId pts:estimatedProgress];}}
[self.audioEffectManager startPlayMusic:musicParam onStart:^(NSInteger errCode) {// 音楽再生を開始} onProgress:^(NSInteger progressMs, NSInteger durationMs) {// TODO歌詞コントロールロジックの更新:// 最新の進行状況とローカルの歌詞進行の誤差に基づいて、seek歌詞コントロールが必要があるかどうかを判断} onComplete:^(NSInteger errCode) {// 音楽再生完了}];
- (void)exitRoomExample {// 合唱モードの実験的インターフェースを停止[self.trtcCloud callExperimentalAPI:@"{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":false,\\"audioSource\\":0}}"];// 低遅延モードの実験的インターフェースを停止[self.trtcCloud callExperimentalAPI:@"{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":false}}"];// 視聴者ロールに切り替える[self.trtcCloud switchRole:TRTCRoleAudience];// 伴奏の再生を停止[[self.trtcCloud getAudioEffectManager] stopPlayMusic:self.musicId];// ローカルオーディオのキャプチャーとパブリッシュを停止[self.trtcCloud stopLocalAudio];// ルームから退出[self.trtcCloud exitRoom];}
- (void)enterRoomWithRoomId:(NSString *)roomId userID:(NSString *)userId {TRTCParams *params = [[TRTCParams alloc] init];// 文字列のルーム番号を例にparams.strRoomId = roomId;params.userId = userId;// 業務バックエンドから取得したUserSigparams.userSig = [self generateUserSig:userId];// 自分のSDKAppIDに置き換えるparams.sdkAppId = SDKAppID;// すべて視聴者ロールで入室する事がお勧めparams.role = TRTCRoleAudience;// 入室シナリオはLIVEを選択[self.trtcCloud enterRoom:params appScene:TRTCAppSceneLIVE];}// 入室結果イベントコールバック- (void)onEnterRoom:(NSInteger)result {if (result > 0) {// resultは入室にかかった時間(ミリ秒)NSLog(@"Enter room succeed!");} else {// result入室失敗のエラーコードNSLog(@"Enter room failed!");}}
TRTCAppSceneLIVEを選択することをお勧めします。- (void)onUserVideoAvailable:(NSString *)userId available:(BOOL)available {if (available) {[self.trtcCloud startRemoteView:userId view:nil];} else {[self.trtcCloud stopRemoteView:userId];}}- (void)onRecvSEIMsg:(NSString *)userId message:(NSData *)message {JSONModel *json = [[JSONModel alloc] initWithData:message error:nil];NSDictionary *dic = json.toDictionary;int32_t musicId = [dic[@"musicId"] intValue];NSInteger progress = [dic[@"progress"] integerValue];NSInteger duration = [dic[@"duration"] integerValue];// ......// TODO歌詞コントロールロジックの更新:// 受信した最新の進行状況とローカルの歌詞進行の誤差に基づいて、歌詞コントロールがseekする必要があるかどうかを判断します。// ......}
// ルームから退出[self.trtcCloud exitRoom];// 退室イベントコールバック- (void)onExitRoom:(NSInteger)reason {if (reason == 0) {NSLog(@"exitRoomアクティブコールでルーム退出します");} else if (reason == 1) {NSLog(@"現在のルームからサーバーによってキックされました");} else if (reason == 2) {NSLog(@"現在のルームは解散されました");}}
{"action": "CreateJob","secretId": "{secretId}","secretKey": "{secretKey}","createJobRequest": {"customId": "{customId}","callback": "{callback}","inputs": [{ "url": "{url}" }],"outputs": [{"contentId": "{contentId}","destination": "{destination}","inputSelectors": [0],"smartContentDescriptor": {"outputPrefix": "{outputPrefix}","vocalScore": {"standardAudio": {"midi": {"url":"{url}"},"standardWav": {"url":"{url}"},"alignWav": {"url":"{url}"}}}}}]}}
{"requestId": "ac004192-110b-46e3-ade8-4e449df84d60","createJobResponse": {"job": {"id": "13f342e4-6866-450e-b44e-3151431c578b","state": 1,"customId": "{customId}","callback": "{callback}","inputs": [ { "url": "{url}" } ],"outputs": [{"contentId": "{contentId}","destination": "{destination}","inputSelectors": [ 0 ],"smartContentDescriptor": {"outputPrefix": "{outputPrefix}","vocalScore": {"standardAudio": {"midi": {"url":"{url}"},"standardWav": {"url":"{url}"},"alignWav": {"url":"{url}"}}}}}],"timing": {"createdAt": "1603432763000","startedAt": "0","completedAt": "0"}}}}
{"action": "GetJob","secretId": "{secretId}","secretKey": "{secretKey}","getJobRequest": {"id": "{id}"}}
{"requestId": "c9845a99-34e3-4b0f-80f5-f0a2a0ee8896","getJobResponse": {"job": {"id": "a95e9d74-6602-4405-a3fc-6408a76bcc98","state": 3,"customId": "{customId}","callback": "{callback}","timing": {"createdAt": "1610513575000","startedAt": "1610513575000","completedAt": "1610513618000"},"inputs": [{ "url": "{url}" }],"outputs": [{"contentId": "{contentId}","destination": "{destination}","inputSelectors": [0],"smartContentDescriptor": {"outputPrefix": "{outputPrefix}","vocalScore": {"standardAudio": {"midi": {"url":"{url}"},"standardWav": {"url":"{url}"},"alignWav": {"url":"{url}"}}}},"smartContentResult": {"vocalScore": "out.json"}}]}}}
- (void)onUserVoiceVolume:(NSArray<TRTCVolumeInfo *> *)userVolumes totalVolume:(NSInteger)totalVolume {if (userVolumes.count) {// マイクオンユーザーに対応する音量値を保存するために使用NSMutableDictionary *volumesMap = [NSMutableDictionary dictionary];for (TRTCVolumeInfo *user in userVolumes) {// 適切な音量のしきい値を設定できますif (user.volume > 10) {volumesMap[user.userId] = @(user.volume);}}JSONModel *json = [[JSONModel alloc] initWithDictionary:volumesMap error:nil];// SEIメッセージを通じてマイクオンユーザーの音量セットを送信[self.trtcCloud sendSEIMsg:json.toJSONData repeatCount:1];}}- (void)onRecvSEIMsg:(NSString *)userId message:(NSData *)message {JSONModel *json = [[JSONModel alloc] initWithData:message error:nil];NSDictionary *dic = json.toDictionary;for (NSString *userId in dic.allKeys) {// すべてのマイクオンユーザーのシングルストリームの音量をプリントNSLog(@"%@: %@", userId, dic[userId]);}}
onNetworkQualityをリスニングすることができます。このコールバックは2秒ごとに一度発生します。#pragma mark - TRTCCloudDelegate- (void)onNetworkQuality:(TRTCQualityInfo *)localQuality remoteQuality:(NSArray<TRTCQualityInfo *> *)remoteQuality {// localQualityはローカルユーザーのネットワーク品質評価結果を表します。// 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でprivateMapKeyパラメータを渡す必要があります。したがって、このSDKAppIDをオンラインで使用しているユーザーがいる場合、この機能を安易には有効にしないでください。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:TRTCAppSceneLIVE];
// 業務バックエンドから最新の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が空であるかどうか確認してください。 |
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 | マイクが使用中です。たとえば、モバイルデバイスが通話中の場合、マイクを開くと失敗します。 |
// イヤーモニターを有効にする[[self.trtcCloud getAudioEffectManager] enableVoiceEarMonitor:YES];// イヤーモニター音量の設定[[self.trtcCloud getAudioEffectManager] setVoiceEarMonitorVolume:volume];
setSystemAudioKitEnabledを通じてハードウェアイヤーモニターを有効にすることで、イヤーモニターの遅延が過度に高い問題を改善することができます。ハードウェアイヤーモニターはパフォーマンスが良く、遅延が少ないですが、ソフトウェアイヤーモニターは遅延が高いものの、互換性が良いです。現在、HuaweiおよびVIVOデバイスについては、SDKはデフォルトでハードウェアイヤーモニターを使用していますが、他のデバイスはデフォルトでソフトウェアイヤーモニターを使用しています。ハードウェアイヤーモニターに互換性の問題がある場合は、お問い合わせにてソフトウェアイヤーモニターを強制的に使用するよう設定することができます。
[[self.trtcCloud getAudioEffectManager] preloadMusic:musicParam onProgress:nil onError:nil];
// BGMのローカル再生ボリュームの設定[[self.trtcCloud getAudioEffectManager] setMusicPlayoutVolume:self.musicId volume:volume];// BGMのリモート再生ボリュームの設定[[self.trtcCloud getAudioEffectManager] setMusicPublishVolume:self.musicId volume:volume];// すべてのBGMのローカルとリモート音量の設定[[self.trtcCloud getAudioEffectManager] setAllMusicVolume:volume];// ボーカルのキャプチャーボリュームの設定[[self.trtcCloud getAudioEffectManager] setVoiceVolume:volume];
フィードバック