Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package io.getstream.video.android.util

import android.annotation.SuppressLint
import android.content.Context
import android.media.AudioAttributes
import android.util.Log
import io.getstream.android.push.firebase.FirebasePushDeviceGenerator
import io.getstream.chat.android.client.ChatClient
Expand All @@ -31,6 +32,8 @@ import io.getstream.video.android.core.StreamVideo
import io.getstream.video.android.core.StreamVideoBuilder
import io.getstream.video.android.core.logging.LoggingLevel
import io.getstream.video.android.core.notifications.NotificationConfig
import io.getstream.video.android.core.notifications.internal.service.livestreamGuestCallServiceConfig
import io.getstream.video.android.core.notifications.internal.service.update
import io.getstream.video.android.core.socket.common.token.TokenProvider
import io.getstream.video.android.data.services.stream.GetAuthDataResponse
import io.getstream.video.android.data.services.stream.StreamService
Expand Down Expand Up @@ -212,6 +215,16 @@ object StreamVideoInitHelper {
},
appName = "Stream Video Demo App",
audioProcessing = NoiseCancellation(context),
callServiceConfig = livestreamGuestCallServiceConfig()
.update(
callType = "default",
runCallServiceInForeground = true,
audioUsage = AudioAttributes.USAGE_MEDIA,
)
.update(
callType = "livestream",
runCallServiceInForeground = true,
),
).build()
}
}
35 changes: 25 additions & 10 deletions stream-video-android-core/api/stream-video-android-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -4324,17 +4324,13 @@ public final class io/getstream/video/android/core/notifications/internal/receiv

public final class io/getstream/video/android/core/notifications/internal/service/CallServiceConfig {
public fun <init> ()V
public fun <init> (ZILjava/util/Map;)V
public synthetic fun <init> (ZILjava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Z
public final fun component2 ()I
public final fun component3 ()Ljava/util/Map;
public final fun copy (ZILjava/util/Map;)Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfig;
public static synthetic fun copy$default (Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfig;ZILjava/util/Map;ILjava/lang/Object;)Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfig;
public fun <init> (ZILjava/util/Map;Ljava/util/Map;)V
public synthetic fun <init> (ZILjava/util/Map;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component4 ()Ljava/util/Map;
public final fun copy (ZILjava/util/Map;Ljava/util/Map;)Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfig;
public static synthetic fun copy$default (Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfig;ZILjava/util/Map;Ljava/util/Map;ILjava/lang/Object;)Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfig;
public fun equals (Ljava/lang/Object;)Z
public final fun getAudioUsage ()I
public final fun getCallServicePerType ()Ljava/util/Map;
public final fun getRunCallServiceInForeground ()Z
public final fun getConfigs ()Ljava/util/Map;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
Expand All @@ -4345,6 +4341,25 @@ public final class io/getstream/video/android/core/notifications/internal/servic
public static final fun livestreamAudioCallServiceConfig ()Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfig;
public static final fun livestreamCallServiceConfig ()Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfig;
public static final fun livestreamGuestCallServiceConfig ()Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfig;
public static final fun update (Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfig;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;)Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfig;
public static synthetic fun update$default (Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfig;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;ILjava/lang/Object;)Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfig;
}

public final class io/getstream/video/android/core/notifications/internal/service/CallTypeServiceConfig {
public fun <init> ()V
public fun <init> (Ljava/lang/Class;ZI)V
public synthetic fun <init> (Ljava/lang/Class;ZIILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Ljava/lang/Class;
public final fun component2 ()Z
public final fun component3 ()I
public final fun copy (Ljava/lang/Class;ZI)Lio/getstream/video/android/core/notifications/internal/service/CallTypeServiceConfig;
public static synthetic fun copy$default (Lio/getstream/video/android/core/notifications/internal/service/CallTypeServiceConfig;Ljava/lang/Class;ZIILjava/lang/Object;)Lio/getstream/video/android/core/notifications/internal/service/CallTypeServiceConfig;
public fun equals (Ljava/lang/Object;)Z
public final fun getAudioUsage ()I
public final fun getRunCallServiceInForeground ()Z
public final fun getServiceClass ()Ljava/lang/Class;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class io/getstream/video/android/core/permission/PermissionRequest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import io.getstream.result.Result.Failure
import io.getstream.result.Result.Success
import io.getstream.video.android.core.call.RtcSession
import io.getstream.video.android.core.call.audio.InputAudioFilter
import io.getstream.video.android.core.call.connection.StreamPeerConnectionFactory
import io.getstream.video.android.core.call.utils.SoundInputProcessor
import io.getstream.video.android.core.call.video.VideoFilter
import io.getstream.video.android.core.call.video.YuvFrame
Expand All @@ -45,6 +46,7 @@ import io.getstream.video.android.core.model.SortField
import io.getstream.video.android.core.model.UpdateUserPermissionsData
import io.getstream.video.android.core.model.VideoTrack
import io.getstream.video.android.core.model.toIceServer
import io.getstream.video.android.core.notifications.internal.service.resolveAudioUsage
import io.getstream.video.android.core.utils.RampValueUpAndDownHelper
import io.getstream.video.android.core.utils.safeCall
import io.getstream.video.android.core.utils.safeCallWithDefault
Expand Down Expand Up @@ -208,6 +210,12 @@ public class Call(
internal var session: RtcSession? = null
var sessionId = UUID.randomUUID().toString()

internal var peerConnectionFactory: StreamPeerConnectionFactory = StreamPeerConnectionFactory(
context = clientImpl.context,
audioProcessing = clientImpl.audioProcessing,
audioUsage = clientImpl.callServiceConfig.resolveAudioUsage(type),
)

internal val mediaManager by lazy {
if (testInstanceProvider.mediaManagerCreator != null) {
testInstanceProvider.mediaManagerCreator!!.invoke()
Expand All @@ -216,8 +224,8 @@ public class Call(
clientImpl.context,
this,
scope,
clientImpl.peerConnectionFactory.eglBase.eglBaseContext,
clientImpl.callServiceConfig.audioUsage,
peerConnectionFactory.eglBase.eglBaseContext,
clientImpl.callServiceConfig.resolveAudioUsage(type),
)
}
}
Expand Down Expand Up @@ -371,6 +379,9 @@ public class Call(
"You can re-define your permissions and their expected state by overriding the [permissionCheck] in [StreamVideoBuilder]\n"
}
}

client.state.setActiveCall(this)

// if we are a guest user, make sure we wait for the token before running the join flow
clientImpl.guestUserJob?.await()
// the join flow should retry up to 3 times
Expand Down Expand Up @@ -486,7 +497,6 @@ public class Call(
} catch (e: Exception) {
return Failure(Error.GenericError(e.message ?: "RtcSession error occurred."))
}
client.state.setActiveCall(this)
monitorSession(result.value)
return Success(value = session!!)
}
Expand Down Expand Up @@ -765,11 +775,11 @@ public class Call(

sfuSocketReconnectionTime = null
stopScreenSharing()
client.state.removeActiveCall() // Will also stop CallService
client.state.removeRingingCall()
(client as StreamVideoClient).onCallCleanUp(this)
camera.disable()
microphone.disable()
client.state.removeActiveCall() // Will also stop CallService
client.state.removeRingingCall()
cleanup()
}

Expand Down Expand Up @@ -866,7 +876,7 @@ public class Call(

// Note this comes from peerConnectionFactory.eglBase
videoRenderer.init(
clientImpl.peerConnectionFactory.eglBase.eglBaseContext,
peerConnectionFactory.eglBase.eglBaseContext,
object : RendererCommon.RendererEvents {
override fun onFirstFrameRendered() {
val width = videoRenderer.measuredWidth
Expand Down Expand Up @@ -1193,7 +1203,7 @@ public class Call(
state.acceptedOnThisDevice = true

clientImpl.state.removeRingingCall()
clientImpl.state.maybeStopForegroundService()
clientImpl.state.maybeStopForegroundService(call = this)
return clientImpl.accept(type, id)
}

Expand Down Expand Up @@ -1267,15 +1277,15 @@ public class Call(
}

fun isAudioProcessingEnabled(): Boolean {
return clientImpl.isAudioProcessingEnabled()
return peerConnectionFactory.isAudioProcessingEnabled()
}

fun setAudioProcessingEnabled(enabled: Boolean) {
return clientImpl.setAudioProcessingEnabled(enabled)
return peerConnectionFactory.setAudioProcessingEnabled(enabled)
}

fun toggleAudioProcessing(): Boolean {
return clientImpl.toggleAudioProcessing()
return peerConnectionFactory.toggleAudioProcessing()
}

suspend fun startTranscription(): Result<StartTranscriptionResponse> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import androidx.core.content.ContextCompat
import io.getstream.log.taggedLogger
import io.getstream.result.Error
import io.getstream.video.android.core.notifications.internal.service.CallService
import io.getstream.video.android.core.notifications.internal.service.resolveRunCallServiceInForeground
import io.getstream.video.android.core.socket.coordinator.state.VideoSocketState
import io.getstream.video.android.core.utils.safeCallWithDefault
import io.getstream.video.android.model.StreamCallId
Expand Down Expand Up @@ -145,14 +146,16 @@ class ClientState(private val client: StreamVideo) {
}

fun setActiveCall(call: Call) {
this._activeCall.value = call
removeRingingCall()
maybeStartForegroundService(call, CallService.TRIGGER_ONGOING_CALL)
this._activeCall.value = call
}

fun removeActiveCall() {
this._activeCall.value = null
maybeStopForegroundService()
if (this._activeCall.value != null) {
maybeStopForegroundService(this._activeCall.value!!)
this._activeCall.value = null
}
removeRingingCall()
}

Expand All @@ -174,7 +177,7 @@ class ClientState(private val client: StreamVideo) {
* This depends on the flag in [StreamVideoBuilder] called `runForegroundServiceForCalls`
*/
internal fun maybeStartForegroundService(call: Call, trigger: String) {
if (streamVideoClient.callServiceConfig.runCallServiceInForeground) {
if (streamVideoClient.callServiceConfig.resolveRunCallServiceInForeground(call.type)) {
val context = streamVideoClient.context
val serviceIntent = CallService.buildStartIntent(
context,
Expand All @@ -189,11 +192,12 @@ class ClientState(private val client: StreamVideo) {
/**
* Stop the foreground service that manages the call even when the UI is gone.
*/
internal fun maybeStopForegroundService() {
if (streamVideoClient.callServiceConfig.runCallServiceInForeground) {
internal fun maybeStopForegroundService(call: Call) {
if (streamVideoClient.callServiceConfig.resolveRunCallServiceInForeground(call.type)) {
val context = streamVideoClient.context
val serviceIntent = CallService.buildStopIntent(
context,
call.type,
callServiceConfiguration = streamVideoClient.callServiceConfig,
)
context.stopService(serviceIntent)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -838,29 +838,29 @@ class MediaManagerImpl(

// source & tracks
val videoSource =
call.clientImpl.peerConnectionFactory.makeVideoSource(false, filterVideoProcessor)
call.peerConnectionFactory.makeVideoSource(false, filterVideoProcessor)

val screenShareVideoSource by lazy {
call.clientImpl.peerConnectionFactory.makeVideoSource(true, screenShareFilterVideoProcessor)
call.peerConnectionFactory.makeVideoSource(true, screenShareFilterVideoProcessor)
}

// for track ids we emulate the browser behaviour of random UUIDs, doing something different would be confusing
val videoTrack = call.clientImpl.peerConnectionFactory.makeVideoTrack(
val videoTrack = call.peerConnectionFactory.makeVideoTrack(
source = videoSource,
trackId = UUID.randomUUID().toString(),
)

val screenShareTrack by lazy {
call.clientImpl.peerConnectionFactory.makeVideoTrack(
call.peerConnectionFactory.makeVideoTrack(
source = screenShareVideoSource,
trackId = UUID.randomUUID().toString(),
)
}

val audioSource = call.clientImpl.peerConnectionFactory.makeAudioSource(buildAudioConstraints())
val audioSource = call.peerConnectionFactory.makeAudioSource(buildAudioConstraints())

// for track ids we emulate the browser behaviour of random UUIDs, doing something different would be confusing
val audioTrack = call.clientImpl.peerConnectionFactory.makeAudioTrack(
val audioTrack = call.peerConnectionFactory.makeAudioTrack(
source = audioSource,
trackId = UUID.randomUUID().toString(),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ import io.getstream.video.android.core.internal.module.CoordinatorConnectionModu
import io.getstream.video.android.core.logging.LoggingLevel
import io.getstream.video.android.core.notifications.NotificationConfig
import io.getstream.video.android.core.notifications.internal.StreamNotificationManager
import io.getstream.video.android.core.notifications.internal.service.ANY_MARKER
import io.getstream.video.android.core.notifications.internal.service.CallServiceConfig
import io.getstream.video.android.core.notifications.internal.service.callServiceConfig
import io.getstream.video.android.core.notifications.internal.service.update
import io.getstream.video.android.core.notifications.internal.storage.DeviceTokenStorage
import io.getstream.video.android.core.permission.android.DefaultStreamPermissionCheck
import io.getstream.video.android.core.permission.android.StreamPermissionCheck
Expand Down Expand Up @@ -210,7 +212,8 @@ public class StreamVideoBuilder @JvmOverloads constructor(
coordinatorConnectionModule = coordinatorConnectionModule,
streamNotificationManager = streamNotificationManager,
callServiceConfig = callServiceConfig
?: callServiceConfig().copy(
?: callServiceConfig().update(
callType = ANY_MARKER,
runCallServiceInForeground = runForegroundServiceForCalls,
audioUsage = defaultAudioUsage,
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,10 @@ import io.getstream.result.Error
import io.getstream.result.Result
import io.getstream.result.Result.Failure
import io.getstream.result.Result.Success
import io.getstream.video.android.core.call.connection.StreamPeerConnectionFactory
import io.getstream.video.android.core.errors.VideoErrorCode
import io.getstream.video.android.core.events.VideoEventListener
import io.getstream.video.android.core.filter.Filters
import io.getstream.video.android.core.filter.toMap
import io.getstream.video.android.core.internal.InternalStreamVideoApi
import io.getstream.video.android.core.internal.module.CoordinatorConnectionModule
import io.getstream.video.android.core.logging.LoggingLevel
import io.getstream.video.android.core.model.EdgeData
Expand All @@ -43,9 +41,11 @@ import io.getstream.video.android.core.model.UpdateUserPermissionsData
import io.getstream.video.android.core.model.toRequest
import io.getstream.video.android.core.notifications.NotificationHandler
import io.getstream.video.android.core.notifications.internal.StreamNotificationManager
import io.getstream.video.android.core.notifications.internal.service.ANY_MARKER
import io.getstream.video.android.core.notifications.internal.service.CallService
import io.getstream.video.android.core.notifications.internal.service.CallServiceConfig
import io.getstream.video.android.core.notifications.internal.service.callServiceConfig
import io.getstream.video.android.core.notifications.internal.service.resolveRunCallServiceInForeground
import io.getstream.video.android.core.permission.android.DefaultStreamPermissionCheck
import io.getstream.video.android.core.permission.android.StreamPermissionCheck
import io.getstream.video.android.core.socket.ErrorResponse
Expand Down Expand Up @@ -177,10 +177,6 @@ internal class StreamVideoClient internal constructor(
internal var guestUserJob: Deferred<Unit>? = null
private lateinit var connectContinuation: Continuation<Result<ConnectedEvent>>

@InternalStreamVideoApi
public var peerConnectionFactory =
StreamPeerConnectionFactory(context, callServiceConfig.audioUsage, audioProcessing)

public override val userId = user.id

private val logger by taggedLogger("Call:StreamVideo")
Expand All @@ -200,14 +196,18 @@ internal class StreamVideoClient internal constructor(
scope.cancel()
// call cleanup on the active call
val activeCall = state.activeCall.value
activeCall?.leave()
// Stop the call service if it was running
if (callServiceConfig.runCallServiceInForeground) {
if (callServiceConfig.resolveRunCallServiceInForeground(activeCall?.type ?: ANY_MARKER)) {
safeCall {
val serviceIntent = CallService.buildStopIntent(context, callServiceConfig)
val serviceIntent = CallService.buildStopIntent(
context = context,
callType = activeCall?.type ?: ANY_MARKER,
callServiceConfiguration = callServiceConfig,
)
context.stopService(serviceIntent)
}
}
activeCall?.leave()
}

/**
Expand Down Expand Up @@ -1085,18 +1085,6 @@ internal class StreamVideoClient internal constructor(
}
}

internal fun isAudioProcessingEnabled(): Boolean {
return peerConnectionFactory.isAudioProcessingEnabled()
}

internal fun setAudioProcessingEnabled(enabled: Boolean) {
return peerConnectionFactory.setAudioProcessingEnabled(enabled)
}

internal fun toggleAudioProcessing(): Boolean {
return peerConnectionFactory.toggleAudioProcessing()
}

suspend fun startTranscription(type: String, id: String, externalStorage: String? = null): Result<StartTranscriptionResponse> {
return apiCall {
val startTranscriptionRequest = StartTranscriptionRequest(externalStorage)
Expand Down
Loading