BLOG | DOCUMENTATION | TRAC

Home --> Documentations --> PJMEDIA Reference

Samples: Mixing WAV files

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

1 /* $Id: mix.c 5170 2015-08-25 08:45:46Z nanang $ */
2 /*
3  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 
29 #include <pjlib.h>
30 #include <pjlib-util.h>
31 #include <pjmedia.h>
32 
33 #define THIS_FILE "mix.c"
34 
35 static const char *desc =
36  " mix\n"
37  "\n"
38  " PURPOSE:\n"
39  " Mix input WAV files and save it to output WAV. Input WAV can have\n"
40  " different clock rate.\n"
41  "\n"
42  "\n"
43  " USAGE:\n"
44  " mix [options] output.wav input1.wav [input2.wav] ...\n"
45  "\n"
46  " arguments:\n"
47  " output.wav Set the output WAV filename.\n"
48  " input1.wav Set the input WAV filename.\n"
49  " input2.wav Set the input WAV filename.\n"
50  "\n"
51  " options:\n"
52  " -c N Set clock rate to N Hz (default 16000)\n"
53  " -f Force write (overwrite output without warning\n"
54 ;
55 
56 #define MAX_WAV 16
57 #define PTIME 20
58 #define APPEND 1000
59 
60 struct wav_input
61 {
62  const char *fname;
63  pjmedia_port *port;
64  unsigned slot;
65 };
66 
67 static int err_ret(const char *title, pj_status_t status)
68 {
69  char errmsg[PJ_ERR_MSG_SIZE];
70  pj_strerror(status, errmsg, sizeof(errmsg));
71  PJ_LOG(3,(THIS_FILE, "%s error: %s", title, errmsg));
72  return 1;
73 }
74 
75 static void usage(void)
76 {
77  puts(desc);
78 }
79 
80 int main(int argc, char *argv[])
81 {
82  pj_caching_pool cp;
83  pj_pool_t *pool;
84  pjmedia_endpt *med_ept;
85  unsigned clock_rate = 16000;
86  int c, force=0;
87  const char *out_fname;
88  pjmedia_conf *conf;
89  pjmedia_port *wavout;
90  struct wav_input wav_input[MAX_WAV];
91  pj_size_t longest = 0, processed;
92  unsigned i, input_cnt = 0;
93  pj_status_t status;
94 
95 #define CHECK(op) do { \
96  status = op; \
97  if (status != PJ_SUCCESS) \
98  return err_ret(#op, status); \
99  } while (0)
100 
101 
102  /* Parse arguments */
103  while ((c=pj_getopt(argc, argv, "c:f")) != -1) {
104  switch (c) {
105  case 'c':
106  clock_rate = atoi(pj_optarg);
107  if (clock_rate < 1000) {
108  puts("Error: invalid clock rate");
109  usage();
110  return -1;
111  }
112  break;
113  case 'f':
114  force = 1;
115  break;
116  }
117  }
118 
119  /* Get output WAV name */
120  if (pj_optind == argc) {
121  puts("Error: no WAV output is specified");
122  usage();
123  return 1;
124  }
125 
126  out_fname = argv[pj_optind++];
127  if (force==0 && pj_file_exists(out_fname)) {
128  char in[8];
129 
130  printf("File %s exists, overwrite? [Y/N] ", out_fname);
131  fflush(stdout);
132  if (fgets(in, sizeof(in), stdin) == NULL)
133  return 1;
134  if (pj_tolower(in[0]) != 'y')
135  return 1;
136  }
137 
138  /* Scan input file names */
139  for (input_cnt=0 ; pj_optind<argc && input_cnt<MAX_WAV;
140  ++pj_optind, ++input_cnt)
141  {
142  if (!pj_file_exists(argv[pj_optind])) {
143  printf("Error: input file %s doesn't exist\n",
144  argv[pj_optind]);
145  return 1;
146  }
147  wav_input[input_cnt].fname = argv[pj_optind];
148  wav_input[input_cnt].port = NULL;
149  wav_input[input_cnt].slot = 0;
150  }
151 
152  if (input_cnt == 0) {
153  puts("Error: no input WAV is specified");
154  return 0;
155  }
156 
157  /* Initialialize */
158  CHECK( pj_init() );
159  CHECK( pjlib_util_init() );
160  pj_caching_pool_init(&cp, NULL, 0);
161  CHECK( pjmedia_endpt_create(&cp.factory, NULL, 1, &med_ept) );
162 
163  pool = pj_pool_create(&cp.factory, "mix", 1000, 1000, NULL);
164 
165  /* Create the bridge */
166  CHECK( pjmedia_conf_create(pool, MAX_WAV+4, clock_rate, 1,
167  clock_rate * PTIME / 1000, 16,
168  PJMEDIA_CONF_NO_DEVICE, &conf) );
169 
170  /* Create the WAV output */
171  CHECK( pjmedia_wav_writer_port_create(pool, out_fname, clock_rate, 1,
172  clock_rate * PTIME / 1000,
173  16, 0, 0, &wavout) );
174 
175  /* Create and register each WAV input to the bridge */
176  for (i=0; i<input_cnt; ++i) {
177  pj_ssize_t len;
178 
179  CHECK( pjmedia_wav_player_port_create(pool, wav_input[i].fname, 20,
181  &wav_input[i].port) );
182  len = pjmedia_wav_player_get_len(wav_input[i].port);
183  len = (pj_ssize_t)(len * 1.0 * clock_rate /
184  PJMEDIA_PIA_SRATE(&wav_input[i].port->info));
185  if (len > (pj_ssize_t)longest)
186  longest = len;
187 
188  CHECK( pjmedia_conf_add_port(conf, pool, wav_input[i].port,
189  NULL, &wav_input[i].slot));
190 
191  CHECK( pjmedia_conf_connect_port(conf, wav_input[i].slot, 0, 0) );
192  }
193 
194  /* Loop reading frame from the bridge and write it to WAV */
195  processed = 0;
196  while (processed < longest + clock_rate * APPEND * 2 / 1000) {
197  pj_int16_t framebuf[PTIME * 48000 / 1000];
199  pjmedia_frame frame;
200 
201  frame.buf = framebuf;
202  frame.size = PJMEDIA_PIA_SPF(&mp->info) * 2;
203  pj_assert(frame.size <= sizeof(framebuf));
204 
205  CHECK( pjmedia_port_get_frame(mp, &frame) );
206 
207  if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO) {
208  pj_bzero(frame.buf, frame.size);
210  }
211 
212  CHECK( pjmedia_port_put_frame(wavout, &frame));
213 
214  processed += frame.size;
215  }
216 
217  PJ_LOG(3,(THIS_FILE, "Done. Output duration: %d.%03d",
218  (processed >> 2)/clock_rate,
219  ((processed >> 2)*1000/clock_rate) % 1000));
220 
221  /* Shutdown everything */
222  CHECK( pjmedia_port_destroy(wavout) );
223  for (i=0; i<input_cnt; ++i) {
224  CHECK( pjmedia_conf_remove_port(conf, wav_input[i].slot) );
225  CHECK( pjmedia_port_destroy(wav_input[i].port) );
226  }
227 
228  CHECK(pjmedia_conf_destroy(conf));
229  CHECK(pjmedia_endpt_destroy(med_ept));
230 
231  pj_pool_release(pool);
233  pj_shutdown();
234 
235  return 0;
236 }
237 
pj_status_t pjmedia_conf_create(pj_pool_t *pool, unsigned max_slots, unsigned sampling_rate, unsigned channel_count, unsigned samples_per_frame, unsigned bits_per_sample, unsigned options, pjmedia_conf **p_conf)
PJMEDIA main header file.
pjmedia_port * pjmedia_conf_get_master_port(pjmedia_conf *conf)
pj_status_t pjmedia_port_get_frame(pjmedia_port *port, pjmedia_frame *frame)
pj_size_t size
Definition: frame.h:60
pjmedia_port_info info
Definition: port.h:366
void pj_pool_release(pj_pool_t *pool)
pj_status_t pjmedia_port_destroy(pjmedia_port *port)
struct pjmedia_endpt pjmedia_endpt
Definition: types.h:187
pj_ssize_t pjmedia_wav_player_get_len(pjmedia_port *port)
pj_status_t pjmedia_wav_writer_port_create(pj_pool_t *pool, const char *filename, unsigned clock_rate, unsigned channel_count, unsigned samples_per_frame, unsigned bits_per_sample, unsigned flags, pj_ssize_t buff_size, pjmedia_port **p_port)
#define PJ_LOG(level, arg)
int pj_status_t
short pj_int16_t
pj_status_t pjmedia_conf_remove_port(pjmedia_conf *conf, unsigned slot)
Definition: mix.c:60
Definition: port.h:364
pj_pool_factory factory
#define pj_assert(expr)
pj_status_t pjmedia_conf_connect_port(pjmedia_conf *conf, unsigned src_slot, unsigned sink_slot, int adj_level)
pj_status_t pjmedia_endpt_create(pj_pool_factory *pf, pj_ioqueue_t *ioqueue, unsigned worker_cnt, pjmedia_endpt **p_endpt)
Definition: endpoint.h:105
struct pjmedia_conf pjmedia_conf
Definition: conference.h:60
void pj_caching_pool_init(pj_caching_pool *ch_pool, const pj_pool_factory_policy *policy, pj_size_t max_capacity)
long pj_ssize_t
void * buf
Definition: frame.h:59
pj_status_t pjmedia_port_put_frame(pjmedia_port *port, pjmedia_frame *frame)
PJ_BEGIN_DECL pj_status_t pjlib_util_init(void)
void pj_bzero(void *dst, pj_size_t size)
pj_str_t pj_strerror(pj_status_t statcode, char *buf, pj_size_t bufsize)
pj_status_t pjmedia_conf_add_port(pjmedia_conf *conf, pj_pool_t *pool, pjmedia_port *strm_port, const pj_str_t *name, unsigned *p_slot)
Definition: wav_port.h:50
pj_status_t pjmedia_conf_destroy(pjmedia_conf *conf)
pj_status_t pjmedia_wav_player_port_create(pj_pool_t *pool, const char *filename, unsigned ptime, unsigned flags, pj_ssize_t buff_size, pjmedia_port **p_port)
unsigned PJMEDIA_PIA_SPF(const pjmedia_port_info *pia)
Definition: port.h:298
#define PJ_ERR_MSG_SIZE
pj_pool_t * pj_pool_create(pj_pool_factory *factory, const char *name, pj_size_t initial_size, pj_size_t increment_size, pj_pool_callback *callback)
unsigned PJMEDIA_PIA_SRATE(const pjmedia_port_info *pia)
Definition: port.h:244
pjmedia_frame_type type
Definition: frame.h:58
pj_bool_t pj_file_exists(const char *filename)
void pj_shutdown(void)
Definition: frame.h:56
int pj_tolower(unsigned char c)
pj_status_t pj_init(void)
pj_status_t pjmedia_endpt_destroy(pjmedia_endpt *endpt)
Definition: endpoint.h:146
size_t pj_size_t
Definition: frame.h:46
Definition: conference.h:94
void pj_caching_pool_destroy(pj_caching_pool *ch_pool)

 


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