Review Board 1.7.16


audiohooks: Update internal sample rate on reads to prevent miscalculation of expected samples

Review Request #4475 - Created March 11, 2015 and submitted

Matt Jordan
11
Reviewers
asterisk-dev
file
Asterisk
Currently, the Asterisk 12+ testsuite test 'snoop_id' is failing due to a stack overflow on 32-bit machines. This occurred after a patch was made that enabled all formats on originated channels, including 192khz SLIN audio. Since it is theoretically possible to create Local channels along with ChanSpy in Asterisk 11 in a similar fashion, this issue is being fixed in that branch as well.

When an audiohook is created (which is used by the various Spy applications and Snoop channel), it initially is given a sample rate of 8kHz. It is expected, however, that this rate may change based on the media that passes through the audiohook. However, the read/write operations on the audiohook behave very differently.

When a frame is written to the audiohook, the format of the frame is checked against the internal sample rate. If the rate of the format does not match the internal sample rate, the internal sample rate is updated and a new SLIN format is chosen based on that sample rate. This works just fine.

When a frame is read, however, we do somehting quite different. If the format rate matches the internal sample rate, all is fine. However, if the rates don't match, the audiohook attempts to "fix up" the number of samples that were requested. This can result in some seriously large number of samples being requested from the read/write factories.

Consider the worst case - 192kHz SLIN. If we attempt to read 20ms worth of audio produced at that rate, we'd request 3840 samples (192000 / (1000 / 20)). However, if the audiohook is still expecting an internal sample rate of 8000, we'll attempt to "fix up" the requested samples to:

  samples_converted = samples * (ast_format_get_sample_rate(format) / (float) audiohook->hook_internal_samp_rate);

  or:

  92160 = 3840 * (192000 / 8000)

This results in us attempting to read 92160 samples from our factories, as opposed to the 3840 that we actually wanted. On a 64-bit machine, this miraculously survives - despite allocating up to two buffers of length 92160 on the stack. The 32-bit machines aren't quite so lucky. Even in the case where this works, we will either (a) get way more samples than we wanted; or (b) get about 3840 samples, assuming the timing is pretty good on the machine.

Either way, this is kind of wrong.

My first inclination was to allocate the buffers on the heap. As it is, however, there's at least two drawbacks with doing this:
(1) It's a bit complicated, as the size of the buffers may change during the lifetime of the audiohook (ew).
(2) The stack is faster (yay); the heap is slower (boo).

Since our calculation is flat out wrong in the first place, I've opted to fix this issue that way instead. Rather than attempting to 'massage' the samples requested, we now instead re-calculate our internal sample rate based on the format requested. This causes us to read the correct number of samples, and has the added benefit of setting the audihook with the right SLIN format.
(1) Tested ChanSpy in 11 and 13 manually. Still works. Yay.
(2) Ran the chanspy tests in 11/13. Those still work too.
(3) Ran the snoop tests. They stopped crashing, and also still work.
Review request changed
Updated (March 12, 2015, 8:27 a.m.)
  • changed from pending to submitted
Committed in revision 432831

https://reviewboard.asterisk.org/ runs on a server provided by Digium, Inc. and uses bandwidth donated to the open source Asterisk community by API Digital Communications in Huntsville, AL USA.
Please report problems with this site to asteriskteam@digium.com.