Skip to content

Commit

Permalink
Upgrading millicas SDK to v1.8.8 with adding switching channels
Browse files Browse the repository at this point in the history
Signed-off-by: Mostafa Ashraf <[email protected]>
  • Loading branch information
mshaa92 committed Aug 2, 2024
1 parent 6b56183 commit 80c7ad7
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 33 deletions.
4 changes: 2 additions & 2 deletions app/src/main/java/io/dolby/rtsviewer/di/DataModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ object DataModule {
// set millicast logs
Logger.setLogLevels(
sdk = LogLevel.MC_DEBUG,
webrtc = LogLevel.MC_LOG,
websocket = LogLevel.MC_DEBUG
webrtc = LogLevel.MC_DEBUG,
websocket = LogLevel.MC_ERROR
)
Logger.setLoggerListener { msg, level ->
Log.d(TAG, "millicast sdk: $level / $msg")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ fun AppNavigation(navController: NavHostController) {
composable(
route = Screen.DetailInputScreen.route
) { backStackEntry ->
val streamNameToPlay = backStackEntry.savedStateHandle.get<String>(Screen.DetailInputScreen.ARG_STREAM_NAME_TO_PLAY)
val accountIDToPlay = backStackEntry.savedStateHandle.get<String>(Screen.DetailInputScreen.ARG_ACCOUNT_ID_TO_PLAY)
val streamNameToPlay = "AminoFPS25"
val accountIDToPlay = "sjf6bf"
var streamingData: StreamingData? = null

if (streamNameToPlay != null && accountIDToPlay != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package io.dolby.rtsviewer.ui.streaming

enum class ChannelNavDirection {
UP, DOWN
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
package io.dolby.rtsviewer.ui.streaming

import android.view.KeyEvent
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.nativeKeyCode
import androidx.compose.ui.input.key.onKeyEvent
import androidx.compose.ui.input.key.type
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.contentDescription
Expand All @@ -32,12 +43,27 @@ fun StreamingScreen(viewModel: StreamingViewModel = hiltViewModel(), onBack: ()
val showSettings = viewModel.showSettings.collectAsState()
val showStatistics = viewModel.showStatistics.collectAsState()
val showSimulcastSettings = viewModel.showSimulcastSettings.collectAsState()

val focusRequester = remember { FocusRequester() }
LaunchedEffect(showSettings.value, showSimulcastSettings.value) {
// always focus at the top level so we get key events
if (!showSettings.value && !showSimulcastSettings.value) {
focusRequester.requestFocus() // Ensure gaining focus after returning from settings
}
}
val screenContentDescription = stringResource(id = R.string.streaming_screen_contentDescription)
DolbyBackgroundBox(
modifier = Modifier.semantics {
contentDescription = screenContentDescription
}
}.focusRequester(focusRequester).onKeyEvent {
if (it.type == KeyEventType.KeyUp && (it.key.nativeKeyCode == KeyEvent.KEYCODE_PAGE_DOWN || it.key.nativeKeyCode == KeyEvent.KEYCODE_CHANNEL_DOWN)) {
viewModel.switchChannel(ChannelNavDirection.DOWN)
return@onKeyEvent true
} else if (it.type == KeyEventType.KeyUp && (it.key.nativeKeyCode == KeyEvent.KEYCODE_PAGE_UP || it.key.nativeKeyCode == KeyEvent.KEYCODE_CHANNEL_UP)) {
viewModel.switchChannel(ChannelNavDirection.UP)
return@onKeyEvent true
}
return@onKeyEvent false
}.focusable()
) {
val context = LocalContext.current
when {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package io.dolby.rtsviewer.ui.streaming

import android.icu.text.SimpleDateFormat
import android.os.CountDownTimer
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import io.dolby.rtscomponentkit.data.RTSViewerDataStore
import io.dolby.rtscomponentkit.data.SingleStreamStatisticsData
import io.dolby.rtscomponentkit.data.multistream.safeLaunch
import io.dolby.rtscomponentkit.domain.StreamingData
import io.dolby.rtscomponentkit.utils.DispatcherProvider
import io.dolby.rtsviewer.R
import io.dolby.rtsviewer.preferenceStore.PrefsStore
Expand Down Expand Up @@ -42,7 +45,7 @@ class StreamingViewModel @Inject constructor(

private val _showLiveIndicator = MutableStateFlow(false)
val showLiveIndicator = _showLiveIndicator.asStateFlow()

private var currentStreamIndex = 0
private val _showToolbarState = MutableStateFlow(false)
val showToolbarState = _showToolbarState.asStateFlow()
private val _showToolbarDelayState = MutableStateFlow(0L)
Expand All @@ -58,7 +61,25 @@ class StreamingViewModel @Inject constructor(
private val _showSimulcastSettings = MutableStateFlow(false)
var showSimulcastSettings = _showSimulcastSettings.asStateFlow()

private var channels = arrayListOf(
StreamingData("sjf6bf", "AminoFPS50"),
StreamingData("sjf6bf", "AminoFPS25"),
StreamingData("sjf6bf", "AminoFPS30"),
StreamingData("sjf6bf", "AminoFPS60"),
StreamingData("MG2zym", "amino60fps"),
StreamingData("MG2zym", "amino50fps"),
StreamingData("MG2zym", "amino30fps"),
StreamingData("MG2zym", "amino25fps")
)
private var alreadyCleared = false
private var switchingChannelsTimer: CountDownTimer? = object : CountDownTimer(1000, 1000) {
override fun onTick(millisUntilFinished: Long) {
}

override fun onFinish() {
subscribeToNewChannel()
}
}

init {
viewModelScope.launch {
Expand All @@ -73,6 +94,7 @@ class StreamingViewModel @Inject constructor(
)
}
}

NetworkStatusObserver.Status.Available -> when (dataStoreState) {
RTSViewerDataStore.State.Connecting -> {
Log.d(TAG, "Connecting")
Expand All @@ -84,6 +106,7 @@ class StreamingViewModel @Inject constructor(
}
}
}

RTSViewerDataStore.State.Subscribed -> {
Log.d(TAG, "Subscribed")
repository.audioPlaybackStart()
Expand All @@ -98,6 +121,7 @@ class StreamingViewModel @Inject constructor(
}
}
}

RTSViewerDataStore.State.StreamActive -> {
Log.d(TAG, "StreamActive")
withContext(dispatcherProvider.main) {
Expand All @@ -111,6 +135,7 @@ class StreamingViewModel @Inject constructor(
}
}
}

RTSViewerDataStore.State.StreamInactive -> {
Log.d(TAG, "StreamInactive")
withContext(dispatcherProvider.main) {
Expand All @@ -122,6 +147,7 @@ class StreamingViewModel @Inject constructor(
}
}
}

is RTSViewerDataStore.State.AudioTrackReady -> {
Log.d(TAG, "AudioTrackReady")
withContext(dispatcherProvider.main) {
Expand All @@ -132,6 +158,7 @@ class StreamingViewModel @Inject constructor(
}
}
}

is RTSViewerDataStore.State.VideoTrackReady -> {
Log.d(TAG, "VideoTrackReady")
withContext(dispatcherProvider.main) {
Expand All @@ -142,6 +169,7 @@ class StreamingViewModel @Inject constructor(
}
}
}

RTSViewerDataStore.State.Disconnecting,
RTSViewerDataStore.State.Disconnected -> {
Log.d(
Expand All @@ -159,6 +187,7 @@ class StreamingViewModel @Inject constructor(
}
}
}

is RTSViewerDataStore.State.Error -> {
Log.d(TAG, "Error")
withContext(dispatcherProvider.main) {
Expand Down Expand Up @@ -208,7 +237,24 @@ class StreamingViewModel @Inject constructor(
}
}

fun switchChannel(navDirection: ChannelNavDirection) {
channels.let { allChannels ->
if (allChannels.isNotEmpty()) {
repository.disconnect()
_uiState.value = StreamingScreenUiState()
currentStreamIndex = if (navDirection == ChannelNavDirection.DOWN) {
(currentStreamIndex + 1).coerceInLoop(allChannels.indices)
} else {
(currentStreamIndex - 1).coerceInLoop(allChannels.indices)
}
startTimer()
Log.i("Mostafa", "switchChannel currentIndex $currentStreamIndex")
}
}
}

override fun onCleared() {
releaseTimer()
clear()
}

Expand Down Expand Up @@ -251,6 +297,27 @@ class StreamingViewModel @Inject constructor(
_showSettings.update { visible }
}

private fun startTimer() {
switchingChannelsTimer?.cancel()
switchingChannelsTimer?.start()
}

private fun releaseTimer() {
switchingChannelsTimer?.cancel()
switchingChannelsTimer = null
}

fun subscribeToNewChannel() {
viewModelScope.safeLaunch(block = {
repository.connect(
channels[currentStreamIndex].streamName,
channels[currentStreamIndex].accountId
)
updateShowSimulcastSettings(false)
settingsVisibility(false)
})
}

private fun streamingStatistics(): Flow<List<Pair<Int, String>>?> =
repository.statisticsData.map { statisticsData -> getStatisticsValuesList(statisticsData) }

Expand Down Expand Up @@ -330,7 +397,12 @@ class StreamingViewModel @Inject constructor(
}
statistics.timestamp?.let {
getDateTime(it)?.let { dateTime ->
statisticsValuesList.add(Pair(R.string.statisticsScreen_timestamp, dateTime))
statisticsValuesList.add(
Pair(
R.string.statisticsScreen_timestamp,
dateTime
)
)
}
}
return statisticsValuesList
Expand Down Expand Up @@ -361,6 +433,7 @@ class StreamingViewModel @Inject constructor(
}
return String.format("%.1f %cB", value / 1000.0, ci.current())
}

fun updateShowSimulcastSettings(show: Boolean) {
_showSimulcastSettings.update { show }
}
Expand All @@ -369,3 +442,15 @@ class StreamingViewModel @Inject constructor(
repository.selectStreamQualityType(streamQualityType)
}
}

fun Int.coerceInLoop(range: ClosedRange<Int>): Int {
if (range is ClosedFloatingPointRange) {
return this.coerceIn<Int>(range)
}
if (range.isEmpty()) throw IllegalArgumentException("Cannot coerce value to an empty range: $range.")
return when {
this < range.start -> range.endInclusive
this > range.endInclusive -> range.start
else -> this
}
}
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ androidx-test-ext-junit = "1.1.5"
espresso-core = "3.5.1"
appcompat = "1.6.1"
material = "1.8.0"
millicast-sdk = "1.8.5"
millicast-sdk = "1.8.8-SNAPSHOT-3318-cfb21137"

[libraries]
androidx-appcompat = "androidx.appcompat:appcompat:1.6.1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package io.dolby.rtscomponentkit.data
import android.util.Log
import com.millicast.Core
import com.millicast.Media
import com.millicast.Subscriber
import com.millicast.clients.ConnectionOptions
import com.millicast.devices.playback.AudioPlayback
import com.millicast.devices.track.AudioTrack
Expand Down Expand Up @@ -46,6 +47,7 @@ class RTSViewerDataStore constructor(
_selectedStreamQualityType.asStateFlow()

private var listener: SingleStreamListener? = null
private lateinit var subscriber: Subscriber

init {
media = millicastSdk.getMedia()
Expand All @@ -58,7 +60,6 @@ class RTSViewerDataStore constructor(
}

_state.emit(State.Connecting)
Core.initialize()

val subscriber = Core.createSubscriber()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.cancellable
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
Expand All @@ -35,7 +36,7 @@ class SingleStreamListener(
private fun <T> Flow<T>.collectInLocalScope(
collector: FlowCollector<T>
) = this.let {
coroutineScope.launch { it.collect(collector) }
coroutineScope.launch { it.cancellable().collect(collector) }
}

fun start() {
Expand Down Expand Up @@ -154,6 +155,7 @@ class SingleStreamListener(
}

private fun onSubscribed() {
Log.i("Mostafa", "onSubscribed")
coroutineScope.launch {
state.emit(RTSViewerDataStore.State.Subscribed)
}
Expand Down Expand Up @@ -197,7 +199,7 @@ class SingleStreamListener(
}

private suspend fun onConnected() {
Log.d(TAG, "onConnected")
Log.d("Mostafa", "onConnected")
try {
subscriber.subscribe(Option(statsDelayMs = 1_000))
} catch (e: MillicastException) {
Expand Down
Loading

0 comments on commit 80c7ad7

Please sign in to comment.