Mod portaudio
From FreeSWITCH Wiki
Introduction
mod_portaudio is used for interfacing with sound card. This scenario is usually used when FreeSWITCH is used for a softphone basis, or as an easy way to get a local connection for development.
Interaction with mod_portaudio usually happens at the Freeswitch CLI, including setup, placing calls, answering calls, etc.
Many Softphones use embedded FreeSWITCH and portaudio at their core. Two examples are FSComm a QT4 cross platform communicator and FSClient a Windows .NET 4.0 softphone.
Portaudio (PA) is a cross-platform library.
Beware mod_portaudio recently had a large hunk of code injected into it and the configuration related to Shared Streams. For most scenarios this is not required and my throw (generally harmless) errors. Please see the note on #Shared_Streams_and_Endpoints for more details.
Features
- Mulitiple calls with hold/call switching.
- Inbound calls can play a ring file on specified device. (global and per call)
- Optional hold music for backgrounded calls. (global and per call)
- Switch audio devices even during a call (see live-stream-switching)
- DTMF and deaf/mute options
Command Reference
- A device_ident is either part of the device name or the device ID number (prefixed with a #) seen in pa devlist.
pa help - print usage summary
Will show the available commands
pa devlist [xml] - list audio devices
The list will be in the following format: device number;short name;input channels;output channels;freeswitch device configuration
The freeswitch device configuration is a comma separated list of these elements:
r device is ring device i device is input device o device is output device
For example:
API CALL [pa(devlist)] output: 0;AC97 Audio (PCM);2;0 1;AC97 Audio (PCM);0;2 2;AC97 Audio (SPDIF);0;2 3;Jabra BT500;1;1
pa indev (device_ident), pa outdev (device_ident), pa switchstream (in_device_ident) (out_device_ident) - Set input/output device streams
Set the input (indev) or output (outdev) audio stream identified by device_ident. pa switchstream can switch both streams at once. These functions can only be use during a call if live-stream-switch configuration option is on.
pa ringdev (device_ident)
Set the device for portaudio to ring on a ringing call.
pa preparestream (in_device_ident) (out_device_ident) - Prepare an input and output device stream for use
Not required but preparing a stream prior to switching to it using the indev/outdev/switchstream allows portaudio to open the stream prior to using it. This makes for much more seamless switching between streams (no audio cut out). You only need to call this once before switching to that stream, streams are kept open until the end of all active calls. Calling it multiple times on the same stream will not cause delays or have negative effects.
pa call (number) [(dialplan)] [(cid_name)] [(cid_num)] - Place a new call
If you currently are on a call the existing call is placed on hold.
pa switch [(call_id)|none] - swap to a new active call
If used without args will switch to the previously active call. If a call_id (from pa list) is past will make that call active. If none is past then all calls are placed on hold.
pa list - view the current calls
pa list
pa dtmf (dtmf_digits) - send a dtmf string (1234) to the current call
pa dtmf 1234
pa answer [(call_id)] - Answer a ringing call
Without a call_id will answer the oldest call, with the call ID will answer that specific call
pa hangup [(call_id)] - End a call
Will end the current call if no ID is given otherwise will end the call with that ID.
pa rescan - Look for new devices
Portaudio assumes devices will not change during use, if they do you will need to use rescan for portaudio to see them. As this causes portaudio to re-init several things it cannot be used during an active call.
pa play [ringtest|(filename)] [(seconds)] [no_close] - Play an audio file or test stream to a device
Allows playing of arbitrary audio on the outdev device, optionally for only a specific number of seconds. no_close causes the audio stream to remain open after playing (allows for faster concurrent playing)
pa playdev (device_ident) [ringtest|(filename)] [(seconds)] [no_close] - Play an audio file or test stream to a specific device
Same as play but takes the device to play to also
pa flags on|off [ear] [mouth] - Set mute or deaf
Mutes the indev so no audio is directed to an active call, or deaf will silence the outdev from playing and audio
pa closestreams - Will close all active open streams
By default all streams are only closed at the end of all active calls, you can force them to close using pa closestreams as long as there is not an active call.
pa dump - Debug dump of all the devices
Dumps a variety of information about the various audio devices PA sees
Sample Implementations
Sample Softphone Configuration
For a sample Softphone configuration, see: Freeswitch_Softphone
Sample Mumble <-> Conference Bridge
Available with full instructions for Linux-based configurations at: Mumble_conference_with_alsa
Sample mod_portaudio intercom (auto answer)
In your dialplan, you can easily setup a portaudio intercom to dial into.
<extension name="Beaker portaudio intercom <pain>"> <condition field="destination_number" expression="^7246$"> <action application="bridge" data="portaudio/auto_answer"/> </condition> </extension>
Note, to easily remember the extension number, we use the T9 translate of the acronym "PortAudio INtercom" aka PAIN, which is 7246. Go ahead and dial 7246 and you will immediately be able to talk over the portaudio speaker :-)
Note too, in real life you should probably have some kind of notifying tone so nobody can silently eavesdrop on you.
PA System w/ Chime
A modification to the Intercom sample can be used to feed to a Public Address system. Chime plays before and after paging.
<extension name="paging-with-chime">
<condition field="destination_number" expression="^7243$">
<action application="set" data="bridge_pre_execute_bleg_app=playback"/>
<action application="set" data="bridge_pre_execute_bleg_data=/tmp/2_tone_chime.wav"/>
<action application="set" data="api_after_bridge=luarun post-chime.lua"/>
<action application="bridge" data="portaudio/auto_answer"/>
</condition>
</extension>
post-chime.lua:
api = freesswitch.API();
api:execute("pa", "play /tmp/2_tone_chime.wav");
Web GUI
mod_xml_rpc loaded portaudio supplies it's own little GUI http://your.box:8080/api/pa
Install Notes
RHEL/CentOS
When building from source, make sure the "alsa-lib-devel" package is installed or you may get build errors.
Windows
Portaudio for windows by default builds with DirectX used for audio. It seems to provide the best results but it is possible to use the two other audio modes if desired by changing the build options.
Mac OS X
It's not the first time I get tons of errors. So if you see "missing required architecture ppc64 in file" when compile, that means you miss some arch files. I resolved this by edit libs/portaudio/Makefile and changed "-arch x86_64 -arch ppc64 -arch i386 -arch ppc" to "-arch i386".
FreeBSD
Tested on FreeBSD-8.1 AMD64 on hardware which meets the 'Intel HD Audio' spec. Add to the FreeBSD kernel config file:
device snd_hda device sound. Build and install the new kernel, no additional audio config is required. The configuration in portaudio.conf.xml has indev, outdev and ringdev value="0" Also requires: <param name="dual-streams" value="true"/>
-kimc
Reference
portaudio.conf settings
These options are set in the <settings> block of the config.
no-ring-during-call
Prevent an incoming call from ringing the ring device if you are already on a call
no-auto-resume-call
Do not auto resume the last call when the current call ends
live-stream-switch
Allows using the indev,outdev, and switchstream commands during a call
indev, outdev, ringdev
Allows you to preset the specific input and output devices you want portaudio using you can use the same device_ident values as used in the command reference
debug
Set the debug level for portaudio
dialplan
Set the default dialplan for making calls
context
Set the default context for calls
dual-streams
The default value is false which means one thread is handling the audio reading/writing from/to the core. Value true means 2 threads are used instead of one.
Shared Streams and Endpoints
Shared streams and endpoints are completely different than everything else mentioned on this page and are not required for most cases of using portaudio (especially if you are just using FS as a single softphone). They are specifically meant for if you need to use multiple audio devices on different calls at the same time. All of the stream commands above are NOT related to shared streams (just confusing terminology). The only documentation on them is found in the configuration file itself and the code was not tested by a large number of people so stability is not guaranteed. Most of the code paths for shared streams/endpoints are completely different from the rest of portaudio so most of the normal portaudio commands do not work with the shared stream/endpoint system. The commands that related to shared streams are the pa shtreams and pa endpoints commands, not the other stream commands. While you may see errors about shared streams in the console if you do not remove the configuration (per the portaudio.conf note below) these will not stop portaudio from working normally.
portaudio.conf <streams> and <endpoints>
See the note on shared streams and endpoints above. You can safely remove the <streams> and <endpoints> configuration sections from portaudio.conf if you do not need them, otherwise they will throw some console errors by default (that can be ignored).
Custom Events
Portaudio emits several custom events for major changes in portaudio. Every event will contain the pa_call_id variable to indicate which call is being changed.
portaudio::ringing
Is emitted when incoming call is received and portaudio plays the ring on the audio device.
Event-Subclass: portaudio::ringing Event-Name: CUSTOM Core-UUID: 950e273a-f74b-11de-bf7c-a394ee5f864b FreeSWITCH-Hostname: jmesquita.dyndns.org FreeSWITCH-IPv4: <IP> FreeSWITCH-IPv6: ::1 Event-Date-Local: 2010-01-02 00:11:00 Event-Date-GMT: Sat, 02 Jan 2010 03:11:00 GMT Event-Date-Timestamp: 1262401860975758 Event-Calling-File: mod_portaudio.c Event-Calling-Function: channel_on_init Event-Calling-Line-Number: 265 event_info: BRRRRING! BRRRRING! call 2 call_id: 2 Channel-State: CS_INIT Channel-State-Number: 1 Channel-Name: portaudio/1000 Unique-ID: 740f37a8-f74c-11de-bf81-a394ee5f864b Call-Direction: outbound Presence-Call-Direction: outbound Answer-State: ringing Channel-Read-Codec-Name: L16 Channel-Read-Codec-Rate: 48000 Channel-Write-Codec-Name: L16 Channel-Write-Codec-Rate: 48000 Caller-Username: 1000 Caller-Dialplan: XML Caller-Caller-ID-Name: Mesquita Caller-Caller-ID-Number: 1000 Caller-Network-Addr: <IP> Caller-ANI: 1000 Caller-Unique-ID: 740f37a8-f74c-11de-bf81-a394ee5f864b Caller-Source: mod_sofia Caller-Context: public Caller-Channel-Name: portaudio/1000 Caller-Profile-Index: 1 Caller-Profile-Created-Time: 1262401860435762 Caller-Channel-Created-Time: 1262401860435762 Caller-Channel-Answered-Time: 0 Caller-Channel-Progress-Time: 1262401860975758 Caller-Channel-Progress-Media-Time: 0 Caller-Channel-Hangup-Time: 0 Caller-Channel-Transfer-Time: 0 Caller-Screen-Bit: true Caller-Privacy-Hide-Name: false Caller-Privacy-Hide-Number: false Other-Leg-Username: 1000 Other-Leg-Dialplan: XML Other-Leg-Caller-ID-Name: Mesquita Other-Leg-Caller-ID-Number: 1000 Other-Leg-Network-Addr: <IP> Other-Leg-ANI: 1000 Other-Leg-Destination-Number: 1001 Other-Leg-Unique-ID: 73b8a0dc-f74c-11de-bf80-a394ee5f864b Other-Leg-Source: mod_sofia Other-Leg-Context: public Other-Leg-Channel-Name: sofia/softphone/1000@<IP> Other-Leg-Profile-Created-Time: 0 Other-Leg-Channel-Created-Time: 0 Other-Leg-Channel-Answered-Time: 0 Other-Leg-Channel-Progress-Time: 1262401860975758 Other-Leg-Channel-Progress-Media-Time: 0 Other-Leg-Channel-Hangup-Time: 0 Other-Leg-Channel-Transfer-Time: 0 Other-Leg-Screen-Bit: true Other-Leg-Privacy-Hide-Name: false Other-Leg-Privacy-Hide-Number: false variable_channel_name: portaudio/1000 variable_is_outbound: true variable_max_forwards: 67 variable_originator_codec: PCMU@8000h@20i variable_originator: 73b8a0dc-f74c-11de-bf80-a394ee5f864b variable_signal_bond: 73b8a0dc-f74c-11de-bf80-a394ee5f864b variable_switch_m_sdp: v=0 o=FreeSWITCH 1262373184 1262373185 IN IP4 <IP> s=FreeSWITCH c=IN IP4 <IP> t=0 0 m=audio 18000 RTP/AVP 0 8 3 101 13 a=rtpmap:0 PCMU/8000 a=rtpmap:8 PCMA/8000 a=rtpmap:3 GSM/8000 a=rtpmap:101 telephone-event/8000 a=fmtp:101 0-16 a=rtpmap:13 CN/8000 a=ptime:20 variable_originate_early_media: true variable_pa_call_id: 2 variable_read_codec: L16 variable_read_rate: 48000 variable_write_codec: L16 variable_write_rate: 48000
portaudio::makecall
Is emitted when a call is placed using pa call API command. fail header is set to true _ONLY_ the mod_portaudio fails to spawn the session, not if call is not completed.
Event-Subclass: portaudio::makecall Event-Name: CUSTOM Core-UUID: 950e273a-f74b-11de-bf7c-a394ee5f864b FreeSWITCH-Hostname: <HOSTNAME> FreeSWITCH-IPv4: <IP> FreeSWITCH-IPv6: ::1 Event-Date-Local: 2010-01-02 00:05:45 Event-Date-GMT: Sat, 02 Jan 2010 03:05:45 GMT Event-Date-Timestamp: 1262401545047757 Event-Calling-File: mod_portaudio.c Event-Calling-Function: place_call Event-Calling-Line-Number: 1810 Channel-State: CS_INIT Channel-State-Number: 1 Channel-Name: portaudio/1000 Unique-ID: b7c096e6-f74b-11de-bf7e-a394ee5f864b Call-Direction: inbound Presence-Call-Direction: inbound Answer-State: answered Channel-Read-Codec-Name: L16 Channel-Read-Codec-Rate: 48000 Channel-Write-Codec-Name: L16 Channel-Write-Codec-Rate: 48000 Caller-Dialplan: XML Caller-Caller-ID-Name: FreeSWITCH Caller-Caller-ID-Number: 0000000000 Caller-Network-Addr: <IP> Caller-Destination-Number: 1000 Caller-Unique-ID: b7c096e6-f74b-11de-bf7e-a394ee5f864b Caller-Source: mod_portaudio Caller-Context: default Caller-Channel-Name: portaudio/1000 Caller-Profile-Index: 1 Caller-Profile-Created-Time: 1262401544513764 Caller-Channel-Created-Time: 1262401544513764 Caller-Channel-Answered-Time: 1262401545047757 Caller-Channel-Progress-Time: 0 Caller-Channel-Progress-Media-Time: 0 Caller-Channel-Hangup-Time: 0 Caller-Channel-Transfer-Time: 0 Caller-Screen-Bit: true Caller-Privacy-Hide-Name: false Caller-Privacy-Hide-Number: false variable_channel_name: portaudio/1000 variable_endpoint_disposition: ANSWER variable_pa_call_id: 1 variable_read_codec: L16 variable_read_rate: 48000 variable_write_codec: L16 variable_write_rate: 48000 fail: false
portaudio::callheld
Event when call is put on hold
portaudio::callresumed
Event when a call is taken off hold

