Esempio n. 1
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;
}
Esempio n. 2
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 = 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;
}
Esempio n. 3
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;
}
Esempio n. 4
0
static void destroy_callback(void *data)
{
	struct volume_information *vi = data;

	/* Destroy the audiohook, and destroy ourselves */
	ast_audiohook_lock(&vi->audiohook);
	ast_audiohook_detach(&vi->audiohook);
	ast_audiohook_unlock(&vi->audiohook);
	ast_audiohook_destroy(&vi->audiohook);
	ast_free(vi);

	return;
}
Esempio n. 5
0
static void destroy_monitor_audiohook(struct mixmonitor *mixmonitor)
{
	if (mixmonitor->mixmonitor_ds) {
		ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
		mixmonitor->mixmonitor_ds->audiohook = NULL;
		ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
	}
	/* kill the audiohook.*/
	ast_audiohook_lock(&mixmonitor->audiohook);
	ast_audiohook_detach(&mixmonitor->audiohook);
	ast_audiohook_unlock(&mixmonitor->audiohook);
	ast_audiohook_destroy(&mixmonitor->audiohook);
}
Esempio n. 6
0
static void hook_datastore_destroy_callback(void *data)
{
	struct hook_state *state = data;

	ast_audiohook_lock(&state->audiohook);
	ast_audiohook_detach(&state->audiohook);
	ast_audiohook_unlock(&state->audiohook);
	ast_audiohook_destroy(&state->audiohook);

	ast_free(state->context);
	ast_free(state->exten);
	ast_free(state);

	ast_module_unref(ast_module_info->self);
}
Esempio n. 7
0
/*! \brief Callback function for hanging up a Snoop channel */
static int snoop_hangup(struct ast_channel *chan)
{
	struct stasis_app_snoop *snoop = ast_channel_tech_pvt(chan);

	if (snoop->spy_active) {
		ast_audiohook_lock(&snoop->spy);
		ast_audiohook_detach(&snoop->spy);
		ast_audiohook_unlock(&snoop->spy);
	}

	if (snoop->whisper_active) {
		ast_audiohook_lock(&snoop->whisper);
		ast_audiohook_detach(&snoop->whisper);
		ast_audiohook_unlock(&snoop->whisper);
	}

	publish_chanspy_message(snoop, 0);

	ao2_cleanup(snoop);

	ast_channel_tech_pvt_set(chan, NULL);

	return 0;
}
Esempio n. 8
0
/*! \brief Callback function for writing to a Snoop whisper audiohook */
static int snoop_write(struct ast_channel *chan, struct ast_frame *frame)
{
	struct stasis_app_snoop *snoop = ast_channel_tech_pvt(chan);

	if (!snoop->whisper_active) {
		return 0;
	}

	ast_audiohook_lock(&snoop->whisper);
	if (snoop->whisper_direction == AST_AUDIOHOOK_DIRECTION_BOTH) {
		ast_audiohook_write_frame(&snoop->whisper, AST_AUDIOHOOK_DIRECTION_READ, frame);
		ast_audiohook_write_frame(&snoop->whisper, AST_AUDIOHOOK_DIRECTION_WRITE, frame);
	} else {
		ast_audiohook_write_frame(&snoop->whisper, snoop->whisper_direction, frame);
	}
	ast_audiohook_unlock(&snoop->whisper);

	return 0;
}
Esempio n. 9
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) {
		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;
}
Esempio n. 10
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;
}
Esempio n. 11
0
static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_autochan,
	int *volfactor, int fd, struct spy_dtmf_options *user_options, struct ast_flags *flags,
	char *exitcontext)
{
	struct chanspy_translation_helper csth;
	int running = 0, res, x = 0;
	char inp[24] = {0};
	char *name;
	struct ast_frame *f;
	struct ast_silence_generator *silgen = NULL;
	struct ast_autochan *spyee_bridge_autochan = NULL;
	const char *spyer_name;
	struct ast_channel *chans[] = { chan, spyee_autochan->chan };

	ast_channel_lock(chan);
	spyer_name = ast_strdupa(chan->name);
	ast_channel_unlock(chan);

	/* We now hold the channel lock on spyee */

	if (ast_check_hangup(chan) || ast_check_hangup(spyee_autochan->chan)) {
		return 0;
	}

	ast_channel_lock(spyee_autochan->chan);
	name = ast_strdupa(spyee_autochan->chan->name);
	ast_channel_unlock(spyee_autochan->chan);

	ast_verb(2, "Spying on channel %s\n", name);
	ast_manager_event_multichan(EVENT_FLAG_CALL, "ChanSpyStart", 2, chans,
			"SpyerChannel: %s\r\n"
			"SpyeeChannel: %s\r\n",
			spyer_name, name);

	memset(&csth, 0, sizeof(csth));
	ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);

	ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");

	if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook)) {
		ast_audiohook_destroy(&csth.spy_audiohook);
		return 0;
	}

	ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
	ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy");
	if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook)) {
		ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
	}
	if ((spyee_bridge_autochan = ast_autochan_setup(ast_bridged_channel(spyee_autochan->chan)))) {
		ast_channel_lock(spyee_bridge_autochan->chan);
		if (start_spying(spyee_bridge_autochan, spyer_name, &csth.bridge_whisper_audiohook)) {
			ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", name);
		}
		ast_channel_unlock(spyee_bridge_autochan->chan);
	}

	ast_channel_lock(chan);
	ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY);
	ast_channel_unlock(chan);

	csth.volfactor = *volfactor;

	if (csth.volfactor) {
		csth.spy_audiohook.options.read_volume = csth.volfactor;
		csth.spy_audiohook.options.write_volume = csth.volfactor;
	}

	csth.fd = fd;

	if (ast_test_flag(flags, OPTION_PRIVATE))
		silgen = ast_channel_start_silence_generator(chan);
	else
		ast_activate_generator(chan, &spygen, &csth);

	/* We can no longer rely on 'spyee' being an actual channel;
	   it can be hung up and freed out from under us. However, the
	   channel destructor will put NULL into our csth.spy.chan
	   field when that happens, so that is our signal that the spyee
	   channel has gone away.
	*/

	/* Note: it is very important that the ast_waitfor() be the first
	   condition in this expression, so that if we wait for some period
	   of time before receiving a frame from our spying channel, we check
	   for hangup on the spied-on channel _after_ knowing that a frame
	   has arrived, since the spied-on channel could have gone away while
	   we were waiting
	*/
	while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
		if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
			running = -1;
			break;
		}

		if (ast_test_flag(flags, OPTION_BARGE) && f->frametype == AST_FRAME_VOICE) {
			ast_audiohook_lock(&csth.whisper_audiohook);
			ast_audiohook_lock(&csth.bridge_whisper_audiohook);
			ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
			ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
			ast_audiohook_unlock(&csth.whisper_audiohook);
			ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
			ast_frfree(f);
			continue;
		} else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
			ast_audiohook_lock(&csth.whisper_audiohook);
			ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
			ast_audiohook_unlock(&csth.whisper_audiohook);
			ast_frfree(f);
			continue;
		}
		
		res = (f->frametype == AST_FRAME_DTMF) ? f->subclass.integer : 0;
		ast_frfree(f);
		if (!res)
			continue;

		if (x == sizeof(inp))
			x = 0;

		if (res < 0) {
			running = -1;
			break;
		}

		if (ast_test_flag(flags, OPTION_EXIT)) {
			char tmp[2];
			tmp[0] = res;
			tmp[1] = '\0';
			if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
				ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
				pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
				running = -2;
				break;
			} else {
				ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
			}
		} else if (res >= '0' && res <= '9') {
			if (ast_test_flag(flags, OPTION_DTMF_SWITCH_MODES)) {
				change_spy_mode(res, flags);
			} else {
				inp[x++] = res;
			}
		}

		if (res == user_options->cycle) {
			running = 0;
			break;
		} else if (res == user_options->exit) {
			running = -2;
			break;
		} else if (res == user_options->volume) {
			if (!ast_strlen_zero(inp)) {
				running = atoi(inp);
				break;
			}

			(*volfactor)++;
			if (*volfactor > 4)
				*volfactor = -4;
			ast_verb(3, "Setting spy volume on %s to %d\n", chan->name, *volfactor);

			csth.volfactor = *volfactor;
			csth.spy_audiohook.options.read_volume = csth.volfactor;
			csth.spy_audiohook.options.write_volume = csth.volfactor;
		}
	}

	if (ast_test_flag(flags, OPTION_PRIVATE))
		ast_channel_stop_silence_generator(chan, silgen);
	else
		ast_deactivate_generator(chan);

	ast_channel_lock(chan);
	ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
	ast_channel_unlock(chan);

	ast_audiohook_lock(&csth.whisper_audiohook);
	ast_audiohook_detach(&csth.whisper_audiohook);
	ast_audiohook_unlock(&csth.whisper_audiohook);
	ast_audiohook_destroy(&csth.whisper_audiohook);
	
	ast_audiohook_lock(&csth.bridge_whisper_audiohook);
	ast_audiohook_detach(&csth.bridge_whisper_audiohook);
	ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
	ast_audiohook_destroy(&csth.bridge_whisper_audiohook);

	ast_audiohook_lock(&csth.spy_audiohook);
	ast_audiohook_detach(&csth.spy_audiohook);
	ast_audiohook_unlock(&csth.spy_audiohook);
	ast_audiohook_destroy(&csth.spy_audiohook);

	if (spyee_bridge_autochan) {
		ast_autochan_destroy(spyee_bridge_autochan);
	}

	ast_verb(2, "Done Spying on channel %s\n", name);
	ast_manager_event(chan, EVENT_FLAG_CALL, "ChanSpyStop", "SpyeeChannel: %s\r\n", name);

	return running;
}
Esempio n. 12
0
static void *mixmonitor_thread(void *obj) 
{
	struct mixmonitor *mixmonitor = obj;

	struct ast_filestream **fs = NULL;
	struct ast_filestream **fs_read = NULL;
	struct ast_filestream **fs_write = NULL;

	unsigned int oflags;
	int errflag = 0;
	struct ast_format format_slin;

	ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name);

	fs = &mixmonitor->mixmonitor_ds->fs;
	fs_read = &mixmonitor->mixmonitor_ds->fs_read;
	fs_write = &mixmonitor->mixmonitor_ds->fs_write;

	ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
	mixmonitor_save_prep(mixmonitor, mixmonitor->filename, fs, &oflags, &errflag);
	mixmonitor_save_prep(mixmonitor, mixmonitor->filename_read, fs_read, &oflags, &errflag);
	mixmonitor_save_prep(mixmonitor, mixmonitor->filename_write, fs_write, &oflags, &errflag);

	ast_format_set(&format_slin, ast_format_slin_by_rate(mixmonitor->mixmonitor_ds->samp_rate), 0);

	ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);


	/* 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;
		struct ast_frame *fr_read = NULL;
		struct ast_frame *fr_write = NULL;

		if (!(fr = ast_audiohook_read_frame_all(&mixmonitor->audiohook, SAMPLES_PER_FRAME, &format_slin,
						&fr_read, &fr_write))) {
			ast_audiohook_trigger_wait(&mixmonitor->audiohook);

			if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
				break;
			}
			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);

		if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->autochan->chan && ast_bridged_channel(mixmonitor->autochan->chan))) {
			ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);

			/* Write out the frame(s) */
			if ((*fs_read) && (fr_read)) {
				struct ast_frame *cur;

				for (cur = fr_read; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
					ast_writestream(*fs_read, cur);
				}
			}

			if ((*fs_write) && (fr_write)) {
				struct ast_frame *cur;

				for (cur = fr_write; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
					ast_writestream(*fs_write, cur);
				}
			}

			if ((*fs) && (fr)) {
				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. */
		if (fr) {
			ast_frame_free(fr, 0);
		}
		if (fr_read) {
			ast_frame_free(fr_read, 0);
		}
		if (fr_write) {
			ast_frame_free(fr_write, 0);
		}

		fr = NULL;
		fr_write = NULL;
		fr_read = NULL;

		ast_audiohook_lock(&mixmonitor->audiohook);
	}
	ast_audiohook_unlock(&mixmonitor->audiohook);

	ast_autochan_destroy(mixmonitor->autochan);

	/* 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;
}
Esempio n. 13
0
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;
}
Esempio n. 14
0
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;
}
Esempio n. 15
0
static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chanspy_ds, 
	int *volfactor, int fd, const struct ast_flags *flags) 
{
	struct chanspy_translation_helper csth;
	int running = 0, res, x = 0;
	char inp[24] = {0};
	char *name;
	struct ast_frame *f;
	struct ast_silence_generator *silgen = NULL;
	struct ast_channel *spyee = NULL;
	const char *spyer_name;

	ast_channel_lock(chan);
	spyer_name = ast_strdupa(chan->name);
	ast_channel_unlock(chan);

	ast_mutex_lock(&spyee_chanspy_ds->lock);
	while ((spyee = spyee_chanspy_ds->chan) && ast_channel_trylock(spyee)) {
		/* avoid a deadlock here, just in case spyee is masqueraded and
		 * chanspy_ds_chan_fixup() is called with the channel locked */
		DEADLOCK_AVOIDANCE(&spyee_chanspy_ds->lock);
	}
	ast_mutex_unlock(&spyee_chanspy_ds->lock);

	if (!spyee)
		return 0;

	/* We now hold the channel lock on spyee */

	if (ast_check_hangup(chan) || ast_check_hangup(spyee)) {
		ast_channel_unlock(spyee);
		return 0;
	}

	name = ast_strdupa(spyee->name);
	if (option_verbose >= 2)
		ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name);

	memset(&csth, 0, sizeof(csth));
	
	ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");

	if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) {
		ast_audiohook_destroy(&csth.spy_audiohook);
		ast_channel_unlock(spyee);
		return 0;
	}
	
	if (ast_test_flag(flags, OPTION_WHISPER)) {
		ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
		start_spying(spyee, spyer_name, &csth.whisper_audiohook);
	}

	ast_channel_unlock(spyee);
	spyee = NULL;

	csth.volfactor = *volfactor;
	
	if (csth.volfactor) {
		csth.spy_audiohook.options.read_volume = csth.volfactor;
		csth.spy_audiohook.options.write_volume = csth.volfactor;
	}
	
	csth.fd = fd;

	if (ast_test_flag(flags, OPTION_PRIVATE))
		silgen = ast_channel_start_silence_generator(chan);
	else
		ast_activate_generator(chan, &spygen, &csth);

	/* We can no longer rely on 'spyee' being an actual channel;
	   it can be hung up and freed out from under us. However, the
	   channel destructor will put NULL into our csth.spy.chan
	   field when that happens, so that is our signal that the spyee
	   channel has gone away.
	*/

	/* Note: it is very important that the ast_waitfor() be the first
	   condition in this expression, so that if we wait for some period
	   of time before receiving a frame from our spying channel, we check
	   for hangup on the spied-on channel _after_ knowing that a frame
	   has arrived, since the spied-on channel could have gone away while
	   we were waiting
	*/
	while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
		if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
			running = -1;
			break;
		}

		if (ast_test_flag(flags, OPTION_WHISPER) && (f->frametype == AST_FRAME_VOICE)) {
			ast_audiohook_lock(&csth.whisper_audiohook);
			ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
			ast_audiohook_unlock(&csth.whisper_audiohook);
			ast_frfree(f);
			continue;
		}

		res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0;
		ast_frfree(f);
		if (!res)
			continue;

		if (x == sizeof(inp))
			x = 0;

		if (res < 0) {
			running = -1;
			break;
		}

		if (res == '*') {
			running = 0;
			break;
		} else if (res == '#') {
			if (!ast_strlen_zero(inp)) {
				running = atoi(inp);
				break;
			}

			(*volfactor)++;
			if (*volfactor > 4)
				*volfactor = -4;
			if (option_verbose > 2)
				ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor);
			csth.volfactor = *volfactor;
			csth.spy_audiohook.options.read_volume = csth.volfactor;
			csth.spy_audiohook.options.write_volume = csth.volfactor;
		} else if (res >= '0' && res <= '9') {
			inp[x++] = res;
		}
	}

	if (ast_test_flag(flags, OPTION_PRIVATE))
		ast_channel_stop_silence_generator(chan, silgen);
	else
		ast_deactivate_generator(chan);

	if (ast_test_flag(flags, OPTION_WHISPER)) {
		ast_audiohook_lock(&csth.whisper_audiohook);
		ast_audiohook_detach(&csth.whisper_audiohook);
		ast_audiohook_unlock(&csth.whisper_audiohook);
		ast_audiohook_destroy(&csth.whisper_audiohook);
	}
	
	ast_audiohook_lock(&csth.spy_audiohook);
	ast_audiohook_detach(&csth.spy_audiohook);
	ast_audiohook_unlock(&csth.spy_audiohook);
	ast_audiohook_destroy(&csth.spy_audiohook);
	
	if (option_verbose >= 2)
		ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
	
	return running;
}