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