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







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を実行して確認してください。dependencies {// TRTC Lite版SDK、TRTCとライブ再生の2つの機能を含み、コンパクトなサイズimplementation 'com.tencent.liteav:LiteAVSDK_TRTC:latest.release'// TRTCフル機能版SDK, 、ライブ配信、ショートビデオ、ビデオオンデマンドなど多機能, を含み、やや大きめのサイズ// implementation 'com.tencent.liteav:LiteAVSDK_Professional:latest.release'}
defaultConfig {ndk {abiFilters "armeabi-v7a", "arm64-v8a"}}
<uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /><uses-permission android:name="android.permission.RECORD_AUDIO" /><uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /><uses-permission android:name="android.permission.BLUETOOTH" />
targetSdkVersionが31または対象デバイスがAndroid 12以上のシステムバージョンに関連している場合、Bluetooth機能を正常に使用するため、公式にはコード内でandroid.permission.BLUETOOTH_CONNECT権限を動的な申請する必要があります。詳細はBluetooth権限を参照してください。-keep class com.tencent.** { *; }

// TRTC SDKのインスタンスを作成する(シングルトンパターン)TRTCCloud mTRTCCloud = TRTCCloud.sharedInstance(context);// イベントリスナーを設定するmTRTCCloud.addListener(trtcSdkListener);// SDKからの各種イベント通知(例:エラーコード、警告コード、オーディオ・ビデオの状態パラメータなど)private TRTCCloudListener trtcSdkListener = new TRTCCloudListener() {@Overridepublic void onError(int errCode, String errMsg, Bundle extraInfo) {Log.d(TAG, errCode + errMsg);}@Overridepublic void onWarning(int warningCode, String warningMsg, Bundle extraInfo) {Log.d(TAG, warningCode + warningMsg);}};// イベントリスナーを削除mTRTCCloud.removeListener(trtcSdkListener);// TRTC SDKインスタンスを破棄する(シングルトンパターン)TRTCCloud.destroySharedInstance();
public void enterRoom(String roomId, String userId) {TRTCCloudDef.TRTCParams params = new TRTCCloudDef.TRTCParams();// 文字列のルーム番号を例にparams.strRoomId = roomId;params.userId = userId;// 業務バックエンドから取得したUserSigparams.userSig = getUserSig(userId);// 自分のSDKAppIDに置き換えるparams.sdkAppId = SDKAppID;// すべて視聴者ロールで入室する事がお勧めparams.role = TRTCCloudDef.TRTCRoleAudience;// 入室シナリオはLIVEを選択mTRTCCloud.enterRoom(params, TRTCCloudDef.TRTC_APP_SCENE_LIVE);}
TRTC_APP_SCENE_LIVEを選択することをお勧めします。// 入室結果イベントコールバック@Overridepublic void onEnterRoom(long result) {if (result > 0) {// resultは入室にかかった時間(ミリ秒)Log.d(TAG, "Enter room succeed");// ブラックフレーム挿入の実験的インターフェースを有効にするmTRTCCloud.callExperimentalAPI("{\\"api\\":\\"enableBlackStream\\",\\"params\\": {\\"enable\\":true}}");} else {// result入室失敗のエラーコードLog.d(TAG, "Enter room failed");}}
// アンカーロールに切り替えmTRTCCloud.switchRole(TRTCCloudDef.TRTCRoleAnchor);// ロール切り替えイベントコールバック@Overridepublic void onSwitchRole(int errCode, String errMsg) {if (errCode == TXLiteAVCode.ERR_NULL) {// メディア音量タイプの設定mTRTCCloud.setSystemVolumeType(TRTCCloudDef.TRTCSystemVolumeTypeMedia);// ローカルオーディオストリームを配布し、音質を設定するmTRTCCloud.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_MUSIC);}}
// オーディオエフェクト管理クラスを取得TXAudioEffectManager mTXAudioEffectManager = mTRTCCloud.getAudioEffectManager();// originMusicId: カスタム原曲識別子。originMusicUrl: 原曲リソースアドレスTXAudioEffectManager.AudioMusicParam originMusicParam = new TXAudioEffectManager.AudioMusicParam(originMusicId, originMusicUrl);// 原曲をリモートにパブリッシュ(またはローカルのみで再生)originMusicParam.publish = true;// accompMusicId: カスタム伴奏識別子。accompMusicUrl: 伴奏リソースアドレスTXAudioEffectManager.AudioMusicParam accompMusicParam = new TXAudioEffectManager.AudioMusicParam(accompMusicId, accompMusicUrl);// 伴奏をリモートにパブリッシュ(またはローカルのみで再生)accompMusicParam.publish = true;// 原曲の再生を開始mTXAudioEffectManager.startPlayMusic(originMusicParam);// 伴奏の再生を開始mTXAudioEffectManager.startPlayMusic(accompMusicParam);// 原曲に切り替えるmTXAudioEffectManager.setMusicPlayoutVolume(originMusicId, 100);mTXAudioEffectManager.setMusicPlayoutVolume(accompMusicId, 0);mTXAudioEffectManager.setMusicPublishVolume(originMusicId, 100);mTXAudioEffectManager.setMusicPublishVolume(accompMusicId, 0);// 伴奏に切り替えるmTXAudioEffectManager.setMusicPlayoutVolume(originMusicId, 0);mTXAudioEffectManager.setMusicPlayoutVolume(accompMusicId, 100);mTXAudioEffectManager.setMusicPublishVolume(originMusicId, 0);mTXAudioEffectManager.setMusicPublishVolume(accompMusicId, 100);
mTXAudioEffectManager.setMusicObserver(musicId, new TXAudioEffectManager.TXMusicPlayObserver() {@Overridepublic void onStart(int id, int errCode) {// 音楽再生を開始}@Overridepublic void onPlayProgress(int id, long curPtsMs, long durationMs) {// 最新の進行状況とローカルの歌詞の進行状況の誤差に基づいて、seekが必要かどうかを判断する// SEIメッセージを送信して曲の進行状況を伝えるtry {JSONObject jsonObject = new JSONObject();jsonObject.put("musicId", id);jsonObject.put("progress", curPtsMs);jsonObject.put("duration", durationMs);mTRTCCloud.sendSEIMsg(jsonObject.toString().getBytes(), 1);} catch (JSONException e) {e.printStackTrace();}}@Overridepublic void onComplete(int id, int errCode) {// 音楽再生完了}});
// 視聴者ロールに切り替えるmTRTCCloud.switchRole(TRTCCloudDef.TRTCRoleAudience);// ロール切り替えイベントコールバック@Overridepublic void onSwitchRole(int errCode, String errMsg) {if (errCode == TXLiteAVCode.ERR_NULL) {// 伴奏の再生を停止mTRTCCloud.getAudioEffectManager().stopPlayMusic(musicId);// ローカルオーディオのキャプチャーとパブリッシュを停止するmTRTCCloud.stopLocalAudio();}}// ルームから退出mTRTCCloud.exitRoom();// 退室イベントコールバック@Overridepublic void onExitRoom(int reason) {if (reason == 0) {Log.d(TAG, "exitRoomアクティブコールでルーム退出します");} else if (reason == 1) {Log.d(TAG, "現在のルームからサーバーによってキックされました");} else if (reason == 2) {Log.d(TAG, "現在のルームは解散されました");}}
onExitRoomコールバック通知をスローして知らせます。enterRoomを呼び出す場合や他のオーディオ・ビデオSDKに切り替える場合は、onExitRoomのコールバックが返ってくるまで関連操作を行わないでください。そうしないと、カメラやマイクが強制的に使用されるなど、さまざまな異常が発生する可能性があります。public void enterRoom(String roomId, String userId) {TRTCCloudDef.TRTCParams params = new TRTCCloudDef.TRTCParams();// 文字列のルーム番号を例にparams.strRoomId = roomId;params.userId = userId;// 業務バックエンドから取得したUserSigparams.userSig = getUserSig(userId);// 自分のSDKAppIDに置き換えるparams.sdkAppId = SDKAppID;// すべて視聴者ロールで入室する事がお勧めparams.role = TRTCCloudDef.TRTCRoleAudience;// 入室シナリオはLIVEを選択mTRTCCloud.enterRoom(params, TRTCCloudDef.TRTC_APP_SCENE_LIVE);}// 入室結果イベントコールバック@Overridepublic void onEnterRoom(long result) {if (result > 0) {// resultは入室にかかった時間(ミリ秒)Log.d(TAG, "Enter room succeed");} else {// result入室失敗のエラーコードLog.d(TAG, "Enter room failed");}}
TRTC_APP_SCENE_LIVEを選択することをお勧めします。@Overridepublic void onUserVideoAvailable(String userId, boolean available) {if (available) {mTRTCCloud.startRemoteView(userId, null);} else {mTRTCCloud.stopRemoteView(userId);}}@Overridepublic void onRecvSEIMsg(String userId, byte[] data) {String result = new String(data);try {JSONObject jsonObject = new JSONObject(result);int musicId = jsonObject.getInt("musicId");long progress = jsonObject.getLong("progress");long duration = jsonObject.getLong("duration");} catch (JSONException e) {e.printStackTrace();}...// TODO歌詞コントロールロジックの更新:// 受信した最新の進行状況とローカルの歌詞進行の誤差に基づいて、歌詞コントロールがseekする必要があるかどうかを判断します。...}
// ルームから退出mTRTCCloud.exitRoom();// 退室イベントコールバック@Overridepublic void onExitRoom(int reason) {if (reason == 0) {Log.d(TAG, "exitRoomアクティブコールでルーム退出します");} else if (reason == 1) {Log.d(TAG, "現在のルームからサーバーによってキックされました");} else if (reason == 2) {Log.d(TAG, "現在のルームは解散されました");}}
// TRTCCloudマスターインスタンス(ボーカルインスタンス)を作成TRTCCloud mTRTCCloud = TRTCCloud.sharedInstance(context);// TRTCCloudサブインスタンス(インストゥルメンタルインスタンス)を作成TRTCCloud subCloud = mTRTCCloud.createSubCloud();// マスターインスタンス(ボーカルインスタンス)が入室TRTCCloudDef.TRTCParams params = new TRTCCloudDef.TRTCParams();params.sdkAppId = SDKAppId;params.userId = UserId;params.userSig = UserSig;params.role = TRTCCloudDef.TRTCRoleAnchor;params.strRoomId = RoomId;mTRTCCloud.enterRoom(params, TRTCCloudDef.TRTC_APP_SCENE_LIVE);// サブインスタンスが手動購読モードを開始し、デフォルトではリモートストリームを購読しないsubCloud.setDefaultStreamRecvMode(false, false);// サブインスタンス(インストゥルメンタルインスタンス)が入室TRTCCloudDef.TRTCParams bgmParams = new TRTCCloudDef.TRTCParams();bgmParams.sdkAppId = SDKAppId;// サブインスタンスのユーザー名は、ルーム内の他のユーザーと重複してはいけません。bgmParams.userId = UserId + "_bgm";bgmParams.userSig = UserSig;bgmParams.role = TRTCCloudDef.TRTCRoleAnchor;bgmParams.strRoomId = RoomId;subCloud.enterRoom(bgmParams, TRTCCloudDef.TRTC_APP_SCENE_LIVE);
// マスターインスタンスの入室結果イベントコールバック@Overridepublic void onEnterRoom(long result) {if (result > 0) {// マスターインスタンスがサブインスタンスがパブリッシュした音楽ストリームの購読をキャンセルmTRTCCloud.muteRemoteAudio(UserId + "_bgm", true);// マスターインスタンスがブラックフレーム挿入の実験的インターフェースを開始mTRTCCloud.callExperimentalAPI("{\\"api\\":\\"enableBlackStream\\",\\"params\\": {\\"enable\\":true}}");// マスターインスタンスが合唱モードの実験的インターフェースを開始mTRTCCloud.callExperimentalAPI("{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":true,\\"audioSource\\":0}}");// マスターインスタンスが低遅延モードの実験的インターフェースを開始mTRTCCloud.callExperimentalAPI("{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":true}}");// マスターインスタンスが音量コールバックを有効にするmTRTCCloud.enableAudioVolumeEvaluation(300, false);// マスターインスタンス全過程のメディア音量タイプを設定mTRTCCloud.setSystemVolumeType(TRTCCloudDef.TRTCSystemVolumeTypeMedia);// マスターインスタンスがローカルオーディオをキャプチャー・パブリッシュし、同時に音質を設定mTRTCCloud.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_MUSIC);} else {// result入室失敗のエラーコードLog.d(TAG, "Enter room failed");}}// サブインスタンスの入室結果イベントコールバック@Overridepublic void onEnterRoom(long result) {if (result > 0) {// サブインスタンスで合唱モードの実験的インターフェースを有効にするsubCloud.callExperimentalAPI("{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":true,\\"audioSource\\":1}}");// サブインスタンスが低遅延モードの実験的インターフェースを開始subCloud.callExperimentalAPI("{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":true}}");// サブインスタンスの全過程のメディア音量タイプを設定subCloud.setSystemVolumeType(TRTCCloudDef.TRTCSystemVolumeTypeMedia);// サブインスタンスの音質設定subCloud.setAudioQuality(TRTCCloudDef.TRTC_AUDIO_QUALITY_MUSIC);} else {// result入室失敗のエラーコードLog.d(TAG, "Enter room failed");}}
audioSourceパラメータの違いに注意する必要があります。private void startPublishMediaToRoom(String roomId, String userId) {// TRTCPublishTargetオブジェクトを作成TRTCCloudDef.TRTCPublishTarget target = new TRTCCloudDef.TRTCPublishTarget();// ミキシング後にルームにプッシュバックtarget.mode = TRTCCloudDef.TRTC_PublishMixStream_ToRoom;target.mixStreamIdentity.strRoomId = roomId;// ミキシングロボットのユーザー名は、ルーム内の他のユーザーと重複してはいけません。target.mixStreamIdentity.userId = userId + "_robot";// トランスコード後のオーディオストリームのエンコードパラメータを設定する(カスタマイズ可能)TRTCCloudDef.TRTCStreamEncoderParam trtcStreamEncoderParam = new TRTCCloudDef.TRTCStreamEncoderParam();trtcStreamEncoderParam.audioEncodedChannelNum = 2;trtcStreamEncoderParam.audioEncodedKbps = 64;trtcStreamEncoderParam.audioEncodedCodecType = 2;trtcStreamEncoderParam.audioEncodedSampleRate = 48000;// トランスコード後のビデオストリームのエンコードパラメータを設定する(ブラックフレームの挿入が必要)trtcStreamEncoderParam.videoEncodedFPS = 15;trtcStreamEncoderParam.videoEncodedGOP = 3;trtcStreamEncoderParam.videoEncodedKbps = 30;trtcStreamEncoderParam.videoEncodedWidth = 64;trtcStreamEncoderParam.videoEncodedHeight = 64;// オーディオストリームミックスのパラメータを設定TRTCCloudDef.TRTCStreamMixingConfig trtcStreamMixingConfig = new TRTCCloudDef.TRTCStreamMixingConfig();// デフォルトでは空欄のままで大丈夫です。これは、ルーム内のすべてのオーディオがミキシングされることを意味します。trtcStreamMixingConfig.audioMixUserList = null;// ビデオストリームミックステンプレートの配置(ブラックフレームを挿入する場合は必須)TRTCCloudDef.TRTCVideoLayout videoLayout = new TRTCCloudDef.TRTCVideoLayout();trtcStreamMixingConfig.videoLayoutList.add(videoLayout);// オーディオ・ビデオストリームプッシュバックを開始mTRTCCloud.startPublishMediaStream(target, trtcStreamEncoderParam, trtcStreamMixingConfig);}
TXLiveBase.setListener(new TXLiveBaseListener() {@Overridepublic void onUpdateNetworkTime(int errCode, String errMsg) {super.onUpdateNetworkTime(errCode, errMsg);// errCode 0: 時刻同期成功、偏差は30ms以内。1: 時刻同期成功、しかし偏差は30ms以上の可能性あります。-1: 時刻同期失敗if (errCode == 0) {// 時刻同期成功、NTPタイムスタンプを取得long ntpTime = TXLiveBase.getNetworkTimestamp();} else {// 時刻同期に失敗しました。時刻同期を再試行してください。TXLiveBase.updateNetworkTime();}}});TXLiveBase.updateNetworkTime();
Timer mTimer = new Timer();mTimer.schedule(new TimerTask() {@Overridepublic void run() {try {JSONObject jsonObject = new JSONObject();jsonObject.put("cmd", "startChorus");// 合唱開始時間を設定: 現在のNTP時間+遅延再生時間(例:3秒)jsonObject.put("startPlayMusicTS", TXLiveBase.getNetworkTimestamp() + 3000);jsonObject.put("musicId", musicId);jsonObject.put("musicDuration", subCloud.getAudioEffectManager().getMusicDurationInMS(originMusicUri));mTRTCCloud.sendCustomCmdMsg(1, jsonObject.toString().getBytes(), false, false);} catch (JSONException e) {e.printStackTrace();}}}, 0, 1000);
// オーディオエフェクト管理クラスを取得TXAudioEffectManager mTXAudioEffectManager = subCloud.getAudioEffectManager();// originMusicId: カスタム原曲識別子。originMusicUrl: 原曲リソースアドレスTXAudioEffectManager.AudioMusicParam originMusicParam = new TXAudioEffectManager.AudioMusicParam(originMusicId, originMusicUrl);// 原曲をリモートにパブリッシュoriginMusicParam.publish = true;// 音楽再生を開始するタイムスタンプ(ミリ秒)originMusicParam.startTimeMS = 0;// accompMusicId: カスタム伴奏識別子。accompMusicUrl: 伴奏リソースアドレスTXAudioEffectManager.AudioMusicParam accompMusicParam = new TXAudioEffectManager.AudioMusicParam(accompMusicId, accompMusicUrl);// 伴奏をリモートにパブリッシュaccompMusicParam.publish = true;// 音楽再生を開始するタイムスタンプ(ミリ秒)accompMusicParam.startTimeMS = 0;// 原曲のプリロードmTXAudioEffectManager.preloadMusic(originMusicParam);// 伴奏をプリロードmTXAudioEffectManager.preloadMusic(accompMusicParam);// 遅延再生時間(例えば3秒)後に原曲を再生開始mTXAudioEffectManager.startPlayMusic(originMusicParam);// 遅延再生時間(例えば3秒)後に伴奏を再生開始mTXAudioEffectManager.startPlayMusic(accompMusicParam);// 原曲に切り替えるmTXAudioEffectManager.setMusicPlayoutVolume(originMusicId, 100);mTXAudioEffectManager.setMusicPlayoutVolume(accompMusicId, 0);mTXAudioEffectManager.setMusicPublishVolume(originMusicId, 100);mTXAudioEffectManager.setMusicPublishVolume(accompMusicId, 0);// 伴奏に切り替えるmTXAudioEffectManager.setMusicPlayoutVolume(originMusicId, 0);mTXAudioEffectManager.setMusicPlayoutVolume(accompMusicId, 100);mTXAudioEffectManager.setMusicPublishVolume(originMusicId, 0);mTXAudioEffectManager.setMusicPublishVolume(accompMusicId, 100);
// 約束の合唱開始時間long mStartPlayMusicTs = jsonObject.getLong("startPlayMusicTS");// 現在伴奏の実際の再生進行状況long currentProgress = subCloud.getAudioEffectManager().getMusicCurrentPosInMS(musicId);// 現在伴奏の理想的な再生進行状況long estimatedProgress = TXLiveBase.getNetworkTimestamp() - mStartPlayMusicTs;// 進捗差が50msを超えた場合、修正を行うif (estimatedProgress >= 0 && Math.abs(currentProgress - estimatedProgress) > 50) {subCloud.getAudioEffectManager().seekMusicToPosInMS(musicId, (int) estimatedProgress);}
mTXAudioEffectManager.setMusicObserver(musicId, new TXAudioEffectManager.TXMusicPlayObserver() {@Overridepublic void onStart(int id, int errCode) {// 音楽再生を開始}@Overridepublic void onPlayProgress(int id, long curPtsMs, long durationMs) {// 最新の進行状況とローカルの歌詞の進行状況の誤差に基づいて、seekが必要かどうかを判断する// SEIメッセージを送信して曲の進行状況を伝えるtry {JSONObject jsonObject = new JSONObject();jsonObject.put("musicId", id);jsonObject.put("progress", curPtsMs);jsonObject.put("duration", durationMs);mTRTCCloud.sendSEIMsg(jsonObject.toString().getBytes(), 1);} catch (JSONException e) {e.printStackTrace();}}@Overridepublic void onComplete(int id, int errCode) {// 音楽再生完了}});
// サブインスタンスが合唱モードの実験的インターフェースを停止subCloud.callExperimentalAPI("{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":false,\\"audioSource\\":1}}");// サブインスタンスが低遅延モードの実験的インターフェースを停止subCloud.callExperimentalAPI("{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":false}}");// サブインスタンスが視聴者ロールに切り替わるsubCloud.switchRole(TRTCCloudDef.TRTCRoleAudience);// サブインスタンスが伴奏の再生を停止subCloud.getAudioEffectManager().stopPlayMusic(musicId);// サブインスタンスがルームから退出subCloud.exitRoom();// マスターインスタンスがブラックフレーム挿入の実験的インターフェースを停止mTRTCCloud.callExperimentalAPI("{\\"api\\":\\"enableBlackStream\\",\\"params\\": {\\"enable\\":false}}");// マスターインスタンスが合唱モードの実験的インターフェースを停止mTRTCCloud.callExperimentalAPI("{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":false,\\"audioSource\\":0}}");// マスターインスタンスが低遅延モードの実験的インターフェイスを停止mTRTCCloud.callExperimentalAPI("{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":false}}");// マスターインスタンスが視聴者ロールに切り替わるmTRTCCloud.switchRole(TRTCCloudDef.TRTCRoleAudience);// マスターインスタンスがローカルオーディオのキャプチャーとパブリッシュを停止mTRTCCloud.stopLocalAudio();// マスターインスタンスがルームから退出mTRTCCloud.exitRoom();
public void enterRoom(String roomId, String userId) {TRTCCloudDef.TRTCParams params = new TRTCCloudDef.TRTCParams();// 文字列のルーム番号を例にparams.strRoomId = roomId;params.userId = userId;// 業務バックエンドから取得したUserSigparams.userSig = getUserSig(userId);// 自分のSDKAppIDに置き換えるparams.sdkAppId = SDKAppID;// サンプルは視聴者ロールとして入室params.role = TRTCCloudDef.TRTCRoleAudience;// 入室シナリオはLIVEを選択mTRTCCloud.enterRoom(params, TRTCCloudDef.TRTC_APP_SCENE_LIVE);}// 入室結果イベントコールバック@Overridepublic void onEnterRoom(long result) {if (result > 0) {// resultは入室にかかった時間(ミリ秒)Log.d(TAG, "Enter room succeed");} else {// result入室失敗のエラーコードLog.d(TAG, "Enter room failed");}}
// アンカーロールに切り替えmTRTCCloud.switchRole(TRTCCloudDef.TRTCRoleAnchor);// ロール切り替えイベントコールバック@Overridepublic void onSwitchRole(int errCode, String errMsg) {if (errCode == TXLiteAVCode.ERR_NULL) {// リードシンガーのサブインスタンスがパブリッシュする音楽ストリームの購読を解除mTRTCCloud.muteRemoteAudio(mBgmUserId, true);// 合唱モードの実験的インターフェースを開始mTRTCCloud.callExperimentalAPI("{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":true,\\"audioSource\\":0}}");// 低遅延モードの実験的インターフェースを開始mTRTCCloud.callExperimentalAPI("{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":true}}");// メディア音量タイプの設定mTRTCCloud.setSystemVolumeType(TRTCCloudDef.TRTCSystemVolumeTypeMedia);// ローカルオーディオストリームを配布し、音質を設定するmTRTCCloud.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_MUSIC);}}
TXLiveBase.setListener(new TXLiveBaseListener() {@Overridepublic void onUpdateNetworkTime(int errCode, String errMsg) {super.onUpdateNetworkTime(errCode, errMsg);// errCode 0: 時刻同期成功、偏差は30ms以内;1: 時刻同期成功、しかし偏差は30ms以上の可能性あり;-1: 時刻同期失敗if (errCode == 0) {// 時刻同期成功、NTPタイムスタンプを取得long ntpTime = TXLiveBase.getNetworkTimestamp();} else {// 時刻同期に失敗しました。時刻同期を再試行してくださいTXLiveBase.updateNetworkTime();}}});TXLiveBase.updateNetworkTime();
@Overridepublic void onRecvCustomCmdMsg(String userId, int cmdID, int seq, byte[] message) {try {JSONObject json = new JSONObject(new String(message, "UTF-8"));// 合唱シグナルのマッチングif (json.getString("cmd").equals("startChorus")) {long startPlayMusicTs = json.getLong("startPlayMusicTS");int musicId = json.getInt("musicId");long musicDuration = json.getLong("musicDuration");// 約束合唱時間と現在の時間との差long delayMs = startPlayMusicTs - TXLiveBase.getNetworkTimestamp();}} catch (JSONException e) {e.printStackTrace();}}
if (delayMs > 0) { // 合唱未開始// 音楽のプリロードを開始preloadMusic(musicId, 0L);// delayMs遅延後に音楽の再生を開始startPlayMusic(musicId, 0L);} else if (Math.abs(delayMs) < musicDuration) { // 合唱進行中// 再生開始時間: 時間差の絶対値+プリロード遅延(例:400ms)long startTimeMS = Math.abs(delayMs) + 400;// 音楽のプリロードを開始preloadMusic(musicId, startTimeMS);// プリロード遅延(例:400ms)後に音楽の再生を開始startPlayMusic(musicId, startTimeMS);} else { // 合唱終了// 合唱への参加は許可されない}// 音楽をプリロードするpublic void preloadMusic(int musicId, long startTimeMS) {// musicId: 合唱シグナルから取得。musicUrl: 対応する音楽リソースのアドレスTXAudioEffectManager.AudioMusicParam musicParam = newTXAudioEffectManager.AudioMusicParam(musicId, musicUrl);// 音楽をローカルでのみ再生musicParam.publish = false;// 音楽再生を開始するタイムスタンプ(ミリ秒)musicParam.startTimeMS = startTimeMS;mTRTCCloud.getAudioEffectManager().preloadMusic(musicParam);}// 音楽の再生を開始public void startPlayMusic(int musicId, long startTimeMS) {// musicId: 合唱シグナルから取得。musicUrl: 対応する音楽リソースのアドレスTXAudioEffectManager.AudioMusicParam musicParam = newTXAudioEffectManager.AudioMusicParam(musicId, musicUrl);// 音楽をローカルでのみ再生musicParam.publish = false;// 音楽再生を開始するタイムスタンプ(ミリ秒)musicParam.startTimeMS = startTimeMS;mTRTCCloud.getAudioEffectManager().startPlayMusic(musicParam);}
delayMsに基づいて、現在の合唱状態を判断できます。異なる状態のstartPlayMusic遅延呼び出しは、開発者が自分で実装する必要があります。// 約束の合唱開始時間long mStartPlayMusicTs = jsonObject.getLong("startPlayMusicTS");// 現在伴奏の実際の再生進行状況long currentProgress = mTRTCCloud.getAudioEffectManager().getMusicCurrentPosInMS(musicId);// 現在伴奏の理想的な再生進行状況long estimatedProgress = TXLiveBase.getNetworkTimestamp() - mStartPlayMusicTs;// 進捗差が50msを超えた場合、修正を行うif (estimatedProgress >= 0 && Math.abs(currentProgress - estimatedProgress) > 50) {mTRTCCloud.getAudioEffectManager().seekMusicToPosInMS(musicId, (int) estimatedProgress);}
mTXAudioEffectManager.setMusicObserver(musicId, new TXAudioEffectManager.TXMusicPlayObserver() {@Overridepublic void onStart(int id, int errCode) {// 音楽再生を開始}@Overridepublic void onPlayProgress(int id, long curPtsMs, long durationMs) {// TODO歌詞コントロールロジックの更新:// 最新の進行状況とローカルの歌詞進行の誤差に基づいて、seek歌詞コントロールが必要があるかどうかを判断}@Overridepublic void onComplete(int id, int errCode) {// 音楽再生完了}});
// 合唱モードの実験的インターフェースを停止mTRTCCloud.callExperimentalAPI("{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":false,\\"audioSource\\":0}}");// 低遅延モードの実験的インターフェースを停止mTRTCCloud.callExperimentalAPI("{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":false}}");// 視聴者ロールに切り替えるmTRTCCloud.switchRole(TRTCCloudDef.TRTCRoleAudience);// 伴奏の再生を停止mTRTCCloud.getAudioEffectManager().stopPlayMusic(musicId);// ローカルオーディオのキャプチャーとパブリッシュを停止mTRTCCloud.stopLocalAudio();// ルームから退出mTRTCCloud.exitRoom();
public void enterRoom(String roomId, String userId) {TRTCCloudDef.TRTCParams params = new TRTCCloudDef.TRTCParams();// 文字列のルーム番号を例にparams.strRoomId = roomId;params.userId = userId;// 業務バックエンドから取得したUserSigparams.userSig = getUserSig(userId);// 自分のSDKAppIDに置き換えるparams.sdkAppId = SDKAppID;// すべて視聴者ロールで入室する事がお勧めparams.role = TRTCCloudDef.TRTCRoleAudience;// 入室シナリオはLIVEを選択mTRTCCloud.enterRoom(params, TRTCCloudDef.TRTC_APP_SCENE_LIVE);}// 入室結果イベントコールバック@Overridepublic void onEnterRoom(long result) {if (result > 0) {// resultは入室にかかった時間(ミリ秒)Log.d(TAG, "Enter room succeed");} else {// result入室失敗のエラーコードLog.d(TAG, "Enter room failed");}}
TRTC_APP_SCENE_LIVEを選択することをお勧めします。@Overridepublic void onUserVideoAvailable(String userId, boolean available) {if (available) {mTRTCCloud.startRemoteView(userId, null);} else {mTRTCCloud.stopRemoteView(userId);}}@Overridepublic void onRecvSEIMsg(String userId, byte[] data) {String result = new String(data);try {JSONObject jsonObject = new JSONObject(result);int musicId = jsonObject.getInt("musicId");long progress = jsonObject.getLong("progress");long duration = jsonObject.getLong("duration");} catch (JSONException e) {e.printStackTrace();}...// TODO歌詞コントロールロジックの更新:// 受信した最新の進行状況とローカルの歌詞進行の誤差に基づいて、歌詞コントロールがseekする必要があるかどうかを判断します。...}
// ルームから退出mTRTCCloud.exitRoom();// 退室イベントコールバック@Overridepublic void onExitRoom(int reason) {if (reason == 0) {Log.d(TAG, "exitRoomアクティブコールでルーム退出します");} else if (reason == 1) {Log.d(TAG, "現在のルームからサーバーによってキックされました");} else if (reason == 2) {Log.d(TAG, "現在のルームは解散されました");}}
{"action": "CreateJob","secretId": "{secretId}","secretKey": "{secretKey}","createJobRequest": {"customId": "{customId}","callback": "{callback}","inputs": [{ "url": "{url}" }],"outputs": [{"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": [{"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"}}]}}}
@Overridepublic void onUserVoiceVolume(ArrayList<TRTCCloudDef.TRTCVolumeInfo> userVolumes, int totalVolume) {super.onUserVoiceVolume(userVolumes, totalVolume);if (userVolumes != null && userVolumes.size() > 0) {// マイクオンユーザーに対応する音量値を保存するために使用HashMap<String, Integer> volumesMap = new HashMap<>();for (TRTCCloudDef.TRTCVolumeInfo user : userVolumes) {// 適切な音量のしきい値を設定できますif (user.volume > 10) {volumesMap.put(user.userId, user.volume);}}Gson gson = new Gson();String body = gson.toJson(volumesMap);// SEIメッセージを通じてマイクオンユーザーの音量セットを送信mTRTCCloud.sendSEIMsg(body.getBytes(), 1);}}@Overridepublic void onRecvSEIMsg(String userId, byte[] data) {Gson gson = new Gson();HashMap<String, Integer> volumesMap = new HashMap<>();try {String message = new String(data, "UTF-8");volumesMap = gson.fromJson(message, volumesMap.getClass());for (String userId : volumesMap.keySet()) {// すべてのマイクオンユーザーのシングルストリームの音量をプリントLog.i(userId, String.valueOf(volumesMap.get(userId)));}} catch (UnsupportedEncodingException e) {e.printStackTrace();}}
onNetworkQualityをリスニングすることができます。このコールバックは2秒ごとに一度発生します。private class TRTCCloudImplListener extends TRTCCloudListener {@Overridepublic void onNetworkQuality(TRTCCloudDef.TRTCQuality localQuality,ArrayList<TRTCCloudDef.TRTCQuality> remoteQuality) {// localQuality userIdは空、ローカルユーザーのネットワーク品質評価結果を表します// remoteQualityは、リモートユーザーのネットワーク品質評価結果を表しており、その結果はリモートとローカルの両方の影響を受けます。switch (localQuality.quality) {case TRTCCloudDef.TRTC_QUALITY_Excellent:Log.i(TAG, "現在のネットワークは非常に良い");break;case TRTCCloudDef.TRTC_QUALITY_Good:Log.i(TAG, "現在のネットワークは比較的良い");break;case TRTCCloudDef.TRTC_QUALITY_Poor:Log.i(TAG, "現在のネットワークは普通");break;case TRTCCloudDef.TRTC_QUALITY_Bad:Log.i(TAG, "現在のネットワークが不安定");break;case TRTCCloudDef.TRTC_QUALITY_Vbad:Log.i(TAG, "現在のネットワークが非常に悪い");break;case TRTCCloudDef.TRTC_QUALITY_Down:Log.i(TAG, "現在のネットワークはTRTC最低要件を満たしていない");break;default:Log.i(TAG, "未定義");break;}}}

TRTCParamsでprivateMapKeyパラメータを渡す必要があります。したがって、このSDKAppIDをオンラインで使用しているユーザーがいる場合、この機能を安易には有効にしないでください。TRTCCloudDef.TRTCParams mTRTCParams = new TRTCCloudDef.TRTCParams();mTRTCParams.sdkAppId = SDKAPPID;mTRTCParams.userId = mUserId;mTRTCParams.strRoomId = mRoomId;// 業務バックエンドから取得したUserSigmTRTCParams.userSig = getUserSig();// 業務バックエンドから取得したPrivateMapKeymTRTCParams.privateMapKey = getPrivateMapKey();mTRTCParams.role = TRTCCloudDef.TRTCRoleAudience;mTRTCCloud.enterRoom(mTRTCParams, TRTCCloudDef.TRTC_APP_SCENE_LIVE);
// 業務バックエンドから最新のPrivateMapKeyを取得し、ロール切り替えインターフェースに渡します。mTRTCCloud.switchRole(TRTCCloudDef.TRTCRoleAnchor, 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 | マイクが使用中です。たとえば、モバイルデバイスが通話中の場合、マイクを開くと失敗します。 |
// イヤーモニターを有効にするmTRTCCloud.getAudioEffectManager().enableVoiceEarMonitor(true);// イヤーモニター音量の設定mTRTCCloud.getAudioEffectManager().setVoiceEarMonitorVolume(int volume);
setSystemAudioKitEnabledを通じてハードウェアイヤーモニターを有効にすることで、イヤーモニターの遅延が過度に高い問題を改善することができます。ハードウェアイヤーモニターはパフォーマンスが良く、遅延が少ないですが、ソフトウェアイヤーモニターは遅延が高いものの、互換性が良いです。現在、HuaweiおよびVIVOデバイスについては、SDKはデフォルトでハードウェアイヤーモニターを使用していますが、他のデバイスはデフォルトでソフトウェアイヤーモニターを使用しています。ハードウェアイヤーモニターに互換性の問題がある場合は、お問い合わせにてソフトウェアイヤーモニターを強制的に使用するよう設定することができます。
public static void copyAssetsToFile(Context context, String name) {// アプリケーション自体のディレクトリ内のfilesディレクトリString savePath = ContextCompat.getExternalFilesDirs(context, null)[0].getAbsolutePath();// アプリケーション自体のディレクトリ内のcacheディレクトリ// String savePath = getApplication().getExternalCacheDir().getAbsolutePath();// アプリケーションのプライベートストレージディレクトリ内のfilesディレクトリ// String savePath = getApplication().getFilesDir().getAbsolutePath();String filename = savePath + "/" + name;File dir = new File(savePath);// ディレクトリが存在しない場合、このディレクトリを作成if (!dir.exists()) {dir.mkdir();}try {if (!(new File(filename)).exists()) {InputStream is = context.getResources().getAssets().open(name);FileOutputStream fos = new FileOutputStream(filename);byte[] buffer = new byte[1024];int count = 0;while ((count = is.read(buffer)) > 0) {fos.write(buffer, 0, count);}fos.close();is.close();}} catch (Exception e) {e.printStackTrace();}}
android:requestLegacyExternalStorage="true"。この属性はtargetSdkVersionが29(Android 10)のアプリケーションでのみ有効で、より高いバージョンのtargetSdkVersionのアプリケーションでは、アプリのプライベートまたは外部ストレージパスの使用を引き続き推奨します。MANAGE_EXTERNAL_STORAGE権限の申請が必要です。<manifest ...><!-- This is the permission itself --><uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /><application ...>...</application></manifest>
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {if (!Environment.isExternalStorageManager()) {Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);Uri uri = Uri.fromParts("package", getPackageName(), null);intent.setData(uri);startActivity(intent);}} else {// For Android versions less than Android 11, you can use the old permissions modelActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);}
mTRTCCloud.getAudioEffectManager().preloadMusic(musicParam);
// BGMのローカル再生ボリュームの設定mTRTCCloud.getAudioEffectManager().setMusicPlayoutVolume(musicID, volume);// BGMのリモート再生ボリュームの設定mTRTCCloud.getAudioEffectManager().setMusicPublishVolume(musicID, volume);// すべてのBGMのローカルとリモート音量の設定mTRTCCloud.getAudioEffectManager().setAllMusicVolume(volume);// ボーカルのキャプチャーボリュームの設定mTRTCCloud.getAudioEffectManager().setVoiceCaptureVolume(volume);
フィードバック