All Products
Search
Document Center

ApsaraVideo Live:Integrate the SDK for iOS

Last Updated:Jan 23, 2024

This topic describes how to integrate the SDK for iOS to implement solo singing in a karaoke room.

The streamer creates a room

/* Implement AliRtcEngineDelegate to listen to related events */
_engine = [AliRtcEngine sharedInstance:self extras:extras];

// Set the channel profile
[self.engine setChannelProfile:AliRtcInteractivelive];
// Set the user role
[self.engine setClientRole:AliRtcClientRoleInteractive];
/* Set the audio profile to the high audio quality mode and set the scenario to KTV */
[self.engine setAudioProfile:AliRtcEngineHighQualityMode audio_scene:AliRtcSceneKtvMode];

// Configure stream pulling settings
[self.engine setDefaultSubscribeAllRemoteAudioStreams:YES];
[self.engine subscribeAllRemoteAudioStreams:YES];
[self.engine publishLocalAudioStream:YES];
[self.engine setAudioOnlyMode:YES];

/* Specify whether to use speaker for playback */
[self.engine enableSpeakerphone:ctrl.useSpeaker];

NSMutableDictionary *raw_token = [[NSMutableDictionary alloc] init];
[raw_token setValue:info.appId forKey:@"appid"];
[raw_token setValue:info.channelId forKey:@"channelid"];
[raw_token setValue:info.userId forKey:@"userid"];
[raw_token setValue:info.nonce forKey:@"nonce"];
[raw_token setValue:@(info.timestamp) forKey:@"timestamp"];
[raw_token setValue:info.gslb forKey:@"gslb"];
[raw_token setValue:info.token forKey:@"token"];
NSData *token_data = [NSJSONSerialization dataWithJSONObject:raw_token options:NSJSONWritingPrettyPrinted error:nil];
NSString *token_str = [token_data base64EncodedStringWithOptions:0];
                
[self.engine joinChannel:token_str channelId:nil userId:nil name:nil onResultWithUserId:^(NSInteger errCode, NSString * _Nonnull channel, NSString * _Nonnull userId, NSInteger elapsed) {
    NSString *sting = [NSString stringWithFormat:@"joinRst: %d", (int)errCode];
    [weakSelf log:sting];
    if(errCode != 0 && ![weakSelf.engine isInCall]){
        weakSelf.callState = YES; // restore gui
    }else{
        weakSelf.callState=NO; // The user successfully joins the room.
        dispatch_async(dispatch_get_main_queue(), ^{
            [weakSelf addTableView]; // Render the remote view.
        });
    }
}];

Audience join the room

Call the same API as creating a room and the audience role to the user.

/* Implement AliRtcEngineDelegate to listen to related events */
_engine = [AliRtcEngine sharedInstance:self extras:extras];

// Set the channel profile
[self.engine setChannelProfile:AliRtcInteractivelive];
// Set the user role
[self.engine setClientRole:AliRtcClientRoleInteractive];
/* Set the audio profile to the high audio quality mode and set the scenario to KTV */
[self.engine setAudioProfile:AliRtcEngineHighQualityMode audio_scene:AliRtcSceneKtvMode];
// Configure stream pulling settings
[self.engine setDefaultSubscribeAllRemoteAudioStreams:YES];
[self.engine subscribeAllRemoteAudioStreams:YES];
[self.engine publishLocalAudioStream:YES];
[self.engine setAudioOnlyMode:YES];

/* Specify whether to use speaker for playback */
[self.engine enableSpeakerphone:ctrl.useSpeaker];

NSMutableDictionary *raw_token = [[NSMutableDictionary alloc] init];
[raw_token setValue:info.appId forKey:@"appid"];
[raw_token setValue:info.channelId forKey:@"channelid"];
[raw_token setValue:info.userId forKey:@"userid"];
[raw_token setValue:info.nonce forKey:@"nonce"];
[raw_token setValue:@(info.timestamp) forKey:@"timestamp"];
[raw_token setValue:info.gslb forKey:@"gslb"];
[raw_token setValue:info.token forKey:@"token"];
NSData *token_data = [NSJSONSerialization dataWithJSONObject:raw_token options:NSJSONWritingPrettyPrinted error:nil];
NSString *token_str = [token_data base64EncodedStringWithOptions:0];
                
[self.engine joinChannel:token_str channelId:nil userId:nil name:nil onResultWithUserId:^(NSInteger errCode, NSString * _Nonnull channel, NSString * _Nonnull userId, NSInteger elapsed) {
    NSString *sting = [NSString stringWithFormat:@"joinRst: %d", (int)errCode];
    [weakSelf log:sting];
    if(errCode != 0 && ![weakSelf.engine isInCall]){
        weakSelf.callState = YES; // restore gui
    }else{
        weakSelf.callState=NO; // The user successfully joins the room.
        dispatch_async(dispatch_get_main_queue(), ^{
            [weakSelf addTableView]; // Render the remote view.
        });
    }
}];

The singer starts singing

AliRtcExternalAudioStreamConfig *config = [AliRtcExternalAudioStreamConfig new];
config.channels = _pcmLocalChannels;
config.sampleRate = _pcmLocalSampleRate;
/* Set the publish volume and playback volume */
config.publishVolume = 60;
config.playoutVolume = 100;
/* Save the stream ID for future operations, such as adding Pulse Code Modulation (PCM) data to the stream and deleting the stream. */
_externalPlayoutStreamId = [self.engine addExternalAudioStream:config];

The singer sends the song progress and plays the accompaniment

/* Input PCM data */ 
AliRtcAudioFrame *sample = [AliRtcAudioFrame new];
sample.dataPtr = _pcmLocalData;
sample.samplesPerSec = _pcmLocalSampleRate;
sample.bytesPerSample = sizeof(int16_t);
sample.numOfChannels = _pcmLocalChannels;
sample.numOfSamples = numOfSamples;
int rc = [self.engine pushExternalAudioStream:_externalPlayoutStreamId rawData:sample];
/* Send the song progress information through the data channel */
AliRtcDataChannelMsg* msg = [[AliRtcDataChannelMsg alloc] init];
msg.type = AliRtcDataMsgCustom;
msg.networkTime = [self.engine getNetworkTime];
msg.data =  [NSData dataWithBytes:&progress length:8];
[self.engine sendDataChannelMessage:msg];

The audience receives song progress

- (void)onDataChannelMessage:(NSString *_Nonnull)uid controlMsg:(AliRtcDataChannelMsg*_Nonnull)controlMsg {
    long long progress = 0;
    [controlMsg.data getBytes:&progress length:sizeof(time)];
}

The streamer stops song playback

[self.engine removeExternalAudioStream:_externalPlayoutStreamId];
/* Stop decoding the song and notify other users in the room by using the IM service */