RTC Engine
  • Overview
  • Web
    • Demo のクイックスタート
    • SDK クイックスタート
    • 基本機能
      • 画面共有
      • ライブブロードキャスト
      • メディアデバイス
      • 音量
      • エンコーディング構成ファイルの設定
      • ネットワーク品質の検出
      • 検出能力
    • 高度な機能
      • AI ノイズ低減の有効化
      • ミキシングを有効にします
      • ウォーターマークを有効にします
      • Enable Virtual Background
      • 美顔とエフェクトの有効化
      • データメッセージ
      • キャプチャーとレンタリングのカスタマイズ
    • インターフェースリスト
    • リリース説明
    • 対応するプラットホーム
    • Web に関するよくあるご質問
      • 複数人でのビデオ通話を最適化
      • 制限付き自動再生の処理
      • ファイアウォール制限への対応
      • その他
  • Android
    • Run Sample Code
    • Integration
    • インテグレーション
      • 7. ネットワーク品質の検出
      • 8. 画面共有の有効化
      • 9. ビデオ品質の設定
      • 10. ビデオの回転
    • Advanced Features
      • ネットワーク品質のテスト
      • キャプチャーとレンタリングのカスタマイズ
      • オーディオキャプチャーと再生のカスタマイズ
    • 顧客インターフェース
      • Overview
      • TRTCCloud
      • TRTCStatistics
      • TRTCCloudListener
      • TXAudioEffectManager
      • TXBeautyManager
      • TXDeviceManager
      • タイプ定義
      • 廃棄インタフェース
      • エラーコード
    • ソリューション
      • リアルタイムコーラス (TUIKaraoke)
        • クイックインテグレーション
        • 実施ステップ
        • 曲の同期
        • 歌詞の同期
        • 音声同期
        • ミクスストリーミングソリューション
        • TRTCKaraoke 関連インターフェース
        • よくあるご質問
    • リリース説明
  • iOS
    • Run Sample Code
    • Integration
    • インテグレーション
      • 7. ネットワーク品質の検出
      • 8. 画面共有の有効化
      • 9. ビデオ品質の設定
      • 10. ビデオの回転
    • Advanced Features
      • ネットワーク品質のテスト
      • キャプチャーとレンタリングのカスタマイズ
      • オーディオキャプチャーと再生のカスタマイズ
    • 顧客インターフェース
      • Overview
      • TRTCCloud
      • TRTCCloudDelegate
      • TRTCStatistics
      • TXAudioEffectManager
      • TXBeautyManager
      • TXDeviceManager
      • タイプ定義
      • 廃棄インタフェース
      • ErrorCode
    • ソリューション
      • クイックインテグレーション
      • 実施ステップ
      • 曲の同期
      • 歌詞の同期
      • 音声同期
      • ミクスストリーミングソリューション
      • TRTCKaraoke 関連インターフェース
      • よくあるご質問
    • リリース説明
  • macOS
    • Run Sample Code
    • Integration
    • インテグレーション
      • 7. ネットワーク品質の検出
      • 8. 画面共有の有効化
      • 9. パソコンサウンドの共有
      • 10. ビデオ品質の設定
      • 11. ビデオの回転
    • Advanced Features
      • ハードウェアデバイスのテスト
      • ネットワーク品質のテスト
      • キャプチャーとレンタリングのカスタマイズ
      • オーディオキャプチャーと再生のカスタマイズ
    • 顧客インターフェース
      • Overview
      • TRTCCloud
      • TRTCCloudDelegate
      • TRTCStatistics
      • TXAudioEffectManager
      • TXBeautyManager
      • TXDeviceManager
      • タイプ定義
      • 廃棄インタフェース
      • ErrorCode
      • リリース説明
    • リリース説明
  • Windows
    • Run Sample Code
    • Integration
    • インテグレーション
      • 7. ネットワーク品質の検出
      • 8. 画面共有の有効化
      • 9. ビデオ品質の設定
      • 10. ビデオの回転
    • Advanced Features
      • ハードウェアデバイスのテスト
      • ネットワーク品質のテスト
      • キャプチャーとレンタリングのカスタマイズ
      • オーディオキャプチャーと再生のカスタマイズ
    • 顧客インターフェース
      • Overview
      • ITRTCCloud
      • ITRTCStatistics
      • TRTCCloudCallback
      • ITXAudioEffectManager
      • ITXDeviceManager
      • タイプ定義
      • 廃棄インタフェース
      • エラーコード
    • リリース説明
  • Electron
    • インテグレーション
      • 1. インターフェースの例
      • 2. SDK のインポート
      • 3. ルームに入る
      • 4. オーディオ・ビデオストリームのサブスクリプション
      • 5. オーディオ・ビデオストリームのリリース
      • 6. ルームからの退出
      • 7. ネットワーク品質の検出
      • 8. 画面共有の有効化
      • 9. パソコンサウンドの共有
      • 10. ビデオ品質の設定
      • 11. ビデオの回転
    • 顧客インターフェース
      • Overview
      • エラーコード
  • Flutter
    • インテグレーション
      • 1. インターフェースの例
      • 2. SDK のインポート
      • 3. ルームに入る
      • 4. オーディオ・ビデオストリームのサブスクリプション
      • 5. オーディオ・ビデオストリームのリリース
      • 6. ルームからの退出
      • 7. ネットワーク品質の検出
      • 8. 画面共有の有効化
      • 9. パソコンサウンドの共有
      • 10. ビデオ品質の設定
      • 11. ビデオの回転
    • 顧客インターフェース
      • Overview
      • エラーコード
  • Unity
    • インテグレーション
      • 1. インターフェースの例
      • 2. SDK のインポート
    • 顧客インターフェース
      • Overview
      • エラーコード
  • QT
    • インテグレーション
      • 1. SDK のインポート
  • Overview
    • Overview
  • 概念
  • Features
  • 性能統計
  • 価格
    • 無料時間
    • RTC-Engine パッケージ
    • サブスクリプションパッケージ期間の課金説明
    • 従量課金
      • 音声・ビデオ時間の課金説明
      • クラウド録画の課金説明
      • ミックストランスコーディングとCDNへのリレーの課金説明
  • よくあるご質問
    • 初心者のよくあるご質問
    • マイグレーションガイド
      • Twilio Video から TRTC への移行
      • 課金
      • Features
      • UserSig
      • ファイアウォール制限
      • インストールパッケージを削減する方法
      • TRTCCalling Web 関連
      • オーディオ・ビデオの品質
      • その他
RTC Engine
このページは現在英語版のみで提供されており、日本語版も近日中に提供される予定です。ご利用いただきありがとうございます。

曲の同期

Real-time synchronization of song progress is required in the real-time solution to avoid increasing end-to-end delay due to song errors after the start of the performance. Synchronizing the song requires using NTP time. The local clocks of different devices are not consistent and there is a certain error, so Tencent Cloud's self-developed NTP service needs to be introduced. At the same time, users who join the chorus midway also need to synchronize the song progress, and only after synchronizing the progress can they participate in the chorus.

Implementation process

The method of synchronizing songs is that the main singer user agrees to start playing the song at a future point in time (such as N seconds after delay), and other users participate in the chorus. The time of each end is based on NTP time, which will start synchronizing after the TRTC SDK is initialized.




The specific process is as follows:
1. Each end performs NTP time calibration, updates and obtains the latest NTP time T to the TRTC cloud.
2. The main singer end sends a chorus signal (custom message) to agree on the start time T2 of the chorus.
3. Preload the song locally based on T2 and play it at a scheduled time.
4. Other chorus users execute step 3 after receiving the chorus signal.
5. During the process, the local song playback progress is verified, and seek calibration is performed when the difference between TE and TC exceeds 50ms.
Note
The 50ms error here is a typical value, which can be adjusted appropriately according to the business tolerance. It is recommended to fluctuate around 50ms.

Timing diagram






The song synchronization timing can mainly be divided into three parts: NTP time calibration, sending and receiving chorus signals, and correcting the song playback progress. The following will provide specific code implementation for these three parts.

Key code implementation

1. NTP calibration time service

// Call the NTP time synchronization interface when entering the room.
[TXLiveBase updateNetworkTime];

// In the TXLiveBaseDelegate callback, determine whether the time synchronization is successful.
- (void)onUpdateNetworkTime:(int)errCode message:(NSString *)errMsg {
// errCode 0: 0: Time synchronization is successful and the deviation is within 30ms;
// 1: Time synchronization is successful, but the deviation may be over 30ms;
// -1: Time synchronization failed.
if (errCode == 0) {
// Call TXLiveBase's getNetworkTimestamp to obtain the NTP timestamp.
NSInteger ntpTime = [TXLiveBase getNetworkTimestamp];
} else {
// Call updateNetworkTime again to initiate a time synchronization.
[TXLiveBase updateNetworkTime];
}
}

2. Sending chorus signals on the main singer end

NSDictionary *json = @{
@"cmd": @"startChorus",
// Scheduled time for a tutti.
@"startPlayMusicTS": @(startTs),
@"musicId": @"musicId",
@"musicDuration": @(musicDuration),
};
NSString *jsonString = [self jsonStringFrom:json];
[trtcCloud sendCustomMessage:jsonString reliable:NO];
Note
It is recommended that the main singer send chorus signal messages to the room at a fixed time frequency in a loop, so that chorus users can join in midway;
The reason for not using SEI messages to send chorus signals is that the SEI information will be inserted into the video frame, causing a lot of invalid information to be carried in the video stream pulled by the audience side.

3. Receiving chorus signals on the chorus end

- (void)onRecvCustomCmdMsgUserId:(NSString *)userId cmdID:(NSInteger)cmdId seq:(UInt32)seq message:(NSData *)message {

NSString *msg = [[NSString alloc] initWithData:message encoding:NSUTF8StringEncoding];
NSError *error;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:[msg dataUsingEncoding:NSUTF8StringEncoding]
options:NSJSONReadingMutableContainers
error:&error];

NSObject *cmdObj = [json objectForKey:@"cmd"];

NSInteger musicDuration = [[json objectForKey:@"musicDuration"] integerValue];

NSString *cmd = (NSString *)cmdObj;

// tutti command
if ([cmd isEqualToString:@"startChorus"]) {
// tutti start time
NSObject *startPlayMusicTsObj = [json objectForKey:@"startPlayMusicTS"];
NSString *musicId = [json objectForKey:@"musicId"];

NSInteger startPlayMusicTs = ((NSNumber *)startPlayMusicTsObj).longLongValue;
// The difference between the scheduled tutti time and the current time.
NSInteger startDelayMS = labs(startPlayMusicTs - [TXLiveBase getNetworkTimestamp]);
// Start preloading, and jump the song progress according to the difference
// between the scheduled duet time and the current NTP time.
NSDictionary *jsonDict = @{
@"api": @"preloadMusic",
@"params": @{
@"musicId": @(musicId),
@"path": path,
@"startTimeMS": @(startDelayMS),
}
};
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonDict options:0 error:NULL];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[subCloud callExperimentalAPI:jsonString];

// play music
TXAudioMusicParam *param = [[TXAudioMusicParam alloc] init];
param.ID = musicId;
param.path = url;
param.loopCount = 0;
param.publish = NO;

[[subCloud getAudioEffectManager] startPlayMusic:param onStart:^(NSInteger errCode) {
// star play callback
} onProgress:^(NSInteger progressMs, NSInteger durationMs) {
// lyric progress callback
} onComplete:^(NSInteger errCode) {
// play completely callback
}];

}
}
Note
After the chorus end receives the first startChorus signal, the status should be changed from "not singing" to "singing", and no longer respond to the startChorus signal to avoid restarting the BGM playback.

4. Song playback progress correction

self.startPlayChorusMusicTs; // The originally scheduled tutti time.
// Current playback progress
NSInteger currentProgress = [[self audioEffecManager] getMusicCurrentPosInMS:self.currentPlayMusicID];
// The ideal playback time progress of the current song.
NSInteger estimatedProgress = [TXLiveBase getNetworkTimestamp] - self.startPlayChorusMusicTs;
if (estimatedProgress >= 0 && labs(currentProgress - estimatedProgress) > 50) {
// When the playback progress exceeds 50ms, make adjustments.
[[subCloud getAudioEffectManager] seekMusicToPosInMS:self.currentPlayMusicID pts:estimatedProgress];
}