pjsip logo pjsip.org
Open source SIP stack and media stack for presence, im/instant messaging, and multimedia communication

HOME

SIP/media Features
High Performance SIP
Small Footprint SIP
Symbian Port

FAQ

Documentation

Licensing

Download

Development (Trac)

Projects using pjsip

Mailing List

Open Source Links


About: PJLIB, PJLIB-UTIL, PJSIP, and PJMEDIA are created by: Benny Prijono
<bennylp@pjsip.org>


 

Home --> Documentations --> PJMEDIA Reference

Samples: Mixing WAV files

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

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

 


PJMEDIA small footprint Open Source media stack
(C)2003-2008 Benny Prijono