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.sudo gem install cocoapods
pod init
platform :ios, '8.0'target 'App' do# TRTC Lite Edition# The installation package has the minimum incremental size. But it only supports two features of Real-Time Communication (TRTC) and TXLivePlayer for live streaming playback.pod 'TXLiteAVSDK_TRTC', :podspec => 'https://liteav.sdk.qcloud.com/pod/liteavsdkspec/TXLiteAVSDK_TRTC.podspec'# Pro Edition# Includes a wide range of features such as Real-Time Communication (TRTC), TXLivePlayer for live streaming playback, TXLivePusher for RTMP push streams, TXVodPlayer for on-demand playback, and UGSV for short video recording and editing.# pod 'TXLiteAVSDK_Professional', :podspec => 'https://liteav.sdk.qcloud.com/pod/liteavsdkspec/TXLiteAVSDK_Professional.podspec'end
pod install
pod update
pod setuppod repo updaterm ~/Library/Caches/CocoaPods/search_index.json
Privacy - Microphone Usage Description. Also enter a prompt specifying the purpose of microphone use.
// Create TRTC SDK instance (Single Instance Pattern).self.trtcCloud = [TRTCCloud sharedInstance];// Set event listeners.self.trtcCloud.delegate = self;// Notifications from various SDK events (e.g., error codes, warning codes, audio and video status parameters, etc.).- (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);}// Remove event listener.self.trtcCloud.delegate = nil;// Terminate TRTC SDK instance (Singleton Pattern).[TRTCCloud destroySharedIntance];
- (void)enterRoomWithRoomId:(NSString *)roomId userID:(NSString *)userId {TRTCParams *params = [[TRTCParams alloc] init];// Take the room ID string as an example.params.strRoomId = roomId;params.userId = userId;// UserSig obtained from the business backend.params.userSig = [self generateUserSig:userId];// Replace with your SDKAppID.params.sdkAppId = SDKAppID;// It is recommended to enter the room as an audience role.params.role = TRTCRoleAudience;// LIVE should be selected for the room entry scenario.[self.trtcCloud enterRoom:params appScene:TRTCAppSceneLIVE];}
TRTCAppSceneLIVE
for room entry scenarios.// Event callback for the result of entering the room.- (void)onEnterRoom:(NSInteger)result {if (result > 0) {// result indicates the time taken (in milliseconds) to join the room.NSLog(@"Enter room succeed!");// Enable the experimental API for black frame insertion.[self.trtcCloud callExperimentalAPI:@"{\\"api\\":\\"enableBlackStream\\",\\"params\\": {\\"enable\\":true}}"];} else {// result indicates the error code when you fail to enter the room.NSLog(@"Enter room failed!");}}
// Switched to the anchor role.[self.trtcCloud switchRole:TRTCRoleAnchor];// Event callback for switching the role.- (void)onSwitchRole:(TXLiteAVError)errCode errMsg:(NSString *)errMsg {if (errCode == ERR_NULL) {// Set media volume type.[self.trtcCloud setSystemVolumeType:TRTCSystemVolumeTypeMedia];// Upstream local audio streams and set audio quality.[self.trtcCloud startLocalAudio:TRTCAudioQualityMusic];}}
// Obtain audio effects management.self.audioEffectManager = [self.trtcCloud getAudioEffectManager];// originMusicId: Custom identifier for the original vocal music. originMusicUrl: URL of the original vocal music resource.TXAudioMusicParam *originMusicParam = [[TXAudioMusicParam alloc] init];originMusicParam.ID = originMusicId;originMusicParam.path = originMusicUrl;// Whether to publish the original vocal music to remote (otherwise play locally only).originMusicParam.publish = YES;// accompMusicId: Custom identifier for the accompaniment music. accompMusicUrl: URL of the accompaniment music resource.TXAudioMusicParam *accompMusicParam = [[TXAudioMusicParam alloc] init];accompMusicParam.ID = accompMusicId;accompMusicParam.path = accompMusicUrl;// Whether to publish the accompaniment to remote (otherwise play locally only).accompMusicParam.publish = YES;// Start playing the original vocal music.[self.audioEffectManager startPlayMusic:originMusicParam onStart:^(NSInteger errCode) {// onStart} onProgress:^(NSInteger progressMs, NSInteger durationMs) {// onProgress} onComplete:^(NSInteger errCode) {// onComplete}];// Start playing the accompaniment music.[self.audioEffectManager startPlayMusic:originMusicParam onStart:^(NSInteger errCode) {// onStart} onProgress:^(NSInteger progressMs, NSInteger durationMs) {// onProgress} onComplete:^(NSInteger errCode) {// onComplete}];// Switch to the original vocal music.[self.audioEffectManager setMusicPlayoutVolume:originMusicId volume:100];[self.audioEffectManager setMusicPublishVolume:originMusicId volume:100];[self.audioEffectManager setMusicPlayoutVolume:accompMusicId volume:0];[self.audioEffectManager setMusicPublishVolume:accompMusicId volume:0];// Switch to the accompaniment music.[self.audioEffectManager setMusicPlayoutVolume:originMusicId volume:0];[self.audioEffectManager setMusicPublishVolume:originMusicId volume:0];[self.audioEffectManager setMusicPlayoutVolume:accompMusicId volume:100];[self.audioEffectManager setMusicPublishVolume:accompMusicId volume:100];
[self.audioEffectManager startPlayMusic:musicParam onStart:^(NSInteger errCode) {// Start playing music.} onProgress:^(NSInteger progressMs, NSInteger 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.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) {// Music playback completed.}];
// Switched to the audience role.[self.trtcCloud switchRole:TRTCRoleAudience];// Event callback for switching the role.- (void)onSwitchRole:(TXLiteAVError)errCode errMsg:(NSString *)errMsg {if (errCode == ERR_NULL) {// Stop playing accompaniment music.[[self.trtcCloud getAudioEffectManager] stopPlayMusic:self.musicId];// Stop local audio capture and publishing.[self.trtcCloud stopLocalAudio];}}// Exit the room.[self.trtcCloud exitRoom];// Exit room event callback.- (void)onExitRoom:(NSInteger)reason {if (reason == 0) {NSLog(@"Proactively call exitRoom to exit the room.");} else if (reason == 1) {NSLog(@"Removed from the current room by the server.");} else if (reason == 2) {NSLog(@"The current room is 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.// Enter the room.- (void)enterRoomWithRoomId:(NSString *)roomId userID:(NSString *)userId {TRTCParams *params = [[TRTCParams alloc] init];// Take the room ID string as an example.params.strRoomId = roomId;params.userId = userId;// UserSig obtained from the business backend.params.userSig = [self generateUserSig:userId];// Replace with your SDKAppID.params.sdkAppId = SDKAppID;// It is recommended to enter the room as an audience role.params.role = TRTCRoleAudience;// LIVE should be selected for the room entry scenario.[self.trtcCloud enterRoom:params appScene:TRTCAppSceneLIVE];}// Event callback for the result of entering the room.- (void)onEnterRoom:(NSInteger)result {if (result > 0) {// result indicates the time taken (in milliseconds) to join the room.NSLog(@"Enter room succeed!");} else {// result indicates the error code when you fail to enter the room.NSLog(@"Enter room failed!");}}
TRTCAppSceneLIVE
for room entry scenarios.- (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: 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.[self.trtcCloud exitRoom];// Exit room event callback.- (void)onExitRoom:(NSInteger)reason {if (reason == 0) {NSLog(@"Proactively call exitRoom to exit the room.");} else if (reason == 1) {NSLog(@"Removed from the current room by the server.");} else if (reason == 2) {NSLog(@"The current room is dissolved.");}}
- (void)enterRoomWithRoomId:(NSString *)roomId userID:(NSString *)userId {// Create a TRTCCloud primary instance (vocal instance).TRTCCloud *mainCloud = [TRTCCloud sharedInstance];// Create a TRTCCloud sub-instance (music instance).TRTCCloud *subCloud = [mainCloud createSubCloud];// The primary instance (vocal instance) enters the room.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];// The sub-instance enables manual subscription mode. By default it does not subscribe to remote streams.[subCloud setDefaultStreamRecvMode:NO video:NO];// The sub-instance (music instance) enters the room.TRTCParams *bgmParams = [[TRTCParams alloc] init];bgmParams.strRoomId = roomId;// The sub-instance username must not duplicate with other users in the room.bgmParams.userId = [userId stringByAppendingString:@"_bgm"];bgmParams.userSig = userSig;bgmParams.sdkAppId = SDKAppID;bgmParams.role = TRTCRoleAnchor;[subCloud enterRoom:bgmParams appScene:TRTCAppSceneLIVE];}
// Event callback for the result of primary instance entering the room.- (void)onEnterRoom:(NSInteger)result {if (result > 0) {// The primary instance unsubscribe from music streams published by sub-instances.[self.trtcCloud muteRemoteAudio:[self.userId stringByAppendingString:@"_bgm"] mute:YES];// The primary instance uses the experimental API to enable black frame insertion.[self.trtcCloud callExperimentalAPI:@"{\\"api\\":\\"enableBlackStream\\",\\"params\\": {\\"enable\\":true}}"];// The primary instance uses the experimental API to enable chorus mode.[self.trtcCloud callExperimentalAPI:@"{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":true,\\"audioSource\\":0}}"];// The primary instance uses the experimental API to enable low-latency mode.[self.trtcCloud callExperimentalAPI:@"{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":true}}"];// The primary instance enables volume level callback.TRTCAudioVolumeEvaluateParams *aveParams = [[TRTCAudioVolumeEvaluateParams alloc] init];aveParams.interval = 300;[self.trtcCloud enableAudioVolumeEvaluation:YES withParams:aveParams];// The primary instance sets the global media volume type.[self.trtcCloud setSystemVolumeType:TRTCSystemVolumeTypeMedia];// The primary instance captures and publishes local audio, and sets audio quality.[self.trtcCloud startLocalAudio:TRTCAudioQualityMusic];} else {// result indicates the error code when you fail to enter the room.NSLog(@"Enter room failed");}}// Event callback for the result of sub-instance entering the room.- (void)onEnterRoom:(NSInteger)result {if (result > 0) {// The sub-instance uses the experimental API to enable chorus mode.[self.subCloud callExperimentalAPI:@"{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":true,\\"audioSource\\":1}}"];// The sub-instance uses the experimental API to enable low-latency mode.[self.subCloud callExperimentalAPI:@"{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":true}}"];// The sub-instance sets global media volume type.[self.subCloud setSystemVolumeType:TRTCSystemVolumeTypeMedia];// The sub-instance sets audio quality.[self.subCloud setAudioQuality:TRTCAudioQualityMusic];} else {// result indicates the error code when you fail to enter the room.NSLog(@"Enter room failed");}}
audioSource
parameter.- (void)startPublishMediaToRoomWithRoomId:(NSString *)roomId userId:(NSString *)userId {// Create TRTCPublishTarget object.TRTCPublishTarget *target = [[TRTCPublishTarget alloc] init];// After mixing, the stream is relayed back to the room.target.mode = TRTCPublishMixStreamToRoom;TRTCUser *mixStreamIdentity = [[TRTCUser alloc] init];mixStreamIdentity.strRoomId = roomId;// The mixing stream robot's username must not duplicate with other users in the room.mixStreamIdentity.userId = [userId stringByAppendingString:@"_robot"];target.mixStreamIdentity = mixStreamIdentity;// Set the encoding parameters of the transcoded audio stream (can be customized).TRTCStreamEncoderParam *encoderParam = [[TRTCStreamEncoderParam alloc] init];encoderParam.audioEncodedChannelNum = 2;encoderParam.audioEncodedKbps = 64;encoderParam.audioEncodedCodecType = 2;encoderParam.audioEncodedSampleRate = 48000;// Set the encoding parameters of the transcoded video stream (black frame mixing required).encoderParam.videoEncodedFPS = 15;encoderParam.videoEncodedGOP = 3;encoderParam.videoEncodedKbps = 30;encoderParam.videoEncodedWidth = 64;encoderParam.videoEncodedHeight = 64;// Set audio mixing parameters.TRTCStreamMixingConfig *mixingConfig = [[TRTCStreamMixingConfig alloc] init];// By default, leave this field empty. It indicates that all audio in the room will be mixed.mixingConfig.audioMixUserList = nil;// Configure video mixed-stream template (black frame mixing required).TRTCVideoLayout *layout = [[TRTCVideoLayout alloc] init];mixingConfig.videoLayoutList = @[layout];// Start mixing and pushing back.[self.trtcCloud startPublishMediaStream:target encoderParam:encoderParam mixingConfig:mixingConfig];}
- (void)updateNetworkTimeExample {[TXLiveBase sharedInstance].delegate = self;[TXLiveBase updateNetworkTime];}- (void)onUpdateNetworkTime:(int)errCode message:(NSString *)errMsg {// errCode 0: 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.NSInteger ntpTime = [TXLiveBase getNetworkTimestamp];} else {NSLog(@"Time synchronization failed, and you can try re-synchronization.");}}
- (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",// Agreed chorus start time: Current NTP time + delayed playback time (for example, 3 seconds).@"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];}
// Obtain audio effects management.TXAudioEffectManager *audioEffectManager = [self.subCloud getAudioEffectManager];// originMusicId: Custom identifier for the original vocal music. originMusicUrl: URL of the original vocal music resource.TXAudioMusicParam *originMusicParam = [[TXAudioMusicParam alloc] init];originMusicParam.ID = originMusicId;originMusicParam.path = originMusicUrl;// Whether to publish the original vocal music to remote (otherwise play locally only).originMusicParam.publish = YES;// Music start playing time point (in milliseconds).originMusicParam.startTimeMS = 0;// accompMusicId: Custom identifier for the accompaniment music. accompMusicUrl: URL of the accompaniment music resource.TXAudioMusicParam *accompMusicParam = [[TXAudioMusicParam alloc] init];accompMusicParam.ID = accompMusicId;accompMusicParam.path = accompMusicUrl;// Whether to publish the accompaniment to remote (otherwise play locally only).accompMusicParam.publish = YES;// Music start playing time point (in milliseconds).accompMusicParam.startTimeMS = 0;// Preload the original vocal music.[audioEffectManager preloadMusic:originMusicParam onProgress:nil onError:nil];// Preload the accompaniment music.[audioEffectManager preloadMusic:accompMusicParam onProgress:nil onError:nil];// Start playing the original vocal music after a delayed playback time (for example, 3 seconds).[self.audioEffectManager startPlayMusic:originMusicParam onStart:^(NSInteger errCode) {// onStart} onProgress:^(NSInteger progressMs, NSInteger durationMs) {// onProgress} onComplete:^(NSInteger errCode) {// onComplete}];// Start playing the accompaniment music after a delayed playback time (for example, 3 seconds).[self.audioEffectManager startPlayMusic:originMusicParam onStart:^(NSInteger errCode) {// onStart} onProgress:^(NSInteger progressMs, NSInteger durationMs) {// onProgress} onComplete:^(NSInteger errCode) {// onComplete}];// Switch to the original vocal music.[self.audioEffectManager setMusicPlayoutVolume:originMusicId volume:100];[self.audioEffectManager setMusicPublishVolume:originMusicId volume:100];[self.audioEffectManager setMusicPlayoutVolume:accompMusicId volume:0];[self.audioEffectManager setMusicPublishVolume:accompMusicId volume:0];// Switch to the accompaniment music.[self.audioEffectManager setMusicPlayoutVolume:originMusicId volume:0];[self.audioEffectManager setMusicPublishVolume:originMusicId volume:0];[self.audioEffectManager setMusicPlayoutVolume:accompMusicId volume:100];[self.audioEffectManager setMusicPublishVolume:accompMusicId volume:100];
// Agreed chorus start time.@property (nonatomic, assign) NSInteger startPlayMusicTS;- (void)syncBgmExample {// Actual playback progress of the current accompaniment music.NSInteger currentProgress = [[self.subCloud getAudioEffectManager] getMusicCurrentPosInMS:self.musicId];// Ideal playback progress of the current accompaniment music.NSInteger estimatedProgress = [TXLiveBase getNetworkTimestamp] - self.startPlayMusicTS;// When the progress difference exceeds 50 ms, corrections are made.if (estimatedProgress >= 0 && labs(currentProgress - estimatedProgress) > 50) {[[self.subCloud getAudioEffectManager] seekMusicToPosInMS:self.musicId pts:estimatedProgress];}}
[[self.subCloud getAudioEffectManager] startPlayMusic:musicParam onStart:^(NSInteger errCode) {// Start playing music.} onProgress:^(NSInteger progressMs, NSInteger 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.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) {// Music playback completed.}];
- (void)exitRoomExample {// The sub-instance uses the experimental API to disable chorus mode.[self.subCloud callExperimentalAPI:@"{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":false,\\"audioSource\\":1}}"];// The sub-instance uses the experimental API to disable low-latency mode.[self.subCloud callExperimentalAPI:@"{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":false}}"];// The sub-instance switches to the audience role.[self.subCloud switchRole:TRTCRoleAudience];// The sub-instance stops playing accompaniment music.[[self.subCloud getAudioEffectManager] stopPlayMusic:self.musicId];// The sub-instance exits the room.[self.subCloud exitRoom];// The primary instance uses the experimental API to disable black frame insertion.[self.trtcCloud callExperimentalAPI:@"{\\"api\\":\\"enableBlackStream\\",\\"params\\": {\\"enable\\":false}}"];// The primary instance uses the experimental API to disable chorus mode.[self.trtcCloud callExperimentalAPI:@"{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":false,\\"audioSource\\":0}}"];// The primary instance uses the experimental API to disable low-latency mode.[self.trtcCloud callExperimentalAPI:@"{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":false}}"];// The primary instance switches to the audience role.[self.trtcCloud switchRole:TRTCRoleAudience];// The primary instance stops local audio capture and publishing.[self.trtcCloud stopLocalAudio];// The primary instance exits the room.[self.trtcCloud exitRoom];}
- (void)enterRoomWithRoomId:(NSString *)roomId userID:(NSString *)userId {TRTCParams *params = [[TRTCParams alloc] init];// Take the room ID string as an example.params.strRoomId = roomId;params.userId = userId;// UserSig obtained from the business backend.params.userSig = [self generateUserSig:userId];// Replace with your SDKAppID.params.sdkAppId = SDKAppID;// Example of entering the room as an audience role.params.role = TRTCRoleAudience;// LIVE should be selected for the room entry scenario.[self.trtcCloud enterRoom:params appScene:TRTCAppSceneLIVE];}// Event callback for the result of entering the room.- (void)onEnterRoom:(NSInteger)result {if (result > 0) {// result indicates the time taken (in milliseconds) to join the room.NSLog(@"Enter room succeed!");} else {// result indicates the error code when you fail to enter the room.NSLog(@"Enter room failed!");}}
// Switched to the anchor role.[self.trtcCloud switchRole:TRTCRoleAnchor];// Event callback for switching the role.- (void)onSwitchRole:(TXLiteAVError)errCode errMsg:(NSString *)errMsg {if (errCode == ERR_NULL) {// Cancel subscription to music streams published by the lead singer sub-instance.[self.trtcCloud muteRemoteAudio:self.bgmUserId mute:YES];// Use the experimental API to enable chorus mode.[self.trtcCloud callExperimentalAPI:@"{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":true,\\"audioSource\\":0}}"];// Use the experimental API to enable low-latency mode.[self.trtcCloud callExperimentalAPI:@"{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":true}}"];// Set media volume type.[self.trtcCloud setSystemVolumeType:TRTCSystemVolumeTypeMedia];// Upstream local audio streams and set audio quality.[self.trtcCloud startLocalAudio:TRTCAudioQualityMusic];}}
- (void)updateNetworkTimeExample {[TXLiveBase sharedInstance].delegate = self;[TXLiveBase updateNetworkTime];}- (void)onUpdateNetworkTime:(int)errCode message:(NSString *)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.NSInteger ntpTime = [TXLiveBase getNetworkTimestamp];} else {NSLog(@"Time synchronization failed, and you can try re-synchronization.");}}
- (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;// Match the chorus signaling.if ([dic[@"cmd"] isEqualToString:@"startChorus"]) {self.startPlayMusicTS = [dic[@"startPlayMusicTS"] integerValue];self.musicId = [dic[@"musicId"] intValue];self.musicDuration = [dic[@"musicDuration"] intValue];// Agree on the time difference between chorus time and current time.self.delayMs = self.startPlayMusicTS - [TXLiveBase getNetworkTimestamp];}}
- (void)playBmgExample {// Chorus has not started.if (self.delayMs > 0) {// Begin to preload music.[self preloadMusicWithStartTimeMS:0];// Play music after a delay of delayMs.[self startPlayMusicWithStartTimeMS:0];} else if (labs(self.delayMs) < self.musicDuration) {// Chorus is in progress.// Play start time: Absolute value of the time difference + preload delay (e.g., 400 ms).NSInteger startTimeMS = labs(self.delayMs) + 400;// Begin to preload music.[self preloadMusicWithStartTimeMS:startTimeMS];// Start playing music after a preload delay (e.g., 400 ms).[self startPlayMusicWithStartTimeMS:startTimeMS];} else {// Chorus has ended.// Joining the chorus is not allowed.}}// Preload music.- (void)preloadMusicWithStartTimeMS:(NSInteger)startTimeMS {// musicId: Obtained from chorus signaling. musicUrl: Corresponding music resource URL.TXAudioMusicParam *musicParam = [[TXAudioMusicParam alloc] init];musicParam.ID = self.musicId;musicParam.path = self.musicUrl;// Only local music playback.musicParam.publish = NO;musicParam.startTimeMS = startTimeMS;[self.audioEffectManager preloadMusic:musicParam onProgress:nil onError:nil];}// Begin to play music.- (void)startPlayMusicWithStartTimeMS:(NSInteger)startTimeMS {// musicId: Obtained from chorus signaling. musicUrl: Corresponding music resource URL.TXAudioMusicParam *musicParam = [[TXAudioMusicParam alloc] init];musicParam.ID = self.musicId;musicParam.path = self.musicUrl;// Only local music playback.musicParam.publish = NO;musicParam.startTimeMS = startTimeMS;[self.audioEffectManager startPlayMusic:musicParam onStart:nil onProgress:nil onComplete:nil];}
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.@property (nonatomic, assign) NSInteger startPlayMusicTS;- (void)syncBgmExample {// Actual playback progress of the current accompaniment music.NSInteger currentProgress = [[self.trtcCloud getAudioEffectManager] getMusicCurrentPosInMS:self.musicId];// Ideal playback progress of the current accompaniment music.NSInteger estimatedProgress = [TXLiveBase getNetworkTimestamp] - self.startPlayMusicTS;// When the progress difference exceeds 50 ms, corrections are made.if (estimatedProgress >= 0 && labs(currentProgress - estimatedProgress) > 50) {[[self.trtcCloud getAudioEffectManager] seekMusicToPosInMS:self.musicId pts:estimatedProgress];}}
[self.audioEffectManager startPlayMusic:musicParam onStart:^(NSInteger errCode) {// Start playing music.} onProgress:^(NSInteger progressMs, NSInteger 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.} onComplete:^(NSInteger errCode) {// Music playback completed.}];
- (void)exitRoomExample {// Use the experimental API to disable chorus mode.[self.trtcCloud callExperimentalAPI:@"{\\"api\\":\\"enableChorus\\",\\"params\\":{\\"enable\\":false,\\"audioSource\\":0}}"];// Use the experimental API to disable low-latency mode.[self.trtcCloud callExperimentalAPI:@"{\\"api\\":\\"setLowLatencyModeEnabled\\",\\"params\\":{\\"enable\\":false}}"];// Switched to the audience role.[self.trtcCloud switchRole:TRTCRoleAudience];// Stop playing accompaniment music.[[self.trtcCloud getAudioEffectManager] stopPlayMusic:self.musicId];// Stop local audio capture and publishing.[self.trtcCloud stopLocalAudio];// Exit the room.[self.trtcCloud exitRoom];}
- (void)enterRoomWithRoomId:(NSString *)roomId userID:(NSString *)userId {TRTCParams *params = [[TRTCParams alloc] init];// Take the room ID string as an example.params.strRoomId = roomId;params.userId = userId;// UserSig obtained from the business backend.params.userSig = [self generateUserSig:userId];// Replace with your SDKAppID.params.sdkAppId = SDKAppID;// It is recommended to enter the room as an audience role.params.role = TRTCRoleAudience;// LIVE should be selected for the room entry scenario.[self.trtcCloud enterRoom:params appScene:TRTCAppSceneLIVE];}// Event callback for the result of entering the room.- (void)onEnterRoom:(NSInteger)result {if (result > 0) {// result indicates the time taken (in milliseconds) to join the room.NSLog(@"Enter room succeed!");} else {// result indicates the error code when you fail to enter the room.NSLog(@"Enter room failed!");}}
TRTCAppSceneLIVE
for room entry scenarios.- (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: 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.[self.trtcCloud exitRoom];// Exit room event callback.- (void)onExitRoom:(NSInteger)reason {if (reason == 0) {NSLog(@"Proactively call exitRoom to exit the room.");} else if (reason == 1) {NSLog(@"Removed from the current room by the server.");} else if (reason == 2) {NSLog(@"The current room is 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"}}]}}}
- (void)onUserVoiceVolume:(NSArray<TRTCVolumeInfo *> *)userVolumes totalVolume:(NSInteger)totalVolume {if (userVolumes.count) {// For storing volume values corresponding to on-mic users.NSMutableDictionary *volumesMap = [NSMutableDictionary dictionary];for (TRTCVolumeInfo *user in userVolumes) {// Can set an appropriate volume threshold.if (user.volume > 10) {volumesMap[user.userId] = @(user.volume);}}JSONModel *json = [[JSONModel alloc] initWithDictionary:volumesMap error:nil];// Transmit a collection of on-mic users' volume via SEI messages.[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) {// Print the volume levels of single streams of all on-mic users.NSLog(@"%@: %@", userId, dic[userId]);}}
onNetworkQuality
to real-time monitor the network quality of both local and remote users. This callback is thrown every 2 seconds.#pragma mark - TRTCCloudDelegate- (void)onNetworkQuality:(TRTCQualityInfo *)localQuality remoteQuality:(NSArray<TRTCQualityInfo *> *)remoteQuality {// localQuality 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 TRTCQuality_Unknown:NSLog(@"Undefined.");break;case TRTCQuality_Excellent:NSLog(@"The current network is excellent.");break;case TRTCQuality_Good:NSLog(@"The current network is good.");break;case TRTCQuality_Poor:NSLog(@"The current network is moderate.");break;case TRTCQuality_Bad:NSLog(@"The current network is poor.");break;case TRTCQuality_Vbad:NSLog(@"The current network is very poor.");break;case TRTCQuality_Down:NSLog(@"The current network does not meet the minimum requirements of TRTC.");break;default:break;}}
privateMapKey
parameter in TRTCParams
to successfully enter the room. Therefore, if you have users online using this SDKAppID, do not enable this feature.TRTCParams *params = [[TRTCParams alloc] init];params.sdkAppId = SDKAppID;params.roomId = self.roomId;params.userId = self.userId;// UserSig obtained from the business backend.params.userSig = [self getUserSig];// PrivateMapKey obtained from the backend.params.privateMapKey = [self getPrivateMapKey];params.role = TRTCRoleAudience;[self.trtcCloud enterRoom:params appScene:TRTCAppSceneLIVE];
// Pass in the latest PrivateMapKey obtained from the backend into the role switching API.[self.trtcCloud switchRole:TRTCRoleAnchor privateMapKey:[self 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.[[self.trtcCloud getAudioEffectManager] enableVoiceEarMonitor:YES];// Set the volume of IEMs.[[self.trtcCloud getAudioEffectManager] setVoiceEarMonitorVolume: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.[[self.trtcCloud getAudioEffectManager] preloadMusic:musicParam onProgress:nil onError:nil];
// Set the local playback volume of a piece of background music.[[self.trtcCloud getAudioEffectManager] setMusicPlayoutVolume:self.musicId volume:volume];// Set the remote playback volume of a specific background music.[[self.trtcCloud getAudioEffectManager] setMusicPublishVolume:self.musicId volume:volume];// Set the local and remote volume of all background music.[[self.trtcCloud getAudioEffectManager] setAllMusicVolume:volume];// Set the volume of voice capture.[[self.trtcCloud getAudioEffectManager] setVoiceVolume:volume];
Was this page helpful?