Skip to content

Commit

Permalink
Merge branch 'refs/heads/develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
aleksandar-apostolov committed Oct 10, 2024
2 parents bf571cb + 9d169cc commit 921c7c8
Show file tree
Hide file tree
Showing 35 changed files with 580 additions and 114 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ object Configuration {
const val minSdk = 24
const val majorVersion = 1
const val minorVersion = 0
const val patchVersion = 15
const val patchVersion = 16
const val versionName = "$majorVersion.$minorVersion.$patchVersion"
const val versionCode = 39
const val snapshotVersionName = "$majorVersion.$minorVersion.${patchVersion + 1}-SNAPSHOT"
const val artifactGroup = "io.getstream"
const val streamVideoCallGooglePlayVersion = "1.1.8"
const val streamWebRtcVersionName = "1.1.1"
const val streamVideoCallGooglePlayVersion = "1.1.9"
const val streamWebRtcVersionName = "1.2.1"
}
3 changes: 3 additions & 0 deletions demo-app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,9 @@ dependencies {
implementation(project(":stream-video-android-filters-video"))
compileOnly(project(":stream-video-android-previewdata"))

// Noise Cancellation
implementation(libs.stream.video.android.noise.cancellation)

// Stream Chat SDK
implementation(libs.stream.chat.compose)
implementation(libs.stream.chat.offline)
Expand Down
1 change: 1 addition & 0 deletions demo-app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Dogfooding"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ import io.getstream.video.android.compose.ui.components.call.renderer.copy
import io.getstream.video.android.core.Call
import io.getstream.video.android.core.RealtimeConnection
import io.getstream.video.android.core.call.state.ChooseLayout
import io.getstream.video.android.core.utils.isEnabled
import io.getstream.video.android.filters.video.BlurredBackgroundVideoFilter
import io.getstream.video.android.filters.video.VirtualBackgroundVideoFilter
import io.getstream.video.android.mock.StreamPreviewDataUtils
Expand Down Expand Up @@ -458,10 +459,17 @@ fun CallScreen(
}

if (isShowingSettingMenu) {
var isNoiseCancellationEnabled by remember {
mutableStateOf(call.isAudioProcessingEnabled())
}
val settings by call.state.settings.collectAsStateWithLifecycle()
val noiseCancellationFeatureEnabled = settings?.audio?.noiseCancellation?.isEnabled == true
SettingsMenu(
call = call,
selectedVideoFilter = selectedVideoFilter,
showDebugOptions = showDebugOptions,
noiseCancellationFeatureEnabled = noiseCancellationFeatureEnabled,
noiseCancellationEnabled = isNoiseCancellationEnabled,
onDismissed = { isShowingSettingMenu = false },
onSelectVideoFilter = { filterIndex ->
selectedVideoFilter = filterIndex
Expand All @@ -482,6 +490,9 @@ fun CallScreen(
isShowingSettingMenu = false
isShowingFeedbackDialog = true
},
onNoiseCancellation = {
isNoiseCancellationEnabled = call.toggleAudioProcessing()
},
) {
isShowingStats = true
isShowingSettingMenu = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,25 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.android.gms.auth.api.signin.GoogleSignInClient
import dagger.hilt.android.lifecycle.HiltViewModel
import io.getstream.android.push.PushProvider
import io.getstream.chat.android.client.ChatClient
import io.getstream.video.android.core.Call
import io.getstream.video.android.core.StreamVideo
import io.getstream.video.android.datastore.delegate.StreamUserDataStore
import io.getstream.video.android.model.Device
import io.getstream.video.android.model.User
import io.getstream.video.android.model.mapper.isValidCallCid
import io.getstream.video.android.model.mapper.toTypeAndId
import io.getstream.video.android.util.NetworkMonitor
import io.getstream.video.android.util.StreamVideoInitHelper
import kotlinx.coroutines.delay
import io.getstream.video.android.util.fcmToken
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.launch
import java.util.UUID
Expand All @@ -49,7 +51,7 @@ class CallJoinViewModel @Inject constructor(
networkMonitor: NetworkMonitor,
) : ViewModel() {
val user: Flow<User?> = dataStore.user
val isLoggedOut = dataStore.user.map { it == null }
val isLoggedOut = MutableStateFlow(false)
var autoLogInAfterLogOut = true
val isNetworkAvailable = networkMonitor.isNetworkAvailable

Expand Down Expand Up @@ -101,12 +103,26 @@ class CallJoinViewModel @Inject constructor(

fun logOut() {
viewModelScope.launch {
googleSignInClient.signOut()
dataStore.clear()
StreamVideo.instance().logOut()
ChatClient.instance().disconnect(true).enqueue()
delay(200)
dataStore.clear() // Demo App DataStore
googleSignInClient.signOut()

StreamVideo.instanceOrNull()?.let { streamVideo ->
fcmToken?.let { fcmToken ->
streamVideo.deleteDevice(
Device(
id = fcmToken,
pushProvider = PushProvider.FIREBASE.key,
pushProviderName = "firebase",
),
)
}
streamVideo.logOut()
}

StreamVideo.removeClient()

isLoggedOut.value = true
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import io.getstream.chat.android.client.ChatClient
import io.getstream.video.android.core.Call
import io.getstream.video.android.core.DeviceStatus
import io.getstream.video.android.core.StreamVideo
import io.getstream.video.android.core.utils.isAutoOn
import io.getstream.video.android.datastore.delegate.StreamUserDataStore
import io.getstream.video.android.model.StreamCallId
import io.getstream.video.android.model.User
Expand Down Expand Up @@ -116,7 +117,7 @@ class CallLobbyViewModel @Inject constructor(
// based on it
val settings = call.state.settings.first { it != null }

val enabled = when (call.camera.status.first()) {
val isCameraEnabled = when (call.camera.status.first()) {
is DeviceStatus.NotSelected -> {
settings?.video?.cameraDefaultOn ?: false
}
Expand All @@ -131,7 +132,10 @@ class CallLobbyViewModel @Inject constructor(
}

// enable/disable camera capture (no preview would be visible otherwise)
call.camera.setEnabled(enabled)
call.camera.setEnabled(isCameraEnabled)

val isNoiseCancellationEnabled = settings?.audio?.noiseCancellation?.isAutoOn ?: false
call.setAudioProcessingEnabled(isNoiseCancellationEnabled)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import androidx.compose.material.icons.filled.HeadsetMic
import androidx.compose.material.icons.filled.PortableWifiOff
import androidx.compose.material.icons.filled.RestartAlt
import androidx.compose.material.icons.filled.SettingsVoice
import androidx.compose.material.icons.filled.SpatialAudioOff
import androidx.compose.material.icons.filled.SpeakerPhone
import androidx.compose.material.icons.filled.SwitchLeft
import androidx.compose.material.icons.filled.VideoFile
Expand All @@ -46,6 +47,8 @@ import io.getstream.video.android.ui.menu.base.SubMenuItem
*/
fun defaultStreamMenu(
showDebugOptions: Boolean = false,
noiseCancellationFeatureEnabled: Boolean = false,
noiseCancellationEnabled: Boolean = false,
codecList: List<MediaCodecInfo>,
onCodecSelected: (MediaCodecInfo) -> Unit,
isScreenShareEnabled: Boolean,
Expand All @@ -57,6 +60,7 @@ fun defaultStreamMenu(
onKillSfuWsClick: () -> Unit,
onSwitchSfuClick: () -> Unit,
onShowFeedback: () -> Unit,
onNoiseCancellation: () -> Unit,
onDeviceSelected: (StreamAudioDevice) -> Unit,
availableDevices: List<StreamAudioDevice>,
loadRecordings: suspend () -> List<MenuItem>,
Expand Down Expand Up @@ -108,6 +112,16 @@ fun defaultStreamMenu(
action = onToggleScreenShare,
),
)
if (noiseCancellationFeatureEnabled) {
add(
ActionMenuItem(
title = "Noise cancellation",
icon = Icons.Default.SpatialAudioOff,
highlight = noiseCancellationEnabled,
action = onNoiseCancellation,
),
)
}
if (showDebugOptions) {
add(
SubMenuItem(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ import com.google.accompanist.permissions.PermissionStatus
import com.google.accompanist.permissions.rememberPermissionState
import io.getstream.video.android.compose.theme.VideoTheme
import io.getstream.video.android.core.Call
import io.getstream.video.android.core.call.audio.AudioFilter
import io.getstream.video.android.core.call.audio.InputAudioFilter
import io.getstream.video.android.core.mapper.ReactionMapper
import io.getstream.video.android.tooling.extensions.toPx
import io.getstream.video.android.ui.call.ReactionsMenu
Expand All @@ -68,9 +68,12 @@ internal fun SettingsMenu(
call: Call,
selectedVideoFilter: Int,
showDebugOptions: Boolean,
noiseCancellationFeatureEnabled: Boolean,
noiseCancellationEnabled: Boolean,
onDismissed: () -> Unit,
onSelectVideoFilter: (Int) -> Unit,
onShowFeedback: () -> Unit,
onNoiseCancellation: () -> Unit,
onShowCallStats: () -> Unit,
) {
val context = LocalContext.current
Expand Down Expand Up @@ -104,7 +107,7 @@ internal fun SettingsMenu(

val onToggleAudioFilterClick: () -> Unit = {
if (call.audioFilter == null) {
call.audioFilter = object : AudioFilter {
call.audioFilter = object : InputAudioFilter {
override fun applyFilter(
audioFormat: Int,
channelCount: Int,
Expand Down Expand Up @@ -206,6 +209,8 @@ internal fun SettingsMenu(
},
items = defaultStreamMenu(
showDebugOptions = showDebugOptions,
noiseCancellationFeatureEnabled = noiseCancellationFeatureEnabled,
noiseCancellationEnabled = noiseCancellationEnabled,
codecList = codecInfos,
availableDevices = availableDevices,
onDeviceSelected = {
Expand All @@ -223,6 +228,7 @@ internal fun SettingsMenu(
onToggleAudioFilterClick = onToggleAudioFilterClick,
onSwitchSfuClick = onSwitchSfuClick,
onShowCallStats = onShowCallStats,
onNoiseCancellation = onNoiseCancellation,
isScreenShareEnabled = isScreenSharing,
loadRecordings = onLoadRecordings,
),
Expand Down Expand Up @@ -284,6 +290,7 @@ private fun SettingsMenuPreview() {
availableDevices = emptyList(),
onDeviceSelected = {},
onShowFeedback = {},
onNoiseCancellation = {},
loadRecordings = { emptyList() },
),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ private fun DynamicMenuPreview() {
availableDevices = emptyList(),
onDeviceSelected = {},
onShowFeedback = {},
onNoiseCancellation = {},
loadRecordings = { emptyList() },
),
)
Expand All @@ -248,6 +249,7 @@ private fun DynamicMenuDebugOptionPreview() {
availableDevices = emptyList(),
onDeviceSelected = {},
onShowFeedback = {},
onNoiseCancellation = {},
loadRecordings = { emptyList() },
),
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2014-2024 Stream.io Inc. All rights reserved.
*
* Licensed under the Stream License;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://github.com/GetStream/stream-video-android/blob/main/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.getstream.video.android.util

import android.util.Log
import com.google.firebase.messaging.FirebaseMessaging
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.tasks.await

val fcmToken: String?
get() = runBlocking {
try {
FirebaseMessaging.getInstance().token.await()
} catch (e: Exception) {
Log.e("FCM Token", "Failed to retrieve FCM token", e)
null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import io.getstream.video.android.data.services.stream.StreamService
import io.getstream.video.android.datastore.delegate.StreamUserDataStore
import io.getstream.video.android.model.ApiKey
import io.getstream.video.android.model.User
import io.getstream.video.android.noise.cancellation.NoiseCancellation
import io.getstream.video.android.util.config.AppConfig
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
Expand Down Expand Up @@ -207,6 +208,7 @@ object StreamVideoInitHelper {
authData.token
},
appName = "Stream Video Demo App",
audioProcessing = NoiseCancellation(context),
).build()
}
}
25 changes: 25 additions & 0 deletions demo-app/src/main/res/xml/network_security_config.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) 2024 Stream.io Inc. All rights reserved.
Licensed under the Stream License;
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://github.com/GetStream/stream-video-android/blob/main/LICENSE
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
<debug-overrides>
<trust-anchors>
<certificates src="user" />
<certificates src="system" />
</trust-anchors>
</debug-overrides>
</network-security-config>
6 changes: 3 additions & 3 deletions docusaurus/docs/Android/02-tutorials/03-livestream.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -363,10 +363,10 @@ It also went into more details about HLS & RTMP-in.
There are several advanced features that can improve the livestreaming experience:

* ** [Co-hosts](../03-guides/02-joining-creating-calls.mdx) ** You can add members to your livestream with elevated permissions. So you can have co-hosts, moderators etc.
* ** [Custom events](../03-guides/09-reactions-and-custom-events.mdx) ** You can use custom events on the call to share any additional data. Think about showing the score for a game, or any other realtime use case.
* ** [Reactions & Chat](../03-guides/09-reactions-and-custom-events.mdx) ** Users can react to the livestream, and you can add chat. This makes for a more engaging experience.
* ** [Custom events](../03-guides/10-reactions-and-custom-events.mdx) ** You can use custom events on the call to share any additional data. Think about showing the score for a game, or any other realtime use case.
* ** [Reactions & Chat](../03-guides/10-reactions-and-custom-events.mdx) ** Users can react to the livestream, and you can add chat. This makes for a more engaging experience.
* ** [Notifications](../06-advanced/01-ringing.mdx) ** You can notify users via push notifications when the livestream starts
* ** [Recording](../06-advanced/06-recording.mdx) ** The call recording functionality allows you to record the call with various options and layouts
* ** [Recording](../06-advanced/09-recording.mdx) ** The call recording functionality allows you to record the call with various options and layouts

### Recap

Expand Down
Loading

0 comments on commit 921c7c8

Please sign in to comment.