static int spy_generate(struct ast_channel *chan, void *data, int len, int samples) { struct chanspy_translation_helper *csth = data; struct ast_frame *f = NULL; ast_audiohook_lock(&csth->spy_audiohook); if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) { /* Channel is already gone more than likely */ ast_audiohook_unlock(&csth->spy_audiohook); return -1; } f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR); ast_audiohook_unlock(&csth->spy_audiohook); if (!f) return 0; if (ast_write(chan, f)) { ast_frfree(f); return -1; } if (csth->fd) write(csth->fd, f->data, f->datalen); ast_frfree(f); return 0; }
static int spy_generate(struct ast_channel *chan, void *data, int len, int samples) { struct chanspy_translation_helper *csth = data; struct ast_frame *f, *cur; ast_audiohook_lock(&csth->spy_audiohook); if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) { ast_audiohook_unlock(&csth->spy_audiohook); return -1; } f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR); ast_audiohook_unlock(&csth->spy_audiohook); if (!f) return 0; for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) { if (ast_write(chan, cur)) { ast_frfree(f); return -1; } if (csth->fd) { if (write(csth->fd, cur->data, cur->datalen) < 0) { ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno)); } } } ast_frfree(f); return 0; }
static int spy_generate(struct ast_channel *chan, void *data, int len, int samples) { struct chanspy_translation_helper *csth = data; struct ast_frame *f, *cur; struct ast_format format_slin; ast_format_set(&format_slin, AST_FORMAT_SLINEAR, 0); ast_audiohook_lock(&csth->spy_audiohook); if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) { /* Channel is already gone more than likely */ ast_audiohook_unlock(&csth->spy_audiohook); return -1; } if (ast_test_flag(&csth->flags, OPTION_READONLY)) { /* Option 'o' was set, so don't mix channel audio */ f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_READ, &format_slin); } else { f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, &format_slin); } ast_audiohook_unlock(&csth->spy_audiohook); if (!f) return 0; for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) { if (ast_write(chan, cur)) { ast_frfree(f); return -1; } if (csth->fd) { if (write(csth->fd, cur->data.ptr, cur->datalen) < 0) { ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno)); } } } ast_frfree(f); return 0; }
/*! \brief Callback function for reading from a Snoop channel */ static struct ast_frame *snoop_read(struct ast_channel *chan) { struct stasis_app_snoop *snoop = ast_channel_tech_pvt(chan); struct ast_frame *frame = NULL; /* If we fail to ack the timer OR if any active audiohooks are done hangup */ if ((ast_timer_ack(snoop->timer, 1) < 0) || (snoop->spy_active && snoop->spy.status != AST_AUDIOHOOK_STATUS_RUNNING) || (snoop->whisper_active && snoop->whisper.status != AST_AUDIOHOOK_STATUS_RUNNING)) { return NULL; } /* Only get audio from the spy audiohook if it is active */ if (!snoop->spy_active) { return &ast_null_frame; } ast_audiohook_lock(&snoop->spy); if (snoop->spy_direction != AST_AUDIOHOOK_DIRECTION_BOTH) { /* * When a singular direction is chosen frames are still written to the * opposing direction's queue. Those frames must be read so the queue * does not continue to grow, however since they are not needed for the * selected direction they can be dropped. */ enum ast_audiohook_direction opposing_direction = snoop->spy_direction == AST_AUDIOHOOK_DIRECTION_READ ? AST_AUDIOHOOK_DIRECTION_WRITE : AST_AUDIOHOOK_DIRECTION_READ; ast_frame_dtor(ast_audiohook_read_frame(&snoop->spy, snoop->spy_samples, opposing_direction, snoop->spy_format)); } frame = ast_audiohook_read_frame(&snoop->spy, snoop->spy_samples, snoop->spy_direction, snoop->spy_format); ast_audiohook_unlock(&snoop->spy); return frame ? frame : &ast_null_frame; }
/*! \brief Callback function for reading from a Snoop channel */ static struct ast_frame *snoop_read(struct ast_channel *chan) { struct stasis_app_snoop *snoop = ast_channel_tech_pvt(chan); struct ast_frame *frame = NULL; /* If we fail to ack the timer OR if any active audiohooks are done hangup */ if ((ast_timer_ack(snoop->timer, 1) < 0) || (snoop->spy_active && snoop->spy.status != AST_AUDIOHOOK_STATUS_RUNNING) || (snoop->whisper_active && snoop->whisper.status != AST_AUDIOHOOK_STATUS_RUNNING)) { return NULL; } /* Only get audio from the spy audiohook if it is active */ if (snoop->spy_active) { ast_audiohook_lock(&snoop->spy); frame = ast_audiohook_read_frame(&snoop->spy, snoop->spy_samples, snoop->spy_direction, snoop->spy_format); ast_audiohook_unlock(&snoop->spy); } return frame ? frame : &ast_null_frame; }
static void *mixmonitor_thread(void *obj) { struct mixmonitor *mixmonitor = obj; struct ast_filestream **fs = NULL; unsigned int oflags; char *ext; int errflag = 0; ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name); fs = &mixmonitor->mixmonitor_ds->fs; /* The audiohook must enter and exit the loop locked */ ast_audiohook_lock(&mixmonitor->audiohook); while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) { struct ast_frame *fr = NULL; ast_audiohook_trigger_wait(&mixmonitor->audiohook); if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) break; if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR))) continue; /* audiohook lock is not required for the next block. * Unlock it, but remember to lock it before looping or exiting */ ast_audiohook_unlock(&mixmonitor->audiohook); ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->mixmonitor_ds->chan && ast_bridged_channel(mixmonitor->mixmonitor_ds->chan))) { /* Initialize the file if not already done so */ if (!*fs && !errflag && !mixmonitor->mixmonitor_ds->fs_quit) { oflags = O_CREAT | O_WRONLY; oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC; if ((ext = strrchr(mixmonitor->filename, '.'))) *(ext++) = '\0'; else ext = "raw"; if (!(*fs = ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0666))) { ast_log(LOG_ERROR, "Cannot open %s.%s\n", mixmonitor->filename, ext); errflag = 1; } } /* Write out the frame(s) */ if (*fs) { struct ast_frame *cur; for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) { ast_writestream(*fs, cur); } } } ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); /* All done! free it. */ ast_frame_free(fr, 0); ast_audiohook_lock(&mixmonitor->audiohook); } ast_audiohook_unlock(&mixmonitor->audiohook); /* Datastore cleanup. close the filestream and wait for ds destruction */ ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds); if (!mixmonitor->mixmonitor_ds->destruction_ok) { ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock); } ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); /* kill the audiohook */ destroy_monitor_audiohook(mixmonitor); if (mixmonitor->post_process) { ast_verb(2, "Executing [%s]\n", mixmonitor->post_process); ast_safe_system(mixmonitor->post_process); } ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name); mixmonitor_free(mixmonitor); return NULL; }
static void *mixmonitor_thread(void *obj) { struct mixmonitor *mixmonitor = obj; struct ast_filestream *fs = NULL; unsigned int oflags; char *ext; int errflag = 0; if (option_verbose > 1) ast_verbose(VERBOSE_PREFIX_2 "Begin MixMonitor Recording %s\n", mixmonitor->name); ast_audiohook_lock(&mixmonitor->audiohook); while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) { struct ast_frame *fr = NULL; ast_audiohook_trigger_wait(&mixmonitor->audiohook); if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) break; if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR))) continue; ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->mixmonitor_ds->chan && ast_bridged_channel(mixmonitor->mixmonitor_ds->chan))) { ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); /* Initialize the file if not already done so */ if (!fs && !errflag) { oflags = O_CREAT | O_WRONLY; oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC; if ((ext = strrchr(mixmonitor->filename, '.'))) *(ext++) = '\0'; else ext = "raw"; if (!(fs = ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0644))) { ast_log(LOG_ERROR, "Cannot open %s.%s\n", mixmonitor->filename, ext); errflag = 1; } } /* Write out the frame */ if (fs) ast_writestream(fs, fr); } else { ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); } /* All done! free it. */ ast_frame_free(fr, 0); } ast_audiohook_detach(&mixmonitor->audiohook); ast_audiohook_unlock(&mixmonitor->audiohook); ast_audiohook_destroy(&mixmonitor->audiohook); if (option_verbose > 1) ast_verbose(VERBOSE_PREFIX_2 "End MixMonitor Recording %s\n", mixmonitor->name); if (fs) ast_closestream(fs); if (mixmonitor->post_process) { if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_2 "Executing [%s]\n", mixmonitor->post_process); ast_safe_system(mixmonitor->post_process); } ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); if (!mixmonitor->mixmonitor_ds->destruction_ok) { ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock); } ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock); ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition); ast_free(mixmonitor->mixmonitor_ds); free(mixmonitor); return NULL; }