Skip to content
This repository was archived by the owner on Feb 20, 2026. It is now read-only.

Latest commit

 

History

History

README.md

Basic Video Chat with ConnectionService

This project enables real-time video calling using a self-managed ConnectionService. The app handles outgoing and incoming calls, integrates with system Telecom APIs, and manages in-call notifications and audio routing.

Features

  • Outgoing and incoming VoIP calls with fullscreen call UIs
  • Integration with Android Telecom API for call and notification management
  • Real-time video sessions using OpenTok
  • Audio device selection and call hold capabilities
  • Self-managed calls for a streamlined calling experience

How It Works

The app customizes Android’s ConnectionService and Connection classes to:

  • Place outgoing calls through a tailored PhoneAccount.
  • Report incoming calls.
  • Manage call state changes, notifications, foreground execution handling and audio routing.
  • Hardcoded local OpenTok credentials.

Configuration

  1. API Credentials:
    Update your OpenTokConfig with your API_KEY, SESSION_ID, and TOKEN variables. You can obtain these values from your TokBox account by creating a new session in the Video API Playground site. In a production setup, these values should be provided from a secure server.

  2. PhoneAccount:
    The PhoneAccountManager registers the PhoneAccount necessary to interface with the Telecom API.

  3. Manifest Setup:
    Verify that AndroidManifest.xml includes all necessary permissions such as CAMERA, RECORD_AUDIO, FOREGROUND_SERVICE, MANAGE_OWN_CALLS, and BIND_TELECOM_CONNECTION_SERVICE.

Register the service in AndroidManifest.xml file.

<service
    android:name=".connectionservice.VonageConnectionService"
    android:exported="true"
    android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
    android:foregroundServiceType="microphone|camera">
    <intent-filter>
        <action android:name="android.telecom.ConnectionService" />
    </intent-filter>
</service>
  1. Audio Focus Management:
    When using ConnectionService, you need to configure the SDK to delegate audio focus control to your app:
   private AudioDeviceManager audioDeviceManager;
   private BaseAudioDevice.AudioFocusManager audioFocusManager;

   public void setupAudioFocusManager(Context context) {
       audioDeviceManager = new AudioDeviceManager(context);
       audioFocusManager = audioDeviceManager.getAudioFocusManager();

       audioFocusManager.setRequestAudioFocus(false);
   }

    public void notifyAudioFocusIsActive() {
        audioFocusManager.audioFocusActivated();
    }

    public void notifyAudioFocusIsInactive() {
        audioFocusManager.audioFocusDeactivated();
    }

When delegating audio focus to the app, the SDK will stop its automatic audio routing. Instead, this routing logic will be handled by ConnectionService, which notifies the app about available audio devices through the Connection's CallEndpoint and CallAudioState APIs. Your app must implement support for audio device enumeration and selection logic.

This delegation ensures proper audio routing and coordination with the Android Telecom system.

Requirements

  • Android API Level 26 or higher is recommended.
  • Ensure proper runtime permissions are granted for camera, audio recording, and foreground service usage.

Overview

A ConnectionService allows apps to manage VoIP or phone calls, whether they need to integrate with the system dialer (system managed) or operate independently (self managed). By implementing this service, a VoIP app can leverage Android’s Telecom APIs to provide features such as call switching, unified audio route management, Bluetooth device support, and integration with companion devices like smartwatches. This ensures calls are accessible and controllable across different devices, with consistent user experiences for actions like answering, rejecting, or ending calls.

TelecomManager and PhoneAccount

To initiate phone or VoIP calls, TelecomManager relies on a registered PhoneAccount. Register your app’s PhoneAccount using TelecomManager.registerPhoneAccount(), and assign it the CAPABILITY_SELF_MANAGED capability. This signals that your app will handle the connection logic and call management independently.

Implementing ConnectionService

To handle outgoing and incoming calls, your app should use TelecomManager.placeCall(Uri, Bundle) for outgoing calls and TelecomManager.addNewIncomingCall() to notify the system of new incoming calls. When these APIs are called, the Telecom framework binds to your app’s ConnectionService.

Your implementation should override the following ConnectionService methods:

Implementing Connection

To represent calls in your app, extend the Connection class. When creating a new Connection instance to return from your ConnectionService, make sure to configure these properties:

  • Use Connection#setAddress(Uri, int) to specify the other party’s identifier. For phone calls, this should be a PhoneAccount#SCHEME_TEL URI.
  • Set the display name with Connection#setCallerDisplayName(String, int), which will appear on Bluetooth and wearable devices—especially important if no phone number is used.
  • Apply Connection#PROPERTY_SELF_MANAGED via Connection#setConnectionProperties(int) to indicate your app manages the call.
  • If your app supports call hold, set Connection#CAPABILITY_SUPPORT_HOLD and Connection#CAPABILITY_HOLD using Connection#setConnectionCapabilities(int) to enable concurrent call scenarios.
  • Call Connection#setAudioModeIsVoip(true) to inform the platform that the call is VoIP.
  • Do not change the call state (e.g., with Connection#setActive() or Connection#setOnHold()) until the Connection has been added to Telecom by returning it from onCreateOutgoingConnection or onCreateIncomingConnection.

Hold/Un hold calls

When receiving and answering an external call while the app is already in a call, ConnectionService will notify your app that the call changed to HOLDING state.

When an external call ended by the remote end the user has to manually unhold the call by pressing the unhold call button. If the external call is ended by the user, the app will automatically unhold the call and resume the audio playback.

Modifying the App for System Managed Calls

To adapt the app so that calls are managed by the system (system managed), follow these steps:

  1. Change the PhoneAccount capability:

    • Replace PhoneAccount.CAPABILITY_SELF_MANAGED with PhoneAccount.CAPABILITY_CALL_PROVIDER when registering your PhoneAccount.
  2. Use standard URI schemes:

    • When placing calls with TelecomManager.placeCall(), use tel: or sip: schemes in the destination URI.
  3. Update ConnectionService address parsing:

    • Ensure your ConnectionService implementation correctly parses and handles tel: or sip: addresses when creating connections.
  4. Activate the PhoneAccount in system settings:

    • The user must manually enable the call account in the system Settings app. You can launch the relevant screen with the following intent:
    startActivity(new Intent(TelecomManager.ACTION_CHANGE_PHONE_ACCOUNTS));
  5. Call history integration:

    • With system-managed mode, calls made and received through your app will appear in the device’s default phone app call history, just like native calls. This allows users to view, return, or manage these calls directly from the standard phone app, providing a more integrated experience.

With these changes, your app’s calls will be fully integrated and managed by the Android system, providing a native calling experience.

Troubleshooting

  • Ensure connected bluetooth speakers have the call audio profile enabled. If that does not work, try disabling and re-enabling the bluetooth speaker.