Wed Jan 8 2020 09:49:42

Asterisk developer's documentation


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 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413586 $")
33 
34 #include <signal.h>
35 
36 #include "asterisk/channel.h"
37 #include "asterisk/utils.h"
38 #include "asterisk/lock.h"
39 #include "asterisk/linkedlists.h"
40 #include "asterisk/audiohook.h"
41 #include "asterisk/slinfactory.h"
42 #include "asterisk/frame.h"
43 #include "asterisk/translate.h"
44 
48 };
49 
56 };
57 
58 /*! \brief Initialize an audiohook structure
59  * \param audiohook Audiohook structure
60  * \param type
61  * \param source
62  * \return Returns 0 on success, -1 on failure
63  */
64 int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source)
65 {
66  /* Need to keep the type and source */
67  audiohook->type = type;
68  audiohook->source = source;
69 
70  /* Initialize lock that protects our audiohook */
71  ast_mutex_init(&audiohook->lock);
72  ast_cond_init(&audiohook->trigger, NULL);
73 
74  /* Setup the factories that are needed for this audiohook type */
75  switch (type) {
77  ast_slinfactory_init(&audiohook->read_factory);
78  /* Fall through intentionally */
80  ast_slinfactory_init(&audiohook->write_factory);
81  break;
82  default:
83  break;
84  }
85 
86  /* Since we are just starting out... this audiohook is new */
88 
89  return 0;
90 }
91 
92 /*! \brief Destroys an audiohook structure
93  * \param audiohook Audiohook structure
94  * \return Returns 0 on success, -1 on failure
95  */
96 int ast_audiohook_destroy(struct ast_audiohook *audiohook)
97 {
98  /* Drop the factories used by this audiohook type */
99  switch (audiohook->type) {
102  /* Fall through intentionally */
105  break;
106  default:
107  break;
108  }
109 
110  /* Destroy translation path if present */
111  if (audiohook->trans_pvt)
113 
114  /* Lock and trigger be gone! */
115  ast_cond_destroy(&audiohook->trigger);
116  ast_mutex_destroy(&audiohook->lock);
117 
118  return 0;
119 }
120 
121 /*! \brief Writes a frame into the audiohook structure
122  * \param audiohook Audiohook structure
123  * \param direction Direction the audio frame came from
124  * \param frame Frame to write in
125  * \return Returns 0 on success, -1 on failure
126  */
127 int ast_audiohook_write_frame(struct ast_audiohook *audiohook, enum ast_audiohook_direction direction, struct ast_frame *frame)
128 {
129  struct ast_slinfactory *factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_factory : &audiohook->write_factory);
130  struct ast_slinfactory *other_factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->write_factory : &audiohook->read_factory);
131  struct timeval *rwtime = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_time : &audiohook->write_time), previous_time = *rwtime;
132  int our_factory_samples;
133  int our_factory_ms;
134  int other_factory_samples;
135  int other_factory_ms;
136  int muteme = 0;
137 
138  /* Update last feeding time to be current */
139  *rwtime = ast_tvnow();
140 
141  our_factory_samples = ast_slinfactory_available(factory);
142  our_factory_ms = ast_tvdiff_ms(*rwtime, previous_time) + (our_factory_samples / 8);
143  other_factory_samples = ast_slinfactory_available(other_factory);
144  other_factory_ms = other_factory_samples / 8;
145 
146  if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC) && other_factory_samples && (our_factory_ms - other_factory_ms > AST_AUDIOHOOK_SYNC_TOLERANCE)) {
147  if (option_debug)
148  ast_log(LOG_DEBUG, "Flushing audiohook %p so it remains in sync\n", audiohook);
149  ast_slinfactory_flush(factory);
150  ast_slinfactory_flush(other_factory);
151  }
152 
153  if (ast_test_flag(audiohook, AST_AUDIOHOOK_SMALL_QUEUE) && (our_factory_samples > 640 || other_factory_samples > 640)) {
154  if (option_debug) {
155  ast_log(LOG_DEBUG, "Audiohook %p has stale audio in its factories. Flushing them both\n", audiohook);
156  }
157  ast_slinfactory_flush(factory);
158  ast_slinfactory_flush(other_factory);
159  }
160 
161  /* swap frame data for zeros if mute is required */
162  if ((ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_READ) && (direction == AST_AUDIOHOOK_DIRECTION_READ)) ||
163  (ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_WRITE) && (direction == AST_AUDIOHOOK_DIRECTION_WRITE)) ||
165  muteme = 1;
166  }
167 
168  if (muteme && frame->datalen > 0) {
169  ast_frame_clear(frame);
170  }
171 
172  /* Write frame out to respective factory */
173  ast_slinfactory_feed(factory, frame);
174 
175  /* If we need to notify the respective handler of this audiohook, do so */
177  ast_cond_signal(&audiohook->trigger);
179  ast_cond_signal(&audiohook->trigger);
180  } else if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC)) {
181  ast_cond_signal(&audiohook->trigger);
182  }
183 
184  return 0;
185 }
186 
187 static struct ast_frame *audiohook_read_frame_single(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction)
188 {
189  struct ast_slinfactory *factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_factory : &audiohook->write_factory);
190  int vol = (direction == AST_AUDIOHOOK_DIRECTION_READ ? audiohook->options.read_volume : audiohook->options.write_volume);
191  short buf[samples];
192  struct ast_frame frame = {
194  .subclass.codec = AST_FORMAT_SLINEAR,
195  .data.ptr = buf,
196  .datalen = sizeof(buf),
197  .samples = samples,
198  };
199 
200  /* Ensure the factory is able to give us the samples we want */
201  if (samples > ast_slinfactory_available(factory))
202  return NULL;
203 
204  /* Read data in from factory */
205  if (!ast_slinfactory_read(factory, buf, samples))
206  return NULL;
207 
208  /* If a volume adjustment needs to be applied apply it */
209  if (vol)
210  ast_frame_adjust_volume(&frame, vol);
211 
212  return ast_frdup(&frame);
213 }
214 
215 static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audiohook, size_t samples)
216 {
217  int i = 0, usable_read, usable_write;
218  short buf1[samples], buf2[samples], *read_buf = NULL, *write_buf = NULL, *final_buf = NULL, *data1 = NULL, *data2 = NULL;
219  struct ast_frame frame = {
221  .subclass.codec = AST_FORMAT_SLINEAR,
222  .data.ptr = NULL,
223  .datalen = sizeof(buf1),
224  .samples = samples,
225  };
226 
227  /* Make sure both factories have the required samples */
228  usable_read = (ast_slinfactory_available(&audiohook->read_factory) >= samples ? 1 : 0);
229  usable_write = (ast_slinfactory_available(&audiohook->write_factory) >= samples ? 1 : 0);
230 
231  if (!usable_read && !usable_write) {
232  /* If both factories are unusable bail out */
233  ast_debug(2, "Read factory %p and write factory %p both fail to provide %zu samples\n", &audiohook->read_factory, &audiohook->write_factory, samples);
234  return NULL;
235  }
236 
237  /* If we want to provide only a read factory make sure we aren't waiting for other audio */
238  if (usable_read && !usable_write && (ast_tvdiff_ms(ast_tvnow(), audiohook->write_time) < (samples/8)*2)) {
239  ast_debug(3, "Write factory %p was pretty quick last time, waiting for them.\n", &audiohook->write_factory);
240  return NULL;
241  }
242 
243  /* If we want to provide only a write factory make sure we aren't waiting for other audio */
244  if (usable_write && !usable_read && (ast_tvdiff_ms(ast_tvnow(), audiohook->read_time) < (samples/8)*2)) {
245  ast_debug(3, "Read factory %p was pretty quick last time, waiting for them.\n", &audiohook->read_factory);
246  return NULL;
247  }
248 
249  /* Start with the read factory... if there are enough samples, read them in */
250  if (usable_read) {
251  if (ast_slinfactory_read(&audiohook->read_factory, buf1, samples)) {
252  read_buf = buf1;
253  /* Adjust read volume if need be */
254  if (audiohook->options.read_volume) {
255  int count = 0;
256  short adjust_value = abs(audiohook->options.read_volume);
257  for (count = 0; count < samples; count++) {
258  if (audiohook->options.read_volume > 0)
259  ast_slinear_saturated_multiply(&buf1[count], &adjust_value);
260  else if (audiohook->options.read_volume < 0)
261  ast_slinear_saturated_divide(&buf1[count], &adjust_value);
262  }
263  }
264  }
265  } else if (option_debug > 2)
266  ast_log(LOG_DEBUG, "Failed to get %d samples from read factory %p\n", (int)samples, &audiohook->read_factory);
267 
268  /* Move on to the write factory... if there are enough samples, read them in */
269  if (usable_write) {
270  if (ast_slinfactory_read(&audiohook->write_factory, buf2, samples)) {
271  write_buf = buf2;
272  /* Adjust write volume if need be */
273  if (audiohook->options.write_volume) {
274  int count = 0;
275  short adjust_value = abs(audiohook->options.write_volume);
276  for (count = 0; count < samples; count++) {
277  if (audiohook->options.write_volume > 0)
278  ast_slinear_saturated_multiply(&buf2[count], &adjust_value);
279  else if (audiohook->options.write_volume < 0)
280  ast_slinear_saturated_divide(&buf2[count], &adjust_value);
281  }
282  }
283  }
284  } else if (option_debug > 2)
285  ast_log(LOG_DEBUG, "Failed to get %d samples from write factory %p\n", (int)samples, &audiohook->write_factory);
286 
287  /* Basically we figure out which buffer to use... and if mixing can be done here */
288  if (!read_buf && !write_buf)
289  return NULL;
290  else if (read_buf && write_buf) {
291  for (i = 0, data1 = read_buf, data2 = write_buf; i < samples; i++, data1++, data2++)
292  ast_slinear_saturated_add(data1, data2);
293  final_buf = buf1;
294  } else if (read_buf)
295  final_buf = buf1;
296  else if (write_buf)
297  final_buf = buf2;
298 
299  /* Make the final buffer part of the frame, so it gets duplicated fine */
300  frame.data.ptr = final_buf;
301 
302  /* Yahoo, a combined copy of the audio! */
303  return ast_frdup(&frame);
304 }
305 
306 /*! \brief Reads a frame in from the audiohook structure
307  * \param audiohook Audiohook structure
308  * \param samples Number of samples wanted
309  * \param direction Direction the audio frame came from
310  * \param format Format of frame remote side wants back
311  * \return Returns frame on success, NULL on failure
312  */
313 struct ast_frame *ast_audiohook_read_frame(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, format_t format)
314 {
315  struct ast_frame *read_frame = NULL, *final_frame = NULL;
316 
317  if (!(read_frame = (direction == AST_AUDIOHOOK_DIRECTION_BOTH ? audiohook_read_frame_both(audiohook, samples) : audiohook_read_frame_single(audiohook, samples, direction))))
318  return NULL;
319 
320  /* If they don't want signed linear back out, we'll have to send it through the translation path */
321  if (format != AST_FORMAT_SLINEAR) {
322  /* Rebuild translation path if different format then previously */
323  if (audiohook->format != format) {
324  if (audiohook->trans_pvt) {
326  audiohook->trans_pvt = NULL;
327  }
328  /* 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 */
329  if (!(audiohook->trans_pvt = ast_translator_build_path(format, AST_FORMAT_SLINEAR))) {
330  ast_frfree(read_frame);
331  return NULL;
332  }
333  }
334  /* Convert to requested format, and allow the read in frame to be freed */
335  final_frame = ast_translate(audiohook->trans_pvt, read_frame, 1);
336  } else {
337  final_frame = read_frame;
338  }
339 
340  return final_frame;
341 }
342 
343 /*! \brief Attach audiohook to channel
344  * \param chan Channel
345  * \param audiohook Audiohook structure
346  * \return Returns 0 on success, -1 on failure
347  */
348 int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
349 {
350  ast_channel_lock(chan);
351 
352  if (!chan->audiohooks) {
353  /* Whoops... allocate a new structure */
354  if (!(chan->audiohooks = ast_calloc(1, sizeof(*chan->audiohooks)))) {
355  ast_channel_unlock(chan);
356  return -1;
357  }
361  }
362 
363  /* Drop into respective list */
364  if (audiohook->type == AST_AUDIOHOOK_TYPE_SPY)
365  AST_LIST_INSERT_TAIL(&chan->audiohooks->spy_list, audiohook, list);
366  else if (audiohook->type == AST_AUDIOHOOK_TYPE_WHISPER)
367  AST_LIST_INSERT_TAIL(&chan->audiohooks->whisper_list, audiohook, list);
368  else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE)
369  AST_LIST_INSERT_TAIL(&chan->audiohooks->manipulate_list, audiohook, list);
370 
371  /* Change status over to running since it is now attached */
373 
374  ast_channel_unlock(chan);
375 
376  return 0;
377 }
378 
379 /*! \brief Update audiohook's status
380  * \param audiohook Audiohook structure
381  * \param status Audiohook status enum
382  *
383  * \note once status is updated to DONE, this function can not be used to set the
384  * status back to any other setting. Setting DONE effectively locks the status as such.
385  */
386 
388 {
389  ast_audiohook_lock(audiohook);
390  if (audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
391  audiohook->status = status;
392  ast_cond_signal(&audiohook->trigger);
393  }
394  ast_audiohook_unlock(audiohook);
395 }
396 
397 /*! \brief Detach audiohook from channel
398  * \param audiohook Audiohook structure
399  * \return Returns 0 on success, -1 on failure
400  */
401 int ast_audiohook_detach(struct ast_audiohook *audiohook)
402 {
403  if (audiohook->status == AST_AUDIOHOOK_STATUS_NEW || audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
404  return 0;
405 
407 
408  while (audiohook->status != AST_AUDIOHOOK_STATUS_DONE)
409  ast_audiohook_trigger_wait(audiohook);
410 
411  return 0;
412 }
413 
414 /*! \brief Detach audiohooks from list and destroy said list
415  * \param audiohook_list List of audiohooks
416  * \return Returns 0 on success, -1 on failure
417  */
419 {
420  int i = 0;
421  struct ast_audiohook *audiohook = NULL;
422 
423  /* Drop any spies */
424  while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->spy_list, list))) {
426  }
427 
428  /* Drop any whispering sources */
429  while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->whisper_list, list))) {
431  }
432 
433  /* Drop any manipulaters */
434  while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->manipulate_list, list))) {
436  audiohook->manipulate_callback(audiohook, NULL, NULL, 0);
437  }
438 
439  /* Drop translation paths if present */
440  for (i = 0; i < 2; i++) {
441  if (audiohook_list->in_translate[i].trans_pvt)
442  ast_translator_free_path(audiohook_list->in_translate[i].trans_pvt);
443  if (audiohook_list->out_translate[i].trans_pvt)
445  }
446 
447  /* Free ourselves */
448  ast_free(audiohook_list);
449 
450  return 0;
451 }
452 
453 /*! \brief find an audiohook based on its source
454  * \param audiohook_list The list of audiohooks to search in
455  * \param source The source of the audiohook we wish to find
456  * \return Return the corresponding audiohook or NULL if it cannot be found.
457  */
458 static struct ast_audiohook *find_audiohook_by_source(struct ast_audiohook_list *audiohook_list, const char *source)
459 {
460  struct ast_audiohook *audiohook = NULL;
461 
462  AST_LIST_TRAVERSE(&audiohook_list->spy_list, audiohook, list) {
463  if (!strcasecmp(audiohook->source, source))
464  return audiohook;
465  }
466 
467  AST_LIST_TRAVERSE(&audiohook_list->whisper_list, audiohook, list) {
468  if (!strcasecmp(audiohook->source, source))
469  return audiohook;
470  }
471 
472  AST_LIST_TRAVERSE(&audiohook_list->manipulate_list, audiohook, list) {
473  if (!strcasecmp(audiohook->source, source))
474  return audiohook;
475  }
476 
477  return NULL;
478 }
479 
480 void ast_audiohook_move_by_source(struct ast_channel *old_chan, struct ast_channel *new_chan, const char *source)
481 {
482  struct ast_audiohook *audiohook;
483  enum ast_audiohook_status oldstatus;
484 
485  if (!old_chan->audiohooks || !(audiohook = find_audiohook_by_source(old_chan->audiohooks, source))) {
486  return;
487  }
488 
489  /* By locking both channels and the audiohook, we can assure that
490  * another thread will not have a chance to read the audiohook's status
491  * as done, even though ast_audiohook_remove signals the trigger
492  * condition.
493  */
494  ast_audiohook_lock(audiohook);
495  oldstatus = audiohook->status;
496 
497  ast_audiohook_remove(old_chan, audiohook);
498  ast_audiohook_attach(new_chan, audiohook);
499 
500  audiohook->status = oldstatus;
501  ast_audiohook_unlock(audiohook);
502 }
503 
504 /*! \brief Detach specified source audiohook from channel
505  * \param chan Channel to detach from
506  * \param source Name of source to detach
507  * \return Returns 0 on success, -1 on failure
508  */
509 int ast_audiohook_detach_source(struct ast_channel *chan, const char *source)
510 {
511  struct ast_audiohook *audiohook = NULL;
512 
513  ast_channel_lock(chan);
514 
515  /* Ensure the channel has audiohooks on it */
516  if (!chan->audiohooks) {
517  ast_channel_unlock(chan);
518  return -1;
519  }
520 
521  audiohook = find_audiohook_by_source(chan->audiohooks, source);
522 
523  ast_channel_unlock(chan);
524 
525  if (audiohook && audiohook->status != AST_AUDIOHOOK_STATUS_DONE)
527 
528  return (audiohook ? 0 : -1);
529 }
530 
531 /*!
532  * \brief Remove an audiohook from a specified channel
533  *
534  * \param chan Channel to remove from
535  * \param audiohook Audiohook to remove
536  *
537  * \return Returns 0 on success, -1 on failure
538  *
539  * \note The channel does not need to be locked before calling this function
540  */
541 int ast_audiohook_remove(struct ast_channel *chan, struct ast_audiohook *audiohook)
542 {
543  ast_channel_lock(chan);
544 
545  if (!chan->audiohooks) {
546  ast_channel_unlock(chan);
547  return -1;
548  }
549 
550  if (audiohook->type == AST_AUDIOHOOK_TYPE_SPY)
551  AST_LIST_REMOVE(&chan->audiohooks->spy_list, audiohook, list);
552  else if (audiohook->type == AST_AUDIOHOOK_TYPE_WHISPER)
553  AST_LIST_REMOVE(&chan->audiohooks->whisper_list, audiohook, list);
554  else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE)
555  AST_LIST_REMOVE(&chan->audiohooks->manipulate_list, audiohook, list);
556 
558 
559  ast_channel_unlock(chan);
560 
561  return 0;
562 }
563 
564 /*! \brief Pass a DTMF frame off to be handled by the audiohook core
565  * \param chan Channel that the list is coming off of
566  * \param audiohook_list List of audiohooks
567  * \param direction Direction frame is coming in from
568  * \param frame The frame itself
569  * \return Return frame on success, NULL on failure
570  */
571 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)
572 {
573  struct ast_audiohook *audiohook = NULL;
574 
575  AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
576  ast_audiohook_lock(audiohook);
577  if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
580  ast_audiohook_unlock(audiohook);
581  audiohook->manipulate_callback(audiohook, NULL, NULL, 0);
582  continue;
583  }
584  if (ast_test_flag(audiohook, AST_AUDIOHOOK_WANTS_DTMF))
585  audiohook->manipulate_callback(audiohook, chan, frame, direction);
586  ast_audiohook_unlock(audiohook);
587  }
589 
590  return frame;
591 }
592 
593 /*!
594  * \brief Pass an AUDIO frame off to be handled by the audiohook core
595  *
596  * \details
597  * This function has 3 ast_frames and 3 parts to handle each. At the beginning of this
598  * function all 3 frames, start_frame, middle_frame, and end_frame point to the initial
599  * input frame.
600  *
601  * Part_1: Translate the start_frame into SLINEAR audio if it is not already in that
602  * format. The result of this part is middle_frame is guaranteed to be in
603  * SLINEAR format for Part_2.
604  * Part_2: Send middle_frame off to spies and manipulators. At this point middle_frame is
605  * either a new frame as result of the translation, or points directly to the start_frame
606  * because no translation to SLINEAR audio was required. The result of this part
607  * is end_frame will be updated to point to middle_frame if any audiohook manipulation
608  * took place.
609  * Part_3: Translate end_frame's audio back into the format of start frame if necessary.
610  * At this point if middle_frame != end_frame, we are guaranteed that no manipulation
611  * took place and middle_frame can be freed as it was translated... If middle_frame was
612  * not translated and still pointed to start_frame, it would be equal to end_frame as well
613  * regardless if manipulation took place which would not result in this free. The result
614  * of this part is end_frame is guaranteed to be the format of start_frame for the return.
615  *
616  * \param chan Channel that the list is coming off of
617  * \param audiohook_list List of audiohooks
618  * \param direction Direction frame is coming in from
619  * \param frame The frame itself
620  * \return Return frame on success, NULL on failure
621  */
622 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)
623 {
624  struct ast_audiohook_translate *in_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook_list->in_translate[0] : &audiohook_list->in_translate[1]);
625  struct ast_audiohook_translate *out_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook_list->out_translate[0] : &audiohook_list->out_translate[1]);
626  struct ast_frame *start_frame = frame, *middle_frame = frame, *end_frame = frame;
627  struct ast_audiohook *audiohook = NULL;
628  int samples = frame->samples;
629 
630  /* ---Part_1. translate start_frame to SLINEAR if necessary. */
631  /* If the frame coming in is not signed linear we have to send it through the in_translate path */
632  if (frame->subclass.codec != AST_FORMAT_SLINEAR) {
633  if (in_translate->format != frame->subclass.codec) {
634  if (in_translate->trans_pvt)
635  ast_translator_free_path(in_translate->trans_pvt);
636  if (!(in_translate->trans_pvt = ast_translator_build_path(AST_FORMAT_SLINEAR, frame->subclass.codec)))
637  return frame;
638  in_translate->format = frame->subclass.codec;
639  }
640  if (!(middle_frame = ast_translate(in_translate->trans_pvt, frame, 0)))
641  return frame;
642  samples = middle_frame->samples;
643  }
644 
645  /* ---Part_2: Send middle_frame to spy and manipulator lists. middle_frame is guaranteed to be SLINEAR here.*/
646  /* Queue up signed linear frame to each spy */
647  AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->spy_list, audiohook, list) {
648  ast_audiohook_lock(audiohook);
649  if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
652  ast_audiohook_unlock(audiohook);
653  continue;
654  }
655  ast_audiohook_write_frame(audiohook, direction, middle_frame);
656  ast_audiohook_unlock(audiohook);
657  }
659 
660  /* If this frame is being written out to the channel then we need to use whisper sources */
661  if (direction == AST_AUDIOHOOK_DIRECTION_WRITE && !AST_LIST_EMPTY(&audiohook_list->whisper_list)) {
662  int i = 0;
663  short read_buf[samples], combine_buf[samples], *data1 = NULL, *data2 = NULL;
664  memset(&combine_buf, 0, sizeof(combine_buf));
665  AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->whisper_list, audiohook, list) {
666  ast_audiohook_lock(audiohook);
667  if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
670  ast_audiohook_unlock(audiohook);
671  continue;
672  }
673  if (ast_slinfactory_available(&audiohook->write_factory) >= samples && ast_slinfactory_read(&audiohook->write_factory, read_buf, samples)) {
674  /* Take audio from this whisper source and combine it into our main buffer */
675  for (i = 0, data1 = combine_buf, data2 = read_buf; i < samples; i++, data1++, data2++)
676  ast_slinear_saturated_add(data1, data2);
677  }
678  ast_audiohook_unlock(audiohook);
679  }
681  /* We take all of the combined whisper sources and combine them into the audio being written out */
682  for (i = 0, data1 = middle_frame->data.ptr, data2 = combine_buf; i < samples; i++, data1++, data2++)
683  ast_slinear_saturated_add(data1, data2);
684  end_frame = middle_frame;
685  }
686 
687  /* Pass off frame to manipulate audiohooks */
688  if (!AST_LIST_EMPTY(&audiohook_list->manipulate_list)) {
689  AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
690  ast_audiohook_lock(audiohook);
691  if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
694  ast_audiohook_unlock(audiohook);
695  /* We basically drop all of our links to the manipulate audiohook and prod it to do it's own destructive things */
696  audiohook->manipulate_callback(audiohook, chan, NULL, direction);
697  continue;
698  }
699  /* Feed in frame to manipulation. */
700  if (audiohook->manipulate_callback(audiohook, chan, middle_frame, direction)) {
701  /* XXX IGNORE FAILURE */
702 
703  /* If the manipulation fails then the frame will be returned in its original state.
704  * Since there are potentially more manipulator callbacks in the list, no action should
705  * be taken here to exit early. */
706  }
707  ast_audiohook_unlock(audiohook);
708  }
710  end_frame = middle_frame;
711  }
712 
713  /* ---Part_3: Decide what to do with the end_frame (whether to transcode or not) */
714  if (middle_frame == end_frame) {
715  /* Middle frame was modified and became the end frame... let's see if we need to transcode */
716  if (end_frame->subclass.codec != start_frame->subclass.codec) {
717  if (out_translate->format != start_frame->subclass.codec) {
718  if (out_translate->trans_pvt)
719  ast_translator_free_path(out_translate->trans_pvt);
720  if (!(out_translate->trans_pvt = ast_translator_build_path(start_frame->subclass.codec, AST_FORMAT_SLINEAR))) {
721  /* We can't transcode this... drop our middle frame and return the original */
722  ast_frfree(middle_frame);
723  return start_frame;
724  }
725  out_translate->format = start_frame->subclass.codec;
726  }
727  /* Transcode from our middle (signed linear) frame to new format of the frame that came in */
728  if (!(end_frame = ast_translate(out_translate->trans_pvt, middle_frame, 0))) {
729  /* Failed to transcode the frame... drop it and return the original */
730  ast_frfree(middle_frame);
731  return start_frame;
732  }
733  /* Here's the scoop... middle frame is no longer of use to us */
734  ast_frfree(middle_frame);
735  }
736  } else {
737  /* No frame was modified, we can just drop our middle frame and pass the frame we got in out */
738  ast_frfree(middle_frame);
739  }
740 
741  return end_frame;
742 }
743 
745 {
746  if (AST_LIST_EMPTY(&audiohook_list->spy_list) &&
747  AST_LIST_EMPTY(&audiohook_list->whisper_list) &&
748  AST_LIST_EMPTY(&audiohook_list->manipulate_list)) {
749 
750  return 1;
751  }
752  return 0;
753 }
754 
755 /*! \brief Pass a frame off to be handled by the audiohook core
756  * \param chan Channel that the list is coming off of
757  * \param audiohook_list List of audiohooks
758  * \param direction Direction frame is coming in from
759  * \param frame The frame itself
760  * \return Return frame on success, NULL on failure
761  */
762 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)
763 {
764  /* Pass off frame to it's respective list write function */
765  if (frame->frametype == AST_FRAME_VOICE)
766  return audio_audiohook_write_list(chan, audiohook_list, direction, frame);
767  else if (frame->frametype == AST_FRAME_DTMF)
768  return dtmf_audiohook_write_list(chan, audiohook_list, direction, frame);
769  else
770  return frame;
771 }
772 
773 /*! \brief Wait for audiohook trigger to be triggered
774  * \param audiohook Audiohook to wait on
775  */
777 {
778  struct timeval wait;
779  struct timespec ts;
780 
781  wait = ast_tvadd(ast_tvnow(), ast_samp2tv(50000, 1000));
782  ts.tv_sec = wait.tv_sec;
783  ts.tv_nsec = wait.tv_usec * 1000;
784 
785  ast_cond_timedwait(&audiohook->trigger, &audiohook->lock, &ts);
786 
787  return;
788 }
789 
790 /* Count number of channel audiohooks by type, regardless of type */
792 {
793  int count = 0;
794  struct ast_audiohook *ah = NULL;
795 
796  if (!chan->audiohooks)
797  return -1;
798 
799  switch (type) {
801  AST_LIST_TRAVERSE(&chan->audiohooks->spy_list, ah, list) {
802  if (!strcmp(ah->source, source)) {
803  count++;
804  }
805  }
806  break;
809  if (!strcmp(ah->source, source)) {
810  count++;
811  }
812  }
813  break;
816  if (!strcmp(ah->source, source)) {
817  count++;
818  }
819  }
820  break;
821  default:
822  ast_log(LOG_DEBUG, "Invalid audiohook type supplied, (%u)\n", type);
823  return -1;
824  }
825 
826  return count;
827 }
828 
829 /* Count number of channel audiohooks by type that are running */
831 {
832  int count = 0;
833  struct ast_audiohook *ah = NULL;
834  if (!chan->audiohooks)
835  return -1;
836 
837  switch (type) {
839  AST_LIST_TRAVERSE(&chan->audiohooks->spy_list, ah, list) {
840  if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
841  count++;
842  }
843  break;
846  if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
847  count++;
848  }
849  break;
852  if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
853  count++;
854  }
855  break;
856  default:
857  ast_log(LOG_DEBUG, "Invalid audiohook type supplied, (%u)\n", type);
858  return -1;
859  }
860  return count;
861 }
862 
863 /*! \brief Audiohook volume adjustment structure */
865  struct ast_audiohook audiohook; /*!< Audiohook attached to the channel */
866  int read_adjustment; /*!< Value to adjust frames read from the channel by */
867  int write_adjustment; /*!< Value to adjust frames written to the channel by */
868 };
869 
870 /*! \brief Callback used to destroy the audiohook volume datastore
871  * \param data Volume information structure
872  * \return Returns nothing
873  */
874 static void audiohook_volume_destroy(void *data)
875 {
876  struct audiohook_volume *audiohook_volume = data;
877 
878  /* Destroy the audiohook as it is no longer in use */
879  ast_audiohook_destroy(&audiohook_volume->audiohook);
880 
881  /* Finally free ourselves, we are of no more use */
882  ast_free(audiohook_volume);
883 
884  return;
885 }
886 
887 /*! \brief Datastore used to store audiohook volume information */
889  .type = "Volume",
890  .destroy = audiohook_volume_destroy,
891 };
892 
893 /*! \brief Helper function which actually gets called by audiohooks to perform the adjustment
894  * \param audiohook Audiohook attached to the channel
895  * \param chan Channel we are attached to
896  * \param frame Frame of audio we want to manipulate
897  * \param direction Direction the audio came in from
898  * \return Returns 0 on success, -1 on failure
899  */
900 static int audiohook_volume_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
901 {
902  struct ast_datastore *datastore = NULL;
903  struct audiohook_volume *audiohook_volume = NULL;
904  int *gain = NULL;
905 
906  /* If the audiohook is shutting down don't even bother */
907  if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) {
908  return 0;
909  }
910 
911  /* Try to find the datastore containg adjustment information, if we can't just bail out */
912  if (!(datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) {
913  return 0;
914  }
915 
916  audiohook_volume = datastore->data;
917 
918  /* Based on direction grab the appropriate adjustment value */
919  if (direction == AST_AUDIOHOOK_DIRECTION_READ) {
920  gain = &audiohook_volume->read_adjustment;
921  } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) {
922  gain = &audiohook_volume->write_adjustment;
923  }
924 
925  /* If an adjustment value is present modify the frame */
926  if (gain && *gain) {
927  ast_frame_adjust_volume(frame, *gain);
928  }
929 
930  return 0;
931 }
932 
933 /*! \brief Helper function which finds and optionally creates an audiohook_volume_datastore datastore on a channel
934  * \param chan Channel to look on
935  * \param create Whether to create the datastore if not found
936  * \return Returns audiohook_volume structure on success, NULL on failure
937  */
938 static struct audiohook_volume *audiohook_volume_get(struct ast_channel *chan, int create)
939 {
940  struct ast_datastore *datastore = NULL;
941  struct audiohook_volume *audiohook_volume = NULL;
942 
943  /* If we are able to find the datastore return the contents (which is actually an audiohook_volume structure) */
944  if ((datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) {
945  return datastore->data;
946  }
947 
948  /* 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 */
949  if (!create || !(datastore = ast_datastore_alloc(&audiohook_volume_datastore, NULL))) {
950  return NULL;
951  }
952 
953  /* Create a new audiohook_volume structure to contain our adjustments and audiohook */
954  if (!(audiohook_volume = ast_calloc(1, sizeof(*audiohook_volume)))) {
955  ast_datastore_free(datastore);
956  return NULL;
957  }
958 
959  /* Setup our audiohook structure so we can manipulate the audio */
960  ast_audiohook_init(&audiohook_volume->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Volume");
962 
963  /* Attach the audiohook_volume blob to the datastore and attach to the channel */
964  datastore->data = audiohook_volume;
965  ast_channel_datastore_add(chan, datastore);
966 
967  /* All is well... put the audiohook into motion */
968  ast_audiohook_attach(chan, &audiohook_volume->audiohook);
969 
970  return audiohook_volume;
971 }
972 
973 /*! \brief Adjust the volume on frames read from or written to a channel
974  * \param chan Channel to muck with
975  * \param direction Direction to set on
976  * \param volume Value to adjust the volume by
977  * \return Returns 0 on success, -1 on failure
978  */
980 {
981  struct audiohook_volume *audiohook_volume = NULL;
982 
983  /* Attempt to find the audiohook volume information, but only create it if we are not setting the adjustment value to zero */
984  if (!(audiohook_volume = audiohook_volume_get(chan, (volume ? 1 : 0)))) {
985  return -1;
986  }
987 
988  /* Now based on the direction set the proper value */
989  if (direction == AST_AUDIOHOOK_DIRECTION_READ || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
990  audiohook_volume->read_adjustment = volume;
991  }
992  if (direction == AST_AUDIOHOOK_DIRECTION_WRITE || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
993  audiohook_volume->write_adjustment = volume;
994  }
995 
996  return 0;
997 }
998 
999 /*! \brief Retrieve the volume adjustment value on frames read from or written to a channel
1000  * \param chan Channel to retrieve volume adjustment from
1001  * \param direction Direction to retrieve
1002  * \return Returns adjustment value
1003  */
1005 {
1006  struct audiohook_volume *audiohook_volume = NULL;
1007  int adjustment = 0;
1008 
1009  /* Attempt to find the audiohook volume information, but do not create it as we only want to look at the values */
1010  if (!(audiohook_volume = audiohook_volume_get(chan, 0))) {
1011  return 0;
1012  }
1013 
1014  /* Grab the adjustment value based on direction given */
1015  if (direction == AST_AUDIOHOOK_DIRECTION_READ) {
1016  adjustment = audiohook_volume->read_adjustment;
1017  } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) {
1018  adjustment = audiohook_volume->write_adjustment;
1019  }
1020 
1021  return adjustment;
1022 }
1023 
1024 /*! \brief Adjust the volume on frames read from or written to a channel
1025  * \param chan Channel to muck with
1026  * \param direction Direction to increase
1027  * \param volume Value to adjust the adjustment by
1028  * \return Returns 0 on success, -1 on failure
1029  */
1031 {
1032  struct audiohook_volume *audiohook_volume = NULL;
1033 
1034  /* Attempt to find the audiohook volume information, and create an audiohook if none exists */
1035  if (!(audiohook_volume = audiohook_volume_get(chan, 1))) {
1036  return -1;
1037  }
1038 
1039  /* Based on the direction change the specific adjustment value */
1040  if (direction == AST_AUDIOHOOK_DIRECTION_READ || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
1041  audiohook_volume->read_adjustment += volume;
1042  }
1043  if (direction == AST_AUDIOHOOK_DIRECTION_WRITE || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
1044  audiohook_volume->write_adjustment += volume;
1045  }
1046 
1047  return 0;
1048 }
1049 
1050 /*! \brief Mute frames read from or written to a channel
1051  * \param chan Channel to muck with
1052  * \param source Type of audiohook
1053  * \param flag which flag to set / clear
1054  * \param clear set or clear
1055  * \return Returns 0 on success, -1 on failure
1056  */
1057 int ast_audiohook_set_mute(struct ast_channel *chan, const char *source, enum ast_audiohook_flags flag, int clear)
1058 {
1059  struct ast_audiohook *audiohook = NULL;
1060 
1061  ast_channel_lock(chan);
1062 
1063  /* Ensure the channel has audiohooks on it */
1064  if (!chan->audiohooks) {
1065  ast_channel_unlock(chan);
1066  return -1;
1067  }
1068 
1069  audiohook = find_audiohook_by_source(chan->audiohooks, source);
1070 
1071  if (audiohook) {
1072  if (clear) {
1073  ast_clear_flag(audiohook, flag);
1074  } else {
1075  ast_set_flag(audiohook, flag);
1076  }
1077  }
1078 
1079  ast_channel_unlock(chan);
1080 
1081  return (audiohook ? 0 : -1);
1082 }
struct ast_audiohook audiohook
Definition: audiohook.c:865
const char * type
Definition: datastore.h:32
static struct ast_datastore_info audiohook_volume_datastore
Datastore used to store audiohook volume information.
Definition: audiohook.c:888
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:979
union ast_frame_subclass subclass
Definition: frame.h:146
Audiohook volume adjustment structure.
Definition: audiohook.c:864
#define ast_channel_lock(chan)
Definition: channel.h:2466
Main Channel structure associated with a channel.
Definition: channel.h:742
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:480
struct ast_audiohook_list::@225 manipulate_list
struct ast_frame * ast_audiohook_read_frame(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, format_t format)
Reads a frame in from the audiohook structure.
Definition: audiohook.c:313
struct ast_slinfactory write_factory
Definition: audiohook.h:111
ast_audiohook_flags
Definition: audiohook.h:60
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
static void audiohook_volume_destroy(void *data)
Callback used to destroy the audiohook volume datastore.
Definition: audiohook.c:874
enum ast_audiohook_type type
Definition: audiohook.h:106
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: frame.c:1629
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:127
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:1004
void ast_slinfactory_flush(struct ast_slinfactory *sf)
Flush the contents of a slinfactory.
Definition: slinfactory.c:201
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:622
#define ast_test_flag(p, flag)
Definition: utils.h:63
int option_debug
Definition: asterisk.c:182
Support for translation of data formats. translate.c.
void * ptr
Definition: frame.h:160
int ast_audiohook_write_list_empty(struct ast_audiohook_list *audiohook_list)
determines if a audiohook_list is empty or not.
Definition: audiohook.c:744
#define ast_set_flag(p, flag)
Definition: utils.h:70
int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source)
Initialize an audiohook structure.
Definition: audiohook.c:64
Audiohooks Architecture.
struct ast_audiohook_translate out_translate[2]
Definition: audiohook.c:52
int ast_audiohook_remove(struct ast_channel *chan, struct ast_audiohook *audiohook)
Remove an audiohook from a specified channel.
Definition: audiohook.c:541
void ast_audiohook_update_status(struct ast_audiohook *audiohook, enum ast_audiohook_status status)
Update audiohook&#39;s status.
Definition: audiohook.c:387
#define AST_FRAME_DTMF
Definition: frame.h:128
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:1057
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:938
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition: audiohook.c:348
#define ast_cond_init(cond, attr)
Definition: lock.h:167
static struct ast_threadstorage buf2
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:142
ast_mutex_t lock
Definition: audiohook.h:104
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
struct ast_trans_pvt * trans_pvt
Definition: audiohook.c:46
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:328
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:90
Structure for a data store object.
Definition: datastore.h:54
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:2604
format_t codec
Definition: frame.h:137
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:841
#define LOG_DEBUG
Definition: logger.h:122
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition: audiohook.c:96
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:600
#define ast_cond_signal(cond)
Definition: lock.h:169
unsigned int ast_slinfactory_available(const struct ast_slinfactory *sf)
Retrieve number of samples currently in a slinfactory.
Definition: slinfactory.c:196
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:65
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:571
Utility functions.
ast_audiohook_manipulate_callback manipulate_callback
Definition: audiohook.h:116
struct ast_trans_pvt * ast_translator_build_path(format_t dest, format_t source)
Builds a translator path Build a path (possibly NULL) from source to dest.
Definition: translate.c:282
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
Definition: audiohook.h:272
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:791
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
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:458
General Asterisk PBX channel definitions.
struct ast_audiohook_list * audiohooks
Definition: channel.h:764
Asterisk internal frame definitions.
ast_audiohook_type
Definition: audiohook.h:36
int datalen
Definition: frame.h:148
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:554
static force_inline void ast_slinear_saturated_add(short *input, short *value)
Definition: utils.h:312
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:191
static force_inline void ast_slinear_saturated_multiply(short *input, short *value)
Definition: utils.h:338
A set of macros to manage forward-linked lists.
struct ast_trans_pvt * trans_pvt
Definition: audiohook.h:115
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
int ast_audiohook_detach_source(struct ast_channel *chan, const char *source)
Detach specified source audiohook from channel.
Definition: audiohook.c:509
void ast_slinfactory_destroy(struct ast_slinfactory *sf)
Destroy the contents of a slinfactory.
Definition: slinfactory.c:64
#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:224
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
Definition: audiohook.c:401
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
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:762
Default structure for translators, with the basic fields and buffers, all allocated as part of the sa...
Definition: translate.h:135
int64_t format_t
Definition: frame_defs.h:32
struct ast_audiohook_list::@224 whisper_list
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: utils.c:1587
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ast_cond_destroy(cond)
Definition: lock.h:168
struct ast_datastore * ast_datastore_alloc(const struct ast_datastore_info *info, const char *uid)
Definition: datastore.c:98
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
static struct ast_threadstorage buf1
struct ast_audiohook::@143 list
#define ast_channel_unlock(chan)
Definition: channel.h:2467
const char * source
Definition: audiohook.h:108
A machine to gather up arbitrary frames and convert them to raw slinear on demand.
#define ast_free(a)
Definition: astmm.h:97
static struct ast_frame * read_frame(struct ast_filestream *s, int *whennext)
Definition: file.c:712
static force_inline void ast_slinear_saturated_divide(short *input, short *value)
Definition: utils.h:351
void ast_slinfactory_init(struct ast_slinfactory *sf)
Initialize a slinfactory.
Definition: slinfactory.c:39
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:1030
static const char type[]
Definition: chan_nbs.c:57
static struct ast_frame * audiohook_read_frame_both(struct ast_audiohook *audiohook, size_t samples)
Definition: audiohook.c:215
#define ast_clear_flag(p, flag)
Definition: utils.h:77
ast_cond_t trigger
Definition: audiohook.h:105
ast_audiohook_direction
Definition: audiohook.h:49
struct ast_slinfactory read_factory
Definition: audiohook.h:110
struct ast_audiohook_translate in_translate[2]
Definition: audiohook.c:51
void * data
Definition: datastore.h:56
struct ast_audiohook_options options
Definition: audiohook.h:117
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:666
#define AST_AUDIOHOOK_SYNC_TOLERANCE
Definition: audiohook.h:76
#define AST_FORMAT_SLINEAR
Definition: frame.h:254
#define ast_calloc(a, b)
Definition: astmm.h:82
struct timeval write_time
Definition: audiohook.h:113
int ast_frame_adjust_volume(struct ast_frame *f, int adjustment)
Adjusts the volume of the audio samples contained in a frame.
Definition: frame.c:1584
Data structure associated with a single frame of data.
Definition: frame.h:142
int ast_slinfactory_read(struct ast_slinfactory *sf, short *buf, size_t samples)
Read samples from a slinfactory.
Definition: slinfactory.c:142
enum ast_audiohook_status status
Definition: audiohook.h:107
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
enum ast_frame_type frametype
Definition: frame.h:144
#define ast_mutex_init(pmutex)
Definition: lock.h:152
#define ast_frfree(fr)
Definition: frame.h:583
#define ast_mutex_destroy(a)
Definition: lock.h:154
struct ast_audiohook_list::@223 spy_list
struct timeval read_time
Definition: audiohook.h:112
ast_audiohook_status
Definition: audiohook.h:42
#define ast_audiohook_lock(ah)
Lock an audiohook.
Definition: audiohook.h:267
static snd_pcm_format_t format
Definition: chan_alsa.c:93
union ast_frame::@172 data
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2590
int ast_audiohook_detach_list(struct ast_audiohook_list *audiohook_list)
Detach audiohooks from list and destroy said list.
Definition: audiohook.c:418
void ast_audiohook_trigger_wait(struct ast_audiohook *audiohook)
Wait for audiohook trigger to be triggered.
Definition: audiohook.c:776
static struct ast_frame * audiohook_read_frame_single(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction)
Definition: audiohook.c:187
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:172
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:830
struct ast_frame * ast_frdup(const struct ast_frame *fr)
Copies a frame.
Definition: frame.c:474
void ast_translator_free_path(struct ast_trans_pvt *tr)
Frees a translator path Frees the given translator path structure.
Definition: translate.c:272
jack_status_t status
Definition: app_jack.c:143
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
int samples
Definition: frame.h:150
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:900