BLOG | DOCUMENTATION | TRAC

Home --> Documentations --> PJMEDIA Reference

Samples: Mixing WAV files

This file is pjsip-apps/src/samples/mix.c

00001 /* $Id: mix.c 3664 2011-07-19 03:42:28Z nanang $ */
00002 /* 
00003  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
00004  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
00019  */
00020 
00029 #include <pjlib.h>
00030 #include <pjlib-util.h>
00031 #include <pjmedia.h>
00032 
00033 #define THIS_FILE   "mix.c"
00034 
00035 static const char *desc = 
00036  " mix\n"
00037  "\n"
00038  " PURPOSE:\n"
00039  "  Mix input WAV files and save it to output WAV. Input WAV can have\n"
00040  "  different clock rate.\n"
00041  "\n"
00042  "\n"
00043  " USAGE:\n"
00044  "  mix [options] output.wav input1.wav [input2.wav] ...\n"
00045  "\n"
00046  " arguments:\n"
00047  "    output.wav    Set the output WAV filename.\n"
00048  "    input1.wav    Set the input WAV filename.\n"
00049  "    input2.wav    Set the input WAV filename.\n"
00050  "\n"
00051  " options:\n"
00052  "    -c N          Set clock rate to N Hz (default 16000)\n"
00053  "    -f            Force write (overwrite output without warning\n"
00054 ;
00055 
00056 #define MAX_WAV     16
00057 #define PTIME       20
00058 #define APPEND      1000
00059 
00060 struct wav_input
00061 {
00062     const char      *fname;
00063     pjmedia_port    *port;
00064     unsigned         slot;
00065 };
00066 
00067 static int err_ret(const char *title, pj_status_t status)
00068 {
00069     char errmsg[PJ_ERR_MSG_SIZE];
00070     pj_strerror(status, errmsg, sizeof(errmsg));
00071     PJ_LOG(3,(THIS_FILE, "%s error: %s", title, errmsg));
00072     return 1;
00073 }
00074 
00075 static void usage(void)
00076 {
00077     puts(desc);
00078 }
00079 
00080 int main(int argc, char *argv[])
00081 {
00082     pj_caching_pool cp;
00083     pj_pool_t *pool;
00084     pjmedia_endpt *med_ept;
00085     unsigned clock_rate = 16000;
00086     int c, force=0;
00087     const char *out_fname;
00088     pjmedia_conf *conf;
00089     pjmedia_port *wavout;
00090     struct wav_input wav_input[MAX_WAV];
00091     pj_size_t longest = 0, processed;
00092     unsigned i, input_cnt = 0;
00093     pj_status_t status;
00094 
00095 #define CHECK(op)   do { \
00096                         status = op; \
00097                         if (status != PJ_SUCCESS) \
00098                             return err_ret(#op, status); \
00099                     } while (0)
00100 
00101 
00102     /* Parse arguments */
00103     while ((c=pj_getopt(argc, argv, "c:f")) != -1) {
00104         switch (c) {
00105         case 'c':
00106             clock_rate = atoi(pj_optarg);
00107             if (clock_rate < 1000) {
00108                 puts("Error: invalid clock rate");
00109                 usage();
00110                 return -1;
00111             }
00112             break;
00113         case 'f':
00114             force = 1;
00115             break;
00116         }
00117     }
00118 
00119     /* Get output WAV name */
00120     if (pj_optind == argc) {
00121         puts("Error: no WAV output is specified");
00122         usage();
00123         return 1;
00124     }
00125 
00126     out_fname = argv[pj_optind++];
00127     if (force==0 && pj_file_exists(out_fname)) {
00128         char in[8];
00129 
00130         printf("File %s exists, overwrite? [Y/N] ", out_fname);
00131         fflush(stdout);
00132         if (fgets(in, sizeof(in), stdin) == NULL)
00133             return 1;
00134         if (pj_tolower(in[0]) != 'y')
00135             return 1;
00136     }
00137 
00138     /* Scan input file names */
00139     for (input_cnt=0 ; pj_optind<argc && input_cnt<MAX_WAV; 
00140          ++pj_optind, ++input_cnt) 
00141     {
00142         if (!pj_file_exists(argv[pj_optind])) {
00143             printf("Error: input file %s doesn't exist\n",
00144                    argv[pj_optind]);
00145             return 1;
00146         }
00147         wav_input[input_cnt].fname = argv[pj_optind];
00148         wav_input[input_cnt].port = NULL;
00149         wav_input[input_cnt].slot = 0;
00150     }
00151 
00152     if (input_cnt == 0) {
00153         puts("Error: no input WAV is specified");
00154         return 0;
00155     }
00156 
00157     /* Initialialize */
00158     CHECK( pj_init() );
00159     CHECK( pjlib_util_init() );
00160     pj_caching_pool_init(&cp, NULL, 0);
00161     CHECK( pjmedia_endpt_create(&cp.factory, NULL, 1, &med_ept) );
00162 
00163     pool = pj_pool_create(&cp.factory, "mix", 1000, 1000, NULL);
00164 
00165     /* Create the bridge */
00166     CHECK( pjmedia_conf_create(pool, MAX_WAV+4, clock_rate, 1, 
00167                                clock_rate * PTIME / 1000, 16, 
00168                                PJMEDIA_CONF_NO_DEVICE, &conf) );
00169 
00170     /* Create the WAV output */
00171     CHECK( pjmedia_wav_writer_port_create(pool, out_fname, clock_rate, 1,
00172                                           clock_rate * PTIME / 1000,
00173                                           16, 0, 0, &wavout) );
00174 
00175     /* Create and register each WAV input to the bridge */
00176     for (i=0; i<input_cnt; ++i) {
00177         pj_ssize_t len;
00178 
00179         CHECK( pjmedia_wav_player_port_create(pool, wav_input[i].fname, 20,
00180                                               PJMEDIA_FILE_NO_LOOP, 0, 
00181                                               &wav_input[i].port) );
00182         len = pjmedia_wav_player_get_len(wav_input[i].port);
00183         len = (pj_ssize_t)(len * 1.0 * clock_rate / 
00184                            PJMEDIA_PIA_SRATE(&wav_input[i].port->info));
00185         if (len > (pj_ssize_t)longest)
00186             longest = len;
00187 
00188         CHECK( pjmedia_conf_add_port(conf, pool, wav_input[i].port,
00189                                      NULL, &wav_input[i].slot));
00190 
00191         CHECK( pjmedia_conf_connect_port(conf, wav_input[i].slot, 0, 0) );
00192     }
00193 
00194     /* Loop reading frame from the bridge and write it to WAV */
00195     processed = 0;
00196     while (processed < longest + clock_rate * APPEND * 2 / 1000) {
00197         pj_int16_t framebuf[PTIME * 48000 / 1000];
00198         pjmedia_port *cp = pjmedia_conf_get_master_port(conf);
00199         pjmedia_frame frame;
00200 
00201         frame.buf = framebuf;
00202         frame.size = PJMEDIA_PIA_SPF(&cp->info) * 2;
00203         pj_assert(frame.size <= sizeof(framebuf));
00204         
00205         CHECK( pjmedia_port_get_frame(cp, &frame) );
00206 
00207         if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO) {
00208             pj_bzero(frame.buf, frame.size);
00209             frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
00210         }
00211 
00212         CHECK( pjmedia_port_put_frame(wavout, &frame));
00213 
00214         processed += frame.size;
00215     }
00216 
00217     PJ_LOG(3,(THIS_FILE, "Done. Output duration: %d.%03d",
00218               (processed >> 2)/clock_rate,
00219               ((processed >> 2)*1000/clock_rate) % 1000));
00220 
00221     /* Shutdown everything */
00222     CHECK( pjmedia_port_destroy(wavout) );
00223     for (i=0; i<input_cnt; ++i) {
00224         CHECK( pjmedia_conf_remove_port(conf, wav_input[i].slot) );
00225         CHECK( pjmedia_port_destroy(wav_input[i].port) );
00226     }
00227 
00228     CHECK(pjmedia_conf_destroy(conf));
00229     CHECK(pjmedia_endpt_destroy(med_ept));
00230 
00231     pj_pool_release(pool);
00232     pj_caching_pool_destroy(&cp);
00233     pj_shutdown();
00234 
00235     return 0;
00236 }
00237 

 


PJMEDIA small footprint Open Source media stack
Copyright (C) 2006-2008 Teluu Inc.