tencent cloud

iOS

Download
フォーカスモード
フォントサイズ
最終更新日: 2026-05-11 15:55:05

業務フロー

このセクションでは、オンラインカラオケにおけるいくつかの一般的な業務フローをまとめて、全体のシナリオの実装をよりよく理解するのに役立ちます。
曲予約の手順
ソロの流れ
リードシンガーの流れ
合唱の流れ
聞き手の流れ
下図は、業務側が音楽ライブラリを組み合わせて曲を予約し、TRTC SDKを使用して再生するプロセスを示しています。



下の図は、マイク順番待ちソロプレイで、歌い手が入室して歌い、歌い終わって退室するプロセスを示しています。



下図は、リアルタイム合唱プレイ中に、リードシンガーが合唱を開始し、合唱を停止して退室するプロセスを示しています。


下図はリアルタイム合唱プレイ中、合唱者が合唱に参加し、合唱を停止して退室するプロセスを示しています。



下図は、オンラインカラオケシナリオにおいて、聞き手が入室して歌を聞き、歌詞同期プロセスを示しています。




アクセスの準備

ステップ1:サービスを利用する

オンラインカラオケシナリオでは通常、Tencent CloudのReal-Time Communication TRTCIntelligent Music Solutionの2つの有料PaaSサービスに依存して構築されます。その中でTRTCはリアルタイムオーディオインタラクションを提供し、スマートミュージックソリューションは歌詞認識、スマート作曲、曲を聴いて曲を識別する機能、音楽スコアリングなどの能力を提供します。
TRTCサービスを利用する
スマート音楽サービスを利用する
1. まず、Real-Time Communication TRTCコントロールパネルにログインしてアプリケーションを作成する必要があります。必要に応じてTRTCアプリケーションのバージョンをアップグレードすることができます。例えば、プロフェッショナル版ではより多くの付加価値機能サービスが使えます。



説明:
テスト環境と本番環境にそれぞれ使用するために2つのアプリケーションを作成することをお勧めします。1年間に各Tencent Cloudアカウント(UIN)には、毎月10,000分の無料時間が提供されます。
TRTC月額プランは体験版(デフォルト)、基本版、プロフェッショナル版に分かれており、異なる付加価値機能サービスが使えます。詳細はバージョン機能と月額プラン説明をご覧ください。
2. アプリケーションが作成された後、アプリケーション管理-アプリケーション概要セクションでそのアプリケーションの基本情報を確認できます。その中で、後で使用するためにSDKAppIDSDKSecretKeyを大切に保管してください。同時に、キーの漏洩はトラフィックの不正利用に繋がりますのでご注意ください。




前置き準備

1. 音楽サービスの利用を開始するには、購入ページに進み、音楽スコアリングなどの適切な機能を選択して利用開始してください。
2. CAMでAK/SKキーペアを作成します(プログラムアクセスユーザーとしてのアクセス方法、ログインやユーザー権限は必要ない)。
3. COS(Cloud Object Storage)バケットを作成し、COSバケット管理インターフェースで作成済みのプログラム専用ユーザーにCOSバケットの読み書き権限を付与してください。
4. パラメータを準備します。
operateUin: Tencent CloudサブユーザーのアカウントID
cosConfig: Cloud Object Storage関連パラメータ
secretId: ストレージバケットのsecretId
secretKey: ストレージバケットのsecretKey
bucket: ストレージバケットの名称
region: ストレージバケットの地域、例えば"ap-guangzhou"

登録をアクティブ化

前提条件を完了した後、リクエストを送信して登録とアクティベーションを行い、約2分間待機する予定です。
リクエストを開始
リクエスト結果
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を実行して確認してください。
説明:
より詳細なスマートミュージックソリューションのアクセス説明については、アクセスガイドを参照してください。

ステップ2:SDKをインポートする

TRTC 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
# 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
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

ステップ3:プロジェクトの設定

1. カラオケシナリオでTRTC SDKは、マイクの権限が必要です。AppのInfo.plistに以下のを追加してください。マイクがシステムの承認ダイアログをポップアップする際のプロンプト情報に対応しています。
Privacy - Microphone Usage Description、そしてマイク使用目的も入力してください



2. バックグラウンドでApp関連機能を継続して実行する必要がある場合は、XCodeで現在のプロジェクトを選択し、Capabilitiesで設定項目Background ModesをONに設定し、AudioとAirPlay and Picture in Pictureにチェックを入れてください。以下の図に示されたように。




ステップ4:認証とライセンス

UserSigはTencent Cloudが設計した一種のセキュリティ保護署名で、悪意のある攻撃者がクラウドサービスの使用権を盗用するのを防ぐためのものです。TRTCは入室時に認証クレデンシャルを検証します。
デバッグフェーズ:クライアントサンプルコードコントロールパネル取得の2つの方法でUserSigを計算生成でき、デバッグテストのみに使用します。
本番フェーズ:クライアントがリバースエンジニアリングでキーが漏洩するのを防ぐため、より高いセキュリティレベルのサーバー側UserSig計算を推奨します。
具体的な実装は以下の通りです:
1. AppがSDKの初期化関数を呼び出す前に、最初にサーバーにUserSigをリクエストします。
2. サーバーはSDKAppIDとUserIDに基づいてUserSigを計算します。
3. サーバーは計算されたUserSigをAppに返します。
4. Appは、特定のAPIを通じてSDKにUserSigを伝達します。
5. SDKがSDKAppID + UserID + UserSigをTencent Cloudのクラウドサーバーに提出して検証します。
6. Tencent CloudはUserSigを検証し、合法性を確認します。
7. 検証を通過した後、TRTC SDKにReal-Time Communicationサービスを提供します。



注意:
デバッグフェーズのローカルUserSig計算方式は、オンライン環境に適用することは推奨しません。逆コンパイルによって容易に解読され、キーが漏洩する可能性があります。
複数の言語(Java/GO/PHP/Nodejs/Python/C#/C++)のUserSigサーバーサイド計算のソースコードを提供しています。詳細はサーバーサイドUserSig計算を参照してください。

ステップ5:SDKの初期化

// 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];
説明:
SDKイベント通知のリスニングを推奨します。一般的なエラーに関するログ出力と処理についての詳細はエラーコード表を参照してください。

シナリオ1:マイク順番待ちソロ

視点1:歌い手のアクション

タイムライン図




1. ルームに入る
- (void)enterRoomWithRoomId:(NSString *)roomId userID:(NSString *)userId {
TRTCParams *params = [[TRTCParams alloc] init];
// 文字列のルーム番号を例に
params.strRoomId = roomId;
params.userId = userId;
// 業務バックエンドから取得したUserSig
params.userSig = [self generateUserSig:userId];
// 自分のSDKAppIDに置き換える
params.sdkAppId = SDKAppID;
// すべて視聴者ロールで入室する事がお勧め
params.role = TRTCRoleAudience;
// 入室シナリオはLIVEを選択
[self.trtcCloud enterRoom:params appScene:TRTCAppSceneLIVE];
}
注意:
歌詞同期用のSEIメッセージをより効果的にパススルーするために、入室シナリオでは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!");
}
}
注意:
オーディオオンリーモードでの歌い手は、SEIメッセージを送信するためにブラックフレーム挿入を有効にする必要があります。このインターフェースは、ルームへの入室成功後に呼び出す必要があります。
2. マイクオンプッシュ
// アンカーロールに切り替え
[self.trtcCloud switchRole:TRTCRoleAnchor];

// ロール切り替えイベントコールバック
- (void)onSwitchRole:(TXLiteAVError)errCode errMsg:(NSString *)errMsg {
if (errCode == ERR_NULL) {
// メディア音量タイプの設定
[self.trtcCloud setSystemVolumeType:TRTCSystemVolumeTypeMedia];
// ローカルオーディオストリームを配布し、音質を設定する
[self.trtcCloud startLocalAudio:TRTCAudioQualityMusic];
}
}
注意:
カラオケシナリオでは、全過程のメディア音量とMusic音質を設定することをお勧めします。これにより、高音質の聴覚体験を得ることができます。
3. 曲の予約
曲を検索し、音楽リソースを取得する
業務バックエンドで目的の曲を検索し、曲の識別子MusicId、曲のアドレスMusicUrl、歌詞のアドレスLyricsUrlなどの音楽リソースを取得します。
業務側には、適切な音楽ライブラリ製品を自ら選択し、正規の音楽リソースを提供することをお勧めします。
伴奏を再生し、歌い始めます。
// オーディオエフェクト管理クラスを取得
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];
注意:
カラオケシナリオでは、原曲と伴奏を同時に再生する必要があります(MusicIDで区別)。ローカルとリモートの再生音量を調整することで、原曲と伴奏の切り替えを実現します。
二重音声トラック(原曲と伴奏を含む)の音楽が再生されている場合、setMusicTrackを使用して音楽の再生トラックを指定し、原曲と伴奏を切り替えることができます。
4. 歌詞同期
歌詞をダウンロード
業務バックエンドから目標の歌詞のダウンロードリンクLyricsUrlを取得し、目標の歌詞をローカルにキャッシュします。
ローカル歌詞同期、及びSEIで曲の進行状況の伝達。
[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) {
// 音楽再生完了
}];
注意:
歌い手がSEIメッセージを送信する頻度はイベントコールバックの頻度によって決まります。ここでは、getMusicCurrentPosInMSを使用して再生進行状況を定期的に同期することもできます。
5. マイクオフして退室
// 視聴者ロールに切り替える
[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(@"現在のルームは解散されました");
}
}
注意:
SDKが使うすべてのリソースがリリースされた後、SDKはonExitRoomコールバック通知をスローして知らせます。
再度enterRoomを呼び出す場合や他のオーディオ・ビデオSDKに切り替える場合は、onExitRoomのコールバックが返ってくるまで関連操作を行わないでください。そうしないと、カメラやマイクが強制的に使用されるなど、さまざまな異常が発生する可能性があります。

視点2:聞き手のアクション

タイムライン図




1. ルームに入る
// 部屋に入る
- (void)enterRoomWithRoomId:(NSString *)roomId userID:(NSString *)userId {
TRTCParams *params = [[TRTCParams alloc] init];
// 文字列のルーム番号を例に
params.strRoomId = roomId;
params.userId = userId;
// 業務バックエンドから取得したUserSig
params.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!");
}
}
注意:
歌詞同期用のSEIメッセージをより効果的にパススルーするために、入室シナリオではTRTCAppSceneLIVEを選択することをお勧めします。
自動購読モード(デフォルト)では、視聴者が入室すると、自動的にマイクオンアンカーのオーディオストリームを購読して再生します。
2. 歌詞同期
歌詞をダウンロード
業務バックエンドから目標の歌詞のダウンロードリンクLyricsUrlを取得し、目標の歌詞をローカルにキャッシュします。
聞き手側の歌詞同期
- (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する必要があるかどうかを判断します。
// ......
}
注意:
聞き手は、ブラックフレームに含まれるSEIメッセージを受信するために、歌い手のビデオストリームを自分から購読する必要があります。
3. ルームから退出
// ルームから退出
[self.trtcCloud exitRoom];

// 退室イベントコールバック
- (void)onExitRoom:(NSInteger)reason {
if (reason == 0) {
NSLog(@"exitRoomアクティブコールでルーム退出します");
} else if (reason == 1) {
NSLog(@"現在のルームからサーバーによってキックされました");
} else if (reason == 2) {
NSLog(@"現在のルームは解散されました");
}
}

シナリオ2:リアルタイム合唱

視点1:リードシンガーのアクション

タイムライン図




1. ダブルインスタンスで入室
- (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];
}
注意:
リアルタイム合唱プランでは、リードシンガー側は、それぞれボーカルおよび伴奏のアップストリームに使用するマスターインスタンスとサブインスタンスを作成する必要があります。
サブインスタンスは、ルーム内の他のユーザーのオーディオストリームを購読する必要がないため、手動購読モードを有効にすることをお勧めします。これは入室前に有効にする必要があります。
2. 入室後の設定
// マスターインスタンスの入室結果イベントコールバック
- (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パラメータの違いに注意する必要があります。
3. ルームにオーディオ・ビデオストリームプッシュバック
- (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];
}
注意:
合唱のボーカルと伴奏を揃えるために、ルームにオーディオ・ビデオストリームプッシュバックを開始することをお勧めします。マイクオンの合唱者は互いにシングルストリームを購読し、マイクオフの聞き手はデフォルトでストリームミックスのみを購読します。
ミキシングロボットは独立したユーザーとして入室し、ストリームをプル、ミキシング、転送します。そのユーザー名はルームの他のユーザー名と重複してはならず、そうでないと相互にキックされる原因となります。
4. 検索と曲予約
業務バックエンドで目的の曲を検索し、曲の識別子MusicId、曲のアドレスMusicUrl、歌詞のアドレスLyricsUrlなどの音楽リソースを取得します。
業務側には、適切な音楽ライブラリ製品を自ら選択し、正規の音楽リソースを提供することをお勧めします。
5. NTP時刻同期
- (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(@"時刻同期に失敗しました。時刻同期を再試行してください");
}
}
注意:
NTP時刻同期の結果は、ユーザーの現在のネットワーク品質を反映することができます。良好な合唱体験を保証するために、時刻同期に失敗した場合はユーザーが合唱を開始することを許可しないことをお勧めします。
6. 合唱シグナルを送信
- (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];
}
注意:
リードシンガーは、新しいユーザーが途中で合唱に参加できるように、定期的な時間間隔(例えば1秒ごと)でルーム内に合唱のシグナルをブロードキャストする必要があります。
7. 伴奏の読み込み再生
// オーディオエフェクト管理クラスを取得
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];
注意:
音楽を再生する前に、事前に音楽リソースをメモリにプリロードすることをお勧めします。これにより、音楽再生のローディング遅延を効果的に低減できます。
カラオケシナリオでは、原曲と伴奏を同時に再生する必要があります(MusicIDで区別)。ローカルとリモートの再生音量を調整することで、原曲と伴奏の切り替えを実現します。
二重音声トラック(原曲と伴奏を含む)の音楽が再生されている場合、setMusicTrackを使用して音楽の再生トラックを指定し、原曲と伴奏を切り替えることができます。
8. 伴奏同期
// 約束の合唱開始時間
@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];
}
}
9. 歌詞同期
歌詞をダウンロード
業務バックエンドから目標の歌詞のダウンロードリンクLyricsUrlを取得し、目標の歌詞をローカルにキャッシュします。
ローカル歌詞同期、及びSEIで曲の進行状況の伝達。
[[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) {
// 音楽再生完了
}];
注意:
歌い手がSEIメッセージを送信する頻度はイベントコールバックの頻度によって決まります。ここでは、getMusicCurrentPosInMSを使用して再生進行状況を定期的に同期することもできます。
10. マイクオフして退室
- (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];
}

視点2:合唱のアクション

タイムライン図




1. ルームに入る
- (void)enterRoomWithRoomId:(NSString *)roomId userID:(NSString *)userId {
TRTCParams *params = [[TRTCParams alloc] init];
// 文字列のルーム番号を例に
params.strRoomId = roomId;
params.userId = userId;
// 業務バックエンドから取得したUserSig
params.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!");
}
}
2. マイクオンプッシュ
// アンカーロールに切り替え
[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];
}
}
注意:
遅延をできるだけ低減するために、合唱者は伴奏をローカルで再生するため、リードシンガーがパブリッシュする音楽ストリームの購読を解除する必要があります。
合唱者も実験的なインターフェースを使用して合唱モードと低遅延モードを有効にする必要があり、合唱体験を最適化します。
カラオケシナリオでは、全過程のメディア音量とMusic音質を設定することをお勧めします。これにより、高音質の聴覚体験を得ることができます。
3. NTP時刻同期
- (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(@"時刻同期に失敗しました。時刻同期を再試行してください");
}
}
注意:
NTP時刻同期の結果は、ユーザーの現在のネットワーク品質を反映することができます。良好な合唱体験を保証するために、時刻同期に失敗した場合はユーザーが合唱に参加することを許可しないことをお勧めします。
4. 合唱シグナルの受信
- (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];
}
}
注意:
合唱者が合唱シグナルを受信し、合唱に参加した後、状態は「合唱中」に変わり、このラウンドの合唱が終了するまで合唱シグナルに再度応答しません。
5. 伴奏を再生し、合唱を始めます。
- (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遅延呼び出しは、開発者が自分で実装する必要があります。
6. 伴奏同期
// 約束の合唱開始時間
@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];
}
}
7. 歌詞同期
歌詞をダウンロード
業務バックエンドから目標の歌詞のダウンロードリンクLyricsUrlを取得し、目標の歌詞をローカルにキャッシュします。
ローカル歌詞同期
[self.audioEffectManager startPlayMusic:musicParam onStart:^(NSInteger errCode) {
// 音楽再生を開始
} onProgress:^(NSInteger progressMs, NSInteger durationMs) {
// TODO歌詞コントロールロジックの更新:
// 最新の進行状況とローカルの歌詞進行の誤差に基づいて、seek歌詞コントロールが必要があるかどうかを判断
} onComplete:^(NSInteger errCode) {
// 音楽再生完了
}];
8. マイクオフして退室
- (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];
}

視点3:聞き手のアクション

タイムライン図




1. ルームに入る
- (void)enterRoomWithRoomId:(NSString *)roomId userID:(NSString *)userId {
TRTCParams *params = [[TRTCParams alloc] init];
// 文字列のルーム番号を例に
params.strRoomId = roomId;
params.userId = userId;
// 業務バックエンドから取得したUserSig
params.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!");
}
}
注意:
歌詞同期用のSEIメッセージをより効果的にパススルーするために、入室シナリオではTRTCAppSceneLIVEを選択することをお勧めします。
自動購読モード(デフォルト)では、視聴者が入室すると、自動的にマイクオンアンカーのオーディオストリームを購読して再生します。
2. 歌詞同期
歌詞をダウンロード
業務バックエンドから目標の歌詞のダウンロードリンクLyricsUrlを取得し、目標の歌詞をローカルにキャッシュします。
聞き手側の歌詞同期
- (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する必要があるかどうかを判断します。
// ......
}
注意:
聞き手は、ブラックフレームに含まれるSEIメッセージを受信するために、リードシンガーのビデオストリームを自分から購読する必要があります。
リードシンガーのストリームミックスにブラックフレームが同時に挿入される場合、ここではミキシングロボットのビデオストリームを購読するだけで済みます。
3. ルームから退出
// ルームから退出
[self.trtcCloud exitRoom];

// 退室イベントコールバック
- (void)onExitRoom:(NSInteger)reason {
if (reason == 0) {
NSLog(@"exitRoomアクティブコールでルーム退出します");
} else if (reason == 1) {
NSLog(@"現在のルームからサーバーによってキックされました");
} else if (reason == 2) {
NSLog(@"現在のルームは解散されました");
}
}

高度機能

音楽スコアリングモジュールアクセス

音楽スコアリングはユーザーにマルチディメンションの歌唱採点能力を提供し、現在サポートされている採点ディメンションには、音の正確さとリズムが含まれます。
1. 評価関連ドキュメントの準備
採点するための歌唱録音ファイル、オリジナルの音楽標準ファイル、MIDI楽譜ファイルなどを事前に準備し、それらをCOSストレージにアップロードしてください。
2. 音楽スコアリングタスクを作成
リクエスト方法:POST(HTTP)
リクエストアドレス:https://api.mediax.tencent.com/job
リクエストヘッダー:Content-Type: application/json
リクエストサンプル:
リクエストサンプル
レスポンスサンプル
{
"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"
}
}
}
}
3. 音楽スコアリングの結果を取得
取得方法:アクティブ取得とパッシブコールバックに分かれます。
タスクを作成した後のレスポンスパケット内のidクエリを通じて、もしクエリしたタスクが成功した場合(state=3)、タスクのOutputにはsmartContentResult構造体が含まれ、その中のvocalScoreフィールドに結果jsonファイル名が保存されます。ユーザーはOutput内のcosおよびdestination情報を基に、出力ファイルのcosパスを自分で結合することができます。
リクエストサンプル
レスポンスサンプル
{
"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"
}
}
]
}
}
}
パッシブコールバックは、タスクを作成する際にcallbackフィールドに記入する必要があります。プラットフォームは、タスクが完了状態(COMPLETED/ERROR)に入ると、Job構造体をcallbackで指定したアドレスに送信します。プラットフォーム側は、タスク結果を取得するためにパッシブコールバックの使用を推奨します。完了状態(COMPLETED/ERROR)に入ったタスクの全Job構造体を、タスク作成時に指定されたcallbackフィールドに対応するアドレスに送信します。Job構造体は、アクティブクエリの例(getJobResponse以下)に記載されています。
説明:
より詳細なスマートミュージックソリューションの音楽スコアリングモジュールのアクセス説明については、音楽スコアリングアクセスを参照してください。

ストリームミックスパススルーシングルストリームの音量

ミキシングを有効にした後、聞き手はマイクオンアンカーのシングルストリーム音量を直接取得することができません。この時、ルームマスターがマイクオンアンカー全員のコールバック音量値をSEIを通じて送信する方法でシングルストリームの音量をパススルーできます。
- (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]);
}
}
注意:
SEIメッセージでストリームミックスからパススルーでシングルストリームの音量を得るには、ルームマスターがビデオストリームをプッシュしているか、またはブラックフレーム挿入を有効にしていること、そして聞き手がルームマスターのビデオストリームを自分から購読する必要があります。

ネットワーク品質リアルタイムコールバック

ローカルおよびリモートユーザーのネットワーク品質をリアルタイムで統計するために、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;
}
}

高度な権限制御

TRTC高度な権限制御を使用して、異なるルームに異なるアクセス権を設定できます。例えば、高級VIPルームなど。また、聞き手のマイクオン権限を制御するためにも使用できます。例えば、ゴーストマイクの処理など。
ステップ1:TRTCコントロールパネルアプリケーションの高度な機能ページで、高度な権限制御スイッチをオンにします。



注意:
特定のSDKAppIDが高度な権限制御を有効にした後、そのSDKAppIDを使用する入室するすべてのユーザーはTRTCParamsprivateMapKeyパラメータを渡す必要があります。したがって、このSDKAppIDをオンラインで使用しているユーザーがいる場合、この機能を安易には有効にしないでください。
ステップ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:TRTCAppSceneLIVE];
マイクオン検証
// 業務バックエンドから最新のPrivateMapKeyを取得し、ロール切り替えインターフェースに渡します。
[self.trtcCloud switchRole:TRTCRoleAnchor privateMapKey:[self getPrivateMapKey]];

異常処理

異常エラー処理

TRTC SDK回復不可能なエラーが発生した場合、onErrorコールバックでスローされます。詳細はエラーコード表を参照してください。
1. UserSig関連
UserSig検証に失敗すると入室に失敗します。UserSigツールを使用して検証できます。
列挙値
取得値
説明
ERR_TRTC_INVALID_USER_SIG
-3320
入室パラメータuserSigが正しくありません。TRTCParams.userSigが空であるかどうかを確認してください。
ERR_TRTC_USER_SIG_CHECK_FAILED
-100018
UserSig検証失敗、パラメータTRTCParams.userSigが正しく入力されているか、または期限切れでないかを確認してください。
2. 入退室関連
入室に失敗した場合は、まず入室パラメータが正しいかどうかを確認してください。また、入退室インターフェースは必ずペアで呼び出す必要があります。入室に失敗した場合でも、退室インターフェースを呼び出す必要があります。
列挙値
取得値
説明
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のルームに連続して入室しようとしていないか確認してください。
3. デバイス関連
デバイス関連のエラーをリスニングし、関連するエラーが発生した場合にUIでユーザーに通知します。
列挙値
取得値
説明
ERR_MIC_START_FAIL
-1302
マイクの起動に失敗しました。例えば、WindowsまたはMacデバイスで、マイクの設定プログラム(ドライバー)に異常があります。デバイスを無効にしてから再度有効にするか、マシンを再起動するか、設定プログラムを更新してください。
ERR_SPEAKER_START_FAIL
-1321
スピーカーの起動に失敗しました。例えば、WindowsやMacのデバイスで、スピーカーの設定プログラム(ドライバー)に異常があります。デバイスを無効にしてから再度有効にするか、マシンを再起動するか、設定プログラムを更新してください。
ERR_MIC_OCCUPY
-1319
マイクが使用中です。たとえば、モバイルデバイスが通話中の場合、マイクを開くと失敗します。

イヤーモニター関連の問題

1. イヤーモニター機能の開始方法とイヤーモニター音量の設定方法
// イヤーモニターを有効にする
[[self.trtcCloud getAudioEffectManager] enableVoiceEarMonitor:YES];
// イヤーモニター音量の設定
[[self.trtcCloud getAudioEffectManager] setVoiceEarMonitorVolume:volume];
注意:
事前にイヤーモニターを設定でき、オーディオルーティングの変更をリスニングする必要はありません。ヘッドフォンを接続すると、イヤーモニター機能が自動的に有効になります。
2. イヤーモニター機能をオンにしても有効にならない
Bluetoothヘッドセットのハードウェア遅延が非常に高いため、ユーザーインターフェース上でアンカーに有線ヘッドセットの着用を促すようにしてください。また、すべてのスマートフォンがこの機能を有効にした後に優れたイヤーモニター効果を達成できるわけではないことにも注意が必要です。TRTC SDKはイヤーモニター効果が悪い一部のスマートフォンに大して、この機能をブロックしています。
3. イヤーモニターの遅延が高すぎる
Bluetoothヘッドセットを使用しているかどうかを確認してください。Bluetoothヘッドセットのハードウェア遅延は非常に高いため、可能な限り有線ヘッドセットの使用をお勧めします。また、実験的インターフェースsetSystemAudioKitEnabledを通じてハードウェアイヤーモニターを有効にすることで、イヤーモニターの遅延が過度に高い問題を改善することができます。ハードウェアイヤーモニターはパフォーマンスが良く、遅延が少ないですが、ソフトウェアイヤーモニターは遅延が高いものの、互換性が良いです。現在、HuaweiおよびVIVOデバイスについては、SDKはデフォルトでハードウェアイヤーモニターを使用していますが、他のデバイスはデフォルトでソフトウェアイヤーモニターを使用しています。ハードウェアイヤーモニターに互換性の問題がある場合は、お問い合わせにてソフトウェアイヤーモニターを強制的に使用するよう設定することができます。

NTP時刻同期の問題

1. NTP time sync finished、but result maybe inaccurate。
NTP時刻同期に成功したけど、偏差が30ms以上の可能性があります。これはクライアントのネットワーク環境が悪いことを示しています。rttが継続的にジッタしています。
2. Error in AddressResolver: No address associated with hostname
NTP時刻同期に失敗しました。現在のネットワーク環境でローカルの運営業者DNSの解析が一時的に異常となっている可能性があります。しばらくしてから再試行してください。
3. NTPサービスリトライ処理ロジック




リアルタイム合唱関連の使用法に関する問題

1. リアルタイム合唱シナリオで、なぜリードシンガーはダブルインスタンスでプッシュする必要がある?
リアルタイム合唱シナリオでは、エンドツーエンドの遅延をできるだけ低減し、ボーカルと伴奏を同期させるために、通常、リードシンガー側は、ボーカルと伴奏をそれぞれアップストリームするためのダブルインスタンスを使用し、他の合唱側はボーカルのみをアップストリーム、伴奏はローカルで再生する方法が採用されます。この場合、合唱側はリードシンガーストリームを購読する必要があり、同時にリードシンガー音楽ストリームは購読しないようにします。これにより、ダブルインスタンスが分離してプッシュすることが実現できます。
2. リアルタイム合唱シナリオでなぜオーディオ・ビデオストリームプッシュバックを有効にすることを推奨する?
聞き手側が同時に複数のシングルストリームをプルすると、複数のボーカルストリームと伴奏ストリームが同期しない可能性が高くなりますが、ストリームミックスをプルすることで、すべてのストリームの完全な同期を保証し、同時にダウンストリームの帯域幅を低減することができます。
3. リアルタイム合唱シナリオで、SEIの用途は?
伴奏の進行を伝達し、聞き手側の歌詞同期に使用します。
ストリームミックスパススルーシングルストリーム音量、聞き手側でのオシロスコープ表示に使用します。
4. 伴奏のロードに時間がかかり、大きな再生遅延がある時?
SDKがネットワーク音楽リソースの読み込みには時間がかかるため、再生開始前に音楽のプリロードをお勧めします。
[[self.trtcCloud getAudioEffectManager] preloadMusic:musicParam onProgress:nil onError:nil];
5. 伴奏を再生する際にボーカルが聞こえない、音楽がボーカルを圧倒している?
デフォルトの音量を使用すると伴奏がボーカルを圧倒する場合がありますので、伴奏とボーカルの音量のバランスを適切に調整することをお勧めします。
// 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];


ヘルプとサポート

この記事はお役に立ちましたか?

フィードバック