MixMonitor recordings shorter than call and skipping words: "Flushing audiohook" / "both fail to provide 160 samples" with ARI ExternalMedia in a mixing bridge (Asterisk 16.8.3)

Environment

  • Asterisk 16.8.3, chan_pjsip, ARI
  • Caller: carrier → OpenSIPS → Asterisk (PJSIP), ulaw, no transcoding anywhere
  • Voice bot connected through ARI ExternalMedia (UnicastRTP, ulaw, RTP/UDP, connection_type: client, direction: both)
  • Recording: MixMonitor on the caller channel, started from the dialplan before the call enters Stasis

I know 16 is EOL. If this is a known audiohook/MixMonitor sync issue fixed in a later release, a pointer to the fix would be very helpful: it would justify our upgrade.

Call flow

  1. Dialplan (AGI) starts MixMonitor(/Recording/.wav,b). The b flag is set when the greeting shouldn’t be recorded.
  2. The call enters Stasis. The app answers it, creates a mixing bridge and adds the caller channel.
  3. The app creates an ExternalMedia channel:
    POST /channels/externalMedia format=ulaw transport=udp encapsulation=rtp
    connection_type=client direction=both
    It adds that channel to the same bridge once the bot’s stream starts.
  4. Our media server sends the bot’s audio back as RTP: one 160-byte PCMU packet every 20ms, with silence packets whenever the bot isn’t speaking. It sends continuous
    sequence numbers and timestamps, and sets the marker bit at the start of each talkspurt.

Problem
For some calls, recordings are much shorter than the call, and words are missing from the recording. Examples:

  • 34s call → 18s recording
  • 58s call → 41s recording

and some calls another bot call is 51 sec → and 51 sec recording same logic everything is same

But on a live call they are listening in proper pace and clear the issue is recording thing

Our media server keeps its own copy of the bot audio it sends, and that copy is full-length. Other customers on the same Asterisk and media servers, with the same
dialplan and code, get recordings that match the call length exactly.

With audiohook debug enabled, a single 34s call shows:
<paste 3-4 real lines, e.g.>
[C-xxxxxxxx] audiohook.c: Flushing audiohook 0x… so it remains in sync
[C-xxxxxxxx] audiohook.c: Read factory 0x… and write factory 0x… both fail to provide 160 samples
[C-xxxxxxxx] audiohook.c: Write factory 0x… was pretty quick last time, waiting for them.
Counts for that call: 191 × “Flushing audiohook”, 568 × “both fail to provide 160 samples”. That’s 568 × 20ms ≈ 11.4s, which roughly matches the missing audio. No strict
RTP messages.

What we tried

  • Set JITTERBUFFER(adaptive)=default on the ExternalMedia channel via ARI setChannelVar, right after creating it and before adding it to the bridge. The recordings
    didn’t change.

Simple Logic behind that is

How our media server sends the bot audio to Asterisk (RTP towards the ExternalMedia channel)

  • One UDP socket, symmetric. We receive the caller’s audio from the UnicastRTP channel and send the bot’s audio back from the same IP:port, to
    UNICASTRTP_LOCAL_ADDRESS:UNICASTRTP_LOCAL_PORT.
  • Packet format. RTP v2, PT 0 (PCMU), 160-byte payload (20ms at 8kHz), one fixed random SSRC per call. Sequence numbers start at 0 and go up by 1 per packet. Timestamps
    start at 0 and go up by 160 per packet.
  • Continuous stream from the start. Sending starts when the bot’s WebSocket connects, before the bot says anything. From then until hangup, a 20ms timer sends exactly
    one packet per tick, whether or not the bot is speaking.
  • Silence packets instead of gaps. The bot sends audio over WebSocket only while it speaks, in whatever chunk sizes it chooses. Whenever there’s no bot audio to send, we
    send a full 160-byte PCMU silence packet (0xFF) on that tick. So Asterisk never sees a gap in sequence numbers or timestamps, and we never use silence suppression or
    DTX.
  • Short buffer at the start of each bot utterance. When bot audio starts arriving after silence, we hold it until 100ms has built up, then play it out at 20ms per tick.
    The first packet of each utterance has the RTP marker bit set. The timestamps stay continuous, because silence packets were being sent in between.
  • Bot audio arrives late in mid-sentence. If our buffer runs dry, we send silence packets and resume as soon as a full 20ms frame is available.
  • End of bot utterance. If no bot audio arrives for 150ms, we treat the utterance as finished. Any leftover partial frame is padded to 160 bytes with silence, and we go
    back to sending silence packets.
  • Barge-in. When the bot asks us to stop playback, we drop the queued audio, but the stream keeps going with silence packets and the timestamps stay continuous.
  • Timer accuracy. The 20ms tick runs on a Node.js setInterval. It can fire a few milliseconds late, and the current build doesn’t catch up on missed ticks, so the
    average rate is slightly below 50 packets/s. We measured about 5% below on an idle server, and more under load. We’re fixing that, but it’s why we ask whether a small
    rate difference between the two directions is enough to trigger the flushes.

Anyone Please help in that

Some suggestions to narrow it down: (HOPE THIS HELPS YOU!)

Reproduce on a supported release (20 or 22 LTS) first. 16 has been end-of-life for years, and the audiohook, bridge and ExternalMedia code has changed a lot since.
Record the mixing bridge itself through ARI (POST /bridges/{id}/record) on the same test calls. If that recording is complete but MixMonitor’s isn’t, the loss is in the channel audiohook, not the media.
Check the bot’s RTP pacing, not just its content. Those audiohook warnings usually mean one direction’s frames aren’t arriving steadily. Take a packet capture and look at inter-arrival times and timestamp jumps from the media server.
Note whether the loss starts when the ExternalMedia channel joins the bridge. That timing narrows it down a lot.

20 has only two and a half days of support left; I’d forget that one.