diff options
Diffstat (limited to 'main/channel.c')
-rw-r--r-- | main/channel.c | 138 |
1 files changed, 74 insertions, 64 deletions
diff --git a/main/channel.c b/main/channel.c index 23ea4b7c0..94b0e8b1c 100644 --- a/main/channel.c +++ b/main/channel.c @@ -2943,12 +2943,13 @@ int ast_channel_get_up_time(struct ast_channel *chan) return (ast_tvdiff_ms(ast_tvnow(), ast_channel_answertime(chan)) / 1000); } -void ast_deactivate_generator(struct ast_channel *chan) +static void deactivate_generator_nolock(struct ast_channel *chan) { - ast_channel_lock(chan); if (ast_channel_generatordata(chan)) { - if (ast_channel_generator(chan) && ast_channel_generator(chan)->release) { - ast_channel_generator(chan)->release(chan, ast_channel_generatordata(chan)); + struct ast_generator *generator = ast_channel_generator(chan); + + if (generator && generator->release) { + generator->release(chan, ast_channel_generatordata(chan)); } ast_channel_generatordata_set(chan, NULL); ast_channel_generator_set(chan, NULL); @@ -2956,14 +2957,23 @@ void ast_deactivate_generator(struct ast_channel *chan) ast_clear_flag(ast_channel_flags(chan), AST_FLAG_WRITE_INT); ast_settimeout(chan, 0, NULL, NULL); } +} + +void ast_deactivate_generator(struct ast_channel *chan) +{ + ast_channel_lock(chan); + deactivate_generator_nolock(chan); ast_channel_unlock(chan); } static void generator_write_format_change(struct ast_channel *chan) { + struct ast_generator *generator; + ast_channel_lock(chan); - if (ast_channel_generator(chan) && ast_channel_generator(chan)->write_format_change) { - ast_channel_generator(chan)->write_format_change(chan, ast_channel_generatordata(chan)); + generator = ast_channel_generator(chan); + if (generator && generator->write_format_change) { + generator->write_format_change(chan, ast_channel_generatordata(chan)); } ast_channel_unlock(chan); } @@ -3009,8 +3019,10 @@ int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, ast_channel_lock(chan); if (ast_channel_generatordata(chan)) { - if (ast_channel_generator(chan) && ast_channel_generator(chan)->release) { - ast_channel_generator(chan)->release(chan, ast_channel_generatordata(chan)); + struct ast_generator *generator_old = ast_channel_generator(chan); + + if (generator_old && generator_old->release) { + generator_old->release(chan, ast_channel_generatordata(chan)); } } if (gen->alloc && !(generatordata = gen->alloc(chan, params))) { @@ -3642,49 +3654,57 @@ static void send_dtmf_end_event(struct ast_channel *chan, static void ast_read_generator_actions(struct ast_channel *chan, struct ast_frame *f) { - if (ast_channel_generator(chan) && ast_channel_generator(chan)->generate && ast_channel_generatordata(chan) && !ast_internal_timing_enabled(chan)) { - void *tmp = ast_channel_generatordata(chan); - int (*generate)(struct ast_channel *chan, void *tmp, int datalen, int samples) = ast_channel_generator(chan)->generate; - int res; - int samples; + struct ast_generator *generator; + void *gendata; + int res; + int samples; + + generator = ast_channel_generator(chan); + if (!generator + || !generator->generate + || f->frametype != AST_FRAME_VOICE + || !ast_channel_generatordata(chan) + || ast_channel_timingfunc(chan)) { + return; + } - if (ast_channel_timingfunc(chan)) { - ast_debug(1, "Generator got voice, switching to phase locked mode\n"); - ast_settimeout(chan, 0, NULL, NULL); - } + /* + * We must generate frames in phase locked mode since + * we have no internal timer available. + */ - ast_channel_generatordata_set(chan, NULL); /* reset, to let writes go through */ + if (ast_format_cmp(&f->subclass.format, ast_channel_writeformat(chan)) == AST_FORMAT_CMP_NOT_EQUAL) { + float factor; - if (ast_format_cmp(&f->subclass.format, ast_channel_writeformat(chan)) == AST_FORMAT_CMP_NOT_EQUAL) { - float factor; - factor = ((float) ast_format_rate(ast_channel_writeformat(chan))) / ((float) ast_format_rate(&f->subclass.format)); - samples = (int) ( ((float) f->samples) * factor ); - } else { - samples = f->samples; - } + factor = ((float) ast_format_rate(ast_channel_writeformat(chan))) / ((float) ast_format_rate(&f->subclass.format)); + samples = (int) (((float) f->samples) * factor); + } else { + samples = f->samples; + } - /* This unlock is here based on two assumptions that hold true at this point in the - * code. 1) this function is only called from within __ast_read() and 2) all generators - * call ast_write() in their generate callback. - * - * The reason this is added is so that when ast_write is called, the lock that occurs - * there will not recursively lock the channel. Doing this will cause intended deadlock - * avoidance not to work in deeper functions - */ - ast_channel_unlock(chan); - res = generate(chan, tmp, f->datalen, samples); - ast_channel_lock(chan); - ast_channel_generatordata_set(chan, tmp); + gendata = ast_channel_generatordata(chan); + ast_channel_generatordata_set(chan, NULL); /* reset, to let writes go through */ + + /* + * This unlock is here based on two assumptions that hold true at + * this point in the code. 1) this function is only called from + * within __ast_read() and 2) all generators call ast_write() in + * their generate callback. + * + * The reason this is added is so that when ast_write is called, + * the lock that occurs there will not recursively lock the + * channel. Doing this will allow deadlock avoidance to work in + * deeper functions. + */ + ast_channel_unlock(chan); + res = generator->generate(chan, gendata, f->datalen, samples); + ast_channel_lock(chan); + if (generator == ast_channel_generator(chan)) { + ast_channel_generatordata_set(chan, gendata); if (res) { ast_debug(1, "Auto-deactivating generator\n"); ast_deactivate_generator(chan); } - - } else if (f->frametype == AST_FRAME_CNG) { - if (ast_channel_generator(chan) && !ast_channel_timingfunc(chan) && (ast_channel_timingfd(chan) > -1)) { - ast_debug(1, "Generator got CNG, switching to timed mode\n"); - ast_settimeout(chan, 50, generator_force, chan); - } } } @@ -4265,11 +4285,6 @@ done: return f; } -int ast_internal_timing_enabled(struct ast_channel *chan) -{ - return (ast_opt_internal_timing && ast_channel_timingfd(chan) > -1); -} - struct ast_frame *ast_read(struct ast_channel *chan) { return __ast_read(chan, 0); @@ -7693,30 +7708,24 @@ struct ast_silence_generator *ast_channel_start_silence_generator(struct ast_cha return state; } -static int internal_deactivate_generator(struct ast_channel *chan, void* generator) +static int deactivate_silence_generator(struct ast_channel *chan) { ast_channel_lock(chan); if (!ast_channel_generatordata(chan)) { - ast_debug(1, "Trying to stop silence generator when there is no " - "generator on '%s'\n", ast_channel_name(chan)); + ast_debug(1, "Trying to stop silence generator when there is no generator on '%s'\n", + ast_channel_name(chan)); ast_channel_unlock(chan); return 0; } - if (ast_channel_generator(chan) != generator) { - ast_debug(1, "Trying to stop silence generator when it is not the current " - "generator on '%s'\n", ast_channel_name(chan)); + if (ast_channel_generator(chan) != &silence_generator) { + ast_debug(1, "Trying to stop silence generator when it is not the current generator on '%s'\n", + ast_channel_name(chan)); ast_channel_unlock(chan); return 0; } - if (ast_channel_generator(chan) && ast_channel_generator(chan)->release) { - ast_channel_generator(chan)->release(chan, ast_channel_generatordata(chan)); - } - ast_channel_generatordata_set(chan, NULL); - ast_channel_generator_set(chan, NULL); - ast_channel_set_fd(chan, AST_GENERATOR_FD, -1); - ast_clear_flag(ast_channel_flags(chan), AST_FLAG_WRITE_INT); - ast_settimeout(chan, 0, NULL, NULL); + deactivate_generator_nolock(chan); + ast_channel_unlock(chan); return 1; @@ -7724,10 +7733,11 @@ static int internal_deactivate_generator(struct ast_channel *chan, void* generat void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_silence_generator *state) { - if (!state) + if (!state) { return; + } - if (internal_deactivate_generator(chan, &silence_generator)) { + if (deactivate_silence_generator(chan)) { ast_debug(1, "Stopped silence generator on '%s'\n", ast_channel_name(chan)); 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"); |