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": "Download the python version demo file [UIN_demo/run_musicBeat.py] from the COS bucket [CosConfig.bucket], replace the input file in the demo, and then execute python run_musicBeat.py","message": "Registration successful, and thank you for registering.","createdAt": <createdAt>,"updatedAt": <updatedAt>}}
demoCosPath
directory. Execute the command python run_musicBeat.py
in a networked environment for verification.dependencies {// TRTC Lite SDK. It includes TRTC and live streaming playback features and is compact in size.implementation 'com.tencent.liteav:LiteAVSDK_TRTC:latest.release'// TRTC Professional SDK. It also includes live streaming, short video, video on demand, and other features, and is slightly larger in size.// 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
is 31 or higher, or if the target device runs Android 12 or a newer version, the official requirement is to dynamically request android.permission.BLUETOOTH_CONNECT
permission in the code to use the Bluetooth feature properly. For more information, see Bluetooth Permissions.-keep class com.tencent.** { *; }
// Create TRTC SDK instance (Single Instance Pattern).TRTCCloud mTRTCCloud = TRTCCloud.sharedInstance(context);// Set event listeners.mTRTCCloud.addListener(trtcSdkListener);// Notifications from various SDK events (e.g., error codes, warning codes, audio and video status parameters, etc.).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);}};// Remove event listener.mTRTCCloud.removeListener(trtcSdkListener);// Terminate TRTC SDK instance (Singleton Pattern).TRTCCloud.destroySharedInstance();
public void enterRoom(String roomId, String userId) {TRTCCloudDef.TRTCParams params = new TRTCCloudDef.TRTCParams();// Take the room ID string as an example.params.strRoomId = roomId;params.userId = userId;// UserSig obtained from the business backend.params.userSig = getUserSig(userId);// Replace with your SDKAppID.params.sdkAppId = SDKAppID;// It is recommended to enter the room as an audience role.params.role = TRTCCloudDef.TRTCRoleAudience;// LIVE should be selected for the room entry scenario.mTRTCCloud.enterRoom(params, TRTCCloudDef.TRTC_APP_SCENE_LIVE);}
TRTC_APP_SCENE_LIVE
for room-entry scenarios.// Event callback for the result of entering the room.@Overridepublic void onEnterRoom(long result) {if (result > 0) {// result indicates the time taken (in milliseconds) to join the room.Log.d(TAG, "Enter room succeed");// Enable the experimental API for black frame insertion.mTRTCCloud.callExperimentalAPI("{\\"api\\":\\"enableBlackStream\\",\\"params\\": {\\"enable\\":true}}");} else {// result indicates the error code when you fail to enter the room.Log.d(TAG, "Enter room failed");}}
// Switched to the anchor role.mTRTCCloud.switchRole(TRTCCloudDef.TRTCRoleAnchor);// Event callback for switching the role.@Overridepublic void onSwitchRole(int errCode, String errMsg) {if (errCode == TXLiteAVCode.ERR_NULL) {// Set media volume type.mTRTCCloud.setSystemVolumeType(TRTCCloudDef.TRTCSystemVolumeTypeMedia);// Upstream local audio streams and set audio quality.mTRTCCloud.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_MUSIC);}}
// Obtain audio effects management.TXAudioEffectManager mTXAudioEffectManager = mTRTCCloud.getAudioEffectManager();// originMusicId: Custom identifier for the original vocal music. originMusicUrl: URL of the original vocal music resource.TXAudioEffectManager.AudioMusicParam originMusicParam = new TXAudioEffectManager.AudioMusicParam(originMusicId, originMusicUrl);// Whether to publish the original vocal music to remote (otherwise play locally only).originMusicParam.publish = true;// accompMusicId: Custom identifier for the accompaniment music. accompMusicUrl: URL of the accompaniment music resource.TXAudioEffectManager.AudioMusicParam accompMusicParam = new TXAudioEffectManager.AudioMusicParam(accompMusicId, accompMusicUrl);// Whether to publish the accompaniment to remote (otherwise play locally only).accompMusicParam.publish = true;// Start playing the original vocal music.mTXAudioEffectManager.startPlayMusic(originMusicParam);// Start playing the accompaniment music.mTXAudioEffectManager.startPlayMusic(accompMusicParam);// Switch to the original vocal music.mTXAudioEffectManager.setMusicPlayoutVolume(originMusicId, 100);mTXAudioEffectManager.setMusicPlayoutVolume(accompMusicId, 0);mTXAudioEffectManager.setMusicPublishVolume(originMusicId, 100);mTXAudioEffectManager.setMusicPublishVolume(accompMusicId, 0);// Switch to the accompaniment music.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) {// Start playing music.}@Overridepublic void onPlayProgress(int id, long curPtsMs, long durationMs) {// Determine whether seek is needed based on the latest progress and the local lyrics progress deviation.// Song progress is transmitted by sending an SEI message.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) {// Music playback completed.}});
// Switched to the audience role.mTRTCCloud.switchRole(TRTCCloudDef.TRTCRoleAudience);// Event callback for switching the role.@Overridepublic void onSwitchRole(int errCode, String errMsg) {if (errCode == TXLiteAVCode.ERR_NULL) {// Stop playing accompaniment music.mTRTCCloud.getAudioEffectManager().stopPlayMusic(musicId);// Stop local audio capture and publishing.mTRTCCloud.stopLocalAudio();}}// Exit the room.mTRTCCloud.exitRoom();// Exit room event callback.@Overridepublic void onExitRoom(int reason) {if (reason == 0) {Log.d(TAG, "Actively call exitRoom to exit the room.");} else if (reason == 1) {Log.d(TAG, "Removed from the current room by the server.");} else if (reason == 2) {Log.d(TAG, "The current room has been dissolved.");}}
onExitRoom
callback notification to inform you.enterRoom
again or switch to another audio and video SDK, wait for the onExitRoom
callback before proceeding. Otherwise, you may encounter various exceptional issues such as the camera, microphone device being forcibly occupied.public void enterRoom(String roomId, String userId) {TRTCCloudDef.TRTCParams params = new TRTCCloudDef.TRTCParams();// Take the room ID string as an example.params.strRoomId = roomId;params.userId = userId;// UserSig obtained from the business backend.params.userSig = getUserSig(userId);// Replace with your SDKAppID.params.sdkAppId = SDKAppID;// It is recommended to enter the room as an audience role.params.role = TRTCCloudDef.TRTCRoleAudience;// LIVE should be selected for the room entry scenario.mTRTCCloud.enterRoom(params, TRTCCloudDef.TRTC_APP_SCENE_LIVE);}// Event callback for the result of entering the room.@Overridepublic void onEnterRoom(long result) {if (result > 0) {// result indicates the time taken (in milliseconds) to join the room.Log.d(TAG, "Enter room succeed");} else {// result indicates the error code when you fail to enter the room.Log.d(TAG, "Enter room failed");}}
TRTC_APP_SCENE_LIVE
for room-entry scenarios.@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: The logic of updating the lyric control.// Based on the received latest progress and the local lyrics progress deviation, determine whether a lyric control seek is necessary....}
// Exit the room.mTRTCCloud.exitRoom();// Exit room event callback.@Overridepublic void onExitRoom(int reason) {if (reason == 0) {Log.d(TAG, "Actively call exitRoom to exit the room.");} else if (reason == 1) {Log.d(TAG, "Removed from the current room by the server.");} else if (reason == 2) {Log.d(TAG, "The current room has been dissolved.");}}
// Create a TRTCCloud primary instance (vocal instance).TRTCCloud mTRTCCloud = TRTCCloud.sharedInstance(context);// Create a TRTCCloud sub-instance (music instance).TRTCCloud subCloud = mTRTCCloud.createSubCloud();// The primary instance (vocal instance) enters the room.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);// The sub-instance enables manual subscription mode. By default it does not subscribe to remote streams.subCloud.setDefaultStreamRecvMode(false, false);// The sub-instance (music instance) enters the room.TRTCCloudDef.TRTCParams bgmParams = new TRTCCloudDef.TRTCParams();bgmParams.sdkAppId = SDKAppId;// The sub-instance username must not duplicate with other users in the room.bgmParams.userId = UserId + "_bgm";bgmParams.userSig = UserSig;bgmParams.role = TRTCCloudDef.TRTCRoleAnchor;bgmParams.strRoomId = RoomId;subCloud.enterRoom(bgmParams, TRTCCloudDef.TRTC_APP_SCENE_LIVE);
// Event callback for the result of primary instance entering the room.@Overridepublic void onEnterRoom(long result) {if (result > 0) {// The primary instance unsubscribe from music streams published by sub-instances.mTRTCCloud.muteRemoteAudio(UserId + "_bgm", true);// The primary instance uses the experimental API to enable black frame insertion.mTRTCCloud.callExperimentalAPI("{\\"api\\":\\"enableBlackStream\\",\\"params\\": {\\"enable\\":true}}");// The primary instance uses the experimental API to enable chorus mode.mTRTCCloud.callExperimentalAPI("{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":true,\\"audioSource\\":0}}");// The primary instance uses the experimental API to enable low-latency mode.mTRTCCloud.callExperimentalAPI("{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":true}}");// The primary instance enables volume level callback.mTRTCCloud.enableAudioVolumeEvaluation(300, false);// The primary instance sets the global media volume type.mTRTCCloud.setSystemVolumeType(TRTCCloudDef.TRTCSystemVolumeTypeMedia);// The primary instance captures and publishes local audio, and sets audio quality.mTRTCCloud.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_MUSIC);} else {// result indicates the error code when you fail to enter the room.Log.d(TAG, "Enter room failed");}}// Event callback for the result of sub-instance entering the room.@Overridepublic void onEnterRoom(long result) {if (result > 0) {// The sub-instance uses the experimental API to enable chorus mode.subCloud.callExperimentalAPI("{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":true,\\"audioSource\\":1}}");// The sub-instance uses the experimental API to enable low-latency mode.subCloud.callExperimentalAPI("{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":true}}");// The sub-instance sets global media volume type.subCloud.setSystemVolumeType(TRTCCloudDef.TRTCSystemVolumeTypeMedia);// The sub-instance sets audio quality.subCloud.setAudioQuality(TRTCCloudDef.TRTC_AUDIO_QUALITY_MUSIC);} else {// result indicates the error code when you fail to enter the room.Log.d(TAG, "Enter room failed");}}
audioSource
parameter.private void startPublishMediaToRoom(String roomId, String userId) {// Create TRTCPublishTarget object.TRTCCloudDef.TRTCPublishTarget target = new TRTCCloudDef.TRTCPublishTarget();// After mixing, the stream is relayed back to the room.target.mode = TRTCCloudDef.TRTC_PublishMixStream_ToRoom;target.mixStreamIdentity.strRoomId = roomId;// The mixing stream robot's username must not duplicate with other users in the room.target.mixStreamIdentity.userId = userId + "_robot";// Set the encoding parameters of the transcoded audio stream (can be customized).TRTCCloudDef.TRTCStreamEncoderParam trtcStreamEncoderParam = new TRTCCloudDef.TRTCStreamEncoderParam();trtcStreamEncoderParam.audioEncodedChannelNum = 2;trtcStreamEncoderParam.audioEncodedKbps = 64;trtcStreamEncoderParam.audioEncodedCodecType = 2;trtcStreamEncoderParam.audioEncodedSampleRate = 48000;// Set the encoding parameters of the transcoded video stream (black frame mixing required).trtcStreamEncoderParam.videoEncodedFPS = 15;trtcStreamEncoderParam.videoEncodedGOP = 3;trtcStreamEncoderParam.videoEncodedKbps = 30;trtcStreamEncoderParam.videoEncodedWidth = 64;trtcStreamEncoderParam.videoEncodedHeight = 64;// Set audio mixing parameters.TRTCCloudDef.TRTCStreamMixingConfig trtcStreamMixingConfig = new TRTCCloudDef.TRTCStreamMixingConfig();// By default, leave this field empty. It indicates that all audio in the room will be mixed.trtcStreamMixingConfig.audioMixUserList = null;// Configure video mixed-stream template (black frame mixing required).TRTCCloudDef.TRTCVideoLayout videoLayout = new TRTCCloudDef.TRTCVideoLayout();trtcStreamMixingConfig.videoLayoutList.add(videoLayout);// Start mixing and pushing back.mTRTCCloud.startPublishMediaStream(target, trtcStreamEncoderParam, trtcStreamMixingConfig);}
TXLiveBase.setListener(new TXLiveBaseListener() {@Overridepublic void onUpdateNetworkTime(int errCode, String errMsg) {super.onUpdateNetworkTime(errCode, errMsg);// errCode 0: Time synchronization successful and deviation within 30 ms. 1: Time synchronization successful but deviation possibly above 30 ms. -1: Time synchronization failed.if (errCode == 0) {// Time synchronization successful and NTP timestamp obtained.long ntpTime = TXLiveBase.getNetworkTimestamp();} else {// If time synchronization fails, an attempt to resynchronize can be made.TXLiveBase.updateNetworkTime();}}});TXLiveBase.updateNetworkTime();
Timer mTimer = new Timer();mTimer.schedule(new TimerTask() {@Overridepublic void run() {try {JSONObject jsonObject = new JSONObject();jsonObject.put("cmd", "startChorus");// Agreed chorus start time: Current NTP time + delayed playback time (for example, 3 seconds).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);
// Obtain audio effects management.TXAudioEffectManager mTXAudioEffectManager = subCloud.getAudioEffectManager();// originMusicId: Custom identifier for the original vocal music. originMusicUrl: URL of the original vocal music resource.TXAudioEffectManager.AudioMusicParam originMusicParam = new TXAudioEffectManager.AudioMusicParam(originMusicId, originMusicUrl);// Publish original music to the remote.originMusicParam.publish = true;// Music start playing time point (in milliseconds).originMusicParam.startTimeMS = 0;// accompMusicId: Custom identifier for the accompaniment music. accompMusicUrl: URL of the accompaniment music resource.TXAudioEffectManager.AudioMusicParam accompMusicParam = new TXAudioEffectManager.AudioMusicParam(accompMusicId, accompMusicUrl);// Publish accompaniment music to the remote.accompMusicParam.publish = true;// Music start playing time point (in milliseconds).accompMusicParam.startTimeMS = 0;// Preload the original vocal music.mTXAudioEffectManager.preloadMusic(originMusicParam);// Preload the accompaniment music.mTXAudioEffectManager.preloadMusic(accompMusicParam);// Start playing the original vocal music after a delayed playback time (for example, 3 seconds).mTXAudioEffectManager.startPlayMusic(originMusicParam);// Start playing the accompaniment music after a delayed playback time (for example, 3 seconds).mTXAudioEffectManager.startPlayMusic(accompMusicParam);// Switch to the original vocal music.mTXAudioEffectManager.setMusicPlayoutVolume(originMusicId, 100);mTXAudioEffectManager.setMusicPlayoutVolume(accompMusicId, 0);mTXAudioEffectManager.setMusicPublishVolume(originMusicId, 100);mTXAudioEffectManager.setMusicPublishVolume(accompMusicId, 0);// Switch to the accompaniment music.mTXAudioEffectManager.setMusicPlayoutVolume(originMusicId, 0);mTXAudioEffectManager.setMusicPlayoutVolume(accompMusicId, 100);mTXAudioEffectManager.setMusicPublishVolume(originMusicId, 0);mTXAudioEffectManager.setMusicPublishVolume(accompMusicId, 100);
// Agreed chorus start time.long mStartPlayMusicTs = jsonObject.getLong("startPlayMusicTS");// Actual playback progress of the current accompaniment music.long currentProgress = subCloud.getAudioEffectManager().getMusicCurrentPosInMS(musicId);// Ideal playback progress of the current accompaniment music.long estimatedProgress = TXLiveBase.getNetworkTimestamp() - mStartPlayMusicTs;// When the progress difference exceeds 50 ms, corrections are made.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) {// Start playing music.}@Overridepublic void onPlayProgress(int id, long curPtsMs, long durationMs) {// Determine whether seek is needed based on the latest progress and the local lyrics progress deviation.// Song progress is transmitted by sending an SEI message.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) {// Music playback completed.}});
// The sub-instance uses the experimental API to disable chorus mode.subCloud.callExperimentalAPI("{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":false,\\"audioSource\\":1}}");// The sub-instance uses the experimental API to disable low-latency mode.subCloud.callExperimentalAPI("{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":false}}");// The sub-instance switches to the audience role.subCloud.switchRole(TRTCCloudDef.TRTCRoleAudience);// The sub-instance stops playing accompaniment music.subCloud.getAudioEffectManager().stopPlayMusic(musicId);// The sub-instance exits the room.subCloud.exitRoom();// The primary instance uses the experimental API to disable black frame insertion.mTRTCCloud.callExperimentalAPI("{\\"api\\":\\"enableBlackStream\\",\\"params\\": {\\"enable\\":false}}");// The primary instance uses the experimental API to disable chorus mode.mTRTCCloud.callExperimentalAPI("{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":false,\\"audioSource\\":0}}");// The primary instance uses the experimental API to disable low-latency mode.mTRTCCloud.callExperimentalAPI("{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":false}}");// The primary instance switches to the audience role.mTRTCCloud.switchRole(TRTCCloudDef.TRTCRoleAudience);// The primary instance stops local audio capture and publishing.mTRTCCloud.stopLocalAudio();// The primary instance exits the room.mTRTCCloud.exitRoom();
public void enterRoom(String roomId, String userId) {TRTCCloudDef.TRTCParams params = new TRTCCloudDef.TRTCParams();// Take the room ID string as an example.params.strRoomId = roomId;params.userId = userId;// UserSig obtained from the business backend.params.userSig = getUserSig(userId);// Replace with your SDKAppID.params.sdkAppId = SDKAppID;// Example of entering the room as an audience role.params.role = TRTCCloudDef.TRTCRoleAudience;// LIVE should be selected for the room entry scenario.mTRTCCloud.enterRoom(params, TRTCCloudDef.TRTC_APP_SCENE_LIVE);}// Event callback for the result of entering the room.@Overridepublic void onEnterRoom(long result) {if (result > 0) {// result indicates the time taken (in milliseconds) to join the room.Log.d(TAG, "Enter room succeed");} else {// result indicates the error code when you fail to enter the room.Log.d(TAG, "Enter room failed");}}
// Switched to the anchor role.mTRTCCloud.switchRole(TRTCCloudDef.TRTCRoleAnchor);// Event callback for switching the role.@Overridepublic void onSwitchRole(int errCode, String errMsg) {if (errCode == TXLiteAVCode.ERR_NULL) {// Cancel subscription to music streams published by the lead singer sub-instance.mTRTCCloud.muteRemoteAudio(mBgmUserId, true);// Use the experimental API to enable chorus mode.mTRTCCloud.callExperimentalAPI("{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":true,\\"audioSource\\":0}}");// Use the experimental API to enable low-latency mode.mTRTCCloud.callExperimentalAPI("{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":true}}");// Set media volume type.mTRTCCloud.setSystemVolumeType(TRTCCloudDef.TRTCSystemVolumeTypeMedia);// Upstream local audio streams and set audio quality.mTRTCCloud.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_MUSIC);}}
TXLiveBase.setListener(new TXLiveBaseListener() {@Overridepublic void onUpdateNetworkTime(int errCode, String errMsg) {super.onUpdateNetworkTime(errCode, errMsg);// errCode 0: Time synchronization successful and deviation within 30 ms. 1: Time synchronization successful but deviation possibly above 30 ms. -1: Time synchronization failed.if (errCode == 0) {// Time synchronization successful and NTP timestamp obtained.long ntpTime = TXLiveBase.getNetworkTimestamp();} else {// If time synchronization fails, an attempt to resynchronize can be made.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"));// Match the chorus signaling.if (json.getString("cmd").equals("startChorus")) {long startPlayMusicTs = json.getLong("startPlayMusicTS");int musicId = json.getInt("musicId");long musicDuration = json.getLong("musicDuration");// Agree on the time difference between chorus time and current time.long delayMs = startPlayMusicTs - TXLiveBase.getNetworkTimestamp();}} catch (JSONException e) {e.printStackTrace();}}
if (delayMs > 0) { // The chorus has not started.// Begin to preload music.preloadMusic(musicId, 0L);// Play music after a delay of delayMs.startPlayMusic(musicId, 0L);} else if (Math.abs(delayMs) < musicDuration) { // The chorus is in progress.// Play start time: Absolute value of the time difference + preload delay (e.g., 400 ms).long startTimeMS = Math.abs(delayMs) + 400;// Begin to preload music.preloadMusic(musicId, startTimeMS);// Start playing music after a preload delay (e.g., 400 ms).startPlayMusic(musicId, startTimeMS);} else { // The chorus has ended.// Joining the chorus is not allowed.}// Preload music.public void preloadMusic(int musicId, long startTimeMS) {// musicId: Obtained from chorus signaling. musicUrl: Corresponding music resource URL.TXAudioEffectManager.AudioMusicParam musicParam = newTXAudioEffectManager.AudioMusicParam(musicId, musicUrl);// Only local music playback.musicParam.publish = false;// Music start playing time point (in milliseconds).musicParam.startTimeMS = startTimeMS;mTRTCCloud.getAudioEffectManager().preloadMusic(musicParam);}// Begin to play music.public void startPlayMusic(int musicId, long startTimeMS) {// musicId: Obtained from chorus signaling. musicUrl: Corresponding music resource URL.TXAudioEffectManager.AudioMusicParam musicParam = newTXAudioEffectManager.AudioMusicParam(musicId, musicUrl);// Only local music playback.musicParam.publish = false;// Music start playing time point (in milliseconds).musicParam.startTimeMS = startTimeMS;mTRTCCloud.getAudioEffectManager().startPlayMusic(musicParam);}
delayMs
, the current chorus status can be determined. Developers must implement the startPlayMusic
delayed call for different statuses on their own.// Agreed chorus start time.long mStartPlayMusicTs = jsonObject.getLong("startPlayMusicTS");// Actual playback progress of the current accompaniment music.long currentProgress = mTRTCCloud.getAudioEffectManager().getMusicCurrentPosInMS(musicId);// Ideal playback progress of the current accompaniment music.long estimatedProgress = TXLiveBase.getNetworkTimestamp() - mStartPlayMusicTs;// When the progress difference exceeds 50 ms, corrections are made.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) {// Start playing music.}@Overridepublic void onPlayProgress(int id, long curPtsMs, long durationMs) {// TODO: The logic of updating the lyric control.// Determine whether seek in the lyrics control is needed based on the latest progress and the local lyrics progress deviation.}@Overridepublic void onComplete(int id, int errCode) {// Music playback completed.}});
// Use the experimental API to disable chorus mode.mTRTCCloud.callExperimentalAPI("{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":false,\\"audioSource\\":0}}");// Use the experimental API to disable low-latency mode.mTRTCCloud.callExperimentalAPI("{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":false}}");// Switched to the audience role.mTRTCCloud.switchRole(TRTCCloudDef.TRTCRoleAudience);// Stop playing accompaniment music.mTRTCCloud.getAudioEffectManager().stopPlayMusic(musicId);// Stop local audio capture and publishing.mTRTCCloud.stopLocalAudio();// Exit the room.mTRTCCloud.exitRoom();
public void enterRoom(String roomId, String userId) {TRTCCloudDef.TRTCParams params = new TRTCCloudDef.TRTCParams();// Take the room ID string as an example.params.strRoomId = roomId;params.userId = userId;// UserSig obtained from the business backend.params.userSig = getUserSig(userId);// Replace with your SDKAppID.params.sdkAppId = SDKAppID;// It is recommended to enter the room as an audience role.params.role = TRTCCloudDef.TRTCRoleAudience;// LIVE should be selected for the room entry scenario.mTRTCCloud.enterRoom(params, TRTCCloudDef.TRTC_APP_SCENE_LIVE);}// Event callback for the result of entering the room.@Overridepublic void onEnterRoom(long result) {if (result > 0) {// result indicates the time taken (in milliseconds) to join the room.Log.d(TAG, "Enter room succeed");} else {// result indicates the error code when you fail to enter the room.Log.d(TAG, "Enter room failed");}}
TRTC_APP_SCENE_LIVE
for room-entry scenarios.@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: The logic of updating the lyric control.// Based on the received latest progress and the local lyrics progress deviation, determine whether a lyric control seek is necessary....}
// Exit the room.mTRTCCloud.exitRoom();// Exit room event callback.@Overridepublic void onExitRoom(int reason) {if (reason == 0) {Log.d(TAG, "Actively call exitRoom to exit the room.");} else if (reason == 1) {Log.d(TAG, "Removed from the current room by the server.");} else if (reason == 2) {Log.d(TAG, "The current room has been dissolved.");}}
{"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"}}]}}}
@Overridepublic void onUserVoiceVolume(ArrayList<TRTCCloudDef.TRTCVolumeInfo> userVolumes, int totalVolume) {super.onUserVoiceVolume(userVolumes, totalVolume);if (userVolumes != null && userVolumes.size() > 0) {// For storing volume values corresponding to on-mic users.HashMap<String, Integer> volumesMap = new HashMap<>();for (TRTCCloudDef.TRTCVolumeInfo user : userVolumes) {// Can set an appropriate volume threshold.if (user.volume > 10) {volumesMap.put(user.userId, user.volume);}}Gson gson = new Gson();String body = gson.toJson(volumesMap);// Transmit a collection of on-mic users' volume via SEI messages.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()) {// Print the volume levels of single streams of all on-mic users.Log.i(userId, String.valueOf(volumesMap.get(userId)));}} catch (UnsupportedEncodingException e) {e.printStackTrace();}}
onNetworkQuality
to real-time monitor the network quality of both local and remote users. This callback is thrown every 2 seconds.private class TRTCCloudImplListener extends TRTCCloudListener {@Overridepublic void onNetworkQuality(TRTCCloudDef.TRTCQuality localQuality,ArrayList<TRTCCloudDef.TRTCQuality> remoteQuality) {// localQuality userId is empty. It represents the local user's network quality evaluation result.// remoteQuality represents the remote user's network quality evaluation result. The result is affected by both remote and local factors.switch (localQuality.quality) {case TRTCCloudDef.TRTC_QUALITY_Excellent:Log.i(TAG, "The current network is excellent.");break;case TRTCCloudDef.TRTC_QUALITY_Good:Log.i(TAG, "The current network is good.");break;case TRTCCloudDef.TRTC_QUALITY_Poor:Log.i(TAG, "The current network is moderate.");break;case TRTCCloudDef.TRTC_QUALITY_Bad:Log.i(TAG, "The current network is poor.");break;case TRTCCloudDef.TRTC_QUALITY_Vbad:Log.i(TAG, "The current network is very poor.");break;case TRTCCloudDef.TRTC_QUALITY_Down:Log.i(TAG, "The current network does not meet the minimum requirements of TRTC.");break;default:Log.i(TAG, "Undefined.");break;}}}
privateMapKey
parameter in TRTCParams
to successfully enter the room. Therefore, if you have users online using this SDKAppID, do not enable this feature.TRTCCloudDef.TRTCParams mTRTCParams = new TRTCCloudDef.TRTCParams();mTRTCParams.sdkAppId = SDKAPPID;mTRTCParams.userId = mUserId;mTRTCParams.strRoomId = mRoomId;// UserSig obtained from the business backend.mTRTCParams.userSig = getUserSig();// PrivateMapKey obtained from the backend.mTRTCParams.privateMapKey = getPrivateMapKey();mTRTCParams.role = TRTCCloudDef.TRTCRoleAudience;mTRTCCloud.enterRoom(mTRTCParams, TRTCCloudDef.TRTC_APP_SCENE_LIVE);
// Pass in the latest PrivateMapKey obtained from the backend into the role switching API.mTRTCCloud.switchRole(TRTCCloudDef.TRTCRoleAnchor, getPrivateMapKey());
onError
callback. For details, see Error Code Table.Enumeration | Value | Description |
ERR_TRTC_INVALID_USER_SIG | -3320 | Room entry parameter userSig is incorrect. Check if TRTCParams.userSig is empty. |
ERR_TRTC_USER_SIG_CHECK_FAILED | -100018 | UserSig verification failed. Check if the parameter TRTCParams.userSig is filled in correctly or has expired. |
Enumeration | Value | Description |
ERR_TRTC_CONNECT_SERVER_TIMEOUT | -3308 | Room entry request timed out. Check if your internet connection is lost or if a VPN is enabled. You may also attempt to switch to 4G for testing. |
ERR_TRTC_INVALID_SDK_APPID | -3317 | Room entry parameter sdkAppId is incorrect. Check if TRTCParams.sdkAppId is empty. |
ERR_TRTC_INVALID_ROOM_ID | -3318 | Room entry parameter roomId is incorrect. Check if TRTCParams.roomId or TRTCParams.strRoomId is empty. Note that roomId and strRoomId cannot be used interchangeably. |
ERR_TRTC_INVALID_USER_ID | -3319 | Room entry parameter userId is incorrect. Check if TRTCParams.userId is empty. |
ERR_TRTC_ENTER_ROOM_REFUSED | -3340 | Room entry request is denied. Check if enterRoom is called consecutively to enter rooms with the same ID. |
Enumeration | Value | Description |
ERR_MIC_START_FAIL | -1302 | Failed to open the mic. For example, if there is an exception for the mic's configuration program (driver) on a Windows or macOS device, you should try disabling then re-enabling the device, restarting the machine, or updating the configuration program. |
ERR_SPEAKER_START_FAIL | -1321 | Failed to open the speaker. For example, if there is an exception for the speaker's configuration program (driver) on a Windows or macOS device, you should try disabling then re-enabling the device, restarting the machine, or updating the configuration program. |
ERR_MIC_OCCUPY | -1319 | The mic is occupied. This occurs when, for example, the user is currently having a call on the mobile device. |
// Enable IEMs.mTRTCCloud.getAudioEffectManager().enableVoiceEarMonitor(true);// Set the volume of IEMs.mTRTCCloud.getAudioEffectManager().setVoiceEarMonitorVolume(int volume);
setSystemAudioKitEnabled
. Hardware IEMs have better performance and lower delay. Software IEMs have higher delay but better compatibility. Currently, for Huawei and VIVO devices, SDK defaults to hardware IEMs. Other devices default to software IEMs. If there are compatibility issues with hardware IEMs, contact us to configure forced use of software IEMs.public static void copyAssetsToFile(Context context, String name) {// The files directory under the application's directory.String savePath = ContextCompat.getExternalFilesDirs(context, null)[0].getAbsolutePath();// The cache directory under the application's directory.// String savePath = getApplication().getExternalCacheDir().getAbsolutePath();// The files directory under the application's private storage directory.// String savePath = getApplication().getFilesDir().getAbsolutePath();String filename = savePath + "/" + name;File dir = new File(savePath);// Create the directory if it does not exist.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"
. This attribute only takes effect on applications with targetSdkVersion 29 (Android 10), and applications with a higher version targetSdkVersion are still recommended to use the application's private or external storage paths.MANAGE_EXTERNAL_STORAGE
permission:<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);
// Set the local playback volume of a piece of background music.mTRTCCloud.getAudioEffectManager().setMusicPlayoutVolume(musicID, volume);// Set the remote playback volume of a specific background music.mTRTCCloud.getAudioEffectManager().setMusicPublishVolume(musicID, volume);// Set the local and remote volume of all background music.mTRTCCloud.getAudioEffectManager().setAllMusicVolume(volume);// Set the volume of voice capture.mTRTCCloud.getAudioEffectManager().setVoiceCaptureVolume(volume);
Was this page helpful?