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 Jun 13, 2024
2 parents eeee7d9 + 95f98f9 commit 8e65b33
Show file tree
Hide file tree
Showing 16 changed files with 169 additions and 98 deletions.
Binary file removed build-logic/gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
5 changes: 0 additions & 5 deletions build-logic/gradle/wrapper/gradle-wrapper.properties

This file was deleted.

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 = 5
const val patchVersion = 6
const val versionName = "$majorVersion.$minorVersion.$patchVersion"
const val versionCode = 28
const val versionCode = 30
const val snapshotVersionName = "$majorVersion.$minorVersion.${patchVersion + 1}-SNAPSHOT"
const val artifactGroup = "io.getstream"
const val streamVideoCallGooglePlayVersion = "1.1.2"
const val streamVideoCallGooglePlayVersion = "1.1.4"
const val streamWebRtcVersionName = "1.1.1"
}
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[versions]
androidGradlePlugin = "8.4.1"
androidGradlePlugin = "8.4.2"
cameraCamera2 = "1.3.0"
spotless = "6.21.0"
nexusPlugin = "1.3.0"
Expand Down
2 changes: 1 addition & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ dependencyResolutionManagement {
}

plugins {
id("com.gradle.enterprise").version("3.13.3")
id("com.gradle.enterprise").version("3.17.4")
id("com.github.burrunan.s3-build-cache").version("1.2")
}
rootProject.name = "stream-video-android"
Expand Down
19 changes: 15 additions & 4 deletions stream-video-android-core/api/stream-video-android-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -409,10 +409,12 @@ public final class io/getstream/video/android/core/LocalStats {
}

public final class io/getstream/video/android/core/MediaManagerImpl {
public fun <init> (Landroid/content/Context;Lio/getstream/video/android/core/Call;Lkotlinx/coroutines/CoroutineScope;Lorg/webrtc/EglBase$Context;)V
public fun <init> (Landroid/content/Context;Lio/getstream/video/android/core/Call;Lkotlinx/coroutines/CoroutineScope;Lorg/webrtc/EglBase$Context;I)V
public synthetic fun <init> (Landroid/content/Context;Lio/getstream/video/android/core/Call;Lkotlinx/coroutines/CoroutineScope;Lorg/webrtc/EglBase$Context;IILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun cleanup ()V
public final fun getAudioSource ()Lorg/webrtc/AudioSource;
public final fun getAudioTrack ()Lorg/webrtc/AudioTrack;
public final fun getAudioUsage ()I
public final fun getCall ()Lio/getstream/video/android/core/Call;
public final fun getContext ()Landroid/content/Context;
public final fun getEglBaseContext ()Lorg/webrtc/EglBase$Context;
Expand Down Expand Up @@ -476,10 +478,12 @@ public final class io/getstream/video/android/core/MemberState {
}

public final class io/getstream/video/android/core/MicrophoneManager {
public fun <init> (Lio/getstream/video/android/core/MediaManagerImpl;Z)V
public fun <init> (Lio/getstream/video/android/core/MediaManagerImpl;ZI)V
public final fun canHandleDeviceSwitch ()Z
public final fun cleanup ()V
public final fun disable (Z)V
public static synthetic fun disable$default (Lio/getstream/video/android/core/MicrophoneManager;ZILjava/lang/Object;)V
public final fun getAudioUsage ()I
public final fun getDevices ()Lkotlinx/coroutines/flow/StateFlow;
public final fun getMediaManager ()Lio/getstream/video/android/core/MediaManagerImpl;
public final fun getPreferSpeakerphone ()Z
Expand Down Expand Up @@ -817,7 +821,8 @@ public final class io/getstream/video/android/core/StreamVideoBuilder {
public fun <init> (Landroid/content/Context;Ljava/lang/String;Lio/getstream/video/android/core/GEO;Lio/getstream/video/android/model/User;Ljava/lang/String;Lkotlin/jvm/functions/Function2;Lio/getstream/video/android/core/logging/LoggingLevel;Lio/getstream/video/android/core/notifications/NotificationConfig;Lkotlin/jvm/functions/Function1;JZLjava/lang/String;ZLjava/lang/String;Lio/getstream/video/android/core/sounds/Sounds;)V
public fun <init> (Landroid/content/Context;Ljava/lang/String;Lio/getstream/video/android/core/GEO;Lio/getstream/video/android/model/User;Ljava/lang/String;Lkotlin/jvm/functions/Function2;Lio/getstream/video/android/core/logging/LoggingLevel;Lio/getstream/video/android/core/notifications/NotificationConfig;Lkotlin/jvm/functions/Function1;JZLjava/lang/String;ZLjava/lang/String;Lio/getstream/video/android/core/sounds/Sounds;Z)V
public fun <init> (Landroid/content/Context;Ljava/lang/String;Lio/getstream/video/android/core/GEO;Lio/getstream/video/android/model/User;Ljava/lang/String;Lkotlin/jvm/functions/Function2;Lio/getstream/video/android/core/logging/LoggingLevel;Lio/getstream/video/android/core/notifications/NotificationConfig;Lkotlin/jvm/functions/Function1;JZLjava/lang/String;ZLjava/lang/String;Lio/getstream/video/android/core/sounds/Sounds;ZLio/getstream/video/android/core/permission/android/StreamPermissionCheck;)V
public synthetic fun <init> (Landroid/content/Context;Ljava/lang/String;Lio/getstream/video/android/core/GEO;Lio/getstream/video/android/model/User;Ljava/lang/String;Lkotlin/jvm/functions/Function2;Lio/getstream/video/android/core/logging/LoggingLevel;Lio/getstream/video/android/core/notifications/NotificationConfig;Lkotlin/jvm/functions/Function1;JZLjava/lang/String;ZLjava/lang/String;Lio/getstream/video/android/core/sounds/Sounds;ZLio/getstream/video/android/core/permission/android/StreamPermissionCheck;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Landroid/content/Context;Ljava/lang/String;Lio/getstream/video/android/core/GEO;Lio/getstream/video/android/model/User;Ljava/lang/String;Lkotlin/jvm/functions/Function2;Lio/getstream/video/android/core/logging/LoggingLevel;Lio/getstream/video/android/core/notifications/NotificationConfig;Lkotlin/jvm/functions/Function1;JZLjava/lang/String;ZLjava/lang/String;Lio/getstream/video/android/core/sounds/Sounds;ZLio/getstream/video/android/core/permission/android/StreamPermissionCheck;I)V
public synthetic fun <init> (Landroid/content/Context;Ljava/lang/String;Lio/getstream/video/android/core/GEO;Lio/getstream/video/android/model/User;Ljava/lang/String;Lkotlin/jvm/functions/Function2;Lio/getstream/video/android/core/logging/LoggingLevel;Lio/getstream/video/android/core/notifications/NotificationConfig;Lkotlin/jvm/functions/Function1;JZLjava/lang/String;ZLjava/lang/String;Lio/getstream/video/android/core/sounds/Sounds;ZLio/getstream/video/android/core/permission/android/StreamPermissionCheck;IILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun build ()Lio/getstream/video/android/core/StreamVideo;
public final fun getScope ()Lkotlinx/coroutines/CoroutineScope;
}
Expand Down Expand Up @@ -1024,7 +1029,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;)V
public fun <init> (Landroid/content/Context;I)V
public synthetic fun <init> (Landroid/content/Context;IILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun getEglBase ()Lorg/webrtc/EglBase;
public final fun makeAudioSource (Lorg/webrtc/MediaConstraints;)Lorg/webrtc/AudioSource;
public static synthetic fun makeAudioSource$default (Lio/getstream/video/android/core/call/connection/StreamPeerConnectionFactory;Lorg/webrtc/MediaConstraints;ILjava/lang/Object;)Lorg/webrtc/AudioSource;
Expand Down Expand Up @@ -10063,6 +10069,11 @@ public final class org/openapitools/client/models/UnpinResponse {
public fun toString ()Ljava/lang/String;
}

public final class org/openapitools/client/models/UnsupportedVideoEventException : java/lang/Exception {
public fun <init> (Ljava/lang/String;)V
public final fun getType ()Ljava/lang/String;
}

public final class org/openapitools/client/models/UpdateCallMembersRequest {
public fun <init> ()V
public fun <init> (Ljava/util/List;Ljava/util/List;)V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ public class Call(
this,
scope,
clientImpl.peerConnectionFactory.eglBase.eglBaseContext,
clientImpl.audioUsage,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import android.os.IBinder
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import io.getstream.log.taggedLogger
import io.getstream.video.android.core.audio.AudioHandler
import io.getstream.video.android.core.audio.AudioSwitchHandler
import io.getstream.video.android.core.audio.StreamAudioDevice
import io.getstream.video.android.core.audio.StreamAudioDevice.Companion.fromAudio
Expand Down Expand Up @@ -328,11 +329,12 @@ class ScreenShareManager(
class MicrophoneManager(
val mediaManager: MediaManagerImpl,
val preferSpeakerphone: Boolean,
val audioUsage: Int,
) {
// Internal data
private val logger by taggedLogger("Media:MicrophoneManager")

private lateinit var audioHandler: AudioSwitchHandler
private lateinit var audioHandler: AudioHandler
private var setupCompleted: Boolean = false
internal var audioManager: AudioManager? = null
internal var priorStatus: DeviceStatus? = null
Expand Down Expand Up @@ -434,6 +436,8 @@ class MicrophoneManager(
setupCompleted = false
}

fun canHandleDeviceSwitch() = audioUsage != AudioAttributes.USAGE_MEDIA

// Internal logic
internal fun setup() {
if (setupCompleted) {
Expand All @@ -445,14 +449,18 @@ class MicrophoneManager(
audioManager?.allowedCapturePolicy = AudioAttributes.ALLOW_CAPTURE_BY_ALL
}

audioHandler =
AudioSwitchHandler(mediaManager.context, preferSpeakerphone) { devices, selected ->
logger.i { "audio devices. selected $selected, available devices are $devices" }
_devices.value = devices.map { it.fromAudio() }
_selectedDevice.value = selected?.fromAudio()
}
if (canHandleDeviceSwitch()) {
audioHandler =
AudioSwitchHandler(mediaManager.context, preferSpeakerphone) { devices, selected ->
logger.i { "audio devices. selected $selected, available devices are $devices" }
_devices.value = devices.map { it.fromAudio() }
_selectedDevice.value = selected?.fromAudio()
}

audioHandler.start()
audioHandler.start()
} else {
logger.d { "[MediaManager#setup] usage is MEDIA, cannot handle device switch" }
}
setupCompleted = true
}

Expand All @@ -463,7 +471,7 @@ class MicrophoneManager(

private fun ifAudioHandlerInitialized(then: (audioHandler: AudioSwitchHandler) -> Unit) {
if (this::audioHandler.isInitialized) {
then(this.audioHandler)
then(this.audioHandler as AudioSwitchHandler)
} else {
logger.e { "Audio handler not initialized. Ensure calling setup(), before using the handler." }
}
Expand Down Expand Up @@ -802,6 +810,7 @@ class MediaManagerImpl(
val call: Call,
val scope: CoroutineScope,
val eglBaseContext: EglBase.Context,
val audioUsage: Int = defaultAudioUsage,
) {
private val filterVideoProcessor =
FilterVideoProcessor({ call.videoFilter }, { camera.surfaceTextureHelper })
Expand Down Expand Up @@ -838,7 +847,7 @@ class MediaManagerImpl(
)

internal val camera = CameraManager(this, eglBaseContext)
internal val microphone = MicrophoneManager(this, preferSpeakerphone = true)
internal val microphone = MicrophoneManager(this, preferSpeakerphone = true, audioUsage)
internal val speaker = SpeakerManager(this, microphone)
internal val screenShare = ScreenShareManager(this, eglBaseContext)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ import kotlinx.coroutines.launch
* @property sounds Overwrite the default SDK sounds. See [Sounds].
* @property crashOnMissingPermission if [permissionCheck] returns false there will be an exception.
* @property permissionCheck used to check for system permission based on call capabilities. See [StreamPermissionCheck].
* @property audioUsage used to signal to the system how to treat the audio tracks (voip or media).
*/
public class StreamVideoBuilder @JvmOverloads constructor(
context: Context,
Expand All @@ -90,6 +91,7 @@ public class StreamVideoBuilder @JvmOverloads constructor(
private val sounds: Sounds = Sounds(),
private val crashOnMissingPermission: Boolean = true,
private val permissionCheck: StreamPermissionCheck = DefaultStreamPermissionCheck(),
private val audioUsage: Int = defaultAudioUsage,
) {
private val context: Context = context.applicationContext

Expand Down Expand Up @@ -171,6 +173,7 @@ public class StreamVideoBuilder @JvmOverloads constructor(
testSfuAddress = localSfuAddress,
sounds = sounds,
permissionCheck = permissionCheck,
audioUsage = audioUsage,
)

if (user.type == UserType.Guest) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package io.getstream.video.android.core

import android.content.Context
import android.media.AudioAttributes
import androidx.lifecycle.Lifecycle
import io.getstream.android.push.PushDevice
import io.getstream.log.taggedLogger
Expand Down Expand Up @@ -125,6 +126,7 @@ import kotlin.coroutines.Continuation
import kotlin.coroutines.resumeWithException

internal const val WAIT_FOR_CONNECTION_ID_TIMEOUT = 5000L
internal const val defaultAudioUsage = AudioAttributes.USAGE_VOICE_COMMUNICATION

/**
* @param lifecycle The lifecycle used to observe changes in the process
Expand All @@ -145,6 +147,7 @@ internal class StreamVideoImpl internal constructor(
internal val sounds: Sounds,
internal val crashOnMissingPermission: Boolean = true,
internal val permissionCheck: StreamPermissionCheck = DefaultStreamPermissionCheck(),
internal val audioUsage: Int = defaultAudioUsage,
) : StreamVideo, NotificationHandler by streamNotificationManager {

private var locationJob: Deferred<Result<String>>? = null
Expand All @@ -165,7 +168,7 @@ internal class StreamVideoImpl internal constructor(
private lateinit var connectContinuation: Continuation<Result<ConnectedEvent>>

@InternalStreamVideoApi
public var peerConnectionFactory = StreamPeerConnectionFactory(context)
public var peerConnectionFactory = StreamPeerConnectionFactory(context, audioUsage)
public override val userId = user.id

private val logger by taggedLogger("Call:StreamVideo")
Expand Down Expand Up @@ -352,11 +355,9 @@ internal class StreamVideoImpl internal constructor(
}
}
scope.launch {
connectionModule.coordinatorSocket.errors.collect {
if (developmentMode) {
logger.e(it) { "failure on socket connection" }
} else {
logger.e(it) { "failure on socket connection" }
connectionModule.coordinatorSocket.errors.collect { throwable ->
(throwable as? ErrorResponse)?.let {
if (it.code == VideoErrorCode.TOKEN_EXPIRED.code) refreshToken(it)
}
}
}
Expand Down Expand Up @@ -427,19 +428,27 @@ internal class StreamVideoImpl internal constructor(
timer.finish()
Success(timer.duration)
} catch (e: ErrorResponse) {
if (e.code == VideoErrorCode.TOKEN_EXPIRED.code && tokenProvider != null) {
val newToken = tokenProvider.invoke(e)
connectionModule.updateToken(newToken)
// quickly reconnect with the new token
socketImpl.reconnect(0)
Failure(Error.GenericError("initialize error. trying to reconnect."))
if (e.code == VideoErrorCode.TOKEN_EXPIRED.code) {
refreshToken(e)
Failure(Error.GenericError("Initialize error. Token expired."))
} else {
throw e
}
}
}
}

private suspend fun refreshToken(error: Throwable) {
tokenProvider?.let {
val newToken = tokenProvider.invoke(error)
connectionModule.updateToken(newToken)

logger.d { "[refreshToken] Token has been refreshed with: $newToken" }

socketImpl.reconnect(0)
}
}

/**
* @see StreamVideo.deleteDevice
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
package io.getstream.video.android.core.call.connection

import android.content.Context
import android.media.AudioAttributes
import android.os.Build
import io.getstream.log.taggedLogger
import io.getstream.video.android.core.call.video.FilterVideoProcessor
import io.getstream.video.android.core.defaultAudioUsage
import io.getstream.video.android.core.model.IceCandidate
import io.getstream.video.android.core.model.StreamPeerType
import kotlinx.coroutines.CoroutineScope
Expand All @@ -44,8 +46,13 @@ import java.nio.ByteBuffer
* Builds a factory that provides [PeerConnection]s when requested.
*
* @param context Used to build the underlying native components for the factory.
* @param audioUsage signal to the system how the audio tracks are used.
* Set this to [AudioAttributes.USAGE_MEDIA] if you want the audio track to behave like media, useful for livestreaming scenarios.
*/
public class StreamPeerConnectionFactory(private val context: Context) {
public class StreamPeerConnectionFactory(
private val context: Context,
private val audioUsage: Int = defaultAudioUsage,
) {

private val webRtcLogger by taggedLogger("Call:WebRTC")
private val audioLogger by taggedLogger("Call:AudioTrackCallback")
Expand Down Expand Up @@ -151,7 +158,15 @@ public class StreamPeerConnectionFactory(private val context: Context) {
.builder(context)
.setUseHardwareAcousticEchoCanceler(
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q,
)
).apply {
if (audioUsage != defaultAudioUsage) {
setAudioAttributes(
AudioAttributes.Builder().setUsage(audioUsage)
.build(),
)
audioLogger.d { "[setAudioAttributes] usage: $audioUsage" }
}
}
.setUseHardwareNoiseSuppressor(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
.setAudioRecordErrorCallback(object :
JavaAudioDeviceModule.AudioRecordErrorCallback {
Expand Down Expand Up @@ -297,7 +312,10 @@ public class StreamPeerConnectionFactory(private val context: Context) {
* @return [VideoSource] that can be used to build tracks.
*/

internal fun makeVideoSource(isScreencast: Boolean, filterVideoProcessor: FilterVideoProcessor): VideoSource =
internal fun makeVideoSource(
isScreencast: Boolean,
filterVideoProcessor: FilterVideoProcessor,
): VideoSource =
factory.createVideoSource(isScreencast).apply {
setVideoProcessor(filterVideoProcessor)
}
Expand Down
Loading

0 comments on commit 8e65b33

Please sign in to comment.