Ticket #446: Added sample application to mix WAV files using conference bridge
git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@1682 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
parent
a268770929
commit
79a1afee3e
|
@ -0,0 +1,215 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
* Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* \page page_pjmedia_samples_mix_c Samples: Mixing WAV files
|
||||
*
|
||||
* This file is pjsip-apps/src/samples/mix.c
|
||||
*
|
||||
* \includelineno mix.c
|
||||
*/
|
||||
|
||||
#include <pjlib.h>
|
||||
#include <pjlib-util.h>
|
||||
#include <pjmedia.h>
|
||||
|
||||
#define THIS_FILE "mix.c"
|
||||
|
||||
static const char *desc =
|
||||
" mix\n"
|
||||
"\n"
|
||||
" PURPOSE:\n"
|
||||
" Mix input WAV files and save it to output WAV. Input WAV can have\n"
|
||||
" different clock rate.\n"
|
||||
"\n"
|
||||
"\n"
|
||||
" USAGE:\n"
|
||||
" mix [options] output.wav input1.wav [input2.wav] ...\n"
|
||||
"\n"
|
||||
" arguments:\n"
|
||||
" output.wav Set the output WAV filename.\n"
|
||||
" input1.wav Set the input WAV filename.\n"
|
||||
" input2.wav Set the input WAV filename.\n"
|
||||
"\n"
|
||||
" options:\n"
|
||||
" -c N Set clock rate to N Hz (default 16000)\n"
|
||||
;
|
||||
|
||||
#define MAX_WAV 16
|
||||
#define PTIME 20
|
||||
|
||||
struct wav_input
|
||||
{
|
||||
const char *fname;
|
||||
pjmedia_port *port;
|
||||
unsigned slot;
|
||||
};
|
||||
|
||||
static int err_ret(const char *title, pj_status_t status)
|
||||
{
|
||||
char errmsg[PJ_ERR_MSG_SIZE];
|
||||
pj_strerror(status, errmsg, sizeof(errmsg));
|
||||
PJ_LOG(3,(THIS_FILE, "%s error: %s", title, errmsg));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
pj_caching_pool cp;
|
||||
pj_pool_t *pool;
|
||||
pjmedia_endpt *med_ept;
|
||||
unsigned clock_rate = 16000;
|
||||
int c;
|
||||
const char *out_fname;
|
||||
pjmedia_conf *conf;
|
||||
pjmedia_port *wavout;
|
||||
struct wav_input wav_input[MAX_WAV];
|
||||
pj_ssize_t longest = 0, processed;
|
||||
unsigned i, input_cnt = 0;
|
||||
pj_status_t status;
|
||||
|
||||
#define CHECK(op) do { \
|
||||
status = op; \
|
||||
if (status != PJ_SUCCESS) \
|
||||
return err_ret(#op, status); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* Parse arguments */
|
||||
while ((c=pj_getopt(argc, argv, "c:")) != -1) {
|
||||
switch (c) {
|
||||
case 'c':
|
||||
clock_rate = atoi(pj_optarg);
|
||||
if (clock_rate < 1000) {
|
||||
puts("Error: invalid clock rate");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get output WAV name */
|
||||
if (pj_optind == argc) {
|
||||
puts("Error: no WAV output is specified");
|
||||
return 1;
|
||||
}
|
||||
|
||||
out_fname = argv[pj_optind++];
|
||||
if (pj_file_exists(out_fname)) {
|
||||
char in[8];
|
||||
|
||||
printf("File %s exists, overwrite? [Y/N] ", out_fname);
|
||||
fflush(stdout);
|
||||
fgets(in, sizeof(in), stdin);
|
||||
if (pj_tolower(in[0]) != 'y')
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Scan input file names */
|
||||
for (input_cnt=0 ; pj_optind<argc && input_cnt<MAX_WAV;
|
||||
++pj_optind, ++input_cnt)
|
||||
{
|
||||
if (!pj_file_exists(argv[pj_optind])) {
|
||||
printf("Error: input file %s doesn't exist\n",
|
||||
argv[pj_optind]);
|
||||
return 1;
|
||||
}
|
||||
wav_input[input_cnt].fname = argv[pj_optind];
|
||||
wav_input[input_cnt].port = NULL;
|
||||
wav_input[input_cnt].slot = 0;
|
||||
}
|
||||
|
||||
if (input_cnt == 0) {
|
||||
puts("Error: no input WAV is specified");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initialialize */
|
||||
CHECK( pj_init() );
|
||||
CHECK( pjlib_util_init() );
|
||||
pj_caching_pool_init(&cp, NULL, 0);
|
||||
CHECK( pjmedia_endpt_create(&cp.factory, NULL, 1, &med_ept) );
|
||||
|
||||
pool = pj_pool_create(&cp.factory, "mix", 1000, 1000, NULL);
|
||||
|
||||
/* Create the bridge */
|
||||
CHECK( pjmedia_conf_create(pool, MAX_WAV+4, clock_rate, 1,
|
||||
clock_rate * PTIME / 1000, 16,
|
||||
PJMEDIA_CONF_NO_DEVICE, &conf) );
|
||||
|
||||
/* Create the WAV output */
|
||||
CHECK( pjmedia_wav_writer_port_create(pool, out_fname, clock_rate, 1,
|
||||
clock_rate * PTIME / 1000,
|
||||
16, 0, 0, &wavout) );
|
||||
|
||||
/* Create and register each WAV input to the bridge */
|
||||
for (i=0; i<input_cnt; ++i) {
|
||||
pj_ssize_t len;
|
||||
|
||||
CHECK( pjmedia_wav_player_port_create(pool, wav_input[i].fname, 20,
|
||||
PJMEDIA_FILE_NO_LOOP, 0,
|
||||
&wav_input[i].port) );
|
||||
len = pjmedia_wav_player_get_len(wav_input[i].port);
|
||||
len = len * clock_rate / wav_input[i].port->info.clock_rate;
|
||||
if (len > longest)
|
||||
longest = len;
|
||||
|
||||
CHECK( pjmedia_conf_add_port(conf, pool, wav_input[i].port,
|
||||
NULL, &wav_input[i].slot));
|
||||
|
||||
CHECK( pjmedia_conf_connect_port(conf, wav_input[i].slot, 0, 0) );
|
||||
}
|
||||
|
||||
/* Loop reading frame from the bridge and write it to WAV */
|
||||
processed = 0;
|
||||
while (processed < longest) {
|
||||
pj_int16_t framebuf[PTIME * 48000 / 1000];
|
||||
pjmedia_port *cp = pjmedia_conf_get_master_port(conf);
|
||||
pjmedia_frame frame;
|
||||
|
||||
frame.buf = framebuf;
|
||||
frame.size = cp->info.samples_per_frame * 2;
|
||||
pj_assert(frame.size <= sizeof(framebuf));
|
||||
|
||||
status = pjmedia_port_get_frame(cp, &frame);
|
||||
if (status != PJ_SUCCESS)
|
||||
break;
|
||||
|
||||
CHECK( pjmedia_port_put_frame(wavout, &frame));
|
||||
|
||||
processed += frame.size;
|
||||
}
|
||||
|
||||
/* Shutdown everything */
|
||||
CHECK( pjmedia_port_destroy(wavout) );
|
||||
for (i=0; i<input_cnt; ++i) {
|
||||
CHECK( pjmedia_conf_remove_port(conf, wav_input[i].slot) );
|
||||
CHECK( pjmedia_port_destroy(wav_input[i].port) );
|
||||
}
|
||||
|
||||
CHECK(pjmedia_conf_destroy(conf));
|
||||
CHECK(pjmedia_endpt_destroy(med_ept));
|
||||
|
||||
pj_pool_release(pool);
|
||||
pj_caching_pool_destroy(&cp);
|
||||
pj_shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue