📄 tonegen.c
字号:
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 + -