![]() |
Home page |
Mailing list |
Docs
Asterisk developer's documentation :: Codename Pineapple
chanspy.h File Reference
Definition in file chanspy.h.
#include "asterisk/linkedlists.h"
Include dependency graph for chanspy.h:

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.
Data Structures | |
| struct | ast_channel_spy |
| struct | ast_channel_spy_queue |
Enumerations | |
| enum | chanspy_flags { CHANSPY_MIXAUDIO = (1 << 0), CHANSPY_READ_VOLADJUST = (1 << 1), CHANSPY_WRITE_VOLADJUST = (1 << 2), CHANSPY_FORMAT_AUDIO = (1 << 3), CHANSPY_TRIGGER_MODE = (3 << 4), CHANSPY_TRIGGER_READ = (1 << 4), CHANSPY_TRIGGER_WRITE = (2 << 4), CHANSPY_TRIGGER_NONE = (3 << 4), CHANSPY_TRIGGER_FLUSH = (1 << 6) } |
| enum | chanspy_states { CHANSPY_NEW = 0, CHANSPY_RUNNING = 1, CHANSPY_DONE = 2, CHANSPY_STOP = 3 } |
Functions | |
| int | ast_channel_spy_add (struct ast_channel *chan, struct ast_channel_spy *spy) |
| Adds a spy to a channel, to begin receiving copies of the channel's audio frames. | |
| void | ast_channel_spy_free (struct ast_channel_spy *spy) |
| Free a spy. | |
| ast_frame * | ast_channel_spy_read_frame (struct ast_channel_spy *spy, unsigned int samples) |
| Read one (or more) frames of audio from a channel being spied upon. | |
| void | ast_channel_spy_remove (struct ast_channel *chan, struct ast_channel_spy *spy) |
| Remove a spy from a channel. | |
| void | ast_channel_spy_stop_by_type (struct ast_channel *chan, const char *type) |
| Find all spies of a particular type on a channel and stop them. | |
| void | ast_channel_spy_trigger_wait (struct ast_channel_spy *spy) |
| Efficiently wait until audio is available for a spy, or an exception occurs. | |
|
|
Definition at line 39 of file chanspy.h. 00039 { 00040 CHANSPY_MIXAUDIO = (1 << 0), 00041 CHANSPY_READ_VOLADJUST = (1 << 1), 00042 CHANSPY_WRITE_VOLADJUST = (1 << 2), 00043 CHANSPY_FORMAT_AUDIO = (1 << 3), 00044 CHANSPY_TRIGGER_MODE = (3 << 4), 00045 CHANSPY_TRIGGER_READ = (1 << 4), 00046 CHANSPY_TRIGGER_WRITE = (2 << 4), 00047 CHANSPY_TRIGGER_NONE = (3 << 4), 00048 CHANSPY_TRIGGER_FLUSH = (1 << 6), 00049 };
|
|
|
Definition at line 32 of file chanspy.h. 00032 { 00033 CHANSPY_NEW = 0, /*!< spy not yet operating */ 00034 CHANSPY_RUNNING = 1, /*!< normal operation, spy is still operating */ 00035 CHANSPY_DONE = 2, /*!< spy is stopped and already removed from channel */ 00036 CHANSPY_STOP = 3, /*!< spy requested to stop, still attached to channel */ 00037 };
|
|
||||||||||||
|
Adds a spy to a channel, to begin receiving copies of the channel's audio frames.
Definition at line 1194 of file channel.c. References ast_calloc, ast_clear_flag, ast_cond_init(), AST_FORMAT_SLINEAR, ast_getformatname(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_HEAD, AST_LIST_INSERT_TAIL, ast_log(), ast_set_flag, ast_test_flag, ast_channel_spy::chan, CHANSPY_FORMAT_AUDIO, CHANSPY_MIXAUDIO, CHANSPY_READ_VOLADJUST, CHANSPY_TRIGGER_MODE, CHANSPY_TRIGGER_NONE, CHANSPY_TRIGGER_READ, CHANSPY_TRIGGER_WRITE, CHANSPY_WRITE_VOLADJUST, ast_channel_spy_queue::format, LOG_DEBUG, LOG_WARNING, option_debug, ast_channel_spy::read_queue, ast_channel::spies, ast_channel_spy::trigger, ast_channel_spy::type, and ast_channel_spy::write_queue. 01195 { 01196 /* Link the owner channel to the spy */ 01197 spy->chan = chan; 01198 01199 if (!ast_test_flag(spy, CHANSPY_FORMAT_AUDIO)) { 01200 ast_log(LOG_WARNING, "Could not add channel spy '%s' to channel '%s', only audio format spies are supported.\n", 01201 spy->type, chan->name); 01202 return -1; 01203 } 01204 01205 if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST) && (spy->read_queue.format != AST_FORMAT_SLINEAR)) { 01206 ast_log(LOG_WARNING, "Cannot provide volume adjustment on '%s' format spies\n", 01207 ast_getformatname(spy->read_queue.format)); 01208 return -1; 01209 } 01210 01211 if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST) && (spy->write_queue.format != AST_FORMAT_SLINEAR)) { 01212 ast_log(LOG_WARNING, "Cannot provide volume adjustment on '%s' format spies\n", 01213 ast_getformatname(spy->write_queue.format)); 01214 return -1; 01215 } 01216 01217 if (ast_test_flag(spy, CHANSPY_MIXAUDIO) && 01218 ((spy->read_queue.format != AST_FORMAT_SLINEAR) || 01219 (spy->write_queue.format != AST_FORMAT_SLINEAR))) { 01220 ast_log(LOG_WARNING, "Cannot provide audio mixing on '%s'-'%s' format spies\n", 01221 ast_getformatname(spy->read_queue.format), ast_getformatname(spy->write_queue.format)); 01222 return -1; 01223 } 01224 01225 if (!chan->spies) { 01226 if (!(chan->spies = ast_calloc(1, sizeof(*chan->spies)))) { 01227 return -1; 01228 } 01229 01230 AST_LIST_HEAD_INIT_NOLOCK(&chan->spies->list); 01231 AST_LIST_INSERT_HEAD(&chan->spies->list, spy, list); 01232 } else { 01233 AST_LIST_INSERT_TAIL(&chan->spies->list, spy, list); 01234 } 01235 01236 if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE) { 01237 ast_cond_init(&spy->trigger, NULL); 01238 ast_set_flag(spy, CHANSPY_TRIGGER_READ); 01239 ast_clear_flag(spy, CHANSPY_TRIGGER_WRITE); 01240 } 01241 01242 if (option_debug) 01243 ast_log(LOG_DEBUG, "Spy %s added to channel %s\n", 01244 spy->type, chan->name); 01245 01246 return 0; 01247 }
|
|
|
Free a spy.
Definition at line 1329 of file channel.c. References ast_cond_destroy(), ast_frfree(), AST_LIST_REMOVE_HEAD, ast_mutex_destroy(), ast_test_flag, CHANSPY_DONE, CHANSPY_TRIGGER_MODE, CHANSPY_TRIGGER_NONE, ast_channel_spy::lock, ast_channel_spy::read_queue, ast_channel_spy::status, ast_channel_spy::trigger, and ast_channel_spy::write_queue. 01330 { 01331 struct ast_frame *f = NULL; 01332 01333 if (spy->status == CHANSPY_DONE) 01334 return; 01335 01336 /* Switch status to done in case we get called twice */ 01337 spy->status = CHANSPY_DONE; 01338 01339 /* Drop any frames in the queue */ 01340 while ((f = AST_LIST_REMOVE_HEAD(&spy->write_queue.list, frame_list))) 01341 ast_frfree(f); 01342 while ((f = AST_LIST_REMOVE_HEAD(&spy->read_queue.list, frame_list))) 01343 ast_frfree(f); 01344 01345 /* Destroy the condition if in use */ 01346 if (ast_test_flag(spy, CHANSPY_TRIGGER_MODE) != CHANSPY_TRIGGER_NONE) 01347 ast_cond_destroy(&spy->trigger); 01348 01349 /* Destroy our mutex since it is no longer in use */ 01350 ast_mutex_destroy(&spy->lock); 01351 01352 return; 01353 }
|
|
||||||||||||
|
Read one (or more) frames of audio from a channel being spied upon.
Note: This function performs no locking; you must hold the spy's lock before calling this function. You must not hold the channel's lock at the same time. Definition at line 4357 of file channel.c. References ast_clear_flag, ast_codec_get_len(), ast_frame_adjust_volume(), ast_frame_slinear_sum(), AST_FRAME_VOICE, ast_frdup(), ast_frfree(), AST_LIST_FIRST, AST_LIST_HEAD_SET_NOLOCK, AST_LIST_NEXT, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, ast_test_flag, CHANSPY_MIXAUDIO, CHANSPY_READ_VOLADJUST, CHANSPY_TRIGGER_FLUSH, CHANSPY_WRITE_VOLADJUST, copy_data_from_queue(), ast_channel_spy_queue::format, ast_frame::frametype, ast_channel_spy::read_queue, ast_channel_spy::read_vol_adjustment, ast_channel_spy_queue::samples, ast_channel_spy::write_queue, and ast_channel_spy::write_vol_adjustment. 04358 { 04359 struct ast_frame *result; 04360 /* buffers are allocated to hold SLINEAR, which is the largest format */ 04361 short read_buf[samples]; 04362 short write_buf[samples]; 04363 struct ast_frame *read_frame; 04364 struct ast_frame *write_frame; 04365 int need_dup; 04366 struct ast_frame stack_read_frame = { .frametype = AST_FRAME_VOICE, 04367 .subclass = spy->read_queue.format, 04368 .data = read_buf, 04369 .samples = samples, 04370 .datalen = ast_codec_get_len(spy->read_queue.format, samples), 04371 }; 04372 struct ast_frame stack_write_frame = { .frametype = AST_FRAME_VOICE, 04373 .subclass = spy->write_queue.format, 04374 .data = write_buf, 04375 .samples = samples, 04376 .datalen = ast_codec_get_len(spy->write_queue.format, samples), 04377 }; 04378 04379 /* if a flush has been requested, dump everything in whichever queue is larger */ 04380 if (ast_test_flag(spy, CHANSPY_TRIGGER_FLUSH)) { 04381 if (spy->read_queue.samples > spy->write_queue.samples) { 04382 if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST)) { 04383 AST_LIST_TRAVERSE(&spy->read_queue.list, result, frame_list) 04384 ast_frame_adjust_volume(result, spy->read_vol_adjustment); 04385 } 04386 result = AST_LIST_FIRST(&spy->read_queue.list); 04387 AST_LIST_HEAD_SET_NOLOCK(&spy->read_queue.list, NULL); 04388 spy->read_queue.samples = 0; 04389 } else { 04390 if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST)) { 04391 AST_LIST_TRAVERSE(&spy->write_queue.list, result, frame_list) 04392 ast_frame_adjust_volume(result, spy->write_vol_adjustment); 04393 } 04394 result = AST_LIST_FIRST(&spy->write_queue.list); 04395 AST_LIST_HEAD_SET_NOLOCK(&spy->write_queue.list, NULL); 04396 spy->write_queue.samples = 0; 04397 } 04398 ast_clear_flag(spy, CHANSPY_TRIGGER_FLUSH); 04399 return result; 04400 } 04401 04402 if ((spy->read_queue.samples < samples) || (spy->write_queue.samples < samples)) 04403 return NULL; 04404 04405 /* short-circuit if both head frames have exactly what we want */ 04406 if ((AST_LIST_FIRST(&spy->read_queue.list)->samples == samples) && 04407 (AST_LIST_FIRST(&spy->write_queue.list)->samples == samples)) { 04408 read_frame = AST_LIST_REMOVE_HEAD(&spy->read_queue.list, frame_list); 04409 write_frame = AST_LIST_REMOVE_HEAD(&spy->write_queue.list, frame_list); 04410 04411 spy->read_queue.samples -= samples; 04412 spy->write_queue.samples -= samples; 04413 04414 need_dup = 0; 04415 } else { 04416 copy_data_from_queue(&spy->read_queue, read_buf, samples); 04417 copy_data_from_queue(&spy->write_queue, write_buf, samples); 04418 04419 read_frame = &stack_read_frame; 04420 write_frame = &stack_write_frame; 04421 need_dup = 1; 04422 } 04423 04424 if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST)) 04425 ast_frame_adjust_volume(read_frame, spy->read_vol_adjustment); 04426 04427 if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST)) 04428 ast_frame_adjust_volume(write_frame, spy->write_vol_adjustment); 04429 04430 if (ast_test_flag(spy, CHANSPY_MIXAUDIO)) { 04431 ast_frame_slinear_sum(read_frame, write_frame); 04432 04433 if (need_dup) 04434 result = ast_frdup(read_frame); 04435 else { 04436 result = read_frame; 04437 ast_frfree(write_frame); 04438 } 04439 } else { 04440 if (need_dup) { 04441 result = ast_frdup(read_frame); 04442 AST_LIST_NEXT(result, frame_list) = ast_frdup(write_frame); 04443 } else { 04444 result = read_frame; 04445 AST_LIST_NEXT(result, frame_list) = write_frame; 04446 } 04447 } 04448 04449 return result; 04450 }
|
|
||||||||||||
|
Remove a spy from a channel.
Definition at line 1319 of file channel.c. References AST_LIST_REMOVE, ast_channel::spies, spy_cleanup(), and spy_detach(). 01320 { 01321 if (!chan->spies) 01322 return; 01323 01324 AST_LIST_REMOVE(&chan->spies->list, spy, list); 01325 spy_detach(spy, chan); 01326 spy_cleanup(chan); 01327 }
|
|
||||||||||||
|
Find all spies of a particular type on a channel and stop them.
Definition at line 1287 of file channel.c. References AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_mutex_lock(), ast_mutex_unlock(), ast_channel_spy::chan, CHANSPY_RUNNING, ast_channel_spy::lock, ast_channel::spies, spy_cleanup(), spy_detach(), ast_channel_spy::status, and ast_channel_spy::type. 01288 { 01289 struct ast_channel_spy *spy = NULL; 01290 01291 if (!chan->spies) 01292 return; 01293 01294 AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->spies->list, spy, list) { 01295 ast_mutex_lock(&spy->lock); 01296 if ((spy->type == type) && (spy->status == CHANSPY_RUNNING)) { 01297 ast_mutex_unlock(&spy->lock); 01298 AST_LIST_REMOVE_CURRENT(&chan->spies->list, list); 01299 spy_detach(spy, chan); 01300 } else 01301 ast_mutex_unlock(&spy->lock); 01302 } 01303 AST_LIST_TRAVERSE_SAFE_END 01304 spy_cleanup(chan); 01305 }
|
|
|
Efficiently wait until audio is available for a spy, or an exception occurs.
Definition at line 1307 of file channel.c. References ast_cond_timedwait(), ast_tvadd(), ast_channel_spy::lock, and ast_channel_spy::trigger. 01308 { 01309 struct timeval tv; 01310 struct timespec ts; 01311 01312 tv = ast_tvadd(ast_tvnow(), ast_samp2tv(50000, 1000)); 01313 ts.tv_sec = tv.tv_sec; 01314 ts.tv_nsec = tv.tv_usec * 1000; 01315 01316 ast_cond_timedwait(&spy->trigger, &spy->lock, &ts); 01317 }
|