Media Project Phase2: SILK 8khz-24khz, SLINEAR 8khz-192khz, SPEEX 32khz, hd audio...
[asterisk/asterisk.git] / main / audiohook.c
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 #include "asterisk.h"
27
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29
30 #include <signal.h>
31
32 #include "asterisk/channel.h"
33 #include "asterisk/utils.h"
34 #include "asterisk/lock.h"
35 #include "asterisk/linkedlists.h"
36 #include "asterisk/audiohook.h"
37 #include "asterisk/slinfactory.h"
38 #include "asterisk/frame.h"
39 #include "asterisk/translate.h"
40
41 #define AST_AUDIOHOOK_SYNC_TOLERANCE 100 /*!< Tolerance in milliseconds for audiohooks synchronization */
42 #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. */
43
44 struct ast_audiohook_translate {
45         struct ast_trans_pvt *trans_pvt;
46         struct ast_format format;
47 };
48
49 struct ast_audiohook_list {
50         /* If all the audiohooks in this list are capable
51          * of processing slinear at any sample rate, this
52          * variable will be set and the sample rate will
53          * be preserved during ast_audiohook_write_list()*/
54         int native_slin_compatible;
55         int list_internal_samp_rate;/*!< Internal sample rate used when writing to the audiohook list */
56
57         struct ast_audiohook_translate in_translate[2];
58         struct ast_audiohook_translate out_translate[2];
59         AST_LIST_HEAD_NOLOCK(, ast_audiohook) spy_list;
60         AST_LIST_HEAD_NOLOCK(, ast_audiohook) whisper_list;
61         AST_LIST_HEAD_NOLOCK(, ast_audiohook) manipulate_list;
62 };
63
64 static int audiohook_set_internal_rate(struct ast_audiohook *audiohook, int rate, int reset)
65 {
66         struct ast_format slin;
67
68         if (audiohook->hook_internal_samp_rate == rate) {
69                 return 0;
70         }
71
72         audiohook->hook_internal_samp_rate = rate;
73
74         ast_format_set(&slin, ast_format_slin_by_rate(rate), 0);
75         /* Setup the factories that are needed for this audiohook type */
76         switch (audiohook->type) {
77         case AST_AUDIOHOOK_TYPE_SPY:
78                 if (reset) {
79                         ast_slinfactory_destroy(&audiohook->read_factory);
80                 }
81                 ast_slinfactory_init_with_format(&audiohook->read_factory, &slin);
82                 /* fall through */
83         case AST_AUDIOHOOK_TYPE_WHISPER:
84                 if (reset) {
85                         ast_slinfactory_destroy(&audiohook->write_factory);
86                 }
87                 ast_slinfactory_init_with_format(&audiohook->write_factory, &slin);
88                 break;
89         default:
90                 break;
91         }
92         return 0;
93 }
94
95 /*! \brief Initialize an audiohook structure
96  * \param audiohook Audiohook structure
97  * \param type
98  * \param source
99  * \return Returns 0 on success, -1 on failure
100  */
101 int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source, enum ast_audiohook_init_flags init_flags)
102 {
103         /* Need to keep the type and source */
104         audiohook->type = type;
105         audiohook->source = source;
106
107         /* Initialize lock that protects our audiohook */
108         ast_mutex_init(&audiohook->lock);
109         ast_cond_init(&audiohook->trigger, NULL);
110
111         audiohook->init_flags = init_flags;
112
113         /* initialize internal rate at 8khz, this will adjust if necessary */
114         audiohook_set_internal_rate(audiohook, 8000, 0);
115
116         /* Since we are just starting out... this audiohook is new */
117         ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_NEW);
118
119         return 0;
120 }
121
122 /*! \brief Destroys an audiohook structure
123  * \param audiohook Audiohook structure
124  * \return Returns 0 on success, -1 on failure
125  */
126 int ast_audiohook_destroy(struct ast_audiohook *audiohook)
127 {
128         /* Drop the factories used by this audiohook type */
129         switch (audiohook->type) {
130         case AST_AUDIOHOOK_TYPE_SPY:
131                 ast_slinfactory_destroy(&audiohook->read_factory);
132         case AST_AUDIOHOOK_TYPE_WHISPER:
133                 ast_slinfactory_destroy(&audiohook->write_factory);
134                 break;
135         default:
136                 break;
137         }
138
139         /* Destroy translation path if present */
140         if (audiohook->trans_pvt)
141                 ast_translator_free_path(audiohook->trans_pvt);
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
150 /*! \brief Writes a frame into the audiohook structure
151  * \param audiohook Audiohook structure
152  * \param direction Direction the audio frame came from
153  * \param frame Frame to write in
154  * \return Returns 0 on success, -1 on failure
155  */
156 int ast_audiohook_write_frame(struct ast_audiohook *audiohook, enum ast_audiohook_direction direction, struct ast_frame *frame)
157 {
158         struct ast_slinfactory *factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_factory : &audiohook->write_factory);
159         struct ast_slinfactory *other_factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->write_factory : &audiohook->read_factory);
160         struct timeval *rwtime = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_time : &audiohook->write_time), previous_time = *rwtime;
161         int our_factory_samples;
162         int our_factory_ms;
163         int other_factory_samples;
164         int other_factory_ms;
165         int muteme = 0;
166
167         /* Update last feeding time to be current */
168         *rwtime = ast_tvnow();
169
170         our_factory_samples = ast_slinfactory_available(factory);
171         our_factory_ms = ast_tvdiff_ms(*rwtime, previous_time) + (our_factory_samples / (audiohook->hook_internal_samp_rate / 1000));
172         other_factory_samples = ast_slinfactory_available(other_factory);
173         other_factory_ms = other_factory_samples / (audiohook->hook_internal_samp_rate / 1000);
174
175         if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC) && other_factory_samples && (our_factory_ms - other_factory_ms > AST_AUDIOHOOK_SYNC_TOLERANCE)) {
176                 ast_debug(1, "Flushing audiohook %p so it remains in sync\n", audiohook);
177                 ast_slinfactory_flush(factory);
178                 ast_slinfactory_flush(other_factory);
179         }
180
181         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))) {
182                 ast_debug(1, "Audiohook %p has stale audio in its factories. Flushing them both\n", audiohook);
183                 ast_slinfactory_flush(factory);
184                 ast_slinfactory_flush(other_factory);
185         }
186
187         /* swap frame data for zeros if mute is required */
188         if ((ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_READ) && (direction == AST_AUDIOHOOK_DIRECTION_READ)) ||
189                 (ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_WRITE) && (direction == AST_AUDIOHOOK_DIRECTION_WRITE)) ||
190                 (ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE) == (AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE))) {
191                         muteme = 1;
192         }
193
194         if (muteme && frame->datalen > 0) {
195                 ast_frame_clear(frame);
196         }
197
198         /* Write frame out to respective factory */
199         ast_slinfactory_feed(factory, frame);
200
201         /* If we need to notify the respective handler of this audiohook, do so */
202         if ((ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_MODE) == AST_AUDIOHOOK_TRIGGER_READ) && (direction == AST_AUDIOHOOK_DIRECTION_READ)) {
203                 ast_cond_signal(&audiohook->trigger);
204         } else if ((ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_MODE) == AST_AUDIOHOOK_TRIGGER_WRITE) && (direction == AST_AUDIOHOOK_DIRECTION_WRITE)) {
205                 ast_cond_signal(&audiohook->trigger);
206         } else if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC)) {
207                 ast_cond_signal(&audiohook->trigger);
208         }
209
210         return 0;
211 }
212
213 static struct ast_frame *audiohook_read_frame_single(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction)
214 {
215         struct ast_slinfactory *factory = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook->read_factory : &audiohook->write_factory);
216         int vol = (direction == AST_AUDIOHOOK_DIRECTION_READ ? audiohook->options.read_volume : audiohook->options.write_volume);
217         short buf[samples];
218         struct ast_frame frame = {
219                 .frametype = AST_FRAME_VOICE,
220                 .data.ptr = buf,
221                 .datalen = sizeof(buf),
222                 .samples = samples,
223         };
224         ast_format_set(&frame.subclass.format, ast_format_slin_by_rate(audiohook->hook_internal_samp_rate), 0);
225
226         /* Ensure the factory is able to give us the samples we want */
227         if (samples > ast_slinfactory_available(factory))
228                 return NULL;
229         
230         /* Read data in from factory */
231         if (!ast_slinfactory_read(factory, buf, samples))
232                 return NULL;
233
234         /* If a volume adjustment needs to be applied apply it */
235         if (vol)
236                 ast_frame_adjust_volume(&frame, vol);
237
238         return ast_frdup(&frame);
239 }
240
241 static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audiohook, size_t samples)
242 {
243         int i = 0, usable_read, usable_write;
244         short buf1[samples], buf2[samples], *read_buf = NULL, *write_buf = NULL, *final_buf = NULL, *data1 = NULL, *data2 = NULL;
245         struct ast_frame frame = {
246                 .frametype = AST_FRAME_VOICE,
247                 .data.ptr = NULL,
248                 .datalen = sizeof(buf1),
249                 .samples = samples,
250         };
251         ast_format_set(&frame.subclass.format, ast_format_slin_by_rate(audiohook->hook_internal_samp_rate), 0);
252
253         /* Make sure both factories have the required samples */
254         usable_read = (ast_slinfactory_available(&audiohook->read_factory) >= samples ? 1 : 0);
255         usable_write = (ast_slinfactory_available(&audiohook->write_factory) >= samples ? 1 : 0);
256
257         if (!usable_read && !usable_write) {
258                 /* If both factories are unusable bail out */
259                 ast_debug(1, "Read factory %p and write factory %p both fail to provide %zd samples\n", &audiohook->read_factory, &audiohook->write_factory, samples);
260                 return NULL;
261         }
262
263         /* If we want to provide only a read factory make sure we aren't waiting for other audio */
264         if (usable_read && !usable_write && (ast_tvdiff_ms(ast_tvnow(), audiohook->write_time) < (samples/8)*2)) {
265                 ast_debug(3, "Write factory %p was pretty quick last time, waiting for them.\n", &audiohook->write_factory);
266                 return NULL;
267         }
268
269         /* If we want to provide only a write factory make sure we aren't waiting for other audio */
270         if (usable_write && !usable_read && (ast_tvdiff_ms(ast_tvnow(), audiohook->read_time) < (samples/8)*2)) {
271                 ast_debug(3, "Read factory %p was pretty quick last time, waiting for them.\n", &audiohook->read_factory);
272                 return NULL;
273         }
274
275         /* Start with the read factory... if there are enough samples, read them in */
276         if (usable_read) {
277                 if (ast_slinfactory_read(&audiohook->read_factory, buf1, samples)) {
278                         read_buf = buf1;
279                         /* Adjust read volume if need be */
280                         if (audiohook->options.read_volume) {
281                                 int count = 0;
282                                 short adjust_value = abs(audiohook->options.read_volume);
283                                 for (count = 0; count < samples; count++) {
284                                         if (audiohook->options.read_volume > 0)
285                                                 ast_slinear_saturated_multiply(&buf1[count], &adjust_value);
286                                         else if (audiohook->options.read_volume < 0)
287                                                 ast_slinear_saturated_divide(&buf1[count], &adjust_value);
288                                 }
289                         }
290                 }
291         }
292         ast_debug(1, "Failed to get %d samples from read factory %p\n", (int)samples, &audiohook->read_factory);
293
294         /* Move on to the write factory... if there are enough samples, read them in */
295         if (usable_write) {
296                 if (ast_slinfactory_read(&audiohook->write_factory, buf2, samples)) {
297                         write_buf = buf2;
298                         /* Adjust write volume if need be */
299                         if (audiohook->options.write_volume) {
300                                 int count = 0;
301                                 short adjust_value = abs(audiohook->options.write_volume);
302                                 for (count = 0; count < samples; count++) {
303                                         if (audiohook->options.write_volume > 0)
304                                                 ast_slinear_saturated_multiply(&buf2[count], &adjust_value);
305                                         else if (audiohook->options.write_volume < 0)
306                                                 ast_slinear_saturated_divide(&buf2[count], &adjust_value);
307                                 }
308                         }
309                 }
310         }
311         ast_debug(1, "Failed to get %d samples from write factory %p\n", (int)samples, &audiohook->write_factory);
312
313         /* Basically we figure out which buffer to use... and if mixing can be done here */
314         if (!read_buf && !write_buf)
315                 return NULL;
316         else if (read_buf && write_buf) {
317                 for (i = 0, data1 = read_buf, data2 = write_buf; i < samples; i++, data1++, data2++)
318                         ast_slinear_saturated_add(data1, data2);
319                 final_buf = buf1;
320         } else if (read_buf)
321                 final_buf = buf1;
322         else if (write_buf)
323                 final_buf = buf2;
324
325         /* Make the final buffer part of the frame, so it gets duplicated fine */
326         frame.data.ptr = final_buf;
327
328         /* Yahoo, a combined copy of the audio! */
329         return ast_frdup(&frame);
330 }
331
332 /*! \brief Reads a frame in from the audiohook structure
333  * \param audiohook Audiohook structure
334  * \param samples Number of samples wanted in requested output format
335  * \param direction Direction the audio frame came from
336  * \param format Format of frame remote side wants back
337  * \return Returns frame on success, NULL on failure
338  */
339 struct ast_frame *ast_audiohook_read_frame(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format)
340 {
341         struct ast_frame *read_frame = NULL, *final_frame = NULL;
342         struct ast_format tmp_fmt;
343         int samples_converted;
344
345         /* the number of samples requested is based on the format they are requesting.  Inorder
346          * to process this correctly samples must be converted to our internal sample rate */
347         if (audiohook->hook_internal_samp_rate == ast_format_rate(format)) {
348                 samples_converted = samples;
349         } else if (audiohook->hook_internal_samp_rate > ast_format_rate(format)) {
350                 samples_converted = samples * (audiohook->hook_internal_samp_rate / (float) ast_format_rate(format));
351         } else {
352                 samples_converted = samples * (ast_format_rate(format) / (float) audiohook->hook_internal_samp_rate);
353         }
354
355         if (!(read_frame = (direction == AST_AUDIOHOOK_DIRECTION_BOTH ?
356                 audiohook_read_frame_both(audiohook, samples_converted) :
357                 audiohook_read_frame_single(audiohook, samples_converted, direction)))) {
358                 return NULL;
359         }
360
361         /* If they don't want signed linear back out, we'll have to send it through the translation path */
362         if (format->id != ast_format_slin_by_rate(audiohook->hook_internal_samp_rate)) {
363                 /* Rebuild translation path if different format then previously */
364                 if (ast_format_cmp(format, &audiohook->format) == AST_FORMAT_CMP_NOT_EQUAL) {
365                         if (audiohook->trans_pvt) {
366                                 ast_translator_free_path(audiohook->trans_pvt);
367                                 audiohook->trans_pvt = NULL;
368                         }
369
370                         /* 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 */
371                         if (!(audiohook->trans_pvt = ast_translator_build_path(format, ast_format_set(&tmp_fmt, ast_format_slin_by_rate(audiohook->hook_internal_samp_rate), 0)))) {
372                                 ast_frfree(read_frame);
373                                 return NULL;
374                         }
375                         ast_format_copy(&audiohook->format, format);
376                 }
377                 /* Convert to requested format, and allow the read in frame to be freed */
378                 final_frame = ast_translate(audiohook->trans_pvt, read_frame, 1);
379         } else {
380                 final_frame = read_frame;
381         }
382
383         return final_frame;
384 }
385
386 static void audiohook_list_set_samplerate_compatibility(struct ast_audiohook_list *audiohook_list)
387 {
388         struct ast_audiohook *ah = NULL;
389         audiohook_list->native_slin_compatible = 1;
390         AST_LIST_TRAVERSE(&audiohook_list->manipulate_list, ah, list) {
391                 if (!(ah->init_flags & AST_AUDIOHOOK_MANIPULATE_ALL_RATES)) {
392                         audiohook_list->native_slin_compatible = 0;
393                         return;
394                 }
395         }
396 }
397
398 /*! \brief Attach audiohook to channel
399  * \param chan Channel
400  * \param audiohook Audiohook structure
401  * \return Returns 0 on success, -1 on failure
402  */
403 int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
404 {
405         ast_channel_lock(chan);
406
407         if (!chan->audiohooks) {
408                 /* Whoops... allocate a new structure */
409                 if (!(chan->audiohooks = ast_calloc(1, sizeof(*chan->audiohooks)))) {
410                         ast_channel_unlock(chan);
411                         return -1;
412                 }
413                 AST_LIST_HEAD_INIT_NOLOCK(&chan->audiohooks->spy_list);
414                 AST_LIST_HEAD_INIT_NOLOCK(&chan->audiohooks->whisper_list);
415                 AST_LIST_HEAD_INIT_NOLOCK(&chan->audiohooks->manipulate_list);
416                 /* This sample rate will adjust as necessary when writing to the list. */
417                 chan->audiohooks->list_internal_samp_rate = 8000;
418         }
419
420         /* Drop into respective list */
421         if (audiohook->type == AST_AUDIOHOOK_TYPE_SPY)
422                 AST_LIST_INSERT_TAIL(&chan->audiohooks->spy_list, audiohook, list);
423         else if (audiohook->type == AST_AUDIOHOOK_TYPE_WHISPER)
424                 AST_LIST_INSERT_TAIL(&chan->audiohooks->whisper_list, audiohook, list);
425         else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE)
426                 AST_LIST_INSERT_TAIL(&chan->audiohooks->manipulate_list, audiohook, list);
427
428
429         audiohook_set_internal_rate(audiohook, chan->audiohooks->list_internal_samp_rate, 1);
430         audiohook_list_set_samplerate_compatibility(chan->audiohooks);
431
432         /* Change status over to running since it is now attached */
433         ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_RUNNING);
434
435         ast_channel_unlock(chan);
436
437         return 0;
438 }
439
440 /*! \brief Update audiohook's status
441  * \param audiohook Audiohook structure
442  * \param status Audiohook status enum
443  *
444  * \note once status is updated to DONE, this function can not be used to set the
445  * status back to any other setting.  Setting DONE effectively locks the status as such.
446  */
447
448 void ast_audiohook_update_status(struct ast_audiohook *audiohook, enum ast_audiohook_status status)
449 {
450         ast_audiohook_lock(audiohook);
451         if (audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
452                 audiohook->status = status;
453                 ast_cond_signal(&audiohook->trigger);
454         }
455         ast_audiohook_unlock(audiohook);
456 }
457
458 /*! \brief Detach audiohook from channel
459  * \param audiohook Audiohook structure
460  * \return Returns 0 on success, -1 on failure
461  */
462 int ast_audiohook_detach(struct ast_audiohook *audiohook)
463 {
464         if (audiohook->status == AST_AUDIOHOOK_STATUS_NEW || audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
465                 return 0;
466
467         ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_SHUTDOWN);
468
469         while (audiohook->status != AST_AUDIOHOOK_STATUS_DONE)
470                 ast_audiohook_trigger_wait(audiohook);
471
472         return 0;
473 }
474
475 /*! \brief Detach audiohooks from list and destroy said list
476  * \param audiohook_list List of audiohooks
477  * \return Returns 0 on success, -1 on failure
478  */
479 int ast_audiohook_detach_list(struct ast_audiohook_list *audiohook_list)
480 {
481         int i = 0;
482         struct ast_audiohook *audiohook = NULL;
483
484         /* Drop any spies */
485         while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->spy_list, list))) {
486                 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
487         }
488
489         /* Drop any whispering sources */
490         while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->whisper_list, list))) {
491                 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
492         }
493
494         /* Drop any manipulaters */
495         while ((audiohook = AST_LIST_REMOVE_HEAD(&audiohook_list->manipulate_list, list))) {
496                 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
497                 audiohook->manipulate_callback(audiohook, NULL, NULL, 0);
498         }
499
500         /* Drop translation paths if present */
501         for (i = 0; i < 2; i++) {
502                 if (audiohook_list->in_translate[i].trans_pvt)
503                         ast_translator_free_path(audiohook_list->in_translate[i].trans_pvt);
504                 if (audiohook_list->out_translate[i].trans_pvt)
505                         ast_translator_free_path(audiohook_list->out_translate[i].trans_pvt);
506         }
507         
508         /* Free ourselves */
509         ast_free(audiohook_list);
510
511         return 0;
512 }
513
514 /*! \brief find an audiohook based on its source
515  * \param audiohook_list The list of audiohooks to search in
516  * \param source The source of the audiohook we wish to find
517  * \return Return the corresponding audiohook or NULL if it cannot be found.
518  */
519 static struct ast_audiohook *find_audiohook_by_source(struct ast_audiohook_list *audiohook_list, const char *source)
520 {
521         struct ast_audiohook *audiohook = NULL;
522
523         AST_LIST_TRAVERSE(&audiohook_list->spy_list, audiohook, list) {
524                 if (!strcasecmp(audiohook->source, source))
525                         return audiohook;
526         }
527
528         AST_LIST_TRAVERSE(&audiohook_list->whisper_list, audiohook, list) {
529                 if (!strcasecmp(audiohook->source, source))
530                         return audiohook;
531         }
532
533         AST_LIST_TRAVERSE(&audiohook_list->manipulate_list, audiohook, list) {
534                 if (!strcasecmp(audiohook->source, source))
535                         return audiohook;
536         }
537
538         return NULL;
539 }
540
541 void ast_audiohook_move_by_source(struct ast_channel *old_chan, struct ast_channel *new_chan, const char *source)
542 {
543         struct ast_audiohook *audiohook;
544         enum ast_audiohook_status oldstatus;
545
546         if (!old_chan->audiohooks || !(audiohook = find_audiohook_by_source(old_chan->audiohooks, source))) {
547                 return;
548         }
549
550         /* By locking both channels and the audiohook, we can assure that
551          * another thread will not have a chance to read the audiohook's status
552          * as done, even though ast_audiohook_remove signals the trigger
553          * condition.
554          */
555         ast_audiohook_lock(audiohook);
556         oldstatus = audiohook->status;
557
558         ast_audiohook_remove(old_chan, audiohook);
559         ast_audiohook_attach(new_chan, audiohook);
560
561         audiohook->status = oldstatus;
562         ast_audiohook_unlock(audiohook);
563 }
564
565 /*! \brief Detach specified source audiohook from channel
566  * \param chan Channel to detach from
567  * \param source Name of source to detach
568  * \return Returns 0 on success, -1 on failure
569  */
570 int ast_audiohook_detach_source(struct ast_channel *chan, const char *source)
571 {
572         struct ast_audiohook *audiohook = NULL;
573
574         ast_channel_lock(chan);
575
576         /* Ensure the channel has audiohooks on it */
577         if (!chan->audiohooks) {
578                 ast_channel_unlock(chan);
579                 return -1;
580         }
581
582         audiohook = find_audiohook_by_source(chan->audiohooks, source);
583
584         ast_channel_unlock(chan);
585
586         if (audiohook && audiohook->status != AST_AUDIOHOOK_STATUS_DONE)
587                 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_SHUTDOWN);
588
589         return (audiohook ? 0 : -1);
590 }
591
592 /*!
593  * \brief Remove an audiohook from a specified channel
594  *
595  * \param chan Channel to remove from
596  * \param audiohook Audiohook to remove
597  *
598  * \return Returns 0 on success, -1 on failure
599  *
600  * \note The channel does not need to be locked before calling this function
601  */
602 int ast_audiohook_remove(struct ast_channel *chan, struct ast_audiohook *audiohook)
603 {
604         ast_channel_lock(chan);
605
606         if (!chan->audiohooks) {
607                 ast_channel_unlock(chan);
608                 return -1;
609         }
610
611         if (audiohook->type == AST_AUDIOHOOK_TYPE_SPY)
612                 AST_LIST_REMOVE(&chan->audiohooks->spy_list, audiohook, list);
613         else if (audiohook->type == AST_AUDIOHOOK_TYPE_WHISPER)
614                 AST_LIST_REMOVE(&chan->audiohooks->whisper_list, audiohook, list);
615         else if (audiohook->type == AST_AUDIOHOOK_TYPE_MANIPULATE)
616                 AST_LIST_REMOVE(&chan->audiohooks->manipulate_list, audiohook, list);
617
618         audiohook_list_set_samplerate_compatibility(chan->audiohooks);
619         ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
620
621         ast_channel_unlock(chan);
622
623         return 0;
624 }
625
626 /*! \brief Pass a DTMF frame off to be handled by the audiohook core
627  * \param chan Channel that the list is coming off of
628  * \param audiohook_list List of audiohooks
629  * \param direction Direction frame is coming in from
630  * \param frame The frame itself
631  * \return Return frame on success, NULL on failure
632  */
633 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)
634 {
635         struct ast_audiohook *audiohook = NULL;
636         int removed = 0;
637
638         AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
639                 ast_audiohook_lock(audiohook);
640                 if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
641                         AST_LIST_REMOVE_CURRENT(list);
642                         removed = 1;
643                         ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
644                         ast_audiohook_unlock(audiohook);
645                         audiohook->manipulate_callback(audiohook, NULL, NULL, 0);
646                         continue;
647                 }
648                 if (ast_test_flag(audiohook, AST_AUDIOHOOK_WANTS_DTMF))
649                         audiohook->manipulate_callback(audiohook, chan, frame, direction);
650                 ast_audiohook_unlock(audiohook);
651         }
652         AST_LIST_TRAVERSE_SAFE_END;
653
654         /* if an audiohook got removed, reset samplerate compatibility */
655         if (removed) {
656                 audiohook_list_set_samplerate_compatibility(audiohook_list);
657         }
658         return frame;
659 }
660
661 static struct ast_frame *audiohook_list_translate_to_slin(struct ast_audiohook_list *audiohook_list,
662         enum ast_audiohook_direction direction, struct ast_frame *frame)
663 {
664         struct ast_audiohook_translate *in_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ?
665                 &audiohook_list->in_translate[0] : &audiohook_list->in_translate[1]);
666         struct ast_frame *new_frame = frame;
667         struct ast_format tmp_fmt;
668         enum ast_format_id slin_id;
669
670         /* If we are capable of maintaining doing samplerates other that 8khz, update
671          * the internal audiohook_list's rate and higher samplerate audio arrives. By
672          * updating the list's rate, all the audiohooks in the list will be updated as well
673          * as the are written and read from. */
674         if (audiohook_list->native_slin_compatible) {
675                 audiohook_list->list_internal_samp_rate =
676                         MAX(ast_format_rate(&frame->subclass.format), audiohook_list->list_internal_samp_rate);
677         }
678
679         slin_id = ast_format_slin_by_rate(audiohook_list->list_internal_samp_rate);
680
681         if (frame->subclass.format.id == slin_id) {
682                 return new_frame;
683         }
684
685         if (ast_format_cmp(&frame->subclass.format, &in_translate->format) == AST_FORMAT_CMP_NOT_EQUAL) {
686                 if (in_translate->trans_pvt) {
687                         ast_translator_free_path(in_translate->trans_pvt);
688                 }
689                 if (!(in_translate->trans_pvt = ast_translator_build_path(ast_format_set(&tmp_fmt, slin_id, 0), &frame->subclass.format))) {
690                         return NULL;
691                 }
692                 ast_format_copy(&in_translate->format, &frame->subclass.format);
693         }
694         if (!(new_frame = ast_translate(in_translate->trans_pvt, frame, 0))) {
695                 return NULL;
696         }
697
698         return new_frame;
699 }
700
701 static struct ast_frame *audiohook_list_translate_to_native(struct ast_audiohook_list *audiohook_list,
702         enum ast_audiohook_direction direction, struct ast_frame *slin_frame, struct ast_format *outformat)
703 {
704         struct ast_audiohook_translate *out_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook_list->out_translate[0] : &audiohook_list->out_translate[1]);
705         struct ast_frame *outframe = NULL;
706         if (ast_format_cmp(&slin_frame->subclass.format, outformat) == AST_FORMAT_CMP_NOT_EQUAL) {
707                 /* rebuild translators if necessary */
708                 if (ast_format_cmp(&out_translate->format, outformat) == AST_FORMAT_CMP_NOT_EQUAL) {
709                         if (out_translate->trans_pvt) {
710                                 ast_translator_free_path(out_translate->trans_pvt);
711                         }
712                         if (!(out_translate->trans_pvt = ast_translator_build_path(outformat, &slin_frame->subclass.format))) {
713                                 return NULL;
714                         }
715                         ast_format_copy(&out_translate->format, outformat);
716                 }
717                 /* translate back to the format the frame came in as. */
718                 if (!(outframe = ast_translate(out_translate->trans_pvt, slin_frame, 0))) {
719                         return NULL;
720                 }
721         }
722         return outframe;
723 }
724
725 /*!
726  * \brief Pass an AUDIO frame off to be handled by the audiohook core
727  *
728  * \details
729  * This function has 3 ast_frames and 3 parts to handle each.  At the beginning of this
730  * function all 3 frames, start_frame, middle_frame, and end_frame point to the initial
731  * input frame.
732  *
733  * Part_1: Translate the start_frame into SLINEAR audio if it is not already in that
734  *         format.  The result of this part is middle_frame is guaranteed to be in
735  *         SLINEAR format for Part_2.
736  * Part_2: Send middle_frame off to spies and manipulators.  At this point middle_frame is
737  *         either a new frame as result of the translation, or points directly to the start_frame
738  *         because no translation to SLINEAR audio was required.
739  * Part_3: Translate end_frame's audio back into the format of start frame if necessary.  This
740  *         is only necessary if manipulation of middle_frame occurred.
741  *         
742  * \param chan Channel that the list is coming off of
743  * \param audiohook_list List of audiohooks
744  * \param direction Direction frame is coming in from
745  * \param frame The frame itself
746  * \return Return frame on success, NULL on failure
747  */
748 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)
749 {
750         struct ast_frame *start_frame = frame, *middle_frame = frame, *end_frame = frame;
751         struct ast_audiohook *audiohook = NULL;
752         int samples;
753         int middle_frame_manipulated = 0;
754         int removed = 0;
755
756         /* ---Part_1. translate start_frame to SLINEAR if necessary. */
757         if (!(middle_frame = audiohook_list_translate_to_slin(audiohook_list, direction, start_frame))) {
758                 return frame;
759         }
760         samples = middle_frame->samples;
761
762         /* ---Part_2: Send middle_frame to spy and manipulator lists.  middle_frame is guaranteed to be SLINEAR here.*/
763         /* Queue up signed linear frame to each spy */
764         AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->spy_list, audiohook, list) {
765                 ast_audiohook_lock(audiohook);
766                 if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
767                         AST_LIST_REMOVE_CURRENT(list);
768                         removed = 1;
769                         ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
770                         ast_audiohook_unlock(audiohook);
771                         continue;
772                 }
773                 audiohook_set_internal_rate(audiohook, audiohook_list->list_internal_samp_rate, 1);
774                 ast_audiohook_write_frame(audiohook, direction, middle_frame);
775                 ast_audiohook_unlock(audiohook);
776         }
777         AST_LIST_TRAVERSE_SAFE_END;
778
779         /* If this frame is being written out to the channel then we need to use whisper sources */
780         if (direction == AST_AUDIOHOOK_DIRECTION_WRITE && !AST_LIST_EMPTY(&audiohook_list->whisper_list)) {
781                 int i = 0;
782                 short read_buf[samples], combine_buf[samples], *data1 = NULL, *data2 = NULL;
783                 memset(&combine_buf, 0, sizeof(combine_buf));
784                 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->whisper_list, audiohook, list) {
785                         ast_audiohook_lock(audiohook);
786                         if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
787                                 AST_LIST_REMOVE_CURRENT(list);
788                                 removed = 1;
789                                 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
790                                 ast_audiohook_unlock(audiohook);
791                                 continue;
792                         }
793                         audiohook_set_internal_rate(audiohook, audiohook_list->list_internal_samp_rate, 1);
794                         if (ast_slinfactory_available(&audiohook->write_factory) >= samples && ast_slinfactory_read(&audiohook->write_factory, read_buf, samples)) {
795                                 /* Take audio from this whisper source and combine it into our main buffer */
796                                 for (i = 0, data1 = combine_buf, data2 = read_buf; i < samples; i++, data1++, data2++)
797                                         ast_slinear_saturated_add(data1, data2);
798                         }
799                         ast_audiohook_unlock(audiohook);
800                 }
801                 AST_LIST_TRAVERSE_SAFE_END;
802                 /* We take all of the combined whisper sources and combine them into the audio being written out */
803                 for (i = 0, data1 = middle_frame->data.ptr, data2 = combine_buf; i < samples; i++, data1++, data2++) {
804                         ast_slinear_saturated_add(data1, data2);
805                 }
806                 middle_frame_manipulated = 1;
807         }
808
809         /* Pass off frame to manipulate audiohooks */
810         if (!AST_LIST_EMPTY(&audiohook_list->manipulate_list)) {
811                 AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
812                         ast_audiohook_lock(audiohook);
813                         if (audiohook->status != AST_AUDIOHOOK_STATUS_RUNNING) {
814                                 AST_LIST_REMOVE_CURRENT(list);
815                                 removed = 1;
816                                 ast_audiohook_update_status(audiohook, AST_AUDIOHOOK_STATUS_DONE);
817                                 ast_audiohook_unlock(audiohook);
818                                 /* We basically drop all of our links to the manipulate audiohook and prod it to do it's own destructive things */
819                                 audiohook->manipulate_callback(audiohook, chan, NULL, direction);
820                                 continue;
821                         }
822                         audiohook_set_internal_rate(audiohook, audiohook_list->list_internal_samp_rate, 1);
823                         /* Feed in frame to manipulation. */
824                         if (audiohook->manipulate_callback(audiohook, chan, middle_frame, direction)) {
825                                 /* XXX IGNORE FAILURE */
826
827                                 /* If the manipulation fails then the frame will be returned in its original state.
828                                  * Since there are potentially more manipulator callbacks in the list, no action should
829                                  * be taken here to exit early. */
830                         }
831                         ast_audiohook_unlock(audiohook);
832                 }
833                 AST_LIST_TRAVERSE_SAFE_END;
834                 middle_frame_manipulated = 1;
835         }
836
837         /* ---Part_3: Decide what to do with the end_frame (whether to transcode or not) */
838         if (middle_frame_manipulated) {
839                 if (!(end_frame = audiohook_list_translate_to_native(audiohook_list, direction, middle_frame, &start_frame->subclass.format))) {
840                         /* translation failed, so just pass back the input frame */
841                         end_frame = start_frame;
842                 }
843         } else {
844                 end_frame = start_frame;
845         }
846         /* clean up our middle_frame if required */
847         if (middle_frame != end_frame) {
848                 ast_frfree(middle_frame);
849                 middle_frame = NULL;
850         }
851
852         /* Before returning, if an audiohook got removed, reset samplerate compatibility */
853         if (removed) {
854                 audiohook_list_set_samplerate_compatibility(audiohook_list);
855         }
856
857         return end_frame;
858 }
859
860 int ast_audiohook_write_list_empty(struct ast_audiohook_list *audiohook_list)
861 {
862         if (AST_LIST_EMPTY(&audiohook_list->spy_list) &&
863                 AST_LIST_EMPTY(&audiohook_list->whisper_list) &&
864                 AST_LIST_EMPTY(&audiohook_list->manipulate_list)) {
865
866                 return 1;
867         }
868         return 0;
869 }
870
871 /*! \brief Pass a frame off to be handled by the audiohook core
872  * \param chan Channel that the list is coming off of
873  * \param audiohook_list List of audiohooks
874  * \param direction Direction frame is coming in from
875  * \param frame The frame itself
876  * \return Return frame on success, NULL on failure
877  */
878 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)
879 {
880         /* Pass off frame to it's respective list write function */
881         if (frame->frametype == AST_FRAME_VOICE)
882                 return audio_audiohook_write_list(chan, audiohook_list, direction, frame);
883         else if (frame->frametype == AST_FRAME_DTMF)
884                 return dtmf_audiohook_write_list(chan, audiohook_list, direction, frame);
885         else
886                 return frame;
887 }
888
889 /*! \brief Wait for audiohook trigger to be triggered
890  * \param audiohook Audiohook to wait on
891  */
892 void ast_audiohook_trigger_wait(struct ast_audiohook *audiohook)
893 {
894         struct timeval wait;
895         struct timespec ts;
896
897         wait = ast_tvadd(ast_tvnow(), ast_samp2tv(50000, 1000));
898         ts.tv_sec = wait.tv_sec;
899         ts.tv_nsec = wait.tv_usec * 1000;
900         
901         ast_cond_timedwait(&audiohook->trigger, &audiohook->lock, &ts);
902         
903         return;
904 }
905
906 /* Count number of channel audiohooks by type, regardless of type */
907 int ast_channel_audiohook_count_by_source(struct ast_channel *chan, const char *source, enum ast_audiohook_type type)
908 {
909         int count = 0;
910         struct ast_audiohook *ah = NULL;
911
912         if (!chan->audiohooks)
913                 return -1;
914
915         switch (type) {
916                 case AST_AUDIOHOOK_TYPE_SPY:
917                         AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->spy_list, ah, list) {
918                                 if (!strcmp(ah->source, source)) {
919                                         count++;
920                                 }
921                         }
922                         AST_LIST_TRAVERSE_SAFE_END;
923                         break;
924                 case AST_AUDIOHOOK_TYPE_WHISPER:
925                         AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->whisper_list, ah, list) {
926                                 if (!strcmp(ah->source, source)) {
927                                         count++;
928                                 }
929                         }
930                         AST_LIST_TRAVERSE_SAFE_END;
931                         break;
932                 case AST_AUDIOHOOK_TYPE_MANIPULATE:
933                         AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->manipulate_list, ah, list) {
934                                 if (!strcmp(ah->source, source)) {
935                                         count++;
936                                 }
937                         }
938                         AST_LIST_TRAVERSE_SAFE_END;
939                         break;
940                 default:
941                         ast_debug(1, "Invalid audiohook type supplied, (%d)\n", type);
942                         return -1;
943         }
944
945         return count;
946 }
947
948 /* Count number of channel audiohooks by type that are running */
949 int ast_channel_audiohook_count_by_source_running(struct ast_channel *chan, const char *source, enum ast_audiohook_type type)
950 {
951         int count = 0;
952         struct ast_audiohook *ah = NULL;
953         if (!chan->audiohooks)
954                 return -1;
955
956         switch (type) {
957                 case AST_AUDIOHOOK_TYPE_SPY:
958                         AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->spy_list, ah, list) {
959                                 if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
960                                         count++;
961                         }
962                         AST_LIST_TRAVERSE_SAFE_END;
963                         break;
964                 case AST_AUDIOHOOK_TYPE_WHISPER:
965                         AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->whisper_list, ah, list) {
966                                 if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
967                                         count++;
968                         }
969                         AST_LIST_TRAVERSE_SAFE_END;
970                         break;
971                 case AST_AUDIOHOOK_TYPE_MANIPULATE:
972                         AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->audiohooks->manipulate_list, ah, list) {
973                                 if ((!strcmp(ah->source, source)) && (ah->status == AST_AUDIOHOOK_STATUS_RUNNING))
974                                         count++;
975                         }
976                         AST_LIST_TRAVERSE_SAFE_END;
977                         break;
978                 default:
979                         ast_debug(1, "Invalid audiohook type supplied, (%d)\n", type);
980                         return -1;
981         }
982         return count;
983 }
984
985 /*! \brief Audiohook volume adjustment structure */
986 struct audiohook_volume {
987         struct ast_audiohook audiohook; /*!< Audiohook attached to the channel */
988         int read_adjustment;            /*!< Value to adjust frames read from the channel by */
989         int write_adjustment;           /*!< Value to adjust frames written to the channel by */
990 };
991
992 /*! \brief Callback used to destroy the audiohook volume datastore
993  * \param data Volume information structure
994  * \return Returns nothing
995  */
996 static void audiohook_volume_destroy(void *data)
997 {
998         struct audiohook_volume *audiohook_volume = data;
999
1000         /* Destroy the audiohook as it is no longer in use */
1001         ast_audiohook_destroy(&audiohook_volume->audiohook);
1002
1003         /* Finally free ourselves, we are of no more use */
1004         ast_free(audiohook_volume);
1005
1006         return;
1007 }
1008
1009 /*! \brief Datastore used to store audiohook volume information */
1010 static const struct ast_datastore_info audiohook_volume_datastore = {
1011         .type = "Volume",
1012         .destroy = audiohook_volume_destroy,
1013 };
1014
1015 /*! \brief Helper function which actually gets called by audiohooks to perform the adjustment
1016  * \param audiohook Audiohook attached to the channel
1017  * \param chan Channel we are attached to
1018  * \param frame Frame of audio we want to manipulate
1019  * \param direction Direction the audio came in from
1020  * \return Returns 0 on success, -1 on failure
1021  */
1022 static int audiohook_volume_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
1023 {
1024         struct ast_datastore *datastore = NULL;
1025         struct audiohook_volume *audiohook_volume = NULL;
1026         int *gain = NULL;
1027
1028         /* If the audiohook is shutting down don't even bother */
1029         if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) {
1030                 return 0;
1031         }
1032
1033         /* Try to find the datastore containg adjustment information, if we can't just bail out */
1034         if (!(datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) {
1035                 return 0;
1036         }
1037
1038         audiohook_volume = datastore->data;
1039
1040         /* Based on direction grab the appropriate adjustment value */
1041         if (direction == AST_AUDIOHOOK_DIRECTION_READ) {
1042                 gain = &audiohook_volume->read_adjustment;
1043         } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) {
1044                 gain = &audiohook_volume->write_adjustment;
1045         }
1046
1047         /* If an adjustment value is present modify the frame */
1048         if (gain && *gain) {
1049                 ast_frame_adjust_volume(frame, *gain);
1050         }
1051
1052         return 0;
1053 }
1054
1055 /*! \brief Helper function which finds and optionally creates an audiohook_volume_datastore datastore on a channel
1056  * \param chan Channel to look on
1057  * \param create Whether to create the datastore if not found
1058  * \return Returns audiohook_volume structure on success, NULL on failure
1059  */
1060 static struct audiohook_volume *audiohook_volume_get(struct ast_channel *chan, int create)
1061 {
1062         struct ast_datastore *datastore = NULL;
1063         struct audiohook_volume *audiohook_volume = NULL;
1064
1065         /* If we are able to find the datastore return the contents (which is actually an audiohook_volume structure) */
1066         if ((datastore = ast_channel_datastore_find(chan, &audiohook_volume_datastore, NULL))) {
1067                 return datastore->data;
1068         }
1069
1070         /* 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 */
1071         if (!create || !(datastore = ast_datastore_alloc(&audiohook_volume_datastore, NULL))) {
1072                 return NULL;
1073         }
1074
1075         /* Create a new audiohook_volume structure to contain our adjustments and audiohook */
1076         if (!(audiohook_volume = ast_calloc(1, sizeof(*audiohook_volume)))) {
1077                 ast_datastore_free(datastore);
1078                 return NULL;
1079         }
1080
1081         /* Setup our audiohook structure so we can manipulate the audio */
1082         ast_audiohook_init(&audiohook_volume->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Volume", AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
1083         audiohook_volume->audiohook.manipulate_callback = audiohook_volume_callback;
1084
1085         /* Attach the audiohook_volume blob to the datastore and attach to the channel */
1086         datastore->data = audiohook_volume;
1087         ast_channel_datastore_add(chan, datastore);
1088
1089         /* All is well... put the audiohook into motion */
1090         ast_audiohook_attach(chan, &audiohook_volume->audiohook);
1091
1092         return audiohook_volume;
1093 }
1094
1095 /*! \brief Adjust the volume on frames read from or written to a channel
1096  * \param chan Channel to muck with
1097  * \param direction Direction to set on
1098  * \param volume Value to adjust the volume by
1099  * \return Returns 0 on success, -1 on failure
1100  */
1101 int ast_audiohook_volume_set(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume)
1102 {
1103         struct audiohook_volume *audiohook_volume = NULL;
1104
1105         /* Attempt to find the audiohook volume information, but only create it if we are not setting the adjustment value to zero */
1106         if (!(audiohook_volume = audiohook_volume_get(chan, (volume ? 1 : 0)))) {
1107                 return -1;
1108         }
1109
1110         /* Now based on the direction set the proper value */
1111         if (direction == AST_AUDIOHOOK_DIRECTION_READ || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
1112                 audiohook_volume->read_adjustment = volume;
1113         }
1114         if (direction == AST_AUDIOHOOK_DIRECTION_WRITE || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
1115                 audiohook_volume->write_adjustment = volume;
1116         }
1117
1118         return 0;
1119 }
1120
1121 /*! \brief Retrieve the volume adjustment value on frames read from or written to a channel
1122  * \param chan Channel to retrieve volume adjustment from
1123  * \param direction Direction to retrieve
1124  * \return Returns adjustment value
1125  */
1126 int ast_audiohook_volume_get(struct ast_channel *chan, enum ast_audiohook_direction direction)
1127 {
1128         struct audiohook_volume *audiohook_volume = NULL;
1129         int adjustment = 0;
1130
1131         /* Attempt to find the audiohook volume information, but do not create it as we only want to look at the values */
1132         if (!(audiohook_volume = audiohook_volume_get(chan, 0))) {
1133                 return 0;
1134         }
1135
1136         /* Grab the adjustment value based on direction given */
1137         if (direction == AST_AUDIOHOOK_DIRECTION_READ) {
1138                 adjustment = audiohook_volume->read_adjustment;
1139         } else if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) {
1140                 adjustment = audiohook_volume->write_adjustment;
1141         }
1142
1143         return adjustment;
1144 }
1145
1146 /*! \brief Adjust the volume on frames read from or written to a channel
1147  * \param chan Channel to muck with
1148  * \param direction Direction to increase
1149  * \param volume Value to adjust the adjustment by
1150  * \return Returns 0 on success, -1 on failure
1151  */
1152 int ast_audiohook_volume_adjust(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume)
1153 {
1154         struct audiohook_volume *audiohook_volume = NULL;
1155
1156         /* Attempt to find the audiohook volume information, and create an audiohook if none exists */
1157         if (!(audiohook_volume = audiohook_volume_get(chan, 1))) {
1158                 return -1;
1159         }
1160
1161         /* Based on the direction change the specific adjustment value */
1162         if (direction == AST_AUDIOHOOK_DIRECTION_READ || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
1163                 audiohook_volume->read_adjustment += volume;
1164         }
1165         if (direction == AST_AUDIOHOOK_DIRECTION_WRITE || direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
1166                 audiohook_volume->write_adjustment += volume;
1167         }
1168
1169         return 0;
1170 }
1171
1172 /*! \brief Mute frames read from or written to a channel
1173  * \param chan Channel to muck with
1174  * \param source Type of audiohook
1175  * \param flag which flag to set / clear
1176  * \param clear set or clear
1177  * \return Returns 0 on success, -1 on failure
1178  */
1179 int ast_audiohook_set_mute(struct ast_channel *chan, const char *source, enum ast_audiohook_flags flag, int clear)
1180 {
1181         struct ast_audiohook *audiohook = NULL;
1182
1183         ast_channel_lock(chan);
1184
1185         /* Ensure the channel has audiohooks on it */
1186         if (!chan->audiohooks) {
1187                 ast_channel_unlock(chan);
1188                 return -1;
1189         }
1190
1191         audiohook = find_audiohook_by_source(chan->audiohooks, source);
1192
1193         if (audiohook) {
1194                 if (clear) {
1195                         ast_clear_flag(audiohook, flag);
1196                 } else {
1197                         ast_set_flag(audiohook, flag);
1198                 }
1199         }
1200
1201         ast_channel_unlock(chan);
1202
1203         return (audiohook ? 0 : -1);
1204 }