Committed by
GitHub
android dtx support (#15)
* update protocol submodule commit * Add option to control DTX (Discontinuous Transmission) * Network monitoring tool to measure tx stats * Move network monitor into sdk for now * Use LKLog instead of timber
正在显示
6 个修改的文件
包含
92 行增加
和
15 行删除
| @@ -208,11 +208,14 @@ internal constructor( | @@ -208,11 +208,14 @@ internal constructor( | ||
| 208 | lossyDataChannel!!.registerObserver(this) | 208 | lossyDataChannel!!.registerObserver(this) |
| 209 | } | 209 | } |
| 210 | 210 | ||
| 211 | + /** | ||
| 212 | + * @param builder an optional builder to include other parameters related to the track | ||
| 213 | + */ | ||
| 211 | suspend fun addTrack( | 214 | suspend fun addTrack( |
| 212 | cid: String, | 215 | cid: String, |
| 213 | name: String, | 216 | name: String, |
| 214 | kind: LivekitModels.TrackType, | 217 | kind: LivekitModels.TrackType, |
| 215 | - dimensions: Track.Dimensions? = null | 218 | + builder: LivekitRtc.AddTrackRequest.Builder = LivekitRtc.AddTrackRequest.newBuilder() |
| 216 | ): LivekitModels.TrackInfo { | 219 | ): LivekitModels.TrackInfo { |
| 217 | if (pendingTrackResolvers[cid] != null) { | 220 | if (pendingTrackResolvers[cid] != null) { |
| 218 | throw TrackException.DuplicateTrackException("Track with same ID $cid has already been published!") | 221 | throw TrackException.DuplicateTrackException("Track with same ID $cid has already been published!") |
| @@ -220,7 +223,7 @@ internal constructor( | @@ -220,7 +223,7 @@ internal constructor( | ||
| 220 | 223 | ||
| 221 | return suspendCoroutine { cont -> | 224 | return suspendCoroutine { cont -> |
| 222 | pendingTrackResolvers[cid] = cont | 225 | pendingTrackResolvers[cid] = cont |
| 223 | - client.sendAddTrack(cid, name, kind, dimensions) | 226 | + client.sendAddTrack(cid, name, kind, builder) |
| 224 | } | 227 | } |
| 225 | } | 228 | } |
| 226 | 229 |
| @@ -252,16 +252,19 @@ constructor( | @@ -252,16 +252,19 @@ constructor( | ||
| 252 | sendRequest(request) | 252 | sendRequest(request) |
| 253 | } | 253 | } |
| 254 | 254 | ||
| 255 | - fun sendAddTrack(cid: String, name: String, type: LivekitModels.TrackType, dimensions: Track.Dimensions? = null) { | ||
| 256 | - val addTrackRequest = LivekitRtc.AddTrackRequest.newBuilder() | 255 | + /** |
| 256 | + * @param builder an optional builder to include other parameters related to the track | ||
| 257 | + */ | ||
| 258 | + fun sendAddTrack( | ||
| 259 | + cid: String, | ||
| 260 | + name: String, | ||
| 261 | + type: LivekitModels.TrackType, | ||
| 262 | + builder: LivekitRtc.AddTrackRequest.Builder = LivekitRtc.AddTrackRequest.newBuilder() | ||
| 263 | + ) { | ||
| 264 | + val addTrackRequest = builder | ||
| 257 | .setCid(cid) | 265 | .setCid(cid) |
| 258 | .setName(name) | 266 | .setName(name) |
| 259 | .setType(type) | 267 | .setType(type) |
| 260 | - if (dimensions != null) { | ||
| 261 | - addTrackRequest.width = dimensions.width | ||
| 262 | - addTrackRequest.height = dimensions.height | ||
| 263 | - } | ||
| 264 | - | ||
| 265 | val request = LivekitRtc.SignalRequest.newBuilder() | 268 | val request = LivekitRtc.SignalRequest.newBuilder() |
| 266 | .setAddTrack(addTrackRequest) | 269 | .setAddTrack(addTrackRequest) |
| 267 | .build() | 270 | .build() |
| @@ -2,8 +2,6 @@ package io.livekit.android.room.participant | @@ -2,8 +2,6 @@ package io.livekit.android.room.participant | ||
| 2 | 2 | ||
| 3 | import android.Manifest | 3 | import android.Manifest |
| 4 | import android.content.Context | 4 | import android.content.Context |
| 5 | -import android.media.MediaCodecInfo | ||
| 6 | -import androidx.annotation.RequiresPermission | ||
| 7 | import com.google.protobuf.ByteString | 5 | import com.google.protobuf.ByteString |
| 8 | import dagger.assisted.Assisted | 6 | import dagger.assisted.Assisted |
| 9 | import dagger.assisted.AssistedFactory | 7 | import dagger.assisted.AssistedFactory |
| @@ -12,6 +10,7 @@ import io.livekit.android.room.RTCEngine | @@ -12,6 +10,7 @@ import io.livekit.android.room.RTCEngine | ||
| 12 | import io.livekit.android.room.track.* | 10 | import io.livekit.android.room.track.* |
| 13 | import io.livekit.android.util.LKLog | 11 | import io.livekit.android.util.LKLog |
| 14 | import livekit.LivekitModels | 12 | import livekit.LivekitModels |
| 13 | +import livekit.LivekitRtc | ||
| 15 | import org.webrtc.* | 14 | import org.webrtc.* |
| 16 | import kotlin.math.abs | 15 | import kotlin.math.abs |
| 17 | 16 | ||
| @@ -75,6 +74,7 @@ internal constructor( | @@ -75,6 +74,7 @@ internal constructor( | ||
| 75 | 74 | ||
| 76 | suspend fun publishAudioTrack( | 75 | suspend fun publishAudioTrack( |
| 77 | track: LocalAudioTrack, | 76 | track: LocalAudioTrack, |
| 77 | + options: AudioTrackPublishOptions = AudioTrackPublishOptions(), | ||
| 78 | publishListener: PublishListener? = null | 78 | publishListener: PublishListener? = null |
| 79 | ) { | 79 | ) { |
| 80 | if (localTrackPublications.any { it.track == track }) { | 80 | if (localTrackPublications.any { it.track == track }) { |
| @@ -83,8 +83,15 @@ internal constructor( | @@ -83,8 +83,15 @@ internal constructor( | ||
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | val cid = track.rtcTrack.id() | 85 | val cid = track.rtcTrack.id() |
| 86 | - val trackInfo = | ||
| 87 | - engine.addTrack(cid = cid, name = track.name, kind = track.kind.toProto()) | 86 | + val builder = LivekitRtc.AddTrackRequest.newBuilder().apply { |
| 87 | + disableDtx = !options.dtx | ||
| 88 | + } | ||
| 89 | + val trackInfo = engine.addTrack( | ||
| 90 | + cid = cid, | ||
| 91 | + name = track.name, | ||
| 92 | + kind = track.kind.toProto(), | ||
| 93 | + builder = builder | ||
| 94 | + ) | ||
| 88 | val transInit = RtpTransceiver.RtpTransceiverInit( | 95 | val transInit = RtpTransceiver.RtpTransceiverInit( |
| 89 | RtpTransceiver.RtpTransceiverDirection.SEND_ONLY, | 96 | RtpTransceiver.RtpTransceiverDirection.SEND_ONLY, |
| 90 | listOf(this.sid) | 97 | listOf(this.sid) |
| @@ -114,11 +121,15 @@ internal constructor( | @@ -114,11 +121,15 @@ internal constructor( | ||
| 114 | } | 121 | } |
| 115 | 122 | ||
| 116 | val cid = track.rtcTrack.id() | 123 | val cid = track.rtcTrack.id() |
| 124 | + val builder = LivekitRtc.AddTrackRequest.newBuilder().apply { | ||
| 125 | + width = track.dimensions.width | ||
| 126 | + height = track.dimensions.height | ||
| 127 | + } | ||
| 117 | val trackInfo = engine.addTrack( | 128 | val trackInfo = engine.addTrack( |
| 118 | cid = cid, | 129 | cid = cid, |
| 119 | name = track.name, | 130 | name = track.name, |
| 120 | kind = LivekitModels.TrackType.VIDEO, | 131 | kind = LivekitModels.TrackType.VIDEO, |
| 121 | - dimensions = track.dimensions | 132 | + builder = builder |
| 122 | ) | 133 | ) |
| 123 | val encodings = computeVideoEncodings(track.dimensions, options) | 134 | val encodings = computeVideoEncodings(track.dimensions, options) |
| 124 | val transInit = RtpTransceiver.RtpTransceiverInit( | 135 | val transInit = RtpTransceiver.RtpTransceiverInit( |
| @@ -312,4 +323,5 @@ data class VideoTrackPublishOptions( | @@ -312,4 +323,5 @@ data class VideoTrackPublishOptions( | ||
| 312 | data class AudioTrackPublishOptions( | 323 | data class AudioTrackPublishOptions( |
| 313 | override val name: String? = null, | 324 | override val name: String? = null, |
| 314 | val audioBitrate: Int? = null, | 325 | val audioBitrate: Int? = null, |
| 326 | + val dtx: Boolean = true | ||
| 315 | ) : TrackPublishOptions | 327 | ) : TrackPublishOptions |
| @@ -30,6 +30,8 @@ class LocalVideoTrack( | @@ -30,6 +30,8 @@ class LocalVideoTrack( | ||
| 30 | /** | 30 | /** |
| 31 | * Note: these dimensions are only requested params, and may differ | 31 | * Note: these dimensions are only requested params, and may differ |
| 32 | * from the actual capture format used by the camera. | 32 | * from the actual capture format used by the camera. |
| 33 | + * | ||
| 34 | + * TODO: capture actual dimensions used | ||
| 33 | */ | 35 | */ |
| 34 | val dimensions: Dimensions | 36 | val dimensions: Dimensions |
| 35 | get() = Dimensions(options.captureParams.width, options.captureParams.height) | 37 | get() = Dimensions(options.captureParams.width, options.captureParams.height) |
| 1 | +package io.livekit.android.stats | ||
| 2 | + | ||
| 3 | +import android.content.Context | ||
| 4 | +import android.net.TrafficStats | ||
| 5 | +import io.livekit.android.util.LKLog | ||
| 6 | +import kotlinx.coroutines.* | ||
| 7 | +import kotlin.coroutines.CoroutineContext | ||
| 8 | + | ||
| 9 | +internal class NetworkMonitor(private val context: Context) { | ||
| 10 | + | ||
| 11 | + private lateinit var coroutineContext: CoroutineContext | ||
| 12 | + private lateinit var scope: CoroutineScope | ||
| 13 | + fun start() { | ||
| 14 | + coroutineContext = SupervisorJob() + Dispatchers.IO | ||
| 15 | + scope = CoroutineScope(coroutineContext) | ||
| 16 | + scope.launch { | ||
| 17 | + | ||
| 18 | + val uid = context.packageManager.getApplicationInfo(context.packageName, 0).uid | ||
| 19 | + | ||
| 20 | + var prevTxBytes = TrafficStats.getUidTxBytes(uid) | ||
| 21 | + var emaTxBytes = 0L | ||
| 22 | + while (this.isActive) { | ||
| 23 | + val totalTxBytes = TrafficStats.getUidTxBytes(uid) | ||
| 24 | + val intervalTxBytes = totalTxBytes - prevTxBytes | ||
| 25 | + prevTxBytes = totalTxBytes | ||
| 26 | + emaTxBytes = emaTxBytes / 2 + intervalTxBytes / 2 | ||
| 27 | + | ||
| 28 | + LKLog.v { "send rate: ${convertBytesToReadableString(emaTxBytes)}" } | ||
| 29 | + | ||
| 30 | + delay(1000) | ||
| 31 | + } | ||
| 32 | + } | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + private fun convertBytesToReadableString(bytes: Long): String { | ||
| 36 | + var num = bytes.toFloat() | ||
| 37 | + var level = 0 | ||
| 38 | + while (num >= 1024 && level < 2) { | ||
| 39 | + num /= 1024 | ||
| 40 | + level++ | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + // MBps should be way more than enough. | ||
| 44 | + val suffix = when (level) { | ||
| 45 | + 0 -> "Bps" | ||
| 46 | + 1 -> "kBps" | ||
| 47 | + 2 -> "MBps" | ||
| 48 | + else -> throw IllegalStateException("this shouldn't happen. level = $level") | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + return "$num $suffix" | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + fun stop() { | ||
| 55 | + coroutineContext.cancel() | ||
| 56 | + } | ||
| 57 | +} |
-
请 注册 或 登录 后发表评论