@@ -240,7 +240,7 @@ class KTVGiantChorusApiImpl(
240
240
// Android Only
241
241
mRtcEngine.setParameters(" {\" che.audio.enable_estimated_device_delay\" :false}" )
242
242
243
- // TopN
243
+ // TopN + SendAudioMetadata
244
244
mRtcEngine.setParameters(" {\" rtc.use_audio4\" : true}" )
245
245
246
246
// mutipath
@@ -753,6 +753,9 @@ class KTVGiantChorusApiImpl(
753
753
mRtcEngine.setParameters(" {\" che.audio.custom_bitrate\" : 48000}" )
754
754
}
755
755
756
+ private val subScribeSingerMap = mutableMapOf<Int , Int >() // <uid, ntpE2eDelay>
757
+ private val singerList = mutableListOf<Int >() // <uid>
758
+ private var mainSingerDelay = 0
756
759
private fun joinChorus (newRole : KTVSingRole ) {
757
760
ktvApiLog(" joinChorus: $newRole " )
758
761
val singChannelMediaOptions = ChannelMediaOptions ()
@@ -763,10 +766,11 @@ class KTVGiantChorusApiImpl(
763
766
if (newRole == KTVSingRole .LeadSinger ) {
764
767
// 主唱不参加TopN
765
768
singChannelMediaOptions.isAudioFilterable = false
766
- mRtcEngine.setParameters(" {\" che.audio.filter_streams\" :${giantChorusApiConfig.topN } }" )
769
+ mRtcEngine.setParameters(" {\" che.audio.filter_streams\" :${KTVApi .routeSelectionConfig.streamNum } }" )
767
770
} else {
768
- mRtcEngine.setParameters(" {\" che.audio.filter_streams\" :${giantChorusApiConfig.topN - 1 } }" )
771
+ mRtcEngine.setParameters(" {\" che.audio.filter_streams\" :${KTVApi .routeSelectionConfig.streamNum - 1 } }" )
769
772
}
773
+
770
774
// 加入演唱频道
771
775
mRtcEngine.joinChannelEx(giantChorusApiConfig.chorusChannelToken, singChannelRtcConnection, singChannelMediaOptions, object :
772
776
IRtcEngineEventHandler () {
@@ -825,8 +829,65 @@ class KTVGiantChorusApiImpl(
825
829
isPublishAudio = false
826
830
}
827
831
}
832
+
833
+ // 延迟选路策略
834
+ override fun onUserJoined (uid : Int , elapsed : Int ) {
835
+ super .onUserJoined(uid, elapsed)
836
+ if (uid != giantChorusApiConfig.musicStreamUid && subScribeSingerMap.size < 8 ) {
837
+ mRtcEngine.muteRemoteAudioStreamEx(uid, false , singChannelRtcConnection)
838
+ if (uid != mainSingerUid) {
839
+ subScribeSingerMap[uid] = 0
840
+ }
841
+ } else if (uid != giantChorusApiConfig.musicStreamUid && subScribeSingerMap.size == 8 ) {
842
+ mRtcEngine.muteRemoteAudioStreamEx(uid, true , singChannelRtcConnection)
843
+ }
844
+ if (uid != giantChorusApiConfig.musicStreamUid && uid != mainSingerUid) {
845
+ singerList.add(uid)
846
+ }
847
+ }
848
+
849
+ override fun onUserOffline (uid : Int , reason : Int ) {
850
+ super .onUserOffline(uid, reason)
851
+ subScribeSingerMap.remove(uid)
852
+ singerList.remove(uid)
853
+ }
854
+
855
+ override fun onLeaveChannel (stats : RtcStats ? ) {
856
+ super .onLeaveChannel(stats)
857
+ subScribeSingerMap.clear()
858
+ singerList.clear()
859
+ }
860
+
861
+ override fun onRemoteAudioStats (stats : RemoteAudioStats ? ) {
862
+ super .onRemoteAudioStats(stats)
863
+ stats ? : return
864
+ if (KTVApi .routeSelectionConfig.type == GiantChorusRouteSelectionType .RANDOM || KTVApi .routeSelectionConfig.type == GiantChorusRouteSelectionType .TOP_N ) return
865
+ val uid = stats.uid
866
+ if (uid == mainSingerUid) {
867
+ mainSingerDelay = stats.e2eDelay
868
+ }
869
+ // if (uid == mainSingerUid && stats.e2eDelay > 300) {
870
+ // //ToastUtils.showToast("主唱 $mainSingerUid 延迟超过300ms,目前延迟:${stats.ntpE2eDelay}")
871
+ // }
872
+ // if (subScribeSingerMap.any { it.key == uid } && stats.e2eDelay > 300) {
873
+ // //ToastUtils.showToast("当前订阅用户 $uid 延迟超过300ms,目前延迟:${stats.ntpE2eDelay}")
874
+ // }
875
+ if (uid != mainSingerUid && uid != giantChorusApiConfig.musicStreamUid && subScribeSingerMap.containsKey(uid)) {
876
+ subScribeSingerMap[uid] = stats.e2eDelay
877
+ }
878
+ }
828
879
})
829
880
mRtcEngine.setParameters(" {\" rtc.use_audio4\" : true}" )
881
+ // 选路策略处理
882
+ if (KTVApi .routeSelectionConfig.type == GiantChorusRouteSelectionType .TOP_N || KTVApi .routeSelectionConfig.type == GiantChorusRouteSelectionType .BY_DELAY_AND_TOP_N ) {
883
+ if (newRole == KTVSingRole .LeadSinger ) {
884
+ mRtcEngine.setParameters(" {\" che.audio.filter_streams\" :${KTVApi .routeSelectionConfig.streamNum} }" )
885
+ } else {
886
+ mRtcEngine.setParameters(" {\" che.audio.filter_streams\" :${KTVApi .routeSelectionConfig.streamNum - 1 } }" )
887
+ }
888
+ } else {
889
+ mRtcEngine.setParameters(" {\" che.audio.filter_streams\" : 0}" )
890
+ }
830
891
mRtcEngine.enableAudioVolumeIndicationEx(50 , 10 , true , singChannelRtcConnection)
831
892
832
893
when (newRole) {
@@ -1063,6 +1124,86 @@ class KTVGiantChorusApiImpl(
1063
1124
}
1064
1125
}
1065
1126
1127
+ // ------------------ 延迟选路 ------------------
1128
+ private var mStopProcessDelay = true
1129
+
1130
+ private val mProcessDelayTask = Runnable {
1131
+ if (! mStopProcessDelay && singerRole != KTVSingRole .Audience ) {
1132
+ val n = if (singerRole == KTVSingRole .LeadSinger ) KTVApi .routeSelectionConfig.streamNum else KTVApi .routeSelectionConfig.streamNum - 1
1133
+ val sortedEntries = subScribeSingerMap.entries.sortedBy { it.value }
1134
+ val other = sortedEntries.drop(3 )
1135
+ val drop = mutableListOf<Int >()
1136
+ if (n > 3 ) {
1137
+ other.drop(n - 3 ).forEach { (uid, _) ->
1138
+ drop.add(uid)
1139
+ mRtcEngine.muteRemoteAudioStreamEx(uid, true , singChannelRtcConnection)
1140
+ subScribeSingerMap.remove(uid)
1141
+ }
1142
+ }
1143
+ ktvApiLog(" 选路重新订阅, drop:$drop " )
1144
+
1145
+ val filteredList = singerList.filter { ! subScribeSingerMap.containsKey(it) }
1146
+ val filteredList2 = filteredList.filter { ! drop.contains(it) }
1147
+ val shuffledList = filteredList2.shuffled()
1148
+ if (subScribeSingerMap.size < 8 ) {
1149
+ val randomSingers = shuffledList.take(8 - subScribeSingerMap.size)
1150
+ ktvApiLog(" 选路重新订阅, newSingers:$randomSingers " )
1151
+ for (singer in randomSingers) {
1152
+ subScribeSingerMap[singer] = 0
1153
+ mRtcEngine.muteRemoteAudioStreamEx(singer, false , singChannelRtcConnection)
1154
+ }
1155
+ }
1156
+ ktvApiLog(" 选路重新订阅, newSubScribeSingerMap:$subScribeSingerMap " )
1157
+ }
1158
+ }
1159
+
1160
+ private val mProcessSubscribeTask = Runnable {
1161
+ if (! mStopProcessDelay && singerRole != KTVSingRole .Audience ) {
1162
+ val n = if (singerRole == KTVSingRole .LeadSinger ) KTVApi .routeSelectionConfig.streamNum else KTVApi .routeSelectionConfig.streamNum - 1
1163
+ val sortedEntries = subScribeSingerMap.entries.sortedBy { it.value }
1164
+ val mustToHave = sortedEntries.take(3 )
1165
+ mustToHave.forEach { (uid, _) ->
1166
+ mRtcEngine.adjustUserPlaybackSignalVolumeEx(uid, 100 , singChannelRtcConnection)
1167
+ }
1168
+ val other = sortedEntries.drop(3 )
1169
+ if (n > 3 ) {
1170
+ other.take(n - 3 ).forEach { (uid, delay) ->
1171
+ if (delay > 300 ) {
1172
+ mRtcEngine.adjustUserPlaybackSignalVolumeEx(uid, 0 , singChannelRtcConnection)
1173
+ } else {
1174
+ mRtcEngine.adjustUserPlaybackSignalVolumeEx(uid, 100 , singChannelRtcConnection)
1175
+ }
1176
+ }
1177
+ other.drop(n - 3 ).forEach { (uid, _) ->
1178
+ mRtcEngine.adjustUserPlaybackSignalVolumeEx(uid, 0 , singChannelRtcConnection)
1179
+ }
1180
+ }
1181
+
1182
+ ktvApiLog(" 选路排序+调整播放音量, mustToHave:$mustToHave , other:$other " )
1183
+ }
1184
+ }
1185
+
1186
+ private var mProcessDelayFuture : ScheduledFuture <* >? = null
1187
+ private var mProcessSubscribeFuture : ScheduledFuture <* >? = null
1188
+ private fun startProcessDelay () {
1189
+ if (KTVApi .routeSelectionConfig.type == GiantChorusRouteSelectionType .TOP_N || KTVApi .routeSelectionConfig.type == GiantChorusRouteSelectionType .RANDOM ) return
1190
+ mStopProcessDelay = false
1191
+ mProcessDelayFuture = scheduledThreadPool.scheduleAtFixedRate(mProcessDelayTask, 10000 , 20000 , TimeUnit .MILLISECONDS )
1192
+ mProcessSubscribeFuture = scheduledThreadPool.scheduleAtFixedRate(mProcessSubscribeTask,15000 ,20000 , TimeUnit .MILLISECONDS )
1193
+ }
1194
+
1195
+ private fun stopProcessDelay () {
1196
+ mStopProcessDelay = true
1197
+
1198
+ mProcessDelayFuture?.cancel(true )
1199
+ mProcessSubscribeFuture?.cancel(true )
1200
+ mProcessDelayFuture = null
1201
+ if (scheduledThreadPool is ScheduledThreadPoolExecutor ) {
1202
+ scheduledThreadPool.remove(mProcessDelayTask)
1203
+ scheduledThreadPool.remove(mProcessSubscribeTask)
1204
+ }
1205
+ }
1206
+
1066
1207
private fun loadLyric (songNo : Long , onLoadLyricCallback : (songNo: Long , lyricUrl: String? ) -> Unit ) {
1067
1208
ktvApiLog(" loadLyric: $songNo " )
1068
1209
val requestId = mMusicCenter.getLyric(songNo, 0 )
@@ -1346,6 +1487,7 @@ class KTVGiantChorusApiImpl(
1346
1487
) {
1347
1488
mPlayer.play()
1348
1489
}
1490
+ startProcessDelay()
1349
1491
}
1350
1492
MediaPlayerState .PLAYER_STATE_PLAYING -> {
1351
1493
mRtcEngine.adjustPlaybackSignalVolume(KTVApi .remoteVolume)
@@ -1356,6 +1498,7 @@ class KTVGiantChorusApiImpl(
1356
1498
MediaPlayerState .PLAYER_STATE_STOPPED -> {
1357
1499
mRtcEngine.adjustPlaybackSignalVolume(100 )
1358
1500
duration = 0
1501
+ stopProcessDelay()
1359
1502
}
1360
1503
else -> {}
1361
1504
}
0 commit comments