Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AND-171] Refactor call service configs #1256

Draft
wants to merge 1 commit into
base: develop
Choose a base branch
from
Draft
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 @@ -31,6 +31,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 @@ -188,6 +190,15 @@ object StreamVideoInitHelper {
token: String,
loggingLevel: LoggingLevel,
): StreamVideo {
val csc = livestreamGuestCallServiceConfig()
.update(
callType = "default",
runCallServiceInForeground = true,
).update(
callType = "livestream",
runCallServiceInForeground = false,
)

return StreamVideoBuilder(
context = context,
apiKey = apiKey,
Expand All @@ -212,6 +223,7 @@ object StreamVideoInitHelper {
},
appName = "Stream Video Demo App",
audioProcessing = NoiseCancellation(context),
callServiceConfig = csc,
).build()
}
}
42 changes: 30 additions & 12 deletions stream-video-android-core/api/stream-video-android-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -1055,8 +1055,8 @@ public final class io/getstream/video/android/core/call/connection/StreamPeerCon
}

public final class io/getstream/video/android/core/call/connection/StreamPeerConnectionFactory {
public fun <init> (Landroid/content/Context;ILorg/webrtc/ManagedAudioProcessingFactory;)V
public synthetic fun <init> (Landroid/content/Context;ILorg/webrtc/ManagedAudioProcessingFactory;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Landroid/content/Context;Lkotlin/jvm/functions/Function0;Lorg/webrtc/ManagedAudioProcessingFactory;)V
public synthetic fun <init> (Landroid/content/Context;Lkotlin/jvm/functions/Function0;Lorg/webrtc/ManagedAudioProcessingFactory;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun getEglBase ()Lorg/webrtc/EglBase;
public final fun isAudioProcessingEnabled ()Z
public final fun makeAudioSource (Lorg/webrtc/MediaConstraints;)Lorg/webrtc/AudioSource;
Expand Down 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,28 @@ 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 resolveAudioUsage (Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfig;Ljava/lang/String;)I
public static final fun resolveRunCallServiceInForeground (Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfig;Ljava/lang/String;)Z
public static final fun resolveServiceClass (Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfig;Ljava/lang/String;)Ljava/lang/Class;
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 @@ -45,6 +45,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 @@ -217,7 +218,7 @@ public class Call(
this,
scope,
clientImpl.peerConnectionFactory.eglBase.eglBaseContext,
clientImpl.callServiceConfig.audioUsage,
clientImpl.callServiceConfig.resolveAudioUsage(type),
)
}
}
Expand Down Expand Up @@ -371,6 +372,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 +490,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 +768,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 @@ -1193,7 +1196,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
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 @@ -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 @@ -43,9 +43,12 @@ 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.resolveAudioUsage
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 @@ -178,8 +181,14 @@ internal class StreamVideoClient internal constructor(
private lateinit var connectContinuation: Continuation<Result<ConnectedEvent>>

@InternalStreamVideoApi
public var peerConnectionFactory =
StreamPeerConnectionFactory(context, callServiceConfig.audioUsage, audioProcessing)
internal var peerConnectionFactory: StreamPeerConnectionFactory = StreamPeerConnectionFactory(
context = context,
audioProcessing = audioProcessing,
getAudioUsage = {
val callType = state.activeCall.value?.type ?: ANY_MARKER
callServiceConfig.resolveAudioUsage(callType)
},
)

public override val userId = user.id

Expand All @@ -200,14 +209,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
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ import java.nio.ByteBuffer
*/
public class StreamPeerConnectionFactory(
private val context: Context,
private val audioUsage: Int = defaultAudioUsage,
private val getAudioUsage: () -> Int,
private var audioProcessing: ManagedAudioProcessingFactory? = null,
) {

Expand All @@ -65,6 +65,8 @@ public class StreamPeerConnectionFactory(
(audioFormat: Int, channelCount: Int, sampleRate: Int, sampleData: ByteBuffer) -> Unit
)? = null

private var audioUsage: Int = getAudioUsage()

/**
* Set to get callbacks when audio input from microphone is received.
* This can be example used to detect whether a person is speaking
Expand Down Expand Up @@ -120,7 +122,19 @@ public class StreamPeerConnectionFactory(
* Factory that builds all the connections based on the extensive configuration provided under
* the hood.
*/
private val factory by lazy {
private var factory: PeerConnectionFactory = createFactory()
get() {
val newAudioUsage = getAudioUsage()
if (audioUsage != newAudioUsage) {
audioUsage = newAudioUsage
field.dispose()
field = createFactory()
}

return field
}

private fun createFactory(): PeerConnectionFactory {
PeerConnectionFactory.initialize(
PeerConnectionFactory.InitializationOptions.builder(context)
.setInjectableLogger({ message, severity, label ->
Expand Down Expand Up @@ -151,7 +165,7 @@ public class StreamPeerConnectionFactory(
.createInitializationOptions(),
)

PeerConnectionFactory.builder()
return PeerConnectionFactory.builder()
.apply {
audioProcessing?.also { setAudioProcessingFactory(it) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ internal open class CallService : Service() {
callDisplayName: String? = null,
callServiceConfiguration: CallServiceConfig = callServiceConfig(),
): Intent {
val serviceClass = resolveServiceClass(callId, callServiceConfiguration)
val serviceClass = callServiceConfiguration.resolveServiceClass(callId.type)
StreamLog.i(TAG) { "Resolved service class: $serviceClass" }
val serviceIntent = Intent(context, serviceClass)
serviceIntent.putExtra(INTENT_EXTRA_CALL_CID, callId)
Expand Down Expand Up @@ -156,10 +156,12 @@ internal open class CallService : Service() {
*/
fun buildStopIntent(
context: Context,
callType: String,
callServiceConfiguration: CallServiceConfig = callServiceConfig(),
) = safeCallWithDefault(Intent(context, CallService::class.java)) {
val intent = callServiceConfiguration.callServicePerType.firstNotNullOfOrNull {
val serviceClass = it.value
val intent = callServiceConfiguration.configs.firstNotNullOfOrNull {
val serviceClass = callServiceConfiguration.resolveServiceClass(callType)

if (isServiceRunning(context, serviceClass)) {
Intent(context, serviceClass)
} else {
Expand Down
Loading
Loading