Skip to content
Snippets Groups Projects
channel.c 117 KiB
Newer Older
  • Learn to ignore specific revisions
  • 					      .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);
    
    	} 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)))) {
    
    		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)
    {
    
    	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)";