# Voice Calling Voice calling with Android Voice and Video SDK. Set up calling between applications, from application to phone, app to SIP and conference calls. Get more information here. The Sinch SDK supports four types of calls: *app-to-app (audio or video)*, *app-to-phone*, *app-to-sip* and *conference* calls. The *CallController* is the entry point for the calling functionality of the Sinch SDK. Calls are placed through the *CallController* and events are received using the *CallControllerListener*. The call controller is owned by the SinchClient and accessed using `sinchClient.callController`. ## Set Up an *App-to-App* Call Use the [CallController.callUser()](https://download.sinch.com/android/latest/reference/sinch-rtc/com.sinch.android.rtc.calling/-call-controller/call-user.html) method so that Sinch services can connect the call to the callee. ```kotlin val callController = sinchClient.callController val call = callController.callUser("", new MediaConstraints(false)) // Or for video call: val call = callController.callUser("", new MediaConstraints(true)) call.addCallListener(...) ``` A call object is returned, containing details about the participants in the call, call details such as start time, call state and possible errors. Assuming the callee's device is available, the [CallListener.onCallProgressing()](https://download.sinch.com/android/latest/reference/sinch-rtc/com.sinch.android.rtc.calling/-call-listener/on-call-progressing.html) is invoked. If a progress tone should be played, this is where it should be started. When the callee receives the call, [CallListener.onCallRinging()](https://download.sinch.com/android/latest/reference/sinch-rtc/com.sinch.android.rtc.calling/-call-listener/on-call-ringing.html) fires. This indicates the callee’s device is ringing. When the other party answers, [CallListener.onCallAnswered()](https://download.sinch.com/android/latest/reference/sinch-rtc/com.sinch.android.rtc.calling/-call-listener/on-call-answered.html) is called. Stop any progress tone. Once full audio connectivity is established, [CallListener.onCallEstablished()](https://download.sinch.com/android/latest/reference/sinch-rtc/com.sinch.android.rtc.calling/-call-listener/on-call-established.html) is emitted. Users can now talk. Typically, connectivity is already established when the call is answered, so `onCallEstablished` may follow immediately after `onCallAnswered`. On poor networks, it can take longer—consider showing a “connecting” indicator. Important For *App-to-App* calls, you must enable managed push by providing FCM or HMS `PushConfiguration` to `SinchClientBuilder`, even if you are the caller. See the full setup in [Push notifications](/docs/in-app-calling/android/push-notifications). ## Set Up an *App-to-Phone* Call An *app-to-phone* call is a call that's made to a phone on the regular telephone network. Setting up an *app-to-phone* call is not much different than setting up an *app-to-app* call. Instead of invoking the `callUser` method, invoke the [CallController.callPhoneNumber()](https://download.sinch.com/android/latest/reference/sinch-rtc/com.sinch.android.rtc.calling/-call-controller/call-phone-number.html). The phone number also should be specified to the [E.164 number formatting standard](https://community.sinch.com/t5/Glossary/E-164/ta-p/7537) and should be prefixed with a `+`. **Example**: To call the US phone number *415 555 0101*, the phone number should be specified as `+14155550101`. The `+` is the required prefix and the US country code `1` prepended to the local subscriber number. ### Presenting a number to the destination you are calling Mandatory step! You must provide a CLI (Calling Line Identifier) or your call will fail. You need a number from Sinch so you can provide a valid CLI to the handset you are calling. If you have a trial account, you can use the [test number](https://community.sinch.com/t5/Virtual-Numbers/How-can-I-activate-my-free-number-for-testing/ta-p/8578) that is available for free. If you have already upgraded your account, you can purchase a number to use on the [dashboard](https://dashboard.sinch.com/numbers/your-numbers). Note: When your account is in trial mode, you can only call your [verified numbers](https://dashboard.sinch.com/numbers/verified-numbers). If you want to call any number, you need to upgrade your account! Credits Required Remember, placing an *App-to-Phone* call requires that your Sinch account has sufficient credits. Add credits on your [Account](https://dashboard.sinch.com/account) page. Credits are used each time an *App-to-Phone* call is placed and your account balance is updated after each call. ```kotlin // Instantiate an app to phone call using the CallController. val callController = sinchClient.callController // If you're on trial account you have to register the destination number first. See https://dashboard.sinch.com/numbers/verified-numbers val destinationNumber = "" // You can either use a test number https://community.sinch.com/t5/Virtual-Numbers/How-can-I-activate-my-free-number-for-testing/ta-p/8578 or purchase one here: // https://dashboard.sinch.com/numbers/your-numbers val cli = "" val call = callController.callPhoneNumber(destinationNumber, cli) ``` Testing DTMF In an *App-to-Phone* scenario, it's possible to issue DTMF sequences using the Sinch SDK. Note that if the receiving end of the call is an iOS device, you might have to disable *VoLTE* ("Voice over LTE") option in the settings of the phone at the receiving end of the call in order to be able to hear DTMF tones. ## Set Up an *App-to-sip* Call An *app-to-sip* call is a call that's made to a SIP server. Setting up an *app-to-sip* call is not much different from setting up an *app-to-app* call. Instead of invoking the `callUser` method, invoke the [CallClient.callSip()](https://download.sinch.com/android/latest/reference/sinch-rtc/com.sinch.android.rtc.calling/-call-controller/call-sip.html). The SIP identity should be in the form ``. By convention, when passing custom headers in the SIP call, the headers should be prefixed with `x-`. If the SIP server reported any errors, the `CallDetails` object will provide an error with the `SIP` error type. ## Set Up a *Conference* Call A *conference* call can be made to connect a user to a conference room where multiple users can be connected at the same time. The identifier for a conference room may not be longer than 64 characters. ```kotlin val callController = sinchClient.callController val call = callController.callConference("") call.addCallListener(...) ``` It is also possible to connect users to a conference call via the [Sinch REST API](/docs/voice/api-reference/voice/callouts/). ## Handle Incoming Calls To answer calls, the application must be notified when the user receives an incoming call. Add a [CallControllerListener](https://download.sinch.com/android/latest/reference/sinch-rtc/com.sinch.android.rtc.calling/-call-controller-listener/index.html) to the `CallController` to act on the incoming calls. As calls come into device [CallControllerListener.onIncomingCall()](https://download.sinch.com/android/latest/reference/sinch-rtc/com.sinch.android.rtc.calling/-call-controller-listener/index.html) will be executed. ```kotlin val callController = sinchClient.callController callController.addCallControllerListener(...) ``` When the incoming call method is executed, the call can either be connected automatically without any user action, or it can wait for the user to press the answer or the hangup button. If the call is set up to wait for a user response, we recommended that a ringtone is played to notify the user that there is an incoming call. ```kotlin override fun onIncomingCall(callController: CallController, call: Call) { // Start playing ringing tone ... // Add call listener call.addCallListener(...) } ``` To get events related to the call, add a call listener. The call object contains details about participants, start time, potential error codes, and error messages. ### Receiving Calls from PSTN or SIP (Phone-to-App / SIP-to-App) The Sinch SDK supports receiving incoming calls that originate from the PSTN (regular phone network) or from SIP endpoints. When a call arrives at a Sinch voice number or via SIP origination, the Sinch platform triggers an **Incoming Call Event (ICE)** callback to your backend. Out platform can then route this call to an in-app user by responding with the `connectMxp` SVAML action. #### Prerequisites 1. Rent a voice number from the [Sinch Build Dashboard](https://dashboard.sinch.com/numbers/overview) and assign it to your application, OR configure SIP origination for your application 2. Configure a callback URL in your app's Voice settings where Sinch will send call-related events 3. Implement the ICE callback handler in your backend to route calls to the appropriate app user #### Backend Implementation When a PSTN or SIP call comes in, respond to the ICE callback with a `connectMxp` action to route the call to an app user: ```json { "action": { "name": "connectMxp", "destination": { "type": "username", "endpoint": "target-user-id" } } } ``` ### Incoming video call When an incoming call is a video call, the [CallControllerListener.onIncomingCall()](https://download.sinch.com/android/latest/reference/sinch-rtc/com.sinch.android.rtc.calling/-call-controller-listener/index.html) is also executed with [isVideoOffered](https://download.sinch.com/android/latest/reference/sinch-rtc/com.sinch.android.rtc.calling/-call-details/is-video-offered.html) flag returning true. See [video calling](https://developers.sinch.com/docs/in-app-calling/android/video-calling/) section for details how to handle video views. ### Answer incoming call To answer the call, use the [Call.answer()](https://download.sinch.com/android/latest/reference/sinch-rtc/com.sinch.android.rtc.calling/-call/answer.html) method on the call to accept it. If a ringtone was previously played, it should be stopped now. User presses the answer button: ```kotlin // User answers the call call.answer() // Stop playing ringing tone ... ``` Now, the clients on both ends establish the connection. When the call is established and the voice streams are running in both directions, the [CallListener.onCallEstablished()](https://download.sinch.com/android/latest/reference/sinch-rtc/com.sinch.android.rtc.calling/-call-listener/on-call-established.html) is called. ### Decline incoming call If the call shouldn't be answered, use the [Call.hangup()](https://download.sinch.com/android/latest/reference/sinch-rtc/com.sinch.android.rtc.calling/-call/hangup.html) on the call to decline. The caller is notified that the incoming call was denied. If a ringtone was previously played, it should be stopped now. User presses the hangup button: ```kotlin // User doesn't want to answer call.hangup() // Stop playing ringing tone ... ``` ## Disconnecting a Call When the user wants to disconnect an ongoing call, use the [Call.hangup()](https://download.sinch.com/android/latest/reference/sinch-rtc/com.sinch.android.rtc.calling/-call/hangup.html) method. Either user taking part in a call can disconnect it. Hanging up a call: ```kotlin call.hangup() ``` When either party disconnects a call, the application is notified using the call listener method [CallListener.onCallEnded()](https://download.sinch.com/android/latest/reference/sinch-rtc/com.sinch.android.rtc.calling/-call-listener/on-call-ended.html). This allows the user interface to be updated, an alert tone to be played or similar actions to occur. A call can be disconnected before it has been completely established. Hanging up a connecting call: ```kotlin // Starts a call asynchronously val call = callController.callUser("") // User changed his/her mind, let's hangup call.hangup() ``` ## Volume Control To make sure that the volume of the call can be modified by the hardware volume controls, `setVolumeControlStream(AudioManager.STREAM_VOICE_CALL)` must be called on the `Activity` where the call is handled. Make sure that `volumeControlStream` is reset to a suitable value when the call has ended, for example, after creating a call (using [CallClient.callUser()](https://download.sinch.com/android/latest/reference/sinch-rtc/com.sinch.android.rtc.calling/-call-controller/call-user.html)). When the call ends, set the volume control stream back to it's previous value. For example in your implementation of `CallListener`: ```kotlin override fun onCallEnded(call: Call) { setVolumeControlStream(AudioManager.USE_DEFAULT_STREAM_TYPE) } ``` ## Audio Routing [AudioController](https://download.sinch.com/android/latest/reference/sinch-rtc/com.sinch.android.rtc/-audio-controller/index.html) interface allows you to control audio routing. Acquire the *AudioController* using [SinchClient.audioController](https://download.sinch.com/android/latest/reference/sinch-rtc/com.sinch.android.rtc/-sinch-client/index.html), and use the following methods: | Method | Description | | --- | --- | | `mute()` | Mutes audio input. | | `unmute()` | Unmutes audio input. | | `enableSpeaker()` | Enables speaker mode. | | `disableSpeaker()` | Disables speaker mode. | | `enableAutomaticAudioRouting()` | Enables automatic audio (AAR). | | `disableAutomaticAudioRouting()` | Disables automatic audio routing (AAR). | ### Automatic audio routing You can enable automatic audio routing using [AudioController.enableAutomaticAudioRouting()](https://download.sinch.com/android/latest/reference/sinch-rtc/com.sinch.android.rtc/-audio-controller/enable-automatic-audio-routing.html). It enables automatic audio routing between earpiece, speakerphone, wired headset, and Bluetooth audio devices. It takes a single `AudioController.AudioRoutingConfig` parameter that allows you to specify: - `boolean manageBluetoothAudio`: if set to `true`, automatically reroutes audio to a Bluetooth headset when available. Throws `MissingPermissionException` if `android.Manifest.permission.BLUETOOTH` is not granted. - `AudioController.UseSpeakerphone useSpeakerphone`: can be set to `AUTO`, `TRUE`, or `FALSE`. The `AUTO` mode uses a proximity sensor to operate. Priorities are as follows: - Bluetooth (if available and `manageBluetoothAudio == true`) - Wired Headset - Default audio device if `useSpeakerphone` is `TRUE` or `FALSE`; or proximity-sensor-based decision (speakerphone/earpiece) if `useSpeakerphone` is `AUTO`. The default audio device (speakerphone/earpiece) is set using the `useSpeakerphone` parameter.