All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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_call -> modemService.le_mcc_call
}

Starting a Call

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

le_mcc_call_Start() must still initiate the call when ready.

The le_mcc_call_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_profile_AddCallEventHandler() API to install that handler function. As the call attempt proceeds, the profile's registered call event handler will receive events.

The le_mcc_profile_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_call_Delete() to free all the allocated resources associated with the object. This will frees the reference, but remains active if other holders are using it.

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->profileRef = le_mcc_profile_GetByName("Modem-Sim1");
le_mcc_profile_AddCallEventHandler(contextPtr->profileRef,
MyCallEventHandler,
contextPtr);
contextPtr->callRef = le_mcc_profile_CreateCall(contextPtr->profileRef, destinationTelPtr);
le_mcc_call_Start(contextPtr->callRef);
}
static void MyCallEventHandler
(
void* contextPtr
)
{
PlayContext_t* myContextPtr = (PlayContext_t*)contextPtr;
switch (event)
{
{
le_audio_PlaySoundFromFile(callAudioTxRef,
myContextPtr->filePath,
MyAudioFinishedHandler,
myContextPtr);
}
break;
// I don't release the Profile for further use
le_mcc_profile_RemoveCallEventHandler(myContextPtr->profileRef);
le_mem_Release(myContextPtr);
break;
}
}
static void MyAudioFinishedHandler
(
le_audio_PlayComplete reason,
void* contextPtr
)
{
PlayContext_t* myContextPtr = (PlayContext_t*)contextPtr;
le_mcc_call_HangUp(myContextPtr->callRef); // This will trigger a TERMINATED event.
}

Answering a call

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

To answer, call le_mcc_call_Answer(). To reject it, call le_mcc_call_Delete().

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. If a call is already active, it can add the new incoming call creating a conference call.

typedef struct
{
uint32_t calledPartyCount;
}
VoiceContext_t;
static le_audio_ConnectorRef_t AudioRxConnectorRef = NULL;
static le_audio_ConnectorRef_t AudioTxConnectorRef = NULL;
void InstallAutomaticAnswer
(
void
)
{
VoiceContext_t* contextPtr = (VoiceContext_t*)le_mem_ForceAlloc(VoiceContextPoolRef);
contextPtr->profileRef = le_mcc_profile_GetByName("Modem-Sim1");
le_mcc_profile_AddCallEventHandler(contextPtr->profileRef,
MyVoiceCallEventHandler,
contextPtr);
}
static void MyVoiceCallEventHandler
(
void* contextPtr
)
{
char tel[TEL_NMBR_MAX_BYTES];
VoiceContext_t* myContextPtr = (VoiceContext_t*)contextPtr;
switch (event)
{
{
le_mcc_call_GetRemoteTel(callRef, &tel, sizeof(tel));
if (IsAnAuthorizedIncomingCall(tel) == TRUE)
{
le_mcc_profile_GetState(myProfile, &myProfileState);
if(myProfileState == LE_MCC_PROFILE_IN_USE)
{
// Another incoming call, turn this into a x-way conference, mixed locally:
myContextPtr->calledPartyCount++;
le_audio_StreamRef_t otherCallRxAudioRef = le_mcc_call_GetRxAudioStream(callRef);
le_audio_StreamRef_t otherCallTxAudioRef = le_mcc_call_GetTxAudioStream(callRef);
le_audio_connector_AddStream(AudioRxConnectorRef, otherCallRxAudioRef);
le_audio_connector_AddStream (AudioTxConnectorRef, otherCallTxAudioRef);
}
else if(myProfileState == LE_MCC_PROFILE_IDLE)
{
// First incoming call
myContextPtr->calledPartyCount = 1;
le_audio_StreamRef_t speakerphoneRef = le_audio_OpenSpeakerphone();
le_audio_StreamRef_t micphoneRef = le_audio_OpenMicphone();
AudioRxConnectorRef = le_audio_CreateConnector();
AudioTxConnectorRef = le_audio_CreateConnector();
le_audio_connector_AddStream(AudioRxConnectorRef, speakerphoneRef);
le_audio_connector_AddStream (AudioRxConnectorRef, callRxAudioRef);
le_audio_connector_AddStream(AudioTxConnectorRef, micphoneRef);
le_audio_connector_AddStream (AudioTxConnectorRef, callTxAudioRef);
}
}
else
{
// Reject the incoming call
}
}
break;
// I delete the Audio connector references if it remains only one called party.
if (myContextPtr->calledPartyCount == 1)
{
le_audio_DeleteConnector(AudioRxConnectorRef);
le_audio_DeleteConnector(AudioTxConnectorRef);
}
else
{
myContextPtr->calledPartyCount--;
}
break;
}
}

Ending all calls

A special function can be used to hang-up all the ongoing calls: le_mcc_call_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_call_SetCallerIdRestrict API. The status is independent for each call object reference. Status can be read with the le_mcc_call_GetCallerIdRestrict() API. Default value is LE_OFF (Enable presentation of own phone number to remote).


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