Newer
Older
Kevin P. Fleming
committed
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
.datalen = ast_codec_get_len(spy->read_queue.format, samples),
};
struct ast_frame stack_write_frame = { .frametype = AST_FRAME_VOICE,
.subclass = spy->write_queue.format,
.data = write_buf,
.samples = samples,
.datalen = ast_codec_get_len(spy->write_queue.format, samples),
};
/* if a flush has been requested, dump everything in whichever queue is larger */
if (ast_test_flag(spy, CHANSPY_TRIGGER_FLUSH)) {
if (spy->read_queue.samples > spy->write_queue.samples) {
if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST)) {
for (result = spy->read_queue.head; result; result = result->next)
ast_frame_adjust_volume(result, spy->read_vol_adjustment);
}
result = spy->read_queue.head;
spy->read_queue.head = NULL;
spy->read_queue.samples = 0;
ast_clear_flag(spy, CHANSPY_TRIGGER_FLUSH);
return result;
} else {
if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST)) {
for (result = spy->write_queue.head; result; result = result->next)
ast_frame_adjust_volume(result, spy->write_vol_adjustment);
}
result = spy->write_queue.head;
spy->write_queue.head = NULL;
spy->write_queue.samples = 0;
ast_clear_flag(spy, CHANSPY_TRIGGER_FLUSH);
return result;
}
}
if ((spy->read_queue.samples < samples) || (spy->write_queue.samples < samples))
return NULL;
/* short-circuit if both head frames have exactly what we want */
if ((spy->read_queue.head->samples == samples) &&
(spy->write_queue.head->samples == samples)) {
read_frame = spy->read_queue.head;
spy->read_queue.head = read_frame->next;
read_frame->next = NULL;
write_frame = spy->write_queue.head;
spy->write_queue.head = write_frame->next;
write_frame->next = NULL;
spy->read_queue.samples -= samples;
spy->write_queue.samples -= samples;
need_dup = 0;
} else {
copy_data_from_queue(&spy->read_queue, read_buf, samples);
copy_data_from_queue(&spy->write_queue, write_buf, samples);
read_frame = &stack_read_frame;
write_frame = &stack_write_frame;
need_dup = 1;
}
if (ast_test_flag(spy, CHANSPY_READ_VOLADJUST))
ast_frame_adjust_volume(read_frame, spy->read_vol_adjustment);
if (ast_test_flag(spy, CHANSPY_WRITE_VOLADJUST))
ast_frame_adjust_volume(write_frame, spy->write_vol_adjustment);
if (ast_test_flag(spy, CHANSPY_MIXAUDIO)) {
ast_frame_slinear_sum(read_frame, write_frame);
if (need_dup)
result = ast_frdup(read_frame);
Kevin P. Fleming
committed
else {
Kevin P. Fleming
committed
result = read_frame;
Kevin P. Fleming
committed
ast_frfree(write_frame);
}
Kevin P. Fleming
committed
} else {
if (need_dup) {
result = ast_frdup(read_frame);
result->next = ast_frdup(write_frame);
} else {
result = read_frame;
result->next = write_frame;
}
}
return result;
}
static void *silence_generator_alloc(struct ast_channel *chan, void *data)
{
/* just store the data pointer in the channel structure */
return data;
}
static void silence_generator_release(struct ast_channel *chan, void *data)
{
/* nothing to do */
}
static int silence_generator_generate(struct ast_channel *chan, void *data, int len, int samples)
short buf[samples];
int x;
struct ast_frame frame = {
.frametype = AST_FRAME_VOICE,
.subclass = AST_FORMAT_SLINEAR,
.data = buf,
.samples = samples,
.datalen = sizeof(buf),
};
for (x = 0; x < samples; x++)
buf[x] = 0;
if (ast_write(chan, &frame))
return -1;
return 0;
}
static struct ast_generator silence_generator = {
.alloc = silence_generator_alloc,
.release = silence_generator_release,
.generate = silence_generator_generate,
};
struct ast_silence_generator {
int old_write_format;
};
struct ast_silence_generator *ast_channel_start_silence_generator(struct ast_channel *chan)
{
struct ast_silence_generator *state;
if (!(state = ast_calloc(1, sizeof(*state)))) {
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
return NULL;
}
state->old_write_format = chan->writeformat;
if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
ast_log(LOG_ERROR, "Could not set write format to SLINEAR\n");
free(state);
return NULL;
}
ast_activate_generator(chan, &silence_generator, state);
if (option_debug)
ast_log(LOG_DEBUG, "Started silence generator on '%s'\n", chan->name);
return state;
}
void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_silence_generator *state)
{
if (!state)
return;
ast_deactivate_generator(chan);
if (option_debug)
ast_log(LOG_DEBUG, "Stopped silence generator on '%s'\n", chan->name);
if (ast_set_write_format(chan, state->old_write_format) < 0)
ast_log(LOG_ERROR, "Could not return write format to its original state\n");
free(state);
}
/*! \ brief Convert channel reloadreason (ENUM) to text string for manager event */
const char *channelreloadreason2txt(enum channelreloadreason reason)
{
switch (reason) {
case CHANNEL_MODULE_LOAD:
return "LOAD (Channel module load)";
case CHANNEL_MODULE_RELOAD:
return "RELOAD (Channel module reload)";
case CHANNEL_CLI_RELOAD:
return "CLIRELOAD (Channel module reload by CLI command)";
default:
return "MANAGERRELOAD (Channel module reload by manager)";