Modem Call Control

API Reference


The Modem Call Control (mcc) API functions of this API are provided by the modemService service.

IPC interfaces binding

Here's a code sample binding to modem services:

bindings:
{
   clientExe.clientComponent.le_mcc -> modemService.le_mcc
}

Starting a Call

To initiate a call, create a new call object with a destination telephone number calling the le_mcc_Create() function.

le_mcc_Start() must still initiate the call when ready.

The le_mcc_Start() function initiates a call attempt (it's asynchronous because it can take time for a call to connect).

It's essential to register a handler function to get the call events. Use le_mcc_AddCallEventHandler() API to install that handler function. The handler will be called for all calls' events (incoming and outgoing).

The le_mcc_RemoveCallEventHandler() API uninstalls the handler function.

The following APIs can be used to manage incoming or outgoing calls:

When finished with the call object, call le_mcc_Delete() to free all the allocated resources associated with the object.

Multi-threading/multi-application behaviour: the callRef is linked to a specific client (i.e. connection with the mcc service). Each client will have its own callRef for a same call. That is, if a call event handler is registered by one thread but le_mcc_Create() is called by another thread, they will each get different call references for the same call. So, when multiple threads are being used to work with the same call, a comparison of the call references themselves can't be used to tell whether or not they refer to the same call.

This code example uses CallAndPlay() to dial a phone number, and if successful, play a sound file. Once the file has played, the call hangs up.

typedef struct
{
char filePath[MAX_FILE_PATH_BYTES];
}
PlayContext_t;
void CallAndPlay
(
const char* destinationTelPtr,
const char* filePathPtr
)
{
PlayContext_t* contextPtr = (PlayContext_t*)le_mem_ForceAlloc(PlayContextPoolRef);
le_str_Copy(contextPtr->filePath, filePathPtr, sizeof(contextPtr->filePath), NULL);
contextPtr->callRef = le_mcc_Create(destinationTelPtr);
contextPtr->eventHandlerRef = le_mcc_AddCallEventHandler(MyCallEventHandler,
contextPtr);
le_mcc_Start(contextPtr->callRef);
}
static void MyCallEventHandler
(
void* contextPtr
)
{
PlayContext_t* myContextPtr = (PlayContext_t*)contextPtr;
switch (event)
{
{
[...]
le_audio_PlayFile(FileAudioRef, AudioFileFd);
[...]
}
break;
le_mcc_Delete(callRef);
// I don't release the Profile for further use
le_mcc_RemoveCallEventHandler(contextPtr->eventHandlerRef);
le_mem_Release(myContextPtr);
break;
}
}
static void MyAudioFinishedHandler
(
le_audio_PlayComplete reason,
void* contextPtr
)
{
PlayContext_t* myContextPtr = (PlayContext_t*)contextPtr;
le_mcc_HangUp(myContextPtr->callRef); // This will trigger a TERMINATED event.
}

Answering a call

Receiving calls is similar sending calls. Add a handler through le_mcc_AddCallEventHandler() to be notified of incoming calls.

To answer, call le_mcc_Answer(). To reject it, call le_mcc_HangUp().

This code example uses InstallAutomaticAnswer() to install a call event handler that automatically answers incoming calls. The handler function verifies the incoming call is permitted (through a predefined list), and then decides whether to answer or terminate it.

static le_audio_ConnectorRef_t AudioRxConnectorRef = NULL;
static le_audio_ConnectorRef_t AudioTxConnectorRef = NULL;
static le_audio_StreamRef_t MicRef = NULL;
static le_audio_StreamRef_t SpeakerRef = NULL;
static le_audio_StreamRef_t CallRxAudioRef = NULL;
static le_audio_StreamRef_t CallTxAudioRef = NULL;
void InstallAutomaticAnswer
(
void
)
{
le_mcc_AddCallEventHandler( MyVoiceCallEventHandler,
contextPtr);
}
static void MyVoiceCallEventHandler
(
void* contextPtr
)
{
char tel[TEL_NMBR_MAX_BYTES];
switch (event)
{
{
le_mcc_GetRemoteTel(callRef, &tel, sizeof(tel));
if (IsAnAuthorizedIncomingCall(tel) == TRUE)
{
SpeakerRef = le_audio_OpenSpeaker();
CallRxAudioRef = le_audio_OpenModemVoiceRx();
MicRef = le_audio_OpenMic();
CallTxAudioRef = le_audio_OpenModemVoiceTx();
AudioRxConnectorRef = le_audio_CreateConnector();
AudioTxConnectorRef = le_audio_CreateConnector();
le_audio_Connect(AudioRxConnectorRef, speakerRef);
le_audio_Connect (AudioRxConnectorRef, callRxAudioRef);
le_audio_Connect(AudioTxConnectorRef, micRef);
le_audio_Connect (AudioTxConnectorRef, callTxAudioRef);
le_mcc_Answer(callRef);
}
else
{
// Reject the incoming call
le_mcc_HangUp(callRef);
}
}
break;
le_audio_Disconnect(speakerRef);
le_audio_Disconnect(AudioRxConnectorRef);
le_audio_Disconnect(AudioTxConnectorRef);
le_mcc_Delete(callRef);
break;
}
}

Ending all calls

A special function can be used to hang-up all the ongoing calls: le_mcc_HangUpAll(). This function can be used to hang-up any calls that have been initiated through another client like AT commands.

Supplementary service.

Calling Line Identification Restriction (CLIR) can be activated or deactivated by le_mcc_SetCallerIdRestrict API. The status is independent for each call object reference. Status can be read with the le_mcc_GetCallerIdRestrict() API. Default value is LE_OFF (Enable presentation of own phone number to remote).

Call waiting and call hold are not yet managed. The event Le_MCC_EVENT_WAITING warns the application for an incoming call, but there's no way to put the current call in hold.


Copyright (C) Sierra Wireless Inc. Use of this work is subject to license.