Asterisk - The Open Source Telephony Project  21.4.1
audiohook.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2007, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  *
21  * \brief Audiohooks Architecture
22  *
23  * \author Joshua Colp <jcolp@digium.com>
24  */
25 
26 /*** MODULEINFO
27  <support_level>core</support_level>
28  ***/
29 
30 #include "asterisk.h"
31 
32 #include <signal.h>
33 
34 #include "asterisk/channel.h"
35 #include "asterisk/utils.h"
36 #include "asterisk/lock.h"
37 #include "asterisk/audiohook.h"
38 #include "asterisk/slinfactory.h"
39 #include "asterisk/frame.h"
40 #include "asterisk/translate.h"
41 #include "asterisk/format_cache.h"
42 #include "asterisk/test.h"
43 
44 #define AST_AUDIOHOOK_SYNC_TOLERANCE 100 /*!< Tolerance in milliseconds for audiohooks synchronization */
45 #define AST_AUDIOHOOK_SMALL_QUEUE_TOLERANCE 100 /*!< When small queue is enabled, this is the maximum amount of audio that can remain queued at a time. */
46 #define AST_AUDIOHOOK_LONG_QUEUE_TOLERANCE 500 /*!< Otheriwise we still don't want the queue to grow indefinitely */
47 
48 #define DEFAULT_INTERNAL_SAMPLE_RATE 8000
49 
51  struct ast_trans_pvt *trans_pvt;
52  struct ast_format *format;
53 };
54 
56  /* If all the audiohooks in this list are capable
57  * of processing slinear at any sample rate, this
58  * variable will be set and the sample rate will
59  * be preserved during ast_audiohook_write_list()*/
60  int native_slin_compatible;
61  int list_internal_samp_rate;/*!< Internal sample rate used when writing to the audiohook list */
62 
63  struct ast_audiohook_translate in_translate[2];
64  struct ast_audiohook_translate out_translate[2];
66  AST_LIST_HEAD_NOLOCK(, ast_audiohook) whisper_list;
67  AST_LIST_HEAD_NOLOCK(, ast_audiohook) manipulate_list;
68 };
69 
70 static int audiohook_set_internal_rate(struct ast_audiohook *audiohook, int rate, int reset)
71 {
72  struct ast_format *slin;
73 
74  if (audiohook->hook_internal_samp_rate == rate) {
75  return 0;
76  }
77 
78  audiohook->hook_internal_samp_rate = rate;
79 
81 
82  /* Setup the factories that are needed for this audiohook type */
83  switch (audiohook->type) {
86  if (reset) {
87  ast_slinfactory_destroy(&audiohook->read_factory);
88  ast_slinfactory_destroy(&audiohook->write_factory);
89  }
90  ast_slinfactory_init_with_format(&audiohook->read_factory, slin);
91  ast_slinfactory_init_with_format(&audiohook->write_factory, slin);
92  break;
93  default:
94  break;
95  }
96 
97  return 0;
98 }
99 
100 int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source, enum ast_audiohook_init_flags init_flags)
101 {
102  /* Need to keep the type and source */
103  audiohook->type = type;
104  audiohook->source = source;
105 
106  /* Initialize lock that protects our audiohook */
107  ast_mutex_init(&audiohook->lock);
108  ast_cond_init(&audiohook->trigger, NULL);
109 
110  audiohook->init_flags = init_flags;
111 
112  /* Set direction to BOTH so that we feed frames in both directions */
114 
115  /* initialize internal rate at 8khz, this will adjust if necessary */
116  audiohook_set_internal_rate(audiohook, DEFAULT_INTERNAL_SAMPLE_RATE, 0);
117 
118  /* Since we are just starting out... this audiohook is new */
120 
121  return 0;
122 }
123 
124 int ast_audiohook_destroy(struct ast_audiohook *audiohook)
125 {
126  /* Drop the factories used by this audiohook type */
127  switch (audiohook->type) {
132  break;
133  default:
134  break;
135  }
136 
137  /* Destroy translation path if present */
138  if (audiohook->trans_pvt)
140 
141  ao2_cleanup(audiohook->format);
142 
143  /* Lock and trigger be gone! */
144  ast_cond_destroy(&audiohook->trigger);
145  ast_mutex_destroy(&audiohook->lock);
146 
147  return 0;
148 }
149 
151 {
152  /* Only set the direction on new audiohooks */
153  if (audiohook->status != AST_AUDIOHOOK_STATUS_NEW) {
154  ast_debug(3, "Can not set direction on attached Audiohook %p\n", audiohook);
155  return -1;
156  }
157 
158  audiohook->direction = direction;
159  return 0;
160 }
161 
162 #define SHOULD_MUTE(hook, dir) \
163  ((ast_test_flag(hook, AST_AUDIOHOOK_MUTE_READ) && (dir == AST_AUDIOHOOK_DIRECTION_READ)) || \
164  (ast_test_flag(hook, AST_AUDIOHOOK_MUTE_WRITE) && (dir == AST_AUDIOHOOK_DIRECTION_WRITE)) || \
165  (ast_test_flag(hook, AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE) == (AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE)))
166 
167 int ast_audiohook_write_frame(struct ast_audiohook *audiohook, enum ast_audiohook_direction direction, struct ast_frame *frame)
168 {
169  struct ast_slinfactory *factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_factory : &audiohook->write_factory);
170  struct ast_slinfactory *other_factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->write_factory : &audiohook->read_factory);
171  struct timeval *rwtime = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_time : &audiohook->write_time), previous_time = *rwtime;
172  int our_factory_samples;
173  int our_factory_ms;
174  int other_factory_samples;
175  int other_factory_ms;
176 
177  /* Don't feed the frame if we are set to read and this is a write frame or if set to
178  write and this is a read frame as we don't want it. Plus, it can cause mis-resampling
179  if the READ and WRITE frames have different bitrates */
180  if (audiohook->direction != AST_AUDIOHOOK_DIRECTION_BOTH && audiohook->direction != direction) {
181  return 0;
182  }
183 
184  /* Update last feeding time to be current */
185  *rwtime = ast_tvnow();
186 
187  our_factory_samples = ast_slinfactory_available(factory);
188  our_factory_ms = ast_tvdiff_ms(*rwtime, previous_time) + (our_factory_samples / (audiohook->hook_internal_samp_rate / 1000));
189  other_factory_samples = ast_slinfactory_available(other_factory);
190  other_factory_ms = other_factory_samples / (audiohook->hook_internal_samp_rate / 1000);
191 
192  if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC) && (our_factory_ms - other_factory_ms > AST_AUDIOHOOK_SYNC_TOLERANCE)) {
193  ast_debug(4, "Flushing audiohook %p so it remains in sync\n", audiohook);
194  ast_slinfactory_flush(factory);
195  ast_slinfactory_flush(other_factory);
196  }
197 
198  if (ast_test_flag(audiohook, AST_AUDIOHOOK_SMALL_QUEUE) && ((our_factory_ms > AST_AUDIOHOOK_SMALL_QUEUE_TOLERANCE) || (other_factory_ms > AST_AUDIOHOOK_SMALL_QUEUE_TOLERANCE))) {
199  ast_debug(4, "Audiohook %p has stale audio in its factories. Flushing them both\n", audiohook);
200  ast_slinfactory_flush(factory);
201  ast_slinfactory_flush(other_factory);
202  } else if ((our_factory_ms > AST_AUDIOHOOK_LONG_QUEUE_TOLERANCE) || (other_factory_ms > AST_AUDIOHOOK_LONG_QUEUE_TOLERANCE)) {
203  ast_debug(4, "Audiohook %p has stale audio in its factories. Flushing them both\n", audiohook);
204  ast_slinfactory_flush(factory);
205  ast_slinfactory_flush(other_factory);
206  }
207 
208  /* Write frame out to respective factory */
209  ast_slinfactory_feed(factory, frame);
210 
211  /* If we need to notify the respective handler of this audiohook, do so */
212  if ((ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_MODE) == AST_AUDIOHOOK_TRIGGER_READ) && (direction == AST_AUDIOHOOK_DIRECTION_READ)) {
213  ast_cond_signal(&audiohook->trigger);
214  } else if ((ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_MODE) == AST_AUDIOHOOK_TRIGGER_WRITE) && (direction == AST_AUDIOHOOK_DIRECTION_WRITE)) {
215  ast_cond_signal(&audiohook->trigger);
216  } else if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC)) {
217  ast_cond_signal(&audiohook->trigger);
218  }
219 
220  return 0;
221 }
222 
223 static struct ast_frame *audiohook_read_frame_single(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction)
224 {
225  struct ast_slinfactory *factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_factory : &audiohook->write_factory);
226  int vol = (direction == AST_AUDIOHOOK_DIRECTION_READ ? audiohook->options.read_volume : audiohook->options.write_volume);
227  short buf[samples];
228  struct ast_frame frame = {
230  .subclass.format = ast_format_cache_get_slin_by_rate(audiohook->hook_internal_samp_rate),
231  .data.ptr = buf,
232  .datalen = sizeof(buf),
233  .samples = samples,
234  };
235 
236  /* Ensure the factory is able to give us the samples we want */
237  if (samples > ast_slinfactory_available(factory)) {
238  return NULL;
239  }
240 
241  /* Read data in from factory */
242  if (!ast_slinfactory_read(factory, buf, samples)) {
243  return NULL;
244  }
245 
246  if (SHOULD_MUTE(audiohook, direction)) {
247  /* Swap frame data for zeros if mute is required */
248  ast_frame_clear(&frame);
249  } else if (vol) {
250  /* If a volume adjustment needs to be applied apply it */
251  ast_frame_adjust_volume(&frame, vol);
252  }
253 
254  return ast_frdup(&frame);
255 }
256 
257 static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audiohook, size_t samples, struct ast_frame **read_reference, struct ast_frame **write_reference)
258 {
259  int count;
260  int usable_read;
261  int usable_write;
262  short adjust_value;
263  short buf1[samples];
264  short buf2[samples];
265  short *read_buf = NULL;
266  short *write_buf = NULL;
267  struct ast_frame frame = {
269  .datalen = sizeof(buf1),
270  .samples = samples,
271  };
272 
273  /* Make sure both factories have the required samples */
274  usable_read = (ast_slinfactory_available(&audiohook->read_factory) >= samples ? 1 : 0);
275  usable_write = (ast_slinfactory_available(&audiohook->write_factory) >= samples ? 1 : 0);
276 
277  if (!usable_read && !usable_write) {
278  /* If both factories are unusable bail out */
279  ast_debug(3, "Read factory %p and write factory %p both fail to provide %zu samples\n", &audiohook->read_factory, &audiohook->write_factory, samples);
280  return NULL;
281  }
282 
283  /* If we want to provide only a read factory make sure we aren't waiting for other audio */
284  if (usable_read && !usable_write && (ast_tvdiff_ms(ast_tvnow(), audiohook->write_time) < (samples/8)*2)) {
285  ast_debug(3, "Write factory %p was pretty quick last time, waiting for them.\n", &audiohook->write_factory);
286  return NULL;
287  }
288 
289  /* If we want to provide only a write factory make sure we aren't waiting for other audio */
290  if (usable_write && !usable_read && (ast_tvdiff_ms(ast_tvnow(), audiohook->read_time) < (samples/8)*2)) {
291  ast_debug(3, "Read factory %p was pretty quick last time, waiting for them.\n", &audiohook->read_factory);
292  return NULL;
293  }
294 
295  /* Start with the read factory... if there are enough samples, read them in */
296  if (usable_read) {
297  if (ast_slinfactory_read(&audiohook->read_factory, buf1, samples)) {
298  read_buf = buf1;
299 
300  if ((ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_READ))) {
301  /* Clear the frame data if we are muting */
302  memset(buf1, 0, sizeof(buf1));
303  } else if (audiohook->options.read_volume) {
304  /* Adjust read volume if need be */
305  adjust_value = abs(audiohook->options.read_volume);
306  for (count = 0; count < samples; count++) {
307  if (audiohook->options.read_volume > 0) {
308  ast_slinear_saturated_multiply(&buf1[count], &adjust_value);
309  } else if (audiohook->options.read_volume < 0) {
310  ast_slinear_saturated_divide(&buf1[count], &adjust_value);
311  }
312  }
313  }
314  }
315  } else {
316  ast_debug(1, "Failed to get %d samples from read factory %p\n", (int)samples, &audiohook->read_factory);
317  }
318 
319  /* Move on to the write factory... if there are enough samples, read them in */
320  if (usable_write) {
321  if (ast_slinfactory_read(&audiohook->write_factory, buf2, samples)) {
322  write_buf = buf2;
323 
324  if ((ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_WRITE))) {
325  /* Clear the frame data if we are muting */
326  memset(buf2, 0, sizeof(buf2));
327  } else if (audiohook->options.write_volume) {
328  /* Adjust write volume if need be */
329  adjust_value = abs(audiohook->options.write_volume);
330  for (count = 0; count < samples; count++) {
331  if (audiohook->options.write_volume > 0) {
332  ast_slinear_saturated_multiply(&buf2[count], &adjust_value);
333  } else if (audiohook->options.write_volume < 0) {
334  ast_slinear_saturated_divide(&buf2[count], &adjust_value);
335  }
336  }
337  }
338  }
339  } else {
340  ast_debug(3, "Failed to get %d samples from write factory %p\n", (int)samples, &audiohook->write_factory);
341  }
342 
344 
345  /* Should we substitute silence if one side lacks audio? */
346  if ((ast_test_flag(audiohook, AST_AUDIOHOOK_SUBSTITUTE_SILENCE))) {
347  if (read_reference && !read_buf && write_buf) {
348  read_buf = buf1;
349  memset(buf1, 0, sizeof(buf1));
350  } else if (write_reference && read_buf && !write_buf) {
351  write_buf = buf2;
352  memset(buf2, 0, sizeof(buf2));
353  }
354  }
355 
356  /* Basically we figure out which buffer to use... and if mixing can be done here */
357  if (read_buf && read_reference) {
358  frame.data.ptr = read_buf;
359  *read_reference = ast_frdup(&frame);
360  }
361  if (write_buf && write_reference) {
362  frame.data.ptr = write_buf;
363  *write_reference = ast_frdup(&frame);
364  }
365 
366  /* Make the correct buffer part of the built frame, so it gets duplicated. */
367  if (read_buf) {
368  frame.data.ptr = read_buf;
369  if (write_buf) {
370  for (count = 0; count < samples; count++) {
371  ast_slinear_saturated_add(read_buf++, write_buf++);
372  }
373  }
374  } else if (write_buf) {
375  frame.data.ptr = write_buf;
376  } else {
377  return NULL;
378  }
379 
380  /* Yahoo, a combined copy of the audio! */
381  return ast_frdup(&frame);
382 }
383 
384 static struct ast_frame *audiohook_read_frame_helper(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format, struct ast_frame **read_reference, struct ast_frame **write_reference)
385 {
386  struct ast_frame *read_frame = NULL, *final_frame = NULL;
387  struct ast_format *slin;
388 
389  /*
390  * Update the rate if compatibility mode is turned off or if it is
391  * turned on and the format rate is higher than the current rate.
392  *
393  * This makes it so any unnecessary rate switching/resetting does
394  * not take place and also any associated audiohook_list's internal
395  * sample rate maintains the highest sample rate between hooks.
396  */
397  if (!ast_test_flag(audiohook, AST_AUDIOHOOK_COMPATIBLE) ||
398  (ast_test_flag(audiohook, AST_AUDIOHOOK_COMPATIBLE) &&
399  ast_format_get_sample_rate(format) > audiohook->hook_internal_samp_rate)) {
400  audiohook_set_internal_rate(audiohook, ast_format_get_sample_rate(format), 1);
401  }
402 
403  /* If the sample rate of the requested format differs from that of the underlying audiohook
404  * sample rate determine how many samples we actually need to get from the audiohook. This
405  * needs to occur as the signed linear factory stores them at the rate of the audiohook.
406  * We do this by determining the duration of audio they've requested and then determining
407  * how many samples that would be in the audiohook format.
408  */
409  if (ast_format_get_sample_rate(format) != audiohook->hook_internal_samp_rate) {
410  samples = (audiohook->hook_internal_samp_rate / 1000) * (samples / (ast_format_get_sample_rate(format) / 1000));
411  }
412 
413  if (!(read_frame = (direction == AST_AUDIOHOOK_DIRECTION_BOTH ?
414  audiohook_read_frame_both(audiohook, samples, read_reference, write_reference) :
415  audiohook_read_frame_single(audiohook, samples, direction)))) {
416  return NULL;
417  }
418 
420 
421  /* If they don't want signed linear back out, we'll have to send it through the translation path */
422  if (ast_format_cmp(format, slin) != AST_FORMAT_CMP_EQUAL) {
423  /* Rebuild translation path if different format then previously */
424  if (ast_format_cmp(format, audiohook->format) == AST_FORMAT_CMP_NOT_EQUAL) {
425  if (audiohook->trans_pvt) {
427  audiohook->trans_pvt = NULL;
428  }
429 
430  /* Setup new translation path for this format... if we fail we can't very well return signed linear so free the frame and return nothing */
431  if (!(audiohook->trans_pvt = ast_translator_build_path(format, slin))) {
432  ast_frfree(read_frame);
433  return NULL;
434  }
435  ao2_replace(audiohook->format, format);
436  }
437  /* Convert to requested format, and allow the read in frame to be freed */
438  final_frame = ast_translate(audiohook->trans_pvt, read_frame, 1);
439  } else {
440  final_frame = read_frame;
441  }
442 
443  return final_frame;
444 }
445 
446 struct ast_frame *ast_audiohook_read_frame(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format)
447 {
448  return audiohook_read_frame_helper(audiohook, samples, direction, format, NULL, NULL);
449 }
450 
451 struct ast_frame *ast_audiohook_read_frame_all(struct ast_audiohook *audiohook, size_t samples, struct ast_format *format, struct ast_frame **read_frame, struct ast_frame **write_frame)
452 {
453  return audiohook_read_frame_helper(audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, format, read_frame, write_frame);
454 }
455 
456 static void audiohook_list_set_samplerate_compatibility(struct ast_audiohook_list *audiohook_list)
457 {
458  struct ast_audiohook *ah = NULL;
459 
460  /*
461  * Anytime the samplerate compatibility is set (attach/remove an audiohook) the
462  * list's internal sample rate needs to be reset so that the next time processing
463  * through write_list, if needed, it will get updated to the correct rate.
464  *
465  * A list's internal rate always chooses the higher between its own rate and a
466  * given rate. If the current rate is being driven by an audiohook that wanted a
467  * higher rate then when this audiohook is removed the list's rate would remain
468  * at that level when it should be lower, and with no way to lower it since any
469  * rate compared against it would be lower.
470  *
471  * By setting it back to the lowest rate it can recalulate the new highest rate.
472  */
473  audiohook_list->list_internal_samp_rate = DEFAULT_INTERNAL_SAMPLE_RATE;
474 
475  audiohook_list->native_slin_compatible = 1;
476  AST_LIST_TRAVERSE(&audiohook_list->manipulate_list, ah, list) {
478  audiohook_list->native_slin_compatible = 0;
479  return;
480  }
481  }
482 }
483 
484 int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
485 {
486  ast_channel_lock(chan);
487 
488  /* Don't allow an audiohook to be attached to a channel that is already hung up.
489  * The hang up process is what actually notifies the audiohook that it should
490  * stop.
491  */
492  if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)) {
493  ast_channel_unlock(chan);
494  return -1;
495  }
496 
497  if (!ast_channel_audiohooks(chan)) {
498  struct ast_audiohook_list *ahlist;
499  /* Whoops... allocate a new structure */
500  if (!(ahlist = ast_calloc(1, sizeof(*ahlist)))) {
501  ast_channel_unlock(chan);
502  return -1;
503  }
504  ast_channel_audiohooks_set(chan, ahlist);
505  AST_LIST_HEAD_INIT_NOLOCK(&ast_channel_audiohooks(chan)->spy_list);
506  AST_LIST_HEAD_INIT_NOLOCK(&ast_channel_audiohooks(chan)->whisper_list);
507  AST_LIST_HEAD_INIT_NOLOCK(&ast_channel_audiohooks(chan)->manipulate_list);
508  /* This sample rate will adjust as necessary when writing to the list. */
509  ast_channel_audiohooks(chan)->list_internal_samp_rate = DEFAULT_INTERNAL_SAMPLE_RATE;
510  }
511 
512  /* Drop into respective list */
513  if (audiohook->type == AST_AUDIOHOOK_TYPE_SPY) {
514  AST_LIST_INSERT_TAIL(&ast_channel_audiohooks(chan)->spy_list, audiohook, list);
515  } else if (audiohook->type == AST_AUDIOHOOK_TYPE_WHISPER) {
516  AST_LIST_INSERT_TAIL(&ast_channel_audiohooks(chan)->whisper_list, audiohook, list);
517  } else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE) {
518  AST_LIST_INSERT_TAIL(&ast_channel_audiohooks(chan)->manipulate_list, audiohook, list);
519  }
520 
521  /*
522  * Initialize the audiohook's rate to the default. If it needs to be,
523  * it will get updated later.
524  */
525  audiohook_set_internal_rate(audiohook, DEFAULT_INTERNAL_SAMPLE_RATE, 1);
526  audiohook_list_set_samplerate_compatibility(ast_channel_audiohooks(chan));
527 
528  /* Change status over to running since it is now attached */
530 
531  if (ast_channel_is_bridged(chan)) {
533  }
534 
535  ast_channel_unlock(chan);
536 
537  return 0;
538 }
539 
541 {
542  ast_audiohook_lock(audiohook);
543  if (audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
544  audiohook->status = status;
545  ast_cond_signal(&audiohook->trigger);
546  }
547  ast_audiohook_unlock(audiohook);
548 }
549 
550 int ast_audiohook_detach(struct ast_audiohook *audiohook)
551 {
552  if (audiohook->status == AST_AUDIOHOOK_STATUS_NEW || audiohook->status == AST_AUDIOHOOK_STATUS_DONE) {
553  return 0;
554  }
555 
557 
558  while (audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
559  ast_audiohook_trigger_wait(audiohook);
560  }
561 
562  return 0;
563 }
564 
565 void ast_audiohook_detach_list(struct ast_audiohook_list *audiohook_list)
566 {
567  int i;
568  struct ast_audiohook *audiohook;
569 
570  if (!audiohook_list) {
571  return;
572  }
573 
574  /* Drop any spies */
575  while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->spy_list, list))) {
577  }
578 
579  /* Drop any whispering sources */
580  while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->whisper_list, list))) {
582  }
583 
584  /* Drop any manipulators */
585  while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->manipulate_list, list))) {
587  audiohook->manipulate_callback(audiohook, NULL, NULL, 0);
588  }
589 
590  /* Drop translation paths if present */
591  for (i = 0; i < 2; i++) {
592  if (audiohook_list->in_translate[i].trans_pvt) {
593  ast_translator_free_path(audiohook_list->in_translate[i].trans_pvt);
594  ao2_cleanup(audiohook_list->in_translate[i].format);
595  }
596  if (audiohook_list->out_translate[i].trans_pvt) {
597  ast_translator_free_path(audiohook_list->out_translate[i].trans_pvt);
598  ao2_cleanup(audiohook_list->in_translate[i].format);
599  }
600  }
601 
602  /* Free ourselves */
603  ast_free(audiohook_list);
604 }
605 
606 /*! \brief find an audiohook based on its source
607  * \param audiohook_list The list of audiohooks to search in
608  * \param source The source of the audiohook we wish to find
609  * \return corresponding audiohook
610  * \retval NULL if it cannot be found
611  */
612 static struct ast_audiohook *find_audiohook_by_source(struct ast_audiohook_list *audiohook_list, const char *source)
613 {
614  struct ast_audiohook *audiohook = NULL;
615 
616  AST_LIST_TRAVERSE(&audiohook_list->spy_list, audiohook, list) {
617  if (!strcasecmp(audiohook->source, source)) {
618  return audiohook;
619  }
620  }
621 
622  AST_LIST_TRAVERSE(&audiohook_list->whisper_list, audiohook, list) {
623  if (!strcasecmp(audiohook->source, source)) {
624  return audiohook;
625  }
626  }
627 
628  AST_LIST_TRAVERSE(&audiohook_list->manipulate_list, audiohook, list) {
629  if (!strcasecmp(audiohook->source, source)) {
630  return audiohook;
631  }
632  }
633 
634  return NULL;
635 }
636 
637 static void audiohook_move(struct ast_channel *old_chan, struct ast_channel *new_chan, struct ast_audiohook *audiohook)
638 {
639  enum ast_audiohook_status oldstatus;
640 
641  /* By locking both channels and the audiohook, we can assure that
642  * another thread will not have a chance to read the audiohook's status
643  * as done, even though ast_audiohook_remove signals the trigger
644  * condition.
645  */
646  ast_audiohook_lock(audiohook);
647  oldstatus = audiohook->status;
648 
649  ast_audiohook_remove(old_chan, audiohook);
650  ast_audiohook_attach(new_chan, audiohook);
651 
652  audiohook->status = oldstatus;
653  ast_audiohook_unlock(audiohook);
654 }
655 
656 void ast_audiohook_move_by_source(struct ast_channel *old_chan, struct ast_channel *new_chan, const char *source)
657 {
658  struct ast_audiohook *audiohook;
659 
660  if (!ast_channel_audiohooks(old_chan)) {
661  return;
662  }
663 
664  audiohook = find_audiohook_by_source(ast_channel_audiohooks(old_chan), source);
665  if (!audiohook) {
666  return;
667  }
668 
669  audiohook_move(old_chan, new_chan, audiohook);
670 }
671 
672 void ast_audiohook_move_all(struct ast_channel *old_chan, struct ast_channel *new_chan)
673 {
674  struct ast_audiohook *audiohook;
675  struct ast_audiohook_list *audiohook_list;
676 
677  audiohook_list = ast_channel_audiohooks(old_chan);
678  if (!audiohook_list) {
679  return;
680  }
681 
682  AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->spy_list, audiohook, list) {
683  audiohook_move(old_chan, new_chan, audiohook);
684  }
686 
687  AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->whisper_list, audiohook, list) {
688  audiohook_move(old_chan, new_chan, audiohook);
689  }
691 
692  AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
693  audiohook_move(old_chan, new_chan, audiohook);
694  }
696 }
697 
698 int ast_audiohook_detach_source(struct ast_channel *chan, const char *source)
699 {
700  struct ast_audiohook *audiohook = NULL;
701 
702  ast_channel_lock(chan);
703 
704  /* Ensure the channel has audiohooks on it */
705  if (!ast_channel_audiohooks(chan)) {
706  ast_channel_unlock(chan);
707  return -1;
708  }
709 
710  audiohook = find_audiohook_by_source(ast_channel_audiohooks(chan), source);
711 
712  ast_channel_unlock(chan);
713 
714  if (audiohook && audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
716  }
717 
718  return (audiohook ? 0 : -1);
719 }
720 
721 int ast_audiohook_remove(struct ast_channel *chan, struct ast_audiohook *audiohook)
722 {
723  ast_channel_lock(chan);
724 
725  if (!ast_channel_audiohooks(chan)) {
726  ast_channel_unlock(chan);
727  return -1;
728  }
729 
730  if (audiohook->type == AST_AUDIOHOOK_TYPE_SPY) {
731  AST_LIST_REMOVE(&ast_channel_audiohooks(chan)->spy_list, audiohook, list);
732  } else if (audiohook->type == AST_AUDIOHOOK_TYPE_WHISPER) {
733  AST_LIST_REMOVE(&ast_channel_audiohooks(chan)->whisper_list, audiohook, list);
734  } else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE) {
735  AST_LIST_REMOVE(&ast_channel_audiohooks(chan)->manipulate_list, audiohook, list);
736  }
737 
738  audiohook_list_set_samplerate_compatibility(ast_channel_audiohooks(chan));
740 
741  if (ast_channel_is_bridged(chan)) {
743  }
744 
745  ast_channel_unlock(chan);
746 
747  return 0;
748 }
749 
750 /*! \brief Pass a DTMF frame off to be handled by the audiohook core
751  * \param chan Channel that the list is coming off of
752  * \param audiohook_list List of audiohooks
753  * \param direction Direction frame is coming in from
754  * \param frame The frame itself
755  * \return frame on success
756  * \retval NULL on failure
757  */
758 static struct ast_frame *dtmf_audiohook_write_list(struct ast_channel *chan, struct ast_audiohook_list *audiohook_list, enum ast_audiohook_direction direction, struct ast_frame *frame)
759 {
760  struct ast_audiohook *audiohook = NULL;
761  int removed = 0;
762 
763  AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
764  ast_audiohook_lock(audiohook);
765  if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
767  removed = 1;
769  ast_audiohook_unlock(audiohook);
770  audiohook->manipulate_callback(audiohook, NULL, NULL, 0);
771  if (ast_channel_is_bridged(chan)) {
773  }
774  continue;
775  }
776  if (ast_test_flag(audiohook, AST_AUDIOHOOK_WANTS_DTMF)) {
777  audiohook->manipulate_callback(audiohook, chan, frame, direction);
778  }
779  ast_audiohook_unlock(audiohook);
780  }
782 
783  /* if an audiohook got removed, reset samplerate compatibility */
784  if (removed) {
785  audiohook_list_set_samplerate_compatibility(audiohook_list);
786  }
787  return frame;
788 }
789 
790 static struct ast_frame *audiohook_list_translate_to_slin(struct ast_audiohook_list *audiohook_list,
791  enum ast_audiohook_direction direction, struct ast_frame *frame)
792 {
793  struct ast_audiohook_translate *in_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ?
794  &audiohook_list->in_translate[0] : &audiohook_list->in_translate[1]);
795  struct ast_frame *new_frame = frame;
796  struct ast_format *slin;
797 
798  /*
799  * If we are capable of sample rates other that 8khz, update the internal
800  * audiohook_list's rate and higher sample rate audio arrives. If native
801  * slin compatibility is turned on all audiohooks in the list will be
802  * updated as well during read/write processing.
803  */
804  audiohook_list->list_internal_samp_rate =
806 
808  if (ast_format_cmp(frame->subclass.format, slin) == AST_FORMAT_CMP_EQUAL) {
809  return new_frame;
810  }
811 
812  if (!in_translate->format ||
813  ast_format_cmp(frame->subclass.format, in_translate->format) != AST_FORMAT_CMP_EQUAL) {
814  struct ast_trans_pvt *new_trans;
815 
816  new_trans = ast_translator_build_path(slin, frame->subclass.format);
817  if (!new_trans) {
818  return NULL;
819  }
820 
821  if (in_translate->trans_pvt) {
822  ast_translator_free_path(in_translate->trans_pvt);
823  }
824  in_translate->trans_pvt = new_trans;
825 
826  ao2_replace(in_translate->format, frame->subclass.format);
827  }
828 
829  if (!(new_frame = ast_translate(in_translate->trans_pvt, frame, 0))) {
830  return NULL;
831  }
832 
833  return new_frame;
834 }
835 
836 static struct ast_frame *audiohook_list_translate_to_native(struct ast_audiohook_list *audiohook_list,
837  enum ast_audiohook_direction direction, struct ast_frame *slin_frame, struct ast_format *outformat)
838 {
839  struct ast_audiohook_translate *out_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook_list->out_translate[0] : &audiohook_list->out_translate[1]);
840  struct ast_frame *outframe = NULL;
841  if (ast_format_cmp(slin_frame->subclass.format, outformat) == AST_FORMAT_CMP_NOT_EQUAL) {
842  /* rebuild translators if necessary */
843  if (ast_format_cmp(out_translate->format, outformat) == AST_FORMAT_CMP_NOT_EQUAL) {
844  if (out_translate->trans_pvt) {
845  ast_translator_free_path(out_translate->trans_pvt);
846  }
847  if (!(out_translate->trans_pvt = ast_translator_build_path(outformat, slin_frame->subclass.format))) {
848  return NULL;
849  }
850  ao2_replace(out_translate->format, outformat);
851  }
852  /* translate back to the format the frame came in as. */
853  if (!(outframe = ast_translate(out_translate->trans_pvt, slin_frame, 0))) {
854  return NULL;
855  }
856  }
857  return outframe;
858 }
859 
860 /*!
861  *\brief Set the audiohook's internal sample rate to the audiohook_list's rate,
862  * but only when native slin compatibility is turned on.
863  *
864  * \param audiohook_list audiohook_list data object
865  * \param audiohook the audiohook to update
866  * \param rate the current max internal sample rate
867  */
868 static void audiohook_list_set_hook_rate(struct ast_audiohook_list *audiohook_list,
869  struct ast_audiohook *audiohook, int *rate)
870 {
871  /* The rate should always be the max between itself and the hook */
872  if (audiohook->hook_internal_samp_rate > *rate) {
873  *rate = audiohook->hook_internal_samp_rate;
874  }
875 
876  /*
877  * If native slin compatibility is turned on then update the audiohook
878  * with the audiohook_list's current rate. Note, the audiohook's rate is
879  * set to the audiohook_list's rate and not the given rate. If there is
880  * a change in rate the hook's rate is changed on its next check.
881  */
882  if (audiohook_list->native_slin_compatible) {
883  ast_set_flag(audiohook, AST_AUDIOHOOK_COMPATIBLE);
884  audiohook_set_internal_rate(audiohook, audiohook_list->list_internal_samp_rate, 1);
885  } else {
886  ast_clear_flag(audiohook, AST_AUDIOHOOK_COMPATIBLE);
887  }
888 }
889 
890 /*!
891  * \brief Pass an AUDIO frame off to be handled by the audiohook core
892  *
893  * \details
894  * This function has 3 ast_frames and 3 parts to handle each. At the beginning of this
895  * function all 3 frames, start_frame, middle_frame, and end_frame point to the initial
896  * input frame.
897  *
898  * Part_1: Translate the start_frame into SLINEAR audio if it is not already in that
899  * format. The result of this part is middle_frame is guaranteed to be in
900  * SLINEAR format for Part_2.
901  * Part_2: Send middle_frame off to spies and manipulators. At this point middle_frame is
902  * either a new frame as result of the translation, or points directly to the start_frame
903  * because no translation to SLINEAR audio was required.
904  * Part_3: Translate end_frame's audio back into the format of start frame if necessary. This
905  * is only necessary if manipulation of middle_frame occurred.
906  *
907  * \param chan Channel that the list is coming off of
908  * \param audiohook_list List of audiohooks
909  * \param direction Direction frame is coming in from
910  * \param frame The frame itself
911  * \return frame on success
912  * \retval NULL on failure
913  */
914 static struct ast_frame *audio_audiohook_write_list(struct ast_channel *chan, struct ast_audiohook_list *audiohook_list, enum ast_audiohook_direction direction, struct ast_frame *frame)
915 {
916  struct ast_frame *start_frame = frame, *middle_frame = frame, *end_frame = frame;
917  struct ast_audiohook *audiohook = NULL;
918  int samples;
919  int middle_frame_manipulated = 0;
920  int removed = 0;
921  int internal_sample_rate;
922 
923  /* ---Part_1. translate start_frame to SLINEAR if necessary. */
924  if (!(middle_frame = audiohook_list_translate_to_slin(audiohook_list, direction, start_frame))) {
925  return frame;
926  }
927 
928  /* If the translation resulted in an interpolated frame then immediately return as audiohooks
929  * rely on actual media being present to do things.
930  */
931  if (!middle_frame->data.ptr) {
932  if (middle_frame != start_frame) {
933  ast_frfree(middle_frame);
934  }
935  return start_frame;
936  }
937 
938  samples = middle_frame->samples;
939 
940  /*
941  * While processing each audiohook check to see if the internal sample rate needs
942  * to be adjusted (it should be the highest rate specified between formats and
943  * hooks). The given audiohook_list's internal sample rate is then set to the
944  * updated value before returning.
945  *
946  * If slin compatibility mode is turned on then an audiohook's internal sample
947  * rate is set to its audiohook_list's rate. If an audiohook_list's rate is
948  * adjusted during this pass then the change is picked up by the audiohooks
949  * on the next pass.
950  */
951  internal_sample_rate = audiohook_list->list_internal_samp_rate;
952 
953  /* ---Part_2: Send middle_frame to spy and manipulator lists. middle_frame is guaranteed to be SLINEAR here.*/
954  /* Queue up signed linear frame to each spy */
955  AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->spy_list, audiohook, list) {
956  ast_audiohook_lock(audiohook);
957  if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
959  removed = 1;
961  ast_audiohook_unlock(audiohook);
962  if (ast_channel_is_bridged(chan)) {
964  }
965  continue;
966  }
967  audiohook_list_set_hook_rate(audiohook_list, audiohook, &internal_sample_rate);
968  ast_audiohook_write_frame(audiohook, direction, middle_frame);
969  ast_audiohook_unlock(audiohook);
970  }
972 
973  /* If this frame is being written out to the channel then we need to use whisper sources */
974  if (!AST_LIST_EMPTY(&audiohook_list->whisper_list)) {
975  int i = 0;
976  short read_buf[samples], combine_buf[samples], *data1 = NULL, *data2 = NULL;
977  memset(&combine_buf, 0, sizeof(combine_buf));
978  AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->whisper_list, audiohook, list) {
979  struct ast_slinfactory *factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_factory : &audiohook->write_factory);
980  ast_audiohook_lock(audiohook);
981  if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
983  removed = 1;
985  ast_audiohook_unlock(audiohook);
986  if (ast_channel_is_bridged(chan)) {
988  }
989  continue;
990  }
991  audiohook_list_set_hook_rate(audiohook_list, audiohook, &internal_sample_rate);
992  if (ast_slinfactory_available(factory) >= samples && ast_slinfactory_read(factory, read_buf, samples)) {
993  /* Take audio from this whisper source and combine it into our main buffer */
994  for (i = 0, data1 = combine_buf, data2 = read_buf; i < samples; i++, data1++, data2++) {
995  ast_slinear_saturated_add(data1, data2);
996  }
997  }
998  ast_audiohook_unlock(audiohook);
999  }
1001  /* We take all of the combined whisper sources and combine them into the audio being written out */
1002  for (i = 0, data1 = middle_frame->data.ptr, data2 = combine_buf; i < samples; i++, data1++, data2++) {
1003  ast_slinear_saturated_add(data1, data2);
1004  }
1005  middle_frame_manipulated = 1;
1006  }
1007 
1008  /* Pass off frame to manipulate audiohooks */
1009  if (!AST_LIST_EMPTY(&audiohook_list->manipulate_list)) {
1010  AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
1011  ast_audiohook_lock(audiohook);
1012  if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
1014  removed = 1;
1016  ast_audiohook_unlock(audiohook);
1017  /* We basically drop all of our links to the manipulate audiohook and prod it to do it's own destructive things */
1018  audiohook->manipulate_callback(audiohook, chan, NULL, direction);
1019  if (ast_channel_is_bridged(chan)) {
1021  }
1022  continue;
1023  }
1024  audiohook_list_set_hook_rate(audiohook_list, audiohook, &internal_sample_rate);
1025  /*
1026  * Feed in frame to manipulation.
1027  */
1028  if (!audiohook->manipulate_callback(audiohook, chan, middle_frame, direction)) {
1029  /*
1030  * XXX FAILURES ARE IGNORED XXX
1031  * If the manipulation fails then the frame will be returned in its original state.
1032  * Since there are potentially more manipulator callbacks in the list, no action should
1033  * be taken here to exit early.
1034  */
1035  middle_frame_manipulated = 1;
1036  }
1037  ast_audiohook_unlock(audiohook);
1038  }
1040  }
1041 
1042  /* ---Part_3: Decide what to do with the end_frame (whether to transcode or not) */
1043  if (middle_frame_manipulated) {
1044  if (!(end_frame = audiohook_list_translate_to_native(audiohook_list, direction, middle_frame, start_frame->subclass.format))) {
1045  /* translation failed, so just pass back the input frame */
1046  end_frame = start_frame;
1047  }
1048  } else {
1049  end_frame = start_frame;
1050  }
1051  /* clean up our middle_frame if required */
1052  if (middle_frame != end_frame) {
1053  ast_frfree(middle_frame);
1054  middle_frame = NULL;
1055  }
1056 
1057  /* Before returning, if an audiohook got removed, reset samplerate compatibility */
1058  if (removed) {
1059  audiohook_list_set_samplerate_compatibility(audiohook_list);
1060  } else {
1061  /*
1062  * Set the audiohook_list's rate to the updated rate. Note that if a hook
1063  * was removed then the list's internal rate is reset to the default.
1064  */
1065  audiohook_list->list_internal_samp_rate = internal_sample_rate;
1066  }
1067 
1068  return end_frame;
1069 }
1070 
1072 {
1073  return !audiohook_list
1074  || (AST_LIST_EMPTY(&audiohook_list->spy_list)
1075  && AST_LIST_EMPTY(&audiohook_list->whisper_list)
1076  && AST_LIST_EMPTY(&audiohook_list->manipulate_list));
1077 }
1078 
1079 struct ast_frame *ast_audiohook_write_list(struct ast_channel *chan, struct ast_audiohook_list *audiohook_list, enum ast_audiohook_direction direction, struct ast_frame *frame)
1080 {
1081  /* Pass off frame to it's respective list write function */
1082  if (frame->frametype == AST_FRAME_VOICE) {
1083  return audio_audiohook_write_list(chan, audiohook_list, direction, frame);
1084  } else if (frame->frametype == AST_FRAME_DTMF) {
1085  return dtmf_audiohook_write_list(chan, audiohook_list, direction, frame);
1086  } else {
1087  return frame;
1088  }
1089 }
1090 
1091 /*! \brief Wait for audiohook trigger to be triggered
1092  * \param audiohook Audiohook to wait on
1093  */
1095 {
1096  struct timeval wait;
1097  struct timespec ts;
1098 
1099  wait = ast_tvadd(ast_tvnow(), ast_samp2tv(50000, 1000));
1100  ts.tv_sec = wait.tv_sec;
1101  ts.tv_nsec = wait.tv_usec * 1000;
1102 
1103  ast_cond_timedwait(&audiohook->trigger, &audiohook->lock, &ts);
1104 
1105  return;
1106 }
1107 
1108 /* Count number of channel audiohooks by type, regardless of type */
1109 int ast_channel_audiohook_count_by_source(struct ast_channel *chan, const char *source, enum ast_audiohook_type type)
1110 {
1111  int count = 0;
1112  struct ast_audiohook *ah = NULL;
1113 
1114  if (!ast_channel_audiohooks(chan)) {
1115  return -1;
1116  }
1117 
1118  switch (type) {
1120  AST_LIST_TRAVERSE(&ast_channel_audiohooks(chan)->spy_list, ah, list) {
1121  if (!strcmp(ah->source, source)) {
1122  count++;
1123  }
1124  }
1125  break;
1127  AST_LIST_TRAVERSE(&ast_channel_audiohooks(chan)->whisper_list, ah, list) {
1128  if (!strcmp(ah->source, source)) {
1129  count++;
1130  }
1131  }
1132  break;
1134  AST_LIST_TRAVERSE(&ast_channel_audiohooks(chan)->manipulate_list, ah, list) {
1135  if (!strcmp(ah->source, source)) {
1136  count++;
1137  }
1138  }
1139  break;
1140  default:
1141  ast_debug(1, "Invalid audiohook type supplied, (%u)\n", type);
1142  return -1;
1143  }
1144 
1145  return count;
1146 }
1147 
1148 /* Count number of channel audiohooks by type that are running */
1150 {
1151  int count = 0;
1152  struct ast_audiohook *ah = NULL;
1153  if (!ast_channel_audiohooks(chan))
1154  return -1;
1155 
1156  switch (type) {
1158  AST_LIST_TRAVERSE(&ast_channel_audiohooks(chan)->spy_list, ah, list) {
1159  if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
1160  count++;
1161  }
1162  break;
1164  AST_LIST_TRAVERSE(&ast_channel_audiohooks(chan)->whisper_list, ah, list) {
1165  if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
1166  count++;
1167  }
1168  break;
1170  AST_LIST_TRAVERSE(&ast_channel_audiohooks(chan)->manipulate_list, ah, list) {
1171  if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
1172  count++;
1173  }
1174  break;
1175  default:
1176  ast_debug(1, "Invalid audiohook type supplied, (%u)\n", type);
1177  return -1;
1178  }
1179  return count;
1180 }
1181 
1182 /*! \brief Audiohook volume adjustment structure */
1184  struct ast_audiohook audiohook; /*!< Audiohook attached to the channel */
1185  int read_adjustment; /*!< Value to adjust frames read from the channel by */
1186  int write_adjustment; /*!< Value to adjust frames written to the channel by */
1187 };
1188 
1189 /*! \brief Callback used to destroy the audiohook volume datastore
1190  * \param data Volume information structure
1191  */
1192 static void audiohook_volume_destroy(void *data)
1193 {
1194  struct audiohook_volume *audiohook_volume = data;
1195 
1196  /* Destroy the audiohook as it is no longer in use */
1197  ast_audiohook_destroy(&audiohook_volume->audiohook);
1198 
1199  /* Finally free ourselves, we are of no more use */
1200  ast_free(audiohook_volume);
1201 
1202  return;
1203 }
1204 
1205 /*! \brief Datastore used to store audiohook volume information */
1207  .type = "Volume",
1208  .destroy = audiohook_volume_destroy,
1209 };
1210 
1211 /*! \brief Helper function which actually gets called by audiohooks to perform the adjustment
1212  * \param audiohook Audiohook attached to the channel
1213  * \param chan Channel we are attached to
1214  * \param frame Frame of audio we want to manipulate
1215  * \param direction Direction the audio came in from
1216  * \retval 0 on success
1217  * \retval -1 on failure
1218  */
1219 static int audiohook_volume_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
1220 {
1221  struct ast_datastore *datastore = NULL;
1222  struct audiohook_volume *audiohook_volume = NULL;
1223  int *gain = NULL;
1224 
1225  /* If the audiohook is shutting down don't even bother */
1226  if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) {
1227  return 0;
1228  }
1229 
1230  /* Try to find the datastore containg adjustment information, if we can't just bail out */
1231  if (!(datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) {
1232  return 0;
1233  }
1234 
1235  audiohook_volume = datastore->data;
1236 
1237  /* Based on direction grab the appropriate adjustment value */
1238  if (direction == AST_AUDIOHOOK_DIRECTION_READ) {
1239  gain = &audiohook_volume->read_adjustment;
1240  } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) {
1241  gain = &audiohook_volume->write_adjustment;
1242  }
1243 
1244  /* If an adjustment value is present modify the frame */
1245  if (gain && *gain) {
1246  ast_frame_adjust_volume(frame, *gain);
1247  }
1248 
1249  return 0;
1250 }
1251 
1252 /*! \brief Helper function which finds and optionally creates an audiohook_volume_datastore datastore on a channel
1253  * \param chan Channel to look on
1254  * \param create Whether to create the datastore if not found
1255  * \return audiohook_volume structure on success
1256  * \retval NULL on failure
1257  */
1258 static struct audiohook_volume *audiohook_volume_get(struct ast_channel *chan, int create)
1259 {
1260  struct ast_datastore *datastore = NULL;
1261  struct audiohook_volume *audiohook_volume = NULL;
1262 
1263  /* If we are able to find the datastore return the contents (which is actually an audiohook_volume structure) */
1264  if ((datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) {
1265  return datastore->data;
1266  }
1267 
1268  /* If we are not allowed to create a datastore or if we fail to create a datastore, bail out now as we have nothing for them */
1269  if (!create || !(datastore = ast_datastore_alloc(&audiohook_volume_datastore, NULL))) {
1270  return NULL;
1271  }
1272 
1273  /* Create a new audiohook_volume structure to contain our adjustments and audiohook */
1274  if (!(audiohook_volume = ast_calloc(1, sizeof(*audiohook_volume)))) {
1275  ast_datastore_free(datastore);
1276  return NULL;
1277  }
1278 
1279  /* Setup our audiohook structure so we can manipulate the audio */
1282 
1283  /* Attach the audiohook_volume blob to the datastore and attach to the channel */
1284  datastore->data = audiohook_volume;
1285  ast_channel_datastore_add(chan, datastore);
1286 
1287  /* All is well... put the audiohook into motion */
1288  ast_audiohook_attach(chan, &audiohook_volume->audiohook);
1289 
1290  return audiohook_volume;
1291 }
1292 
1294 {
1295  struct audiohook_volume *audiohook_volume = NULL;
1296 
1297  /* Attempt to find the audiohook volume information, but only create it if we are not setting the adjustment value to zero */
1298  if (!(audiohook_volume = audiohook_volume_get(chan, (volume ? 1 : 0)))) {
1299  return -1;
1300  }
1301 
1302  /* Now based on the direction set the proper value */
1303  if (direction == AST_AUDIOHOOK_DIRECTION_READ || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
1304  audiohook_volume->read_adjustment = volume;
1305  }
1306  if (direction == AST_AUDIOHOOK_DIRECTION_WRITE || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
1307  audiohook_volume->write_adjustment = volume;
1308  }
1309 
1310  return 0;
1311 }
1312 
1314 {
1315  struct audiohook_volume *audiohook_volume = NULL;
1316  int adjustment = 0;
1317 
1318  /* Attempt to find the audiohook volume information, but do not create it as we only want to look at the values */
1319  if (!(audiohook_volume = audiohook_volume_get(chan, 0))) {
1320  return 0;
1321  }
1322 
1323  /* Grab the adjustment value based on direction given */
1324  if (direction == AST_AUDIOHOOK_DIRECTION_READ) {
1325  adjustment = audiohook_volume->read_adjustment;
1326  } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) {
1327  adjustment = audiohook_volume->write_adjustment;
1328  }
1329 
1330  return adjustment;
1331 }
1332 
1334 {
1335  struct audiohook_volume *audiohook_volume = NULL;
1336 
1337  /* Attempt to find the audiohook volume information, and create an audiohook if none exists */
1338  if (!(audiohook_volume = audiohook_volume_get(chan, 1))) {
1339  return -1;
1340  }
1341 
1342  /* Based on the direction change the specific adjustment value */
1343  if (direction == AST_AUDIOHOOK_DIRECTION_READ || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
1344  audiohook_volume->read_adjustment += volume;
1345  }
1346  if (direction == AST_AUDIOHOOK_DIRECTION_WRITE || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
1347  audiohook_volume->write_adjustment += volume;
1348  }
1349 
1350  return 0;
1351 }
1352 
1353 int ast_audiohook_set_mute(struct ast_channel *chan, const char *source, enum ast_audiohook_flags flag, int clear)
1354 {
1355  struct ast_audiohook *audiohook = NULL;
1356 
1357  ast_channel_lock(chan);
1358 
1359  /* Ensure the channel has audiohooks on it */
1360  if (!ast_channel_audiohooks(chan)) {
1361  ast_channel_unlock(chan);
1362  return -1;
1363  }
1364 
1365  audiohook = find_audiohook_by_source(ast_channel_audiohooks(chan), source);
1366 
1367  if (audiohook) {
1368  if (clear) {
1369  ast_clear_flag(audiohook, flag);
1370  } else {
1371  ast_set_flag(audiohook, flag);
1372  }
1373  }
1374 
1375  ast_channel_unlock(chan);
1376 
1377  return (audiohook ? 0 : -1);
1378 }
1379 
1380 int ast_audiohook_set_mute_all(struct ast_channel *chan, const char *source, enum ast_audiohook_flags flag, int clearmute)
1381 {
1382  struct ast_audiohook *audiohook = NULL;
1383  int count = 0;
1384 
1385  ast_channel_lock(chan);
1386 
1387  if (!ast_channel_audiohooks(chan)) {
1388  ast_channel_unlock(chan);
1389  return -1;
1390  }
1391 
1392  AST_LIST_TRAVERSE(&ast_channel_audiohooks(chan)->spy_list, audiohook, list) {
1393  if (!strcasecmp(audiohook->source, source)) {
1394  count++;
1395  if (clearmute) {
1396  ast_clear_flag(audiohook, flag);
1397  } else {
1398  ast_set_flag(audiohook, flag);
1399  }
1400  }
1401  }
1402 
1403  ast_test_suite_event_notify("AUDIOHOOK_GROUP_MUTE_TOGGLE", "Channel: %s\r\nSource: %s\r\nCount: %d\r\n",
1404  ast_channel_name(chan), source, count);
1405 
1406  ast_channel_unlock(chan);
1407 
1408  return count;
1409 }
struct ast_audiohook audiohook
Definition: audiohook.c:1184
const char * type
Definition: datastore.h:32
Audiohook volume adjustment structure.
Definition: audiohook.c:1183
int ast_audiohook_set_mute_all(struct ast_channel *chan, const char *source, enum ast_audiohook_flags flag, int clearmute)
Mute frames read from or written for all audiohooks on a channel.
Definition: audiohook.c:1380
Main Channel structure associated with a channel.
#define ast_frdup(fr)
Copies a frame.
struct ast_slinfactory write_factory
Definition: audiohook.h:113
ast_audiohook_flags
Definition: audiohook.h:54
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
int ast_audiohook_volume_set(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume)
Adjust the volume on frames read from or written to a channel.
Definition: audiohook.c:1293
static void audiohook_volume_destroy(void *data)
Callback used to destroy the audiohook volume datastore.
Definition: audiohook.c:1192
enum ast_audiohook_type type
Definition: audiohook.h:107
void ast_slinfactory_flush(struct ast_slinfactory *sf)
Flush the contents of a slinfactory.
Definition: slinfactory.c:204
int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source, enum ast_audiohook_init_flags init_flags)
Initialize an audiohook structure.
Definition: audiohook.c:100
static struct ast_frame * audio_audiohook_write_list(struct ast_channel *chan, struct ast_audiohook_list *audiohook_list, enum ast_audiohook_direction direction, struct ast_frame *frame)
Pass an AUDIO frame off to be handled by the audiohook core.
Definition: audiohook.c:914
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition: audiohook.c:484
int list_internal_samp_rate
Definition: audiohook.c:61
ast_audiohook_init_flags
Definition: audiohook.h:71
Support for translation of data formats. translate.c.
int ast_audiohook_volume_get(struct ast_channel *chan, enum ast_audiohook_direction direction)
Retrieve the volume adjustment value on frames read from or written to a channel. ...
Definition: audiohook.c:1313
void ast_audiohook_update_status(struct ast_audiohook *audiohook, enum ast_audiohook_status status)
Update audiohook's status.
Definition: audiohook.c:540
Audiohooks Architecture.
int ast_audiohook_write_frame(struct ast_audiohook *audiohook, enum ast_audiohook_direction direction, struct ast_frame *frame)
Writes a frame into the audiohook structure.
Definition: audiohook.c:167
Test Framework API.
int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f)
Feed audio into a slinfactory.
Definition: slinfactory.c:77
Structure for a data store type.
Definition: datastore.h:31
static struct audiohook_volume * audiohook_volume_get(struct ast_channel *chan, int create)
Helper function which finds and optionally creates an audiohook_volume_datastore datastore on a chann...
Definition: audiohook.c:1258
Definition of a media format.
Definition: format.c:43
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
ast_mutex_t lock
Definition: audiohook.h:105
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
struct ast_frame * ast_translate(struct ast_trans_pvt *tr, struct ast_frame *f, int consume)
translates one or more frames Apply an input frame into the translator and receive zero or one output...
Definition: translate.c:566
static const struct ast_datastore_info audiohook_volume_datastore
Datastore used to store audiohook volume information.
Definition: audiohook.c:1206
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
Structure for a data store object.
Definition: datastore.h:64
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2399
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:856
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
struct ast_format * format
Definition: audiohook.h:116
unsigned int ast_slinfactory_available(const struct ast_slinfactory *sf)
Retrieve number of samples currently in a slinfactory.
Definition: slinfactory.c:199
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
static struct ast_frame * dtmf_audiohook_write_list(struct ast_channel *chan, struct ast_audiohook_list *audiohook_list, enum ast_audiohook_direction direction, struct ast_frame *frame)
Pass a DTMF frame off to be handled by the audiohook core.
Definition: audiohook.c:758
struct ast_frame_subclass subclass
void ast_audiohook_detach_list(struct ast_audiohook_list *audiohook_list)
Detach audiohooks from list and destroy said list.
Definition: audiohook.c:565
Utility functions.
int ast_channel_audiohook_count_by_source(struct ast_channel *chan, const char *source, enum ast_audiohook_type type)
Find out how many audiohooks from a certain source exist on a given channel, regardless of status...
Definition: audiohook.c:1109
#define AST_AUDIOHOOK_LONG_QUEUE_TOLERANCE
Definition: audiohook.c:46
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition: audiohook.c:124
#define AST_AUDIOHOOK_SYNC_TOLERANCE
Definition: audiohook.c:44
ast_audiohook_manipulate_callback manipulate_callback
Definition: audiohook.h:118
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
Definition: audiohook.h:318
static struct ast_audiohook * find_audiohook_by_source(struct ast_audiohook_list *audiohook_list, const char *source)
find an audiohook based on its source
Definition: audiohook.c:612
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition: format.c:201
struct ast_trans_pvt * ast_translator_build_path(struct ast_format *dest, struct ast_format *source)
Builds a translator path Build a path (possibly NULL) from source to dest.
Definition: translate.c:486
General Asterisk PBX channel definitions.
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
Definition: audiohook.c:550
void ast_audiohook_move_by_source(struct ast_channel *old_chan, struct ast_channel *new_chan, const char *source)
Move an audiohook from one channel to a new one.
Definition: audiohook.c:656
int ast_audiohook_set_mute(struct ast_channel *chan, const char *source, enum ast_audiohook_flags flag, int clear)
Mute frames read from or written to a channel.
Definition: audiohook.c:1353
enum ast_audiohook_init_flags init_flags
Definition: audiohook.h:109
struct ast_frame * ast_audiohook_write_list(struct ast_channel *chan, struct ast_audiohook_list *audiohook_list, enum ast_audiohook_direction direction, struct ast_frame *frame)
Pass a frame off to be handled by the audiohook core.
Definition: audiohook.c:1079
ast_audiohook_type
Definition: audiohook.h:35
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
Asterisk internal frame definitions.
struct timeval ast_samp2tv(unsigned int _nsamp, unsigned int _rate)
Returns a timeval corresponding to the duration of n samples at rate r. Useful to convert samples to ...
Definition: time.h:282
struct ast_trans_pvt * trans_pvt
Definition: audiohook.h:117
#define ast_debug(level,...)
Log a DEBUG message.
void ast_channel_set_unbridged_nolock(struct ast_channel *chan, int value)
Variant of ast_channel_set_unbridged. Use this if the channel is already locked prior to calling...
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
enum ast_audiohook_direction direction
Definition: audiohook.h:121
void ast_audiohook_trigger_wait(struct ast_audiohook *audiohook)
Wait for audiohook trigger to be triggered.
Definition: audiohook.c:1094
void ast_slinfactory_destroy(struct ast_slinfactory *sf)
Destroy the contents of a slinfactory.
Definition: slinfactory.c:58
unsigned int hook_internal_samp_rate
Definition: audiohook.h:120
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:225
int ast_slinfactory_init_with_format(struct ast_slinfactory *sf, struct ast_format *slin_out)
Initialize a slinfactory.
Definition: slinfactory.c:46
int ast_audiohook_write_list_empty(struct ast_audiohook_list *audiohook_list)
Determine if a audiohook_list is empty or not.
Definition: audiohook.c:1071
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
Default structure for translators, with the basic fields and buffers, all allocated as part of the sa...
Definition: translate.h:213
static void audiohook_list_set_hook_rate(struct ast_audiohook_list *audiohook_list, struct ast_audiohook *audiohook, int *rate)
Set the audiohook's internal sample rate to the audiohook_list's rate, but only when native slin comp...
Definition: audiohook.c:868
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2282
struct ast_frame * ast_audiohook_read_frame_all(struct ast_audiohook *audiohook, size_t samples, struct ast_format *format, struct ast_frame **read_frame, struct ast_frame **write_frame)
Reads a frame in from the audiohook structure in mixed audio mode and copies read and write frame dat...
Definition: audiohook.c:451
#define AST_AUDIOHOOK_SMALL_QUEUE_TOLERANCE
Definition: audiohook.c:45
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition: channel.c:10545
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
const char * source
Definition: audiohook.h:110
A machine to gather up arbitrary frames and convert them to raw slinear on demand.
union ast_frame::@224 data
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
ast_cond_t trigger
Definition: audiohook.h:106
ast_audiohook_direction
Definition: audiohook.h:48
int ast_audiohook_detach_source(struct ast_channel *chan, const char *source)
Detach specified source audiohook from channel.
Definition: audiohook.c:698
struct ast_slinfactory read_factory
Definition: audiohook.h:112
struct ast_audiohook::@185 list
void * data
Definition: datastore.h:66
struct ast_audiohook_options options
Definition: audiohook.h:119
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
int ast_frame_clear(struct ast_frame *frame)
Clear all audio samples from an ast_frame. The frame must be AST_FRAME_VOICE and AST_FORMAT_SLINEAR.
Definition: main/frame.c:859
#define ao2_replace(dst, src)
Replace one object reference with another cleaning up the original.
Definition: astobj2.h:501
struct timeval write_time
Definition: audiohook.h:115
int ast_channel_audiohook_count_by_source_running(struct ast_channel *chan, const char *source, enum ast_audiohook_type type)
Find out how many spies of a certain type exist on a given channel, and are in state running...
Definition: audiohook.c:1149
unsigned int ast_format_get_sample_rate(const struct ast_format *format)
Get the sample rate of a media format.
Definition: format.c:379
Data structure associated with a single frame of data.
int ast_slinfactory_read(struct ast_slinfactory *sf, short *buf, size_t samples)
Read samples from a slinfactory.
Definition: slinfactory.c:145
int ast_audiohook_volume_adjust(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume)
Adjust the volume on frames read from or written to a channel.
Definition: audiohook.c:1333
enum ast_audiohook_status status
Definition: audiohook.h:108
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
enum ast_frame_type frametype
int ast_frame_adjust_volume(struct ast_frame *f, int adjustment)
Adjusts the volume of the audio samples contained in a frame.
Definition: main/frame.c:787
void ast_audiohook_move_all(struct ast_channel *old_chan, struct ast_channel *new_chan)
Move all audiohooks from one channel to another.
Definition: audiohook.c:672
struct ast_format * format
struct ast_frame * ast_audiohook_read_frame(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format)
Reads a frame in from the audiohook structure.
Definition: audiohook.c:446
struct timeval read_time
Definition: audiohook.h:114
ast_audiohook_status
Definition: audiohook.h:41
#define ast_audiohook_lock(ah)
Lock an audiohook.
Definition: audiohook.h:313
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2385
int ast_audiohook_remove(struct ast_channel *chan, struct ast_audiohook *audiohook)
Remove an audiohook from a specified channel.
Definition: audiohook.c:721
struct ast_format * ast_format_cache_get_slin_by_rate(unsigned int rate)
Retrieve the best signed linear format given a sample rate.
Definition: format_cache.c:512
void ast_translator_free_path(struct ast_trans_pvt *tr)
Frees a translator path Frees the given translator path structure.
Definition: translate.c:476
static int audiohook_volume_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
Helper function which actually gets called by audiohooks to perform the adjustment.
Definition: audiohook.c:1219
Media Format Cache API.
int ast_audiohook_set_frame_feed_direction(struct ast_audiohook *audiohook, enum ast_audiohook_direction direction)
Sets direction on audiohook.
Definition: audiohook.c:150