Click here for the API Reference documentation.
Using Profiles
Starting a Call
Answering a call
The Modem Call Control (mcc) API uses profiles. Calls can be initiated or received through these profiles. Each profile represents a call type or specific configuration of a given call (e.g., a profile can represent a given cellular modem/SIM combination - if the modem in question supports multiple SIM operation).
A given Legato device can support multiple profiles, but usually, the MCC API will be configured with a single profile name that will initiate or receive calls.
Call cle_mcc_profile_GetByName()
to access a specific profile by name.
le_mcc_profile_GetState()
API allows the application to get the current state of the profile.
le_mcc_profile_AddStateChangeHandler()
API installs a handler function that is notified when the profile's state changes.
le_mcc_profile_RemoveStateChangeHandler()
API uninstalls the handler function.
When the Profile object is no longer needed, call le_mcc_profile_Release()
must be used to release the profile.
Here's a profile code sample:
void ManageMyProfile(void) { [...] // Get the Modem profile working on SIM card #1 le_mcc_profile_Ref_t myProfile = le_mcc_profile_GetByName("Modem-Sim1"); // Create and start a call on that profile le_mcc_call_Ref_t myCall = le_mcc_profile_CreateCall(myProfile, "+18008800800"); le_mcc_call_Start(myCall); [...] // Set the profile into 'Do Not Disturb' mode: it will disable it's ablity to accept incoming // calls. le_mcc_profile_SetDoNotDisturb(myProfile); [...] // Clear the 'Do Not Disturb' mode: the profile gets back to be able to accept incoming calls. le_mcc_profile_ClearDoNotDisturb(myProfile); [...] // Set the profile into 'call forward mode': all calls incoming to this profile will // automatically be forwarded to another telephone number. le_mcc_profile_SetForwarding(myProfile, "+18008910910"); [...] }
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:
le_mcc_call_GetTerminationReason()
- termination reason.le_mcc_call_IsConnected()
- connection status.le_mcc_call_GetRemoteTel()
- displays remote party telephone number associated with the call.le_mcc_call_GetRxAudioStream()
must be called to receive audio stream for this call. Audio received from the other end of the call uses this stream.le_mcc_call_GetTxAudioStream()
must be called to transmit audio stream this call. Audio generated on this end is sent on this stream.le_mcc_call_HangUp()
will disconnect this call. All active calls will be disconnected.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 { le_mcc_profile_Ref_t profileRef; le_mcc_call_Ref_t callRef; 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 ( le_mcc_call_Ref_t callRef, le_mcc_call_Event_t event, void* contextPtr ) { PlayContext_t* myContextPtr = (PlayContext_t*)contextPtr; switch (event) { case LE_MCC_EVENT_CONNECTED: { le_audio_StreamRef_t callAudioTxRef = le_mcc_call_GetTxAudioStream(callRef); le_audio_PlaySoundFromFile(callAudioTxRef, myContextPtr->filePath, MyAudioFinishedHandler, myContextPtr); } break; case LE_MCC_EVENT_TERMINATED: le_mcc_call_Delete(callRef); // 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. }
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 { le_mcc_profile_Ref_t profileRef; le_mcc_call_Ref_t callRef; 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 ( le_mcc_call_Ref_t callRef, le_mcc_call_Event_t event, void* contextPtr ) { char tel[TEL_NMBR_MAX_LEN]; VoiceContext_t* myContextPtr = (VoiceContext_t*)contextPtr; switch (event) { case LE_MCC_EVENT_INCOMING: { le_mcc_profile_State_t myProfileState = LE_MCC_PROFILE_NOT_AVAILABLE; 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 callRxAudioRef = le_mcc_call_GetRxAudioStream(callRef); le_audio_StreamRef_t micphoneRef = le_audio_OpenMicphone(); le_audio_StreamRef_t callTxAudioRef = le_mcc_call_GetTxAudioStream(callRef); 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); } le_mcc_call_Answer(callRef); } else { // Reject the incoming call le_mcc_call_Delete(callRef); } } break; case LE_MCC_EVENT_TERMINATED: le_mcc_call_Delete(callRef); // 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; } }
Copyright (C) Sierra Wireless, Inc. 2013. All rights reserved. Use of this work is subject to license.