davidliu
Committed by GitHub

Add network type to websocket query (#140)

1 package io.livekit.android.dagger 1 package io.livekit.android.dagger
2 2
  3 +import android.content.Context
3 import androidx.annotation.Nullable 4 import androidx.annotation.Nullable
4 import dagger.Module 5 import dagger.Module
5 import dagger.Provides 6 import dagger.Provides
  7 +import dagger.Reusable
  8 +import io.livekit.android.stats.AndroidNetworkInfo
  9 +import io.livekit.android.stats.NetworkInfo
6 import okhttp3.OkHttpClient 10 import okhttp3.OkHttpClient
7 import okhttp3.WebSocket 11 import okhttp3.WebSocket
8 import javax.inject.Named 12 import javax.inject.Named
@@ -24,4 +28,10 @@ object WebModule { @@ -24,4 +28,10 @@ object WebModule {
24 fun websocketFactory(okHttpClient: OkHttpClient): WebSocket.Factory { 28 fun websocketFactory(okHttpClient: OkHttpClient): WebSocket.Factory {
25 return okHttpClient 29 return okHttpClient
26 } 30 }
  31 +
  32 + @Provides
  33 + @Reusable
  34 + fun networkInfo(context: Context): NetworkInfo {
  35 + return AndroidNetworkInfo(context)
  36 + }
27 } 37 }
@@ -6,6 +6,7 @@ import io.livekit.android.RoomOptions @@ -6,6 +6,7 @@ import io.livekit.android.RoomOptions
6 import io.livekit.android.dagger.InjectionNames 6 import io.livekit.android.dagger.InjectionNames
7 import io.livekit.android.room.participant.ParticipantTrackPermission 7 import io.livekit.android.room.participant.ParticipantTrackPermission
8 import io.livekit.android.room.track.Track 8 import io.livekit.android.room.track.Track
  9 +import io.livekit.android.stats.NetworkInfo
9 import io.livekit.android.stats.getClientInfo 10 import io.livekit.android.stats.getClientInfo
10 import io.livekit.android.util.CloseableCoroutineScope 11 import io.livekit.android.util.CloseableCoroutineScope
11 import io.livekit.android.util.Either 12 import io.livekit.android.util.Either
@@ -42,6 +43,7 @@ constructor( @@ -42,6 +43,7 @@ constructor(
42 private val okHttpClient: OkHttpClient, 43 private val okHttpClient: OkHttpClient,
43 @Named(InjectionNames.DISPATCHER_IO) 44 @Named(InjectionNames.DISPATCHER_IO)
44 private val ioDispatcher: CoroutineDispatcher, 45 private val ioDispatcher: CoroutineDispatcher,
  46 + private val networkInfo: NetworkInfo,
45 ) : WebSocketListener() { 47 ) : WebSocketListener() {
46 var isConnected = false 48 var isConnected = false
47 private set 49 private set
@@ -147,6 +149,7 @@ constructor( @@ -147,6 +149,7 @@ constructor(
147 queryParams.add(CONNECT_QUERY_DEVICE_MODEL to clientInfo.deviceModel) 149 queryParams.add(CONNECT_QUERY_DEVICE_MODEL to clientInfo.deviceModel)
148 queryParams.add(CONNECT_QUERY_OS to clientInfo.os) 150 queryParams.add(CONNECT_QUERY_OS to clientInfo.os)
149 queryParams.add(CONNECT_QUERY_OS_VERSION to clientInfo.osVersion) 151 queryParams.add(CONNECT_QUERY_OS_VERSION to clientInfo.osVersion)
  152 + queryParams.add(CONNECT_QUERY_NETWORK_TYPE to networkInfo.getNetworkType().protoName)
150 153
151 return queryParams.foldIndexed("") { index, acc, pair -> 154 return queryParams.foldIndexed("") { index, acc, pair ->
152 val separator = if(index == 0) "?" else "&" 155 val separator = if(index == 0) "?" else "&"
@@ -604,6 +607,7 @@ constructor( @@ -604,6 +607,7 @@ constructor(
604 const val CONNECT_QUERY_DEVICE_MODEL = "device_model" 607 const val CONNECT_QUERY_DEVICE_MODEL = "device_model"
605 const val CONNECT_QUERY_OS = "os" 608 const val CONNECT_QUERY_OS = "os"
606 const val CONNECT_QUERY_OS_VERSION = "os_version" 609 const val CONNECT_QUERY_OS_VERSION = "os_version"
  610 + const val CONNECT_QUERY_NETWORK_TYPE = "network"
607 611
608 const val SD_TYPE_ANSWER = "answer" 612 const val SD_TYPE_ANSWER = "answer"
609 const val SD_TYPE_OFFER = "offer" 613 const val SD_TYPE_OFFER = "offer"
  1 +package io.livekit.android.stats
  2 +
  3 +import android.content.Context
  4 +import android.net.ConnectivityManager
  5 +import android.net.NetworkCapabilities
  6 +import android.os.Build
  7 +
  8 +interface NetworkInfo {
  9 + fun getNetworkType(): NetworkType
  10 +}
  11 +
  12 +class AndroidNetworkInfo(private val context: Context) : NetworkInfo {
  13 + override fun getNetworkType(): NetworkType {
  14 + val connectivityManager =
  15 + context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager ?: return NetworkType.UNKNOWN
  16 +
  17 + @Suppress("DEPRECATION")
  18 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  19 + val nw = connectivityManager.activeNetwork ?: return NetworkType.UNKNOWN
  20 + val actNw = connectivityManager.getNetworkCapabilities(nw) ?: return NetworkType.UNKNOWN
  21 + return when {
  22 + actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> NetworkType.WIFI
  23 + actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> NetworkType.ETHERNET
  24 + actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> NetworkType.CELLULAR
  25 + actNw.hasTransport(NetworkCapabilities.TRANSPORT_VPN) -> NetworkType.VPN
  26 + actNw.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> NetworkType.BLUETOOTH
  27 + actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI_AWARE) -> NetworkType.OTHER
  28 + actNw.hasTransport(NetworkCapabilities.TRANSPORT_LOWPAN) -> NetworkType.OTHER
  29 + actNw.hasTransport(NetworkCapabilities.TRANSPORT_USB) -> NetworkType.OTHER
  30 + else -> NetworkType.UNKNOWN
  31 + }
  32 + } else {
  33 + val info = connectivityManager.activeNetworkInfo
  34 + if (info == null || !info.isConnected) return NetworkType.UNKNOWN
  35 + return when (info.type) {
  36 + ConnectivityManager.TYPE_BLUETOOTH -> NetworkType.BLUETOOTH
  37 + ConnectivityManager.TYPE_DUMMY -> NetworkType.UNKNOWN
  38 + ConnectivityManager.TYPE_ETHERNET -> NetworkType.ETHERNET
  39 + ConnectivityManager.TYPE_MOBILE -> NetworkType.CELLULAR
  40 + ConnectivityManager.TYPE_MOBILE_DUN -> NetworkType.CELLULAR
  41 + ConnectivityManager.TYPE_MOBILE_HIPRI -> NetworkType.CELLULAR
  42 + ConnectivityManager.TYPE_MOBILE_MMS -> NetworkType.CELLULAR
  43 + ConnectivityManager.TYPE_MOBILE_SUPL -> NetworkType.CELLULAR
  44 + ConnectivityManager.TYPE_VPN -> NetworkType.VPN
  45 + ConnectivityManager.TYPE_WIFI -> NetworkType.WIFI
  46 + ConnectivityManager.TYPE_WIMAX -> NetworkType.CELLULAR
  47 + else -> NetworkType.UNKNOWN
  48 + }
  49 + }
  50 + }
  51 +}
  52 +
  53 +enum class NetworkType(val protoName: String) {
  54 + WIFI("wifi"),
  55 + ETHERNET("ethernet"),
  56 + CELLULAR("cellular"),
  57 + VPN("vpn"),
  58 + BLUETOOTH("bluetooth"),
  59 + OTHER("other"),
  60 + UNKNOWN(""),
  61 +}
@@ -2,7 +2,10 @@ package io.livekit.android.mock.dagger @@ -2,7 +2,10 @@ package io.livekit.android.mock.dagger
2 2
3 import dagger.Module 3 import dagger.Module
4 import dagger.Provides 4 import dagger.Provides
  5 +import dagger.Reusable
5 import io.livekit.android.mock.MockWebSocketFactory 6 import io.livekit.android.mock.MockWebSocketFactory
  7 +import io.livekit.android.stats.NetworkInfo
  8 +import io.livekit.android.stats.NetworkType
6 import okhttp3.OkHttpClient 9 import okhttp3.OkHttpClient
7 import okhttp3.Response 10 import okhttp3.Response
8 import okhttp3.WebSocket 11 import okhttp3.WebSocket
@@ -35,4 +38,12 @@ object TestWebModule { @@ -35,4 +38,12 @@ object TestWebModule {
35 fun mockWebsocketFactory(): MockWebSocketFactory { 38 fun mockWebsocketFactory(): MockWebSocketFactory {
36 return MockWebSocketFactory() 39 return MockWebSocketFactory()
37 } 40 }
  41 +
  42 + @Provides
  43 + @Reusable
  44 + fun networkInfo(): NetworkInfo {
  45 + return object : NetworkInfo {
  46 + override fun getNetworkType() = NetworkType.WIFI
  47 + }
  48 + }
38 } 49 }
@@ -3,6 +3,8 @@ package io.livekit.android.room @@ -3,6 +3,8 @@ package io.livekit.android.room
3 import io.livekit.android.BaseTest 3 import io.livekit.android.BaseTest
4 import io.livekit.android.mock.MockWebSocketFactory 4 import io.livekit.android.mock.MockWebSocketFactory
5 import io.livekit.android.mock.TestData 5 import io.livekit.android.mock.TestData
  6 +import io.livekit.android.stats.NetworkInfo
  7 +import io.livekit.android.stats.NetworkType
6 import io.livekit.android.util.toOkioByteString 8 import io.livekit.android.util.toOkioByteString
7 import io.livekit.android.util.toPBByteString 9 import io.livekit.android.util.toPBByteString
8 import kotlinx.coroutines.ExperimentalCoroutinesApi 10 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -39,7 +41,10 @@ class SignalClientTest : BaseTest() { @@ -39,7 +41,10 @@ class SignalClientTest : BaseTest() {
39 wsFactory, 41 wsFactory,
40 Json, 42 Json,
41 okHttpClient = okHttpClient, 43 okHttpClient = okHttpClient,
42 - ioDispatcher = coroutineRule.dispatcher 44 + ioDispatcher = coroutineRule.dispatcher,
  45 + networkInfo = object : NetworkInfo {
  46 + override fun getNetworkType() = NetworkType.WIFI
  47 + }
43 ) 48 )
44 client.listener = listener 49 client.listener = listener
45 } 50 }