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: Using Stereo Port

This example demonstrates how to use Monochannel and multichannel audio frame converter to change the channel count of the media streams.

This file is pjsip-apps/src/samples/stereotest.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
31#include <pjmedia.h>
32#include <pjlib-util.h>
33#include <pjlib.h>
34
35#include <stdio.h>
36#include <stdlib.h>
37
38#include "util.h"
39
40#define REC_CLOCK_RATE 16000
41#define PTIME 20
42
43#define MODE_PLAY 1
44#define MODE_RECORD 2
45
46
47/* For logging purpose. */
48#define THIS_FILE "stereotest.c"
49
50
51static const char *desc =
52" FILE \n"
53" \n"
54" stereotest.c \n"
55" \n"
56" PURPOSE \n"
57" \n"
58" Demonstrate how use stereo port to play a WAV file to sound \n"
59" device or record to a WAV file from sound device with different \n"
60" channel count. \n"
61" \n"
62" USAGE \n"
63" \n"
64" stereotest [options] WAV \n"
65" \n"
66" Options: \n"
67" -m, --mode=N Operation mode: 1 = playing, 2 = recording.\n"
68" -C, --rec-ch-cnt=N Number of channel for recording file. \n"
69" -c, --snd-ch-cnt=N Number of channel for opening sound device.\n"
70" \n";
71
72int main(int argc, char *argv[])
73{
75 pjmedia_endpt *med_endpt;
76 pj_pool_t *pool;
77
78 pjmedia_port *file_port = NULL;
79 pjmedia_port *stereo_port = NULL;
80 pjmedia_snd_port *snd_port = NULL;
81
82 int dev_id = -1;
83 char tmp[10];
84 pj_status_t status;
85
86 char *wav_file = NULL;
87 unsigned mode = 0;
88 unsigned rec_ch_cnt = 1;
89 unsigned snd_ch_cnt = 2;
90
91 enum {
92 OPT_MODE = 'm',
93 OPT_REC_CHANNEL = 'C',
94 OPT_SND_CHANNEL = 'c',
95 };
96
97 struct pj_getopt_option long_options[] = {
98 { "mode", 1, 0, OPT_MODE },
99 { "rec-ch-cnt", 1, 0, OPT_REC_CHANNEL },
100 { "snd-ch-cnt", 1, 0, OPT_SND_CHANNEL },
101 { NULL, 0, 0, 0 },
102 };
103
104 int c;
105 int option_index;
106
107 /* Must init PJLIB first: */
108 status = pj_init();
109 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
110
111 /* Parse arguments */
112 pj_optind = 0;
113 while((c=pj_getopt_long(argc,argv, "m:C:c:", long_options, &option_index))!=-1) {
114
115 switch (c) {
116 case OPT_MODE:
117 if (mode) {
118 app_perror(THIS_FILE, "Cannot record and play at once!",
119 PJ_EINVAL);
120 return 1;
121 }
122 mode = atoi(pj_optarg);
123 break;
124
125 case OPT_REC_CHANNEL:
126 rec_ch_cnt = atoi(pj_optarg);
127 break;
128
129 case OPT_SND_CHANNEL:
130 snd_ch_cnt = atoi(pj_optarg);
131 break;
132
133 default:
134 printf("Invalid options %s\n", argv[pj_optind]);
135 puts(desc);
136 return 1;
137 }
138
139 }
140
141 wav_file = argv[pj_optind];
142
143 /* Verify arguments. */
144 if (!wav_file) {
145 app_perror(THIS_FILE, "WAV file not specified!", PJ_EINVAL);
146 puts(desc);
147 return 1;
148 }
149 if (!snd_ch_cnt || !rec_ch_cnt || rec_ch_cnt > 6) {
150 app_perror(THIS_FILE, "Invalid or too many channel count!", PJ_EINVAL);
151 puts(desc);
152 return 1;
153 }
154 if (mode != MODE_RECORD && mode != MODE_PLAY) {
155 app_perror(THIS_FILE, "Invalid operation mode!", PJ_EINVAL);
156 puts(desc);
157 return 1;
158 }
159
160 /* Must create a pool factory before we can allocate any memory. */
162
163 /*
164 * Initialize media endpoint.
165 * This will implicitly initialize PJMEDIA too.
166 */
167 status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
168 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
169
170 /* Create memory pool for our file player */
171 pool = pj_pool_create( &cp.factory, /* pool factory */
172 "app", /* pool name. */
173 4000, /* init size */
174 4000, /* increment size */
175 NULL /* callback on error */
176 );
177
178 if (mode == MODE_PLAY) {
179 /* Create WAVE file player port. */
180 status = pjmedia_wav_player_port_create( pool, wav_file, PTIME, 0,
181 0, &file_port);
182 if (status != PJ_SUCCESS) {
183 app_perror(THIS_FILE, "Unable to open file", status);
184 return 1;
185 }
186
187 /* Create sound player port. */
189 pool, /* pool */
190 dev_id, /* device id. */
191 PJMEDIA_PIA_SRATE(&file_port->info),/* clock rate. */
192 snd_ch_cnt, /* # of channels. */
193 snd_ch_cnt * PTIME * /* samples per frame. */
194 PJMEDIA_PIA_SRATE(&file_port->info) / 1000,
195 PJMEDIA_PIA_BITS(&file_port->info),/* bits per sample. */
196 0, /* options */
197 &snd_port /* returned port */
198 );
199 if (status != PJ_SUCCESS) {
200 app_perror(THIS_FILE, "Unable to open sound device", status);
201 return 1;
202 }
203
204 if (snd_ch_cnt != PJMEDIA_PIA_CCNT(&file_port->info)) {
205 status = pjmedia_stereo_port_create( pool,
206 file_port,
207 snd_ch_cnt,
208 0,
209 &stereo_port);
210 if (status != PJ_SUCCESS) {
211 app_perror(THIS_FILE, "Unable to create stereo port", status);
212 return 1;
213 }
214
215 status = pjmedia_snd_port_connect(snd_port, stereo_port);
216 } else {
217 status = pjmedia_snd_port_connect(snd_port, file_port);
218 }
219
220 if (status != PJ_SUCCESS) {
221 app_perror(THIS_FILE, "Unable to connect sound port", status);
222 return 1;
223 }
224
225 } else {
226 /* Create WAVE file writer port. */
227 status = pjmedia_wav_writer_port_create(pool, wav_file,
228 REC_CLOCK_RATE,
229 rec_ch_cnt,
230 rec_ch_cnt * PTIME *
231 REC_CLOCK_RATE / 1000,
232 NBITS,
233 0, 0,
234 &file_port);
235 if (status != PJ_SUCCESS) {
236 app_perror(THIS_FILE, "Unable to open file", status);
237 return 1;
238 }
239
240 /* Create sound player port. */
242 pool, /* pool */
243 dev_id, /* device id. */
244 REC_CLOCK_RATE, /* clock rate. */
245 snd_ch_cnt, /* # of channels. */
246 snd_ch_cnt * PTIME *
247 REC_CLOCK_RATE / 1000, /* samples per frame. */
248 NBITS, /* bits per sample. */
249 0, /* options */
250 &snd_port /* returned port */
251 );
252 if (status != PJ_SUCCESS) {
253 app_perror(THIS_FILE, "Unable to open sound device", status);
254 return 1;
255 }
256
257 if (rec_ch_cnt != snd_ch_cnt) {
258 status = pjmedia_stereo_port_create( pool,
259 file_port,
260 snd_ch_cnt,
261 0,
262 &stereo_port);
263 if (status != PJ_SUCCESS) {
264 app_perror(THIS_FILE, "Unable to create stereo port", status);
265 return 1;
266 }
267
268 status = pjmedia_snd_port_connect(snd_port, stereo_port);
269 } else {
270 status = pjmedia_snd_port_connect(snd_port, file_port);
271 }
272
273 if (status != PJ_SUCCESS) {
274 app_perror(THIS_FILE, "Unable to connect sound port", status);
275 return 1;
276 }
277 }
278
279 /* Dump memory usage */
280 dump_pool_usage(THIS_FILE, &cp);
281
282 /*
283 * File should be playing and looping now, using sound device's thread.
284 */
285
286
287 /* Sleep to allow log messages to flush */
288 pj_thread_sleep(100);
289
290 printf("Mode = %s\n", (mode == MODE_PLAY? "playing" : "recording") );
291 printf("File port channel count = %d\n", PJMEDIA_PIA_CCNT(&file_port->info));
292 printf("Sound port channel count = %d\n",
294 puts("");
295 puts("Press <ENTER> to stop and quit");
296
297 if (fgets(tmp, sizeof(tmp), stdin) == NULL) {
298 puts("EOF while reading stdin, will quit now..");
299 }
300
301 /* Start deinitialization: */
302
303
304 /* Destroy sound device */
305 status = pjmedia_snd_port_destroy( snd_port );
306 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
307
308
309 /* Destroy stereo port and file_port.
310 * Stereo port will destroy all downstream ports (e.g. the file port)
311 */
312 status = pjmedia_port_destroy( stereo_port? stereo_port : file_port);
313 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
314
315
316 /* Release application pool */
317 pj_pool_release( pool );
318
319 /* Destroy media endpoint. */
320 pjmedia_endpt_destroy( med_endpt );
321
322 /* Destroy pool factory */
324
325 /* Shutdown PJLIB */
326 pj_shutdown();
327
328
329 /* Done. */
330 return 0;
331
332}
333
334
335
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)
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)
pj_status_t pjmedia_port_destroy(pjmedia_port *port)
unsigned PJMEDIA_PIA_BITS(const pjmedia_port_info *pia)
Definition: port.h:283
unsigned PJMEDIA_PIA_CCNT(const pjmedia_port_info *pia)
Definition: port.h:270
unsigned PJMEDIA_PIA_SRATE(const pjmedia_port_info *pia)
Definition: port.h:257
pj_status_t pjmedia_stereo_port_create(pj_pool_t *pool, pjmedia_port *dn_port, unsigned channel_count, unsigned options, pjmedia_port **p_port)
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 pjmedia_snd_port_connect(pjmedia_snd_port *snd_port, pjmedia_port *port)
pjmedia_port * pjmedia_snd_port_get_port(pjmedia_snd_port *snd_port)
pj_status_t pjmedia_snd_port_create_player(pj_pool_t *pool, int index, unsigned clock_rate, unsigned channel_count, unsigned samples_per_frame, unsigned bits_per_sample, unsigned options, pjmedia_snd_port **p_port)
pj_status_t pjmedia_snd_port_destroy(pjmedia_snd_port *snd_port)
pj_status_t pjmedia_snd_port_create_rec(pj_pool_t *pool, int index, unsigned clock_rate, unsigned channel_count, unsigned samples_per_frame, unsigned bits_per_sample, unsigned options, pjmedia_snd_port **p_port)
struct pjmedia_snd_port pjmedia_snd_port
Definition: sound_port.h:145
pj_status_t pj_init(void)
int pj_status_t
void pj_shutdown(void)
PJ_SUCCESS
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_pool_factory_policy pj_pool_factory_default_policy
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)
pj_status_t pj_thread_sleep(unsigned msec)
#define PJ_ASSERT_RETURN(expr, retval)
PJMEDIA main header file.
pj_pool_factory factory
Definition: port.h:378
pjmedia_port_info info
Definition: port.h:379

 


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