PearlPBX2
← All posts

Asterisk MixMonitor: record each side of a call separately

MixMonitor is the Asterisk application that records a channel’s audio to a file. By default it mixes both directions of the call — what the channel hears and what it says — into a single mono file. That is fine for a plain recording of an operator talking to a customer. But once the recording goes into speech-to-text, sentiment analysis or QA scoring, a mixed file gets in the way: you no longer know who said what.

This post shows how to record each side of an Asterisk call into its own file with the r() and t() options, when the stereo D option is the better choice, and what to watch out for.

Basic call

MixMonitor(filename.extension,[options,[command]])

The extension picks the audio format (.wav, .gsm, .sln and so on). A relative filename ends up in Asterisk’s monitor directory, /var/spool/asterisk/monitor by default.

The channel has to be answered (Answer or Progress) before MixMonitor runs — it doesn’t do that itself. If you need the file inside the same dialplan run, for example to process it right away, close the recording with StopMixMonitor. That is what guarantees the file is fully written and available on disk.

Two options are worth knowing before the split:

  • a appends to an existing file instead of overwriting it;
  • b saves audio only while the channel is bridged, so ringing and IVR time stay out of the recording.

How to record each side of a call separately: r() and t()

Two options write each direction of the audio to its own file, independently of each other:

  • r(file) — the receive stream: what the channel hears;
  • t(file) — the transmit stream: what the channel says.
MixMonitor(call.wav,r(call-in.wav)t(call-out.wav))

call.wav is still the ordinary mixed file, because the filename argument is mandatory. The other two are independent streams written at the same time. This is not post-processing of one file; it is three recordings made in parallel.

In an AEL dialplan it looks like this:

context incoming {
  s => {
    Answer();
    MixMonitor(${UNIQUEID}.wav,r(${UNIQUEID}-in.wav)t(${UNIQUEID}-out.wav));
    Dial(PJSIP/operator);
    StopMixMonitor();
  }
}

Using ${UNIQUEID} in the names gives every call its own set of files and makes them easy to match with a CDR row later.

When r() or t() is used, MixMonitor inserts silence into both files so they stay in sync with each other. The n option turns that off when synchronization isn’t needed.

One stereo file instead: the D option

The D option does something different: it interleaves both directions into a single stereo file, one direction per channel (left and right). The choice comes down to “two separate files” versus “one file with two audio channels”.

You need Use
A recording to play back to a person the default mixed file
Two files you can send to different services or tools r() and t()
One file that keeps the speakers apart, easy to move around D

Most speech-to-text services accept stereo input and treat each channel as a separate speaker, so D is often the shortest path. If your pipeline wants one file per speaker, use r() and t().

Why separate channels matter for speech-to-text and analytics

When the operator and the customer are already on separate tracks, a recognition service doesn’t have to separate speakers (diarization) on a mixed stream. Each track goes into recognition by itself, with a guaranteed answer to “who said this”. The same applies to sentiment analysis or QA scoring: when the input is already split by role, the accuracy doesn’t depend on how well a third-party diarization algorithm happens to work.

It also makes simple metrics possible without any AI: talk-time ratio, how often the operator interrupts the customer, and silence at the start of the call.

Recording in PearlPBX2

PearlPBX2 starts recordings from its FastAGI handler. For each call it looks at the recording rules (force-enable or force-disable by caller ID or destination), sets the MIXMONITOR channel variable to 1 or 0, creates the database record and the YYYY/MM/DD directory, and then runs MixMonitor on a .wav file with the a option. The result is one mixed file per call, indexed by source, destination and CDR uniqueid, and downloadable via GET /api/v1/recordings/<uniqueid>/ with HTTP Range support. Queue calls are recorded by app_queue itself, which PearlPBX2 configures with monitor-type = MixMonitor.

So out of the box PearlPBX2 does not split channels. If you want separate streams, MixMonitor is on the application whitelist of the AEL editor, so you can call it with r() and t() from your own dialplan. Keep in mind that a recording started this way is your responsibility: the FastAGI handler is what creates the database record for a recording.

Things to watch out for

  • Disk space. An 8 kHz mono WAV takes roughly 1 MB per minute. With r() and t() you get the mixed file plus two more, so plan for about three times as much. Converting finished recordings to MP3 cuts it down.
  • Answer first. MixMonitor on an unanswered channel records nothing useful.
  • Read the file only after StopMixMonitor if you use it in the same dialplan run.
  • Consent. Recording rules differ by country. Check what you must tell the caller before you turn recording on.

Summary

Option What it does
no options one mixed mono file (default)
a append to the file instead of overwriting it
b record only while the channel is bridged
r(file) separate file for the incoming (receive) stream
t(file) separate file for the outgoing (transmit) stream
n disables automatic silence insertion for r()/t() synchronization
D one stereo file instead of two separate ones (receive/transmit per channel)

For the full list of options, see the MixMonitor page in the Asterisk documentation.