tencent cloud

文档反馈

最后更新时间:2024-07-04 10:10:52

    1.1 实现流程

    歌词同步方案中,三种不同角色的动作如下:
    主唱
    合唱
    观众
    NTP 校时
    开启补黑帧
    发送 SEI 消息
    本地歌词同步
    更新歌词控件
    NTP 校时
    本地歌词同步
    更新歌词控件
    NTP 校时
    接收 SEI 消息
    更新歌词控件
    其中,主唱及合唱根据同步后的歌曲播放进度,在本地更新歌词进度;观众端则需要接收由主唱端发送的,包含最新歌词进度的 SEI 消息来更新本地的歌词进度。
    
    
    

    时序图

    
    
    
    歌词同步时序主要可以分为三个部分:NTP 校时、开启补黑帧、本地及远端歌词同步。NTP 校时的代码实现在 歌曲同步 中已经给出,下面将针对后两个部分给出具体的代码实现。

    关键代码实现

    1. 开启补黑帧

    // 纯音频模式下,主实例(人声实例)需要开启补黑帧以携带 SEI 消息
    NSDictionary *jsonDic = @{
    @"api": @"enableBlackStream",
    @"params":
    @{
    @"enable": @(1)
    }
    };
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonDic options:NSJSONWritingPrettyPrinted error:nil];
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    [trtcCloud callExperimentalAPI:jsonString];
    说明:
    该实验性接口 enableBlackStream 需要在进房之后调用;
    在 Android 端,enable 参数的值类型为布尔型,在 iOS 端为整型;
    接收端需要在收到 onUserVideoAvailable(userId, true) 时调用 startRemoteView(userId, null)。

    2. 通过 SEI 消息发送歌曲进度

    TXAudioMusicProgressBlock progressBlock = ^(NSInteger progressMs, NSInteger durationMs) {
    //当前 ntp 时间
    NSInteger ntpTime = [TXLiveBase getNetworkTimestamp];
    //通知歌曲进度,用户会在这里进行歌词的滚动
    NSDictionary *progressMsg = @{
    @"bgmProgressTime":@(progressMs),
    @"ntpTime":@(ntpTime),
    @"musicId": @(musicId),
    @"duration": @(durationMs),
    };
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:progressMsg options:NSJSONWritingPrettyPrinted error:nil];
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    [trtcCloud sendSEIMsg:[jsonString dataUsingEncoding:NSUTF8StringEncoding] repeatCount:1];
    };
    说明:
    主唱发送 SEI 消息的频率由背景音乐播放事件回调的频率决定,一般为 200ms;
    不直接使用 CMD 消息发送歌曲进度的原因:SEI 通道传输的信令可以伴随视频帧一直传输到直播 CDN 上,对于拉取 CDN 流的观众具有更好的兼容性。

    3. 本地及远端歌词同步

    // 本地歌词同步
    TXAudioMusicProgressBlock progressBlock = ^(NSInteger progressMs, NSInteger durationMs) {
    ...
    // TODO 更新歌词控件逻辑:
    // 根据最新进度和本地歌词进度误差,判断是否需要 seek 歌词控件
    ...
    };
    
    // 远端歌词同步
    - (void)onRecvSEIMsg:(NSString *)userId message:(NSData *)message {
    NSError *err = nil;
    NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:message options:NSJSONReadingMutableContainers error:&err];
    if (err || ![dic isKindOfClass:[NSDictionary class]]) {
    // 解析出错
    return;
    }
    NSInteger bgmProgressTime = [[dic objectForKey:@"bgmProgressTime"] integerValue];
    NSInteger ntpTime = [[dic objectForKey:@"ntpTime"] integerValue];
    int32_t musicId = [[dic objectForKey:@"musicId"] intValue];
    NSInteger duration = [[dic objectForKey:@"duration"] integerValue];
    ...
    // TODO 更新歌词控件逻辑:
    // 根据接收到的最新进度和本地歌词进度误差,判断是否需要 seek 歌词控件
    ...
    }
    说明:
    如果复用 TUIKaraoke 组件的歌词控件,请参照 TUIKaraoke TRTCLyricView 部分的代码逻辑同步歌词控件进度。
    联系我们

    联系我们,为您的业务提供专属服务。

    技术支持

    如果你想寻求进一步的帮助,通过工单与我们进行联络。我们提供7x24的工单服务。

    7x24 电话支持