WARNING: The online documentation has moved to https://docs.pjsip.org.

Visit the new documentation at https://docs.pjsip.org:

BLOG | DOCUMENTATION | GITHUB

Home --> Documentations --> PJMEDIA Reference

Samples: Mixing WAV files

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

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

 


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