davidliu
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
... ... @@ -208,11 +208,14 @@ internal constructor(
lossyDataChannel!!.registerObserver(this)
}
/**
* @param builder an optional builder to include other parameters related to the track
*/
suspend fun addTrack(
cid: String,
name: String,
kind: LivekitModels.TrackType,
dimensions: Track.Dimensions? = null
builder: LivekitRtc.AddTrackRequest.Builder = LivekitRtc.AddTrackRequest.newBuilder()
): LivekitModels.TrackInfo {
if (pendingTrackResolvers[cid] != null) {
throw TrackException.DuplicateTrackException("Track with same ID $cid has already been published!")
... ... @@ -220,7 +223,7 @@ internal constructor(
return suspendCoroutine { cont ->
pendingTrackResolvers[cid] = cont
client.sendAddTrack(cid, name, kind, dimensions)
client.sendAddTrack(cid, name, kind, builder)
}
}
... ...
... ... @@ -252,16 +252,19 @@ constructor(
sendRequest(request)
}
fun sendAddTrack(cid: String, name: String, type: LivekitModels.TrackType, dimensions: Track.Dimensions? = null) {
val addTrackRequest = LivekitRtc.AddTrackRequest.newBuilder()
/**
* @param builder an optional builder to include other parameters related to the track
*/
fun sendAddTrack(
cid: String,
name: String,
type: LivekitModels.TrackType,
builder: LivekitRtc.AddTrackRequest.Builder = LivekitRtc.AddTrackRequest.newBuilder()
) {
val addTrackRequest = builder
.setCid(cid)
.setName(name)
.setType(type)
if (dimensions != null) {
addTrackRequest.width = dimensions.width
addTrackRequest.height = dimensions.height
}
val request = LivekitRtc.SignalRequest.newBuilder()
.setAddTrack(addTrackRequest)
.build()
... ...
... ... @@ -2,8 +2,6 @@ package io.livekit.android.room.participant
import android.Manifest
import android.content.Context
import android.media.MediaCodecInfo
import androidx.annotation.RequiresPermission
import com.google.protobuf.ByteString
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
... ... @@ -12,6 +10,7 @@ import io.livekit.android.room.RTCEngine
import io.livekit.android.room.track.*
import io.livekit.android.util.LKLog
import livekit.LivekitModels
import livekit.LivekitRtc
import org.webrtc.*
import kotlin.math.abs
... ... @@ -75,6 +74,7 @@ internal constructor(
suspend fun publishAudioTrack(
track: LocalAudioTrack,
options: AudioTrackPublishOptions = AudioTrackPublishOptions(),
publishListener: PublishListener? = null
) {
if (localTrackPublications.any { it.track == track }) {
... ... @@ -83,8 +83,15 @@ internal constructor(
}
val cid = track.rtcTrack.id()
val trackInfo =
engine.addTrack(cid = cid, name = track.name, kind = track.kind.toProto())
val builder = LivekitRtc.AddTrackRequest.newBuilder().apply {
disableDtx = !options.dtx
}
val trackInfo = engine.addTrack(
cid = cid,
name = track.name,
kind = track.kind.toProto(),
builder = builder
)
val transInit = RtpTransceiver.RtpTransceiverInit(
RtpTransceiver.RtpTransceiverDirection.SEND_ONLY,
listOf(this.sid)
... ... @@ -114,11 +121,15 @@ internal constructor(
}
val cid = track.rtcTrack.id()
val builder = LivekitRtc.AddTrackRequest.newBuilder().apply {
width = track.dimensions.width
height = track.dimensions.height
}
val trackInfo = engine.addTrack(
cid = cid,
name = track.name,
kind = LivekitModels.TrackType.VIDEO,
dimensions = track.dimensions
builder = builder
)
val encodings = computeVideoEncodings(track.dimensions, options)
val transInit = RtpTransceiver.RtpTransceiverInit(
... ... @@ -312,4 +323,5 @@ data class VideoTrackPublishOptions(
data class AudioTrackPublishOptions(
override val name: String? = null,
val audioBitrate: Int? = null,
val dtx: Boolean = true
) : TrackPublishOptions
\ No newline at end of file
... ...
... ... @@ -30,6 +30,8 @@ class LocalVideoTrack(
/**
* Note: these dimensions are only requested params, and may differ
* from the actual capture format used by the camera.
*
* TODO: capture actual dimensions used
*/
val dimensions: Dimensions
get() = Dimensions(options.captureParams.width, options.captureParams.height)
... ...
package io.livekit.android.stats
import android.content.Context
import android.net.TrafficStats
import io.livekit.android.util.LKLog
import kotlinx.coroutines.*
import kotlin.coroutines.CoroutineContext
internal class NetworkMonitor(private val context: Context) {
private lateinit var coroutineContext: CoroutineContext
private lateinit var scope: CoroutineScope
fun start() {
coroutineContext = SupervisorJob() + Dispatchers.IO
scope = CoroutineScope(coroutineContext)
scope.launch {
val uid = context.packageManager.getApplicationInfo(context.packageName, 0).uid
var prevTxBytes = TrafficStats.getUidTxBytes(uid)
var emaTxBytes = 0L
while (this.isActive) {
val totalTxBytes = TrafficStats.getUidTxBytes(uid)
val intervalTxBytes = totalTxBytes - prevTxBytes
prevTxBytes = totalTxBytes
emaTxBytes = emaTxBytes / 2 + intervalTxBytes / 2
LKLog.v { "send rate: ${convertBytesToReadableString(emaTxBytes)}" }
delay(1000)
}
}
}
private fun convertBytesToReadableString(bytes: Long): String {
var num = bytes.toFloat()
var level = 0
while (num >= 1024 && level < 2) {
num /= 1024
level++
}
// MBps should be way more than enough.
val suffix = when (level) {
0 -> "Bps"
1 -> "kBps"
2 -> "MBps"
else -> throw IllegalStateException("this shouldn't happen. level = $level")
}
return "$num $suffix"
}
fun stop() {
coroutineContext.cancel()
}
}
\ No newline at end of file
... ...
Subproject commit 1dadf893095928a27ae47b63cdce74607c38f229
Subproject commit 4d580badfde3d8b794ea54fcf417747aa60af20a
... ...