Adding AT commands to activate call audio over USB endpoint

Aleksander Morgado aleksander at aleksander.es
Wed Aug 8 11:32:44 UTC 2018


Hey,

>>> We're using a SIMCom SIM7100 modem which has the ability to exchange
>>> call audio data over a USB serial endpoint⁰.  To enable this, the modem
>>> needs an AT command after the call has connected, AT+CPCMREG=1, and a
>>> command after call has disconnected, AT+CPCMREG=0.
>>>
>>
>> Would these commands be needed as soon as a call is started (even if
>> not established)? or just when established?
>
> After you send ATD.  The SIMCom docs say after your receive "VOICE CALL:
> BEGIN" but it also says "If you want hear the ring back tone, you can
> run "AT+CPCMREG=1" command after ATDXXX;" which is what we'd want.  I've
> tested sending it immediately after ATD and that works.
>
>> Also, how would it work for received calls, at which point should the
>> command be executed?
>
> I believe you get "VOICE CALL: BEGIN" when you answer the call so after
> that.
>
> To summarise:
>
> --------------------------------------------------
>   Command    |         When            | Call type
> --------------------------------------------------
> AT+CPCMREG=1 | After ATD               | outgoing
> AT+CPCMREG=1 | After VOICE CALL: BEGIN | incoming
> AT+CPCMREG=0 | After VOICE CALL: END   |   both
> --------------------------------------------------
>

Ok.


>
>>> Not knowing the internals of ModemManager too well, I'm wondering if
>>> anyone could advise on an appropriate way to add these AT commands for
>>> our particular modem?
>
>> The way to do this would be to define a new async command in the Voice
>> interface struct (mm-iface-modem-voice.h) and then in the same voice
>> interface implementation setup the logic to call that command whenever
>> needed, but only if it is implemented (e.g. in this case we would have
>> NULL defaults as others modems don't need this). Once that logic is in
>> place, we would need a new "simcom" plugin (there is none right now),
>> which creates a new MMBroadbandModemSimcom that implements the voice
>> interface and subclasses the specific command.
>
> I'm still trying to get my head around this.  There doesn't seem to be
> anything similar in the voice interface, can you suggest another
> interface with some similar functionality?
>

All interfaces are really organized in the same way: they provide a
common logic with steps that maybe subclassed by plugins. Take for
example the Voice interface, there is a method called
enable_unsolicited_events() in the interface. This method is
implemented by MMBroadbandModem in some specific way (e.g. running
+CLIP=1 to show caller number on RING), and is then subclassed by the
u-blox plugin to not only run the parent +CLIP=1 but also to also
enable detailed call states with +UCALLSTAT=1. In your case, all the
core logic is probably based on the MMBroadbandModem implementation
(unless you're using QMI... are you?) so a new "simcom" plugin could
subclass any specific step from any of the defined interfaces.

> I don't understand the setup function you suggest.  What would this do?
> If there is a SIMCom-specific subclass for the modem which adds the
> AT+CPCMREG calls to the existing ATD calls or "VOICE CALL" handlers,
> what would the MMIfaceModemVoice setup function do?
>

Forget about the Voice interface, this kind of logic should go in the
Call interface instead. The "setup" command I was suggesting was
something that would be called in the cases you listed above, e.g.
just after ATD is executed or just after a call is accepted. This
would fit within the logic of the Call interface, implemented by
MMBaseCall; check the class definition in mm-base-call.h.

But if you don't want to add any new subclass-able "setup" method,
that would be ok as well. Instead you could just create a custom
MMCallSimcom object and subclass methods of the parent MMBaseCall
object:
  * Subclass MMBaseCall start() so that the parent start() is first
called, and only then you run AT+CPCMREG=1.
  * Subclass MMBaseCall accept() so that the parent accept() is first
called, and only then you run AT+CPCMREG=1.
  * Subclass MMBaseCall hangup() so that you run AT+CPCMREG=0 and then
the parent hangup() is called.
  * You may also need to setup URC handlers for the VOICE CALL
notifications, e.g. if VOICE CALL: END is the only way you have to get
reported of terminated calls, so that you call AT+CPCMREG=0 also in
that case.

My "aleksander/next" branch in git has several voice related changes,
including the MMUbloxCall subclass to support UCALLSTAT, that may help
a bit:
https://gitlab.freedesktop.org/mobile-broadband/ModemManager/tree/aleksander/next

-- 
Aleksander
https://aleksander.est


More information about the ModemManager-devel mailing list