All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Modem Call Control

Click here for the API Reference documentation.


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_LEN];
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.


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