summaryrefslogtreecommitdiff
path: root/main/audiohook.c
diff options
context:
space:
mode:
authorMatthew Jordan <mjordan@digium.com>2015-03-12 12:58:41 +0000
committerMatthew Jordan <mjordan@digium.com>2015-03-12 12:58:41 +0000
commit38ee441ea7debef3ebf6b162fc290b121fa3588d (patch)
tree4ab73af8603f372e699fe6e9f3c18d630b8b9913 /main/audiohook.c
parent29304d10a0981fddf020b0c8655d041d3f15960f (diff)
main/audiohook: Update internal sample rate on reads
When an audiohook is created (which is used by the various Spy applications and Snoop channel in Asterisk 13+), 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 something 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); which is: 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, the calculation being performed is wrong, based on the API users expectations. 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, this patch fixes this issue by instead updating the internal sample rate based on the format passed into the read operation. This causes us to read the correct number of samples, and has the added benefit of setting the audihook with the right SLIN format. Note that this issue was caught by the Asterisk Test Suite as a result of r432195 in the 13 branch. Because this issue is also theoretically possible in Asterisk 11, the change is being made here as well. Review: https://reviewboard.asterisk.org/r/4475/ ........ Merged revisions 432810 from http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged revisions 432811 from http://svn.asterisk.org/svn/asterisk/branches/13 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@432812 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main/audiohook.c')
-rw-r--r--main/audiohook.c17
1 files changed, 4 insertions, 13 deletions
diff --git a/main/audiohook.c b/main/audiohook.c
index e01b1ce92..1883c0091 100644
--- a/main/audiohook.c
+++ b/main/audiohook.c
@@ -360,21 +360,12 @@ static struct ast_frame *audiohook_read_frame_helper(struct ast_audiohook *audio
{
struct ast_frame *read_frame = NULL, *final_frame = NULL;
struct ast_format *slin;
- int samples_converted;
-
- /* the number of samples requested is based on the format they are requesting. Inorder
- * to process this correctly samples must be converted to our internal sample rate */
- if (audiohook->hook_internal_samp_rate == ast_format_get_sample_rate(format)) {
- samples_converted = samples;
- } else if (audiohook->hook_internal_samp_rate > ast_format_get_sample_rate(format)) {
- samples_converted = samples * (audiohook->hook_internal_samp_rate / (float) ast_format_get_sample_rate(format));
- } else {
- samples_converted = samples * (ast_format_get_sample_rate(format) / (float) audiohook->hook_internal_samp_rate);
- }
+
+ audiohook_set_internal_rate(audiohook, ast_format_get_sample_rate(format), 1);
if (!(read_frame = (direction == AST_AUDIOHOOK_DIRECTION_BOTH ?
- audiohook_read_frame_both(audiohook, samples_converted, read_reference, write_reference) :
- audiohook_read_frame_single(audiohook, samples_converted, direction)))) {
+ audiohook_read_frame_both(audiohook, samples, read_reference, write_reference) :
+ audiohook_read_frame_single(audiohook, samples, direction)))) {
return NULL;
}