Skip to content

Integrate Telecom into the Stream Video SDK #1322

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

Open
wants to merge 31 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
41ad257
Implement telecom integration as a `ConnectionService`
aleksandar-apostolov Feb 20, 2025
e5757c6
Spotless and Api dump
aleksandar-apostolov Feb 20, 2025
982570a
Add endpoint switch and accept/leave actions
liviu-timar Feb 20, 2025
0f37ae4
Open call screen when accepting from BT device
liviu-timar Feb 21, 2025
6b96286
Merge branch 'develop' into telecom-v3
aleksandar-apostolov Feb 21, 2025
d858d47
Merge conflicts
aleksandar-apostolov Feb 21, 2025
406e2a5
Spotless & ApiDump
aleksandar-apostolov Feb 21, 2025
8dbc47d
Update config for telecom
aleksandar-apostolov Feb 28, 2025
e339c33
Merge branch 'develop' into telecom-v3
aleksandar-apostolov Mar 13, 2025
b0104d8
Do not require READ_PHONE_NUMBERS permission
aleksandar-apostolov Mar 13, 2025
32d400e
Spotless & API
aleksandar-apostolov Mar 17, 2025
436e9b6
Revert testing behaviour on CalljoinScreen
aleksandar-apostolov Mar 17, 2025
0785027
do not setActive in call events
aleksandar-apostolov Mar 17, 2025
d555633
Mark VoipConnection as internal
aleksandar-apostolov Mar 17, 2025
67e257d
Spotless & ApiDump
aleksandar-apostolov Mar 17, 2025
42dd498
Allow to enable/disable telecom via config
aleksandar-apostolov Mar 17, 2025
9f72b33
Add test for TelecomCallService
aleksandar-apostolov Mar 17, 2025
2f0e190
Spotless & ApiDump
aleksandar-apostolov Mar 17, 2025
35f62ee
add voip connection test
aleksandar-apostolov Mar 17, 2025
c029fa7
Spotless & Api
aleksandar-apostolov Mar 17, 2025
33f72dc
Enable telecom config for testing
aleksandar-apostolov Mar 20, 2025
97a3ed6
Merge branch 'develop' into telecom-v3
liviu-timar Mar 20, 2025
ab6f922
Add changes to fix tests
liviu-timar Mar 20, 2025
0e836c0
Fix for #4 (notification canceled on click)
liviu-timar Mar 26, 2025
03ce1e3
Fix for #8 (rejected straight away)
liviu-timar Mar 27, 2025
ea8cebc
Spotless
liviu-timar Mar 28, 2025
0a3f839
Merge branch 'refs/heads/develop' into telecom-v3
liviu-timar Apr 4, 2025
9a1a5c1
Have working incoming & outgoing calls on wearable (wip)
liviu-timar Apr 7, 2025
5cb3a4e
Merge branch 'develop' into telecom-v3
liviu-timar Apr 23, 2025
541f87e
Add call sounds
liviu-timar Apr 23, 2025
0624044
WIP
liviu-timar Apr 23, 2025
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 @@ -211,6 +211,7 @@ private fun CallJoinHeader(
horizontalArrangement = Arrangement.SpaceAround,
) {
user?.let {
val context = LocalContext.current
Box(
modifier = if (isProduction) {
Modifier.combinedClickable(
Expand Down Expand Up @@ -401,14 +402,17 @@ private fun CallActualContent(
onClick = { onNewCall() },
)
Spacer(modifier = Modifier.height(VideoTheme.dimens.spacingS))
val context = LocalContext.current
StreamButton(
style = VideoTheme.styles.buttonStyles.tertiaryButtonStyle(),
modifier = Modifier
.fillMaxWidth()
.testTag("Stream_ScanQrCodeButton"),
text = stringResource(id = R.string.scan_qr_code),
icon = Icons.Default.QrCodeScanner,
onClick = { gotoQR() },
onClick = {
gotoQR()
},
)
}
}
Expand Down
95 changes: 65 additions & 30 deletions stream-video-android-core/api/stream-video-android-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -5732,8 +5732,10 @@ public final class io/getstream/video/android/core/ClientState {
public final fun handleEvent (Lio/getstream/android/video/generated/models/VideoEvent;)V
public final fun hasActiveOrRingingCall ()Z
public final fun removeActiveCall ()V
public final fun removeRingingCall ()V
public final fun removeRingingCall (Z)V
public static synthetic fun removeRingingCall$default (Lio/getstream/video/android/core/ClientState;ZILjava/lang/Object;)V
public final fun setActiveCall (Lio/getstream/video/android/core/Call;)V
public final fun setActiveCall2 (Lio/getstream/video/android/core/Call;)V
}

public abstract interface class io/getstream/video/android/core/ConnectionState {
Expand Down Expand Up @@ -6334,14 +6336,15 @@ public abstract interface class io/getstream/video/android/core/api/SignalServer
}

public abstract interface class io/getstream/video/android/core/audio/AudioHandler {
public abstract fun selectDevice (Lio/getstream/video/android/core/audio/StreamAudioDevice;)V
public abstract fun start ()V
public abstract fun stop ()V
}

public final class io/getstream/video/android/core/audio/AudioSwitchHandler : io/getstream/video/android/core/audio/AudioHandler {
public static final field Companion Lio/getstream/video/android/core/audio/AudioSwitchHandler$Companion;
public fun <init> (Landroid/content/Context;Lkotlin/jvm/functions/Function2;)V
public final fun selectDevice (Lcom/twilio/audioswitch/AudioDevice;)V
public fun selectDevice (Lio/getstream/video/android/core/audio/StreamAudioDevice;)V
public fun start ()V
public fun stop ()V
}
Expand All @@ -6352,21 +6355,25 @@ public final class io/getstream/video/android/core/audio/AudioSwitchHandler$Comp
public abstract class io/getstream/video/android/core/audio/StreamAudioDevice {
public static final field Companion Lio/getstream/video/android/core/audio/StreamAudioDevice$Companion;
public static final fun fromAudio (Lcom/twilio/audioswitch/AudioDevice;)Lio/getstream/video/android/core/audio/StreamAudioDevice;
public abstract fun getAudio ()Lcom/twilio/audioswitch/AudioDevice;
public abstract fun getAudioSwitchDevice ()Lcom/twilio/audioswitch/AudioDevice;
public abstract fun getName ()Ljava/lang/String;
public abstract fun getTelecomDevice ()Landroid/telecom/CallEndpoint;
public static final fun toAudioDevice (Lio/getstream/video/android/core/audio/StreamAudioDevice;)Lcom/twilio/audioswitch/AudioDevice;
}

public final class io/getstream/video/android/core/audio/StreamAudioDevice$BluetoothHeadset : io/getstream/video/android/core/audio/StreamAudioDevice {
public fun <init> (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;)V
public synthetic fun <init> (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> ()V
public fun <init> (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;Landroid/telecom/CallEndpoint;)V
public synthetic fun <init> (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;Landroid/telecom/CallEndpoint;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Ljava/lang/String;
public final fun component2 ()Lcom/twilio/audioswitch/AudioDevice;
public final fun copy (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;)Lio/getstream/video/android/core/audio/StreamAudioDevice$BluetoothHeadset;
public static synthetic fun copy$default (Lio/getstream/video/android/core/audio/StreamAudioDevice$BluetoothHeadset;Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;ILjava/lang/Object;)Lio/getstream/video/android/core/audio/StreamAudioDevice$BluetoothHeadset;
public final fun component3 ()Landroid/telecom/CallEndpoint;
public final fun copy (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;Landroid/telecom/CallEndpoint;)Lio/getstream/video/android/core/audio/StreamAudioDevice$BluetoothHeadset;
public static synthetic fun copy$default (Lio/getstream/video/android/core/audio/StreamAudioDevice$BluetoothHeadset;Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;Landroid/telecom/CallEndpoint;ILjava/lang/Object;)Lio/getstream/video/android/core/audio/StreamAudioDevice$BluetoothHeadset;
public fun equals (Ljava/lang/Object;)Z
public fun getAudio ()Lcom/twilio/audioswitch/AudioDevice;
public fun getAudioSwitchDevice ()Lcom/twilio/audioswitch/AudioDevice;
public fun getName ()Ljava/lang/String;
public fun getTelecomDevice ()Landroid/telecom/CallEndpoint;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
Expand All @@ -6377,43 +6384,52 @@ public final class io/getstream/video/android/core/audio/StreamAudioDevice$Compa
}

public final class io/getstream/video/android/core/audio/StreamAudioDevice$Earpiece : io/getstream/video/android/core/audio/StreamAudioDevice {
public fun <init> (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;)V
public synthetic fun <init> (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> ()V
public fun <init> (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;Landroid/telecom/CallEndpoint;)V
public synthetic fun <init> (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;Landroid/telecom/CallEndpoint;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Ljava/lang/String;
public final fun component2 ()Lcom/twilio/audioswitch/AudioDevice;
public final fun copy (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;)Lio/getstream/video/android/core/audio/StreamAudioDevice$Earpiece;
public static synthetic fun copy$default (Lio/getstream/video/android/core/audio/StreamAudioDevice$Earpiece;Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;ILjava/lang/Object;)Lio/getstream/video/android/core/audio/StreamAudioDevice$Earpiece;
public final fun component3 ()Landroid/telecom/CallEndpoint;
public final fun copy (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;Landroid/telecom/CallEndpoint;)Lio/getstream/video/android/core/audio/StreamAudioDevice$Earpiece;
public static synthetic fun copy$default (Lio/getstream/video/android/core/audio/StreamAudioDevice$Earpiece;Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;Landroid/telecom/CallEndpoint;ILjava/lang/Object;)Lio/getstream/video/android/core/audio/StreamAudioDevice$Earpiece;
public fun equals (Ljava/lang/Object;)Z
public fun getAudio ()Lcom/twilio/audioswitch/AudioDevice;
public fun getAudioSwitchDevice ()Lcom/twilio/audioswitch/AudioDevice;
public fun getName ()Ljava/lang/String;
public fun getTelecomDevice ()Landroid/telecom/CallEndpoint;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class io/getstream/video/android/core/audio/StreamAudioDevice$Speakerphone : io/getstream/video/android/core/audio/StreamAudioDevice {
public fun <init> (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;)V
public synthetic fun <init> (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> ()V
public fun <init> (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;Landroid/telecom/CallEndpoint;)V
public synthetic fun <init> (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;Landroid/telecom/CallEndpoint;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Ljava/lang/String;
public final fun component2 ()Lcom/twilio/audioswitch/AudioDevice;
public final fun copy (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;)Lio/getstream/video/android/core/audio/StreamAudioDevice$Speakerphone;
public static synthetic fun copy$default (Lio/getstream/video/android/core/audio/StreamAudioDevice$Speakerphone;Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;ILjava/lang/Object;)Lio/getstream/video/android/core/audio/StreamAudioDevice$Speakerphone;
public final fun component3 ()Landroid/telecom/CallEndpoint;
public final fun copy (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;Landroid/telecom/CallEndpoint;)Lio/getstream/video/android/core/audio/StreamAudioDevice$Speakerphone;
public static synthetic fun copy$default (Lio/getstream/video/android/core/audio/StreamAudioDevice$Speakerphone;Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;Landroid/telecom/CallEndpoint;ILjava/lang/Object;)Lio/getstream/video/android/core/audio/StreamAudioDevice$Speakerphone;
public fun equals (Ljava/lang/Object;)Z
public fun getAudio ()Lcom/twilio/audioswitch/AudioDevice;
public fun getAudioSwitchDevice ()Lcom/twilio/audioswitch/AudioDevice;
public fun getName ()Ljava/lang/String;
public fun getTelecomDevice ()Landroid/telecom/CallEndpoint;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class io/getstream/video/android/core/audio/StreamAudioDevice$WiredHeadset : io/getstream/video/android/core/audio/StreamAudioDevice {
public fun <init> (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;)V
public synthetic fun <init> (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> ()V
public fun <init> (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;Landroid/telecom/CallEndpoint;)V
public synthetic fun <init> (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;Landroid/telecom/CallEndpoint;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Ljava/lang/String;
public final fun component2 ()Lcom/twilio/audioswitch/AudioDevice;
public final fun copy (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;)Lio/getstream/video/android/core/audio/StreamAudioDevice$WiredHeadset;
public static synthetic fun copy$default (Lio/getstream/video/android/core/audio/StreamAudioDevice$WiredHeadset;Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;ILjava/lang/Object;)Lio/getstream/video/android/core/audio/StreamAudioDevice$WiredHeadset;
public final fun component3 ()Landroid/telecom/CallEndpoint;
public final fun copy (Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;Landroid/telecom/CallEndpoint;)Lio/getstream/video/android/core/audio/StreamAudioDevice$WiredHeadset;
public static synthetic fun copy$default (Lio/getstream/video/android/core/audio/StreamAudioDevice$WiredHeadset;Ljava/lang/String;Lcom/twilio/audioswitch/AudioDevice;Landroid/telecom/CallEndpoint;ILjava/lang/Object;)Lio/getstream/video/android/core/audio/StreamAudioDevice$WiredHeadset;
public fun equals (Ljava/lang/Object;)Z
public fun getAudio ()Lcom/twilio/audioswitch/AudioDevice;
public fun getAudioSwitchDevice ()Lcom/twilio/audioswitch/AudioDevice;
public fun getName ()Ljava/lang/String;
public fun getTelecomDevice ()Landroid/telecom/CallEndpoint;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
Expand Down Expand Up @@ -9999,17 +10015,19 @@ 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;Ljava/lang/Class;)V
public synthetic fun <init> (ZILjava/util/Map;Ljava/lang/Class;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (ZZILjava/util/Map;Ljava/lang/Class;)V
public synthetic fun <init> (ZZILjava/util/Map;Ljava/lang/Class;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 component4 ()Ljava/lang/Class;
public final fun copy (ZILjava/util/Map;Ljava/lang/Class;)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/lang/Class;ILjava/lang/Object;)Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfig;
public final fun component2 ()Z
public final fun component3 ()I
public final fun component4 ()Ljava/util/Map;
public final fun component5 ()Ljava/lang/Class;
public final fun copy (ZZILjava/util/Map;Ljava/lang/Class;)Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfig;
public static synthetic fun copy$default (Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfig;ZZILjava/util/Map;Ljava/lang/Class;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 getEnableTelecomIntegration ()Z
public final fun getRunCallServiceInForeground ()Z
public final fun getServiceClass ()Ljava/lang/Class;
public fun hashCode ()I
Expand All @@ -10019,6 +10037,7 @@ public final class io/getstream/video/android/core/notifications/internal/servic
public final class io/getstream/video/android/core/notifications/internal/service/CallServiceConfigBuilder {
public fun <init> ()V
public final fun build ()Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfig;
public final fun enableTelecomIntegration (Z)Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfigBuilder;
public final fun setAudioUsage (I)Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfigBuilder;
public final fun setRunCallServiceInForeground (Z)Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfigBuilder;
public final fun setServiceClass (Ljava/lang/Class;)Lio/getstream/video/android/core/notifications/internal/service/CallServiceConfigBuilder;
Expand Down Expand Up @@ -10053,6 +10072,15 @@ public final class io/getstream/video/android/core/notifications/internal/servic
public final fun getLivestreamGuestCallServiceConfig ()Ljava/util/Map;
}

public final class io/getstream/video/android/core/notifications/internal/service/telecom/TelecomUtilsKt {
public static final fun getMyPhoneAccountHandle (Landroid/content/Context;)Landroid/telecom/PhoneAccountHandle;
public static final fun getTelecomManager (Landroid/content/Context;)Landroid/telecom/TelecomManager;
public static final fun isTelecomSupported (Landroid/content/Context;)Z
public static final fun promptEnablePhoneAccount (Landroid/content/Context;)V
public static final fun registerMyPhoneAccount (Landroid/content/Context;)V
public static final fun toStreamAudioDevice (Landroid/telecom/CallEndpoint;)Lio/getstream/video/android/core/audio/StreamAudioDevice;
}

public final class io/getstream/video/android/core/permission/PermissionRequest {
public fun <init> (Lio/getstream/video/android/core/Call;Lio/getstream/android/video/generated/models/PermissionRequestEvent;)V
public fun <init> (Lio/getstream/video/android/core/Call;Lio/getstream/video/android/model/User;Lorg/threeten/bp/OffsetDateTime;Ljava/util/List;Lorg/threeten/bp/OffsetDateTime;Lorg/threeten/bp/OffsetDateTime;)V
Expand Down Expand Up @@ -10815,6 +10843,13 @@ public final class io/getstream/video/android/core/socket/sfu/state/SfuSocketSta
public fun toString ()Ljava/lang/String;
}

public final class io/getstream/video/android/core/sounds/CallSoundPlayer {
public fun <init> (Landroid/content/Context;)V
public final fun cleanUpAudioResources ()V
public final fun playCallSound (Landroid/net/Uri;)V
public final fun stopCallSound ()V
}

public abstract interface class io/getstream/video/android/core/sounds/RingingConfig {
public abstract fun getIncomingCallSoundUri ()Landroid/net/Uri;
public abstract fun getOutgoingCallSoundUri ()Landroid/net/Uri;
Expand Down
12 changes: 12 additions & 0 deletions stream-video-android-core/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS"/>

<!-- Call foreground service permission -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
Expand Down Expand Up @@ -111,5 +112,16 @@
android:name=".notifications.internal.service.AudioCallService"
android:foregroundServiceType="microphone|shortService"
android:exported="false" />

<service
android:exported="true"
android:name=".notifications.internal.service.telecom.TelecomCallService"
android:label="Your Telecom Connection Service"
android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE">
<intent-filter>
<action android:name="android.telecom.ConnectionService" />
</intent-filter>
</service>

</application>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -1189,8 +1189,9 @@ public class Call(
logger.d { "[accept] #ringing; no args" }
state.acceptedOnThisDevice = true

clientImpl.state.removeRingingCall()
clientImpl.state.removeRingingCall(willTransitionToOngoing = true)
clientImpl.state.maybeStopForegroundService(call = this)

return clientImpl.accept(type, id)
}

Expand Down
Loading
Loading