⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tonegen.c

📁 一个开源的sip源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
    status = pjmedia_port_info_init(&tonegen->base.info, name, 
				    SIGNATURE, clock_rate, channel_count, 
				    bits_per_sample, samples_per_frame);
    if (status != PJ_SUCCESS)
	return status;

    tonegen->options = options;
    tonegen->base.get_frame = &tonegen_get_frame;
    tonegen->digit_map = &digit_map;

    /* Done */
    *p_port = &tonegen->base;
    return PJ_SUCCESS;
}


PJ_DEF(pj_status_t) pjmedia_tonegen_create( pj_pool_t *pool,
					    unsigned clock_rate,
					    unsigned channel_count,
					    unsigned samples_per_frame,
					    unsigned bits_per_sample,
					    unsigned options,
					    pjmedia_port **p_port)
{
    return pjmedia_tonegen_create2(pool, NULL, clock_rate, channel_count,
				   samples_per_frame, bits_per_sample, 
				   options, p_port);
}


/*
 * Check if the tone generator is still busy producing some tones.
 */
PJ_DEF(pj_bool_t) pjmedia_tonegen_is_busy(pjmedia_port *port)
{
    struct tonegen *tonegen = (struct tonegen*) port;
    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_TRUE);
    return tonegen->count != 0;
}


/*
 * Instruct the tone generator to stop current processing.
 */
PJ_DEF(pj_status_t) pjmedia_tonegen_stop(pjmedia_port *port)
{
    struct tonegen *tonegen = (struct tonegen*) port;
    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
    tonegen->count = 0;
    tonegen->cur_digit = 0;
    tonegen->dig_samples = 0;
    return PJ_SUCCESS;
}


/*
 * Fill a frame with tones.
 */
static pj_status_t tonegen_get_frame(pjmedia_port *port, 
				     pjmedia_frame *frame)
{
    struct tonegen *tonegen = (struct tonegen*) port;
    short *dst, *end;
    unsigned clock_rate = tonegen->base.info.clock_rate;

    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);

    if (tonegen->count == 0) {
	/* We don't have digits to play */
	frame->type = PJMEDIA_FRAME_TYPE_NONE;
	return PJ_SUCCESS;
    }

    if (tonegen->cur_digit > tonegen->count) {
	/* We have played all the digits */
	if ((tonegen->options|tonegen->playback_options)&PJMEDIA_TONEGEN_LOOP)
	{
	    /* Reset back to the first tone */
	    tonegen->cur_digit = 0;
	    tonegen->dig_samples = 0;

	} else {
	    tonegen->count = 0;
	    frame->type = PJMEDIA_FRAME_TYPE_NONE;
	    return PJ_SUCCESS;
	}
    }

    if (tonegen->dig_samples>=(tonegen->digits[tonegen->cur_digit].on_msec+
			       tonegen->digits[tonegen->cur_digit].off_msec)*
			       clock_rate / 1000)
    {
	/* We have finished with current digit */
	tonegen->cur_digit++;
	tonegen->dig_samples = 0;
    }

    if (tonegen->cur_digit > tonegen->count) {
	/* After we're finished with the last digit, we have played all 
	 * the digits 
	 */
	if ((tonegen->options|tonegen->playback_options)&PJMEDIA_TONEGEN_LOOP)
	{
	    /* Reset back to the first tone */
	    tonegen->cur_digit = 0;
	    tonegen->dig_samples = 0;

	} else {
	    tonegen->count = 0;
	    frame->type = PJMEDIA_FRAME_TYPE_NONE;
	    return PJ_SUCCESS;
	}
    }
    
    dst = (short*) frame->buf;
    end = dst + port->info.samples_per_frame;

    while (dst < end) {
	const pjmedia_tone_desc *dig = &tonegen->digits[tonegen->cur_digit];
	unsigned required, cnt, on_samp, off_samp;

	required = end - dst;
	on_samp = dig->on_msec * clock_rate / 1000;
	off_samp = dig->off_msec * clock_rate / 1000;

	/* Init tonegen */
	if (tonegen->dig_samples == 0) {
	    init_generate_tone(&tonegen->state, port->info.clock_rate,
			       dig->freq1, dig->freq2, dig->volume);
	}

	/* Add tone signal */
	if (tonegen->dig_samples < on_samp) {
	    cnt = on_samp - tonegen->dig_samples;
	    if (cnt > required)
		cnt = required;
	    generate_tone(&tonegen->state, port->info.channel_count,
			  cnt, dst);
	    dst += cnt;
	    tonegen->dig_samples += cnt;
	    required -= cnt;

	    if (dst == end)
		break;
	}

	/* Add silence signal */
	cnt = off_samp + on_samp - tonegen->dig_samples;
	if (cnt > required)
	    cnt = required;
	pjmedia_zero_samples(dst, cnt);
	dst += cnt;
	tonegen->dig_samples += cnt;

	/* Move to next digit if we're finished with this tone */
	if (tonegen->dig_samples == on_samp + off_samp) {
	    tonegen->cur_digit++;
	    tonegen->dig_samples = 0;

	    if (tonegen->cur_digit >= tonegen->count) {
		/* All digits have been played */
		if ((tonegen->options & PJMEDIA_TONEGEN_LOOP) ||
		    (tonegen->playback_options & PJMEDIA_TONEGEN_LOOP))
		{
		    tonegen->cur_digit = 0;
		} else {
		    break;
		}
	    }
	}
    }

    if (dst < end)
	pjmedia_zero_samples(dst, end-dst);

    frame->type = PJMEDIA_FRAME_TYPE_AUDIO;
    frame->size = port->info.bytes_per_frame;

    if (tonegen->cur_digit >= tonegen->count) {
	if ((tonegen->options|tonegen->playback_options)&PJMEDIA_TONEGEN_LOOP)
	{
	    /* Reset back to the first tone */
	    tonegen->cur_digit = 0;
	    tonegen->dig_samples = 0;

	} else {
	    tonegen->count = 0;
	}
    }

    return PJ_SUCCESS;
}


/*
 * Play tones.
 */
PJ_DEF(pj_status_t) pjmedia_tonegen_play( pjmedia_port *port,
					  unsigned count,
					  const pjmedia_tone_desc tones[],
					  unsigned options)
{
    struct tonegen *tonegen = (struct tonegen*) port;
    unsigned i;

    PJ_ASSERT_RETURN(port && port->info.signature == SIGNATURE &&
		     count && tones, PJ_EINVAL);

    /* Don't put more than available buffer */
    PJ_ASSERT_RETURN(count+tonegen->count <= PJMEDIA_TONEGEN_MAX_DIGITS,
		     PJ_ETOOMANY);

    /* Set playback options */
    tonegen->playback_options = options;
    
    /* Copy digits */
    pj_memcpy(tonegen->digits + tonegen->count,
	      tones, count * sizeof(pjmedia_tone_desc));
    
    /* Normalize volume */
    for (i=0; i<count; ++i) {
	pjmedia_tone_desc *t = &tonegen->digits[i+tonegen->count];
	if (t->volume == 0)
	    t->volume = AMP;
	else if (t->volume < 0)
	    t->volume = (short) -t->volume;
    }

    tonegen->count += count;

    return PJ_SUCCESS;
}


/*
 * Play digits.
 */
PJ_DEF(pj_status_t) pjmedia_tonegen_play_digits( pjmedia_port *port,
						 unsigned count,
						 const pjmedia_tone_digit digits[],
						 unsigned options)
{
    struct tonegen *tonegen = (struct tonegen*) port;
    pjmedia_tone_desc tones[PJMEDIA_TONEGEN_MAX_DIGITS];
    const pjmedia_tone_digit_map *map = tonegen->digit_map;
    unsigned i;

    PJ_ASSERT_RETURN(port && port->info.signature == SIGNATURE &&
		     count && digits, PJ_EINVAL);
    PJ_ASSERT_RETURN(count < PJMEDIA_TONEGEN_MAX_DIGITS, PJ_ETOOMANY);

    for (i=0; i<count; ++i) {
	int d = pj_tolower(digits[i].digit);
	unsigned j;

	/* Translate ASCII digits with digitmap */
	for (j=0; j<map->count; ++j) {
	    if (d == map->digits[j].digit)
		break;
	}
	if (j == map->count)
	    return PJMEDIA_RTP_EINDTMF;

	tones[i].freq1 = map->digits[j].freq1;
	tones[i].freq2 = map->digits[j].freq2;
	tones[i].on_msec = digits[i].on_msec;
	tones[i].off_msec = digits[i].off_msec;
	tones[i].volume = digits[i].volume;
    }

    return pjmedia_tonegen_play(port, count, tones, options);
}


/*
 * Get the digit-map currently used by this tone generator.
 */
PJ_DEF(pj_status_t) pjmedia_tonegen_get_digit_map(pjmedia_port *port,
						  const pjmedia_tone_digit_map **m)
{
    struct tonegen *tonegen = (struct tonegen*) port;
    
    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
    PJ_ASSERT_RETURN(m != NULL, PJ_EINVAL);

    *m = tonegen->digit_map;

    return PJ_SUCCESS;
}


/*
 * Set digit map to be used by the tone generator.
 */
PJ_DEF(pj_status_t) pjmedia_tonegen_set_digit_map(pjmedia_port *port,
						  pjmedia_tone_digit_map *m)
{
    struct tonegen *tonegen = (struct tonegen*) port;
    
    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
    PJ_ASSERT_RETURN(m != NULL, PJ_EINVAL);

    tonegen->digit_map = m;

    return PJ_SUCCESS;
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -