diff options
author | Benny Prijono <bennylp@teluu.com> | 2007-01-24 02:02:09 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2007-01-24 02:02:09 +0000 |
commit | b7680744381c03eeaf56d600c30ba95c062cec1b (patch) | |
tree | 3ee9d55c6ddd44483c5b69c399da7d9e6c0f293f | |
parent | f362291d6e707ba5400937d89350f98827ff6e85 (diff) |
Implement ticket #62: option to play tones continuously, and added --play-tone option in pjsua
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@904 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r-- | pjmedia/include/pjmedia/tonegen.h | 51 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/tonegen.c | 90 | ||||
-rw-r--r-- | pjsip-apps/src/pjsua/pjsua_app.c | 72 |
3 files changed, 192 insertions, 21 deletions
diff --git a/pjmedia/include/pjmedia/tonegen.h b/pjmedia/include/pjmedia/tonegen.h index 21a4f063..c167e11d 100644 --- a/pjmedia/include/pjmedia/tonegen.h +++ b/pjmedia/include/pjmedia/tonegen.h @@ -98,6 +98,18 @@ typedef struct pjmedia_tone_digit_map } pjmedia_tone_digit_map; +/** + * Tone generator options. + */ +enum +{ + /** + * Play the tones in loop, restarting playing the first tone after + * the last tone has been played. + */ + PJMEDIA_TONEGEN_LOOP = 1 +}; + /** * Create an instance of tone generator with the specified parameters. @@ -111,7 +123,8 @@ typedef struct pjmedia_tone_digit_map * @param samples_per_frame Number of samples per frame. * @param bits_per_sample Number of bits per sample. This version of PJMEDIA * only supports 16bit per sample. - * @param options Option flags, must be zero for now. + * @param options Option flags. Application may specify + * PJMEDIA_TONEGEN_LOOP to play the tone in a loop. * @param p_port Pointer to receive the port instance. * * @return PJ_SUCCESS on success, or the appropriate @@ -127,6 +140,36 @@ PJ_DECL(pj_status_t) pjmedia_tonegen_create(pj_pool_t *pool, /** + * Create an instance of tone generator with the specified parameters. + * When the tone generator is first created, it will be loaded with the + * default digit map. + * + * @param pool Pool to allocate memory for the port structure. + * @param name Optional name for the tone generator. + * @param clock_rate Sampling rate. + * @param channel_count Number of channels. Currently only mono and stereo + * are supported. + * @param samples_per_frame Number of samples per frame. + * @param bits_per_sample Number of bits per sample. This version of PJMEDIA + * only supports 16bit per sample. + * @param options Option flags. Application may specify + * PJMEDIA_TONEGEN_LOOP to play the tone in a loop. + * @param p_port Pointer to receive the port instance. + * + * @return PJ_SUCCESS on success, or the appropriate + * error code. + */ +PJ_DECL(pj_status_t) pjmedia_tonegen_create2(pj_pool_t *pool, + const pj_str_t *name, + unsigned clock_rate, + unsigned channel_count, + unsigned samples_per_frame, + unsigned bits_per_sample, + unsigned options, + pjmedia_port **p_port); + + +/** * Check if the tone generator is still busy producing some tones. * * @param tonegen The tone generator instance. @@ -156,7 +199,8 @@ PJ_DECL(pj_status_t) pjmedia_tonegen_stop(pjmedia_port *tonegen); * @param tonegen The tone generator instance. * @param count The number of tones in the array. * @param tones Array of tones to be played. - * @param options Playback options, must be zero for now. + * @param options Option flags. Application may specify + * PJMEDIA_TONEGEN_LOOP to play the tone in a loop. * * @return PJ_SUCCESS on success, or PJ_ETOOMANY if * there are too many digits in the queue. @@ -178,7 +222,8 @@ PJ_DECL(pj_status_t) pjmedia_tonegen_play(pjmedia_port *tonegen, * @param tonegen The tone generator instance. * @param count Number of digits in the array. * @param digits Array of MF digits. - * @param options Playback options, must be zero for now. + * @param options Option flags. Application may specify + * PJMEDIA_TONEGEN_LOOP to play the tone in a loop. * * @return PJ_SUCCESS on success, or PJ_ETOOMANY if * there are too many digits in the queue, or diff --git a/pjmedia/src/pjmedia/tonegen.c b/pjmedia/src/pjmedia/tonegen.c index 2e62ce88..e913e6aa 100644 --- a/pjmedia/src/pjmedia/tonegen.c +++ b/pjmedia/src/pjmedia/tonegen.c @@ -27,7 +27,7 @@ #define DATA double /* amplitude */ -#define AMP 16383 +#define AMP 8192 #ifndef M_PI @@ -233,6 +233,10 @@ struct tonegen { pjmedia_port base; + /* options */ + unsigned options; + unsigned playback_options; + /* Digit map */ pjmedia_tone_digit_map *digit_map; @@ -280,7 +284,8 @@ static pj_status_t tonegen_get_frame(pjmedia_port *this_port, * When the tone generator is first created, it will be loaded with the * default digit map. */ -PJ_DEF(pj_status_t) pjmedia_tonegen_create( pj_pool_t *pool, +PJ_DEF(pj_status_t) pjmedia_tonegen_create2(pj_pool_t *pool, + const pj_str_t *name, unsigned clock_rate, unsigned channel_count, unsigned samples_per_frame, @@ -294,19 +299,21 @@ PJ_DEF(pj_status_t) pjmedia_tonegen_create( pj_pool_t *pool, PJ_ASSERT_RETURN(pool && clock_rate && channel_count && samples_per_frame && bits_per_sample == 16 && - options == 0 && p_port != NULL, PJ_EINVAL); + p_port != NULL, PJ_EINVAL); /* Only support mono and stereo */ PJ_ASSERT_RETURN(channel_count==1 || channel_count==2, PJ_EINVAL); /* Create and initialize port */ tonegen = pj_pool_zalloc(pool, sizeof(struct tonegen)); - status = pjmedia_port_info_init(&tonegen->base.info, &STR_TONE_GEN, + if (name == NULL || name->slen == 0) name = &STR_TONE_GEN; + 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; @@ -316,6 +323,20 @@ PJ_DEF(pj_status_t) pjmedia_tonegen_create( pj_pool_t *pool, } +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. */ @@ -358,9 +379,17 @@ static pj_status_t tonegen_get_frame(pjmedia_port *port, if (tonegen->cur_digit > tonegen->count) { /* We have played all the digits */ - tonegen->count = 0; - frame->type = PJMEDIA_FRAME_TYPE_NONE; - return PJ_SUCCESS; + 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+ @@ -376,15 +405,23 @@ static pj_status_t tonegen_get_frame(pjmedia_port *port, /* After we're finished with the last digit, we have played all * the digits */ - tonegen->count = 0; - frame->type = PJMEDIA_FRAME_TYPE_NONE; - return PJ_SUCCESS; + 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 = frame->buf; end = dst + port->info.samples_per_frame; - while (dst < end && tonegen->cur_digit < tonegen->count) { + while (dst < end) { const pjmedia_tone_desc *dig = &tonegen->digits[tonegen->cur_digit]; unsigned required, cnt, on_samp, off_samp; @@ -425,6 +462,17 @@ static pj_status_t tonegen_get_frame(pjmedia_port *port, 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; + } + } } } @@ -434,8 +482,17 @@ static pj_status_t tonegen_get_frame(pjmedia_port *port, frame->type = PJMEDIA_FRAME_TYPE_AUDIO; frame->size = port->info.bytes_per_frame; - if (tonegen->cur_digit >= tonegen->count) - tonegen->count = 0; + 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; } @@ -453,12 +510,15 @@ PJ_DEF(pj_status_t) pjmedia_tonegen_play( pjmedia_port *port, unsigned i; PJ_ASSERT_RETURN(port && port->info.signature == SIGNATURE && - count && tones && options==0, PJ_EINVAL); + 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)); @@ -492,7 +552,7 @@ PJ_DEF(pj_status_t) pjmedia_tonegen_play_digits( pjmedia_port *port, unsigned i; PJ_ASSERT_RETURN(port && port->info.signature == SIGNATURE && - count && digits && options==0, PJ_EINVAL); + count && digits, PJ_EINVAL); PJ_ASSERT_RETURN(count < PJMEDIA_TONEGEN_MAX_DIGITS, PJ_ETOOMANY); for (i=0; i<count; ++i) { diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c index 4ce1a59e..641c32cc 100644 --- a/pjsip-apps/src/pjsua/pjsua_app.c +++ b/pjsip-apps/src/pjsua/pjsua_app.c @@ -60,6 +60,9 @@ static struct app_config pj_bool_t null_audio; unsigned wav_count; pj_str_t wav_files[32]; + unsigned tone_count; + pjmedia_tone_desc tones[32]; + pjsua_conf_port_id tone_slots[32]; pjsua_player_id wav_id; pjsua_conf_port_id wav_port; pj_bool_t auto_play; @@ -158,7 +161,11 @@ static void usage(void) puts (" --add-codec=name Manually add codec (default is to enable all)"); puts (" --clock-rate=N Override sound device clock rate"); puts (" --null-audio Use NULL audio device"); - puts (" --play-file=file Register WAV file in conference bridge"); + puts (" --play-file=file Register WAV file in conference bridge."); + puts (" This can be specified multiple times."); + puts (" --play-tone=F1,F2,ON,OFF Register tone to the conference bridge."); + puts (" f1,f2=frequency, on,off=on/off duration in msec."); + puts (" This can be specified multiple times."); puts (" --auto-play Automatically play the file (to incoming calls only)"); puts (" --auto-loop Automatically loop incoming RTP to outgoing RTP"); puts (" --auto-conf Automatically put calls in conference with others"); @@ -309,8 +316,8 @@ static pj_status_t parse_args(int argc, char *argv[], OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE, OPT_AUTO_ANSWER, OPT_AUTO_HANGUP, OPT_AUTO_PLAY, OPT_AUTO_LOOP, OPT_AUTO_CONF, OPT_CLOCK_RATE, - OPT_PLAY_FILE, OPT_RTP_PORT, OPT_ADD_CODEC, OPT_ILBC_MODE, - OPT_REC_FILE, OPT_AUTO_REC, + OPT_PLAY_FILE, OPT_PLAY_TONE, OPT_RTP_PORT, OPT_ADD_CODEC, + OPT_ILBC_MODE, OPT_REC_FILE, OPT_AUTO_REC, OPT_COMPLEXITY, OPT_QUALITY, OPT_PTIME, OPT_NO_VAD, OPT_RX_DROP_PCT, OPT_TX_DROP_PCT, OPT_EC_TAIL, OPT_NEXT_ACCOUNT, OPT_NEXT_CRED, OPT_MAX_CALLS, @@ -357,6 +364,7 @@ static pj_status_t parse_args(int argc, char *argv[], { "auto-loop", 0, 0, OPT_AUTO_LOOP}, { "auto-conf", 0, 0, OPT_AUTO_CONF}, { "play-file", 1, 0, OPT_PLAY_FILE}, + { "play-tone", 1, 0, OPT_PLAY_TONE}, { "rec-file", 1, 0, OPT_REC_FILE}, { "rtp-port", 1, 0, OPT_RTP_PORT}, { "add-codec", 1, 0, OPT_ADD_CODEC}, @@ -681,6 +689,25 @@ static pj_status_t parse_args(int argc, char *argv[], cfg->wav_files[cfg->wav_count++] = pj_str(pj_optarg); break; + case OPT_PLAY_TONE: + { + int f1, f2, on, off; + int n; + + n = sscanf(pj_optarg, "%d,%d,%d,%d", &f1, &f2, &on, &off); + if (n != 4) { + puts("Expecting f1,f2,on,off in --play-tone"); + return -1; + } + + cfg->tones[cfg->tone_count].freq1 = (short)f1; + cfg->tones[cfg->tone_count].freq2 = (short)f2; + cfg->tones[cfg->tone_count].on_msec = (short)on; + cfg->tones[cfg->tone_count].off_msec = (short)off; + ++cfg->tone_count; + } + break; + case OPT_REC_FILE: cfg->rec_file = pj_str(pj_optarg); break; @@ -1136,6 +1163,12 @@ static int write_settings(const struct app_config *config, config->wav_files[i].ptr); pj_strcat2(&cfg, line); } + for (i=0; i<config->tone_count; ++i) { + pj_ansi_sprintf(line, "--play-tone %d,%d,%d,%d\n", + config->tones[i].freq1, config->tones[i].freq2, + config->tones[i].on_msec, config->tones[i].off_msec); + pj_strcat2(&cfg, line); + } if (config->rec_file.slen) { pj_ansi_sprintf(line, "--rec-file %s\n", config->rec_file.ptr); @@ -2925,6 +2958,33 @@ pj_status_t app_init(int argc, char *argv[]) } } + /* Optionally registers tone players */ + for (i=0; i<app_config.tone_count; ++i) { + pjmedia_port *tport; + char name[80]; + pj_str_t label; + pj_status_t status; + + pj_ansi_snprintf(name, sizeof(name), "tone-%d,%d", + app_config.tones[i].freq1, + app_config.tones[i].freq2); + label = pj_str(name); + status = pjmedia_tonegen_create2(app_config.pool, &label, + 8000, 1, 160, 16, + PJMEDIA_TONEGEN_LOOP, &tport); + if (status != PJ_SUCCESS) { + pjsua_perror(THIS_FILE, "Unable to create tone generator", status); + goto on_error; + } + + status = pjsua_conf_add_port(app_config.pool, tport, + &app_config.tone_slots[i]); + pj_assert(status == PJ_SUCCESS); + + status = pjmedia_tonegen_play(tport, 1, &app_config.tones[i], 0); + pj_assert(status == PJ_SUCCESS); + } + /* Optionally create recorder file, if any. */ if (app_config.rec_file.slen) { status = pjsua_recorder_create(&app_config.rec_file, 0, NULL, 0, 0, @@ -3056,6 +3116,7 @@ pj_status_t app_main(void) pj_status_t app_destroy(void) { pj_status_t status; + unsigned i; #ifdef STEREO_DEMO if (app_config.snd) { @@ -3064,6 +3125,11 @@ pj_status_t app_destroy(void) } #endif + /* Close tone generators */ + for (i=0; i<app_config.tone_count; ++i) { + pjsua_conf_remove_port(app_config.tone_slots[i]); + } + if (app_config.pool) { pj_pool_release(app_config.pool); app_config.pool = NULL; |