blob: fd9bf00f3a4691003e6cbb5511ead5996faf801e [file] [log] [blame]
Benny Prijono204ce5e2006-03-20 16:59:23 +00001/* $Id$ */
2/*
3 * Copyright (C) 2003-2006 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
20static const char *desc =
21 " sndinfo.c \n"
22 " \n"
23 " PURPOSE: \n"
24 " Print sound device info and test open device. \n"
25 " \n"
26 " USAGE: \n"
Benny Prijonoa8df6542006-03-23 14:20:42 +000027 " sndinfo [id rec/play/both clockrate nchan bits] \n"
Benny Prijono204ce5e2006-03-20 16:59:23 +000028 " \n"
29 " DESCRIPTION: \n"
30 " When invoked without any arguments, it displays information about all \n"
31 " sound devices in the system. \n"
32 " \n"
33 " When invoked with arguments, the program tests if device can be opened \n"
34 " with the specified arguments. All these arguments must be specified: \n"
Benny Prijonoa8df6542006-03-23 14:20:42 +000035 " - id The device ID (-1 for the first capable device) \n"
36 " - rec/play/both Specify which streams to open. \n"
37 " - clockrate Specify clock rate (e.g. 8000, 11025, etc.) \n"
38 " - nchan Number of channels (1=mono, 2=stereo). \n"
39 " - bits Number of bits per sample (normally 16). \n";
Benny Prijono204ce5e2006-03-20 16:59:23 +000040
41#include <pjmedia.h>
42#include <pjlib.h>
43
44#include <stdlib.h> /* atoi() */
45#include <stdio.h>
46
47
48static void enum_devices(void)
49{
50 int i, count;
51
52 count = pjmedia_snd_get_dev_count();
53 if (count == 0) {
54 puts("No devices found");
55 return;
56 }
57
58 for (i=0; i<count; ++i) {
59 const pjmedia_snd_dev_info *info;
60
61 info = pjmedia_snd_get_dev_info(i);
62 pj_assert(info != NULL);
63
64 printf( "Device #%02d: \n"
65 " Name : %s\n"
66 " # of input channels : %d\n"
67 " # of output channels: %d\n"
68 " Default clock rate : %d Hz\n\n",
69 i, info->name, info->input_count, info->output_count,
70 info->default_samples_per_sec);
71 }
Benny Prijonoa8df6542006-03-23 14:20:42 +000072 puts("");
73 puts("Run with -h to get more options");
Benny Prijono204ce5e2006-03-20 16:59:23 +000074}
75
Benny Prijono15953012006-04-27 22:37:08 +000076static unsigned clock_rate;
77static unsigned play_counter;
78static unsigned rec_counter;
79static unsigned min_delay = 0xFFFF, max_delay;
Benny Prijonoe452dda2006-04-03 09:43:36 +000080static char play_delays[1000];
Benny Prijono5012da82006-04-25 10:02:40 +000081static pj_uint32_t last_play_timestamp, last_rec_timestamp;
Benny Prijono204ce5e2006-03-20 16:59:23 +000082
83static pj_status_t play_cb(void *user_data, pj_uint32_t timestamp,
84 void *output, unsigned size)
85{
Benny Prijonoc708f932006-04-03 11:42:56 +000086 static pj_timestamp last_cb;
Benny Prijonoe452dda2006-04-03 09:43:36 +000087
Benny Prijono15953012006-04-27 22:37:08 +000088
89 PJ_UNUSED_ARG(user_data);
90 PJ_UNUSED_ARG(output);
91 PJ_UNUSED_ARG(size);
92
93
Benny Prijonoa8df6542006-03-23 14:20:42 +000094 ++play_counter;
Benny Prijono5012da82006-04-25 10:02:40 +000095 last_play_timestamp = timestamp;
Benny Prijonoe452dda2006-04-03 09:43:36 +000096
Benny Prijonoc708f932006-04-03 11:42:56 +000097 if (last_cb.u64 == 0) {
98 pj_get_timestamp(&last_cb);
Benny Prijono5012da82006-04-25 10:02:40 +000099 } else if (play_counter <= PJ_ARRAY_SIZE(play_delays)) {
Benny Prijonoc708f932006-04-03 11:42:56 +0000100 pj_timestamp now;
Benny Prijono15953012006-04-27 22:37:08 +0000101 unsigned delay;
Benny Prijonoe452dda2006-04-03 09:43:36 +0000102
Benny Prijonoc708f932006-04-03 11:42:56 +0000103 pj_get_timestamp(&now);
104
105 delay = pj_elapsed_msec(&last_cb, &now);
Benny Prijonoe452dda2006-04-03 09:43:36 +0000106 if (delay < min_delay)
107 min_delay = delay;
108 if (delay > max_delay)
109 max_delay = delay;
110
Benny Prijonoc708f932006-04-03 11:42:56 +0000111 last_cb = now;
Benny Prijonoe452dda2006-04-03 09:43:36 +0000112
Benny Prijono15953012006-04-27 22:37:08 +0000113 play_delays[play_counter-1] = (char)delay;
Benny Prijonoe452dda2006-04-03 09:43:36 +0000114 }
115
Benny Prijono204ce5e2006-03-20 16:59:23 +0000116 return PJ_SUCCESS;
117}
118
119static pj_status_t rec_cb(void *user_data, pj_uint32_t timestamp,
Benny Prijonof521eb02006-08-06 23:07:25 +0000120 void *input, unsigned size)
Benny Prijono204ce5e2006-03-20 16:59:23 +0000121{
Benny Prijono15953012006-04-27 22:37:08 +0000122
123 PJ_UNUSED_ARG(size);
124 PJ_UNUSED_ARG(input);
125 PJ_UNUSED_ARG(user_data);
126
127
Benny Prijonoa8df6542006-03-23 14:20:42 +0000128 ++rec_counter;
Benny Prijono5012da82006-04-25 10:02:40 +0000129
Benny Prijonoed8c0fc2006-05-14 21:29:53 +0000130 if (timestamp - last_rec_timestamp >= clock_rate && last_play_timestamp) {
Benny Prijono5012da82006-04-25 10:02:40 +0000131 int diff;
132 diff = last_play_timestamp - timestamp;
133 printf("Play timestamp=%u, capture timestamp=%u, diff=%d\n",
134 last_play_timestamp, timestamp, diff);
135 last_rec_timestamp = timestamp;
136 }
Benny Prijono204ce5e2006-03-20 16:59:23 +0000137 return PJ_SUCCESS;
138}
139
Benny Prijonoa8df6542006-03-23 14:20:42 +0000140static void app_perror(const char *title, pj_status_t status)
Benny Prijono204ce5e2006-03-20 16:59:23 +0000141{
Benny Prijonoa8df6542006-03-23 14:20:42 +0000142 char errmsg[PJ_ERR_MSG_SIZE];
143
144 pj_strerror(status, errmsg, sizeof(errmsg));
145 printf( "%s: %s (err=%d)\n",
146 title, errmsg, status);
147}
Benny Prijonoe452dda2006-04-03 09:43:36 +0000148
Benny Prijonoa8df6542006-03-23 14:20:42 +0000149static int open_device(int dev_id, pjmedia_dir dir,
Benny Prijono5012da82006-04-25 10:02:40 +0000150 int nchannel, int bits)
Benny Prijonoa8df6542006-03-23 14:20:42 +0000151{
152 pj_status_t status = PJ_SUCCESS;
Benny Prijono204ce5e2006-03-20 16:59:23 +0000153 unsigned nsamples;
154 pjmedia_snd_stream *strm;
Benny Prijonoa8df6542006-03-23 14:20:42 +0000155 const char *dirtype;
Benny Prijono5012da82006-04-25 10:02:40 +0000156 char tmp[10];
Benny Prijonoe452dda2006-04-03 09:43:36 +0000157 unsigned i;
Benny Prijono204ce5e2006-03-20 16:59:23 +0000158
Benny Prijonoa8df6542006-03-23 14:20:42 +0000159 switch (dir) {
160 case PJMEDIA_DIR_CAPTURE:
161 dirtype = "capture"; break;
162 case PJMEDIA_DIR_PLAYBACK:
163 dirtype = "playback"; break;
164 case PJMEDIA_DIR_CAPTURE_PLAYBACK:
165 dirtype = "capture/playback"; break;
166 default:
167 return 1;
168 }
169
Benny Prijono204ce5e2006-03-20 16:59:23 +0000170 nsamples = clock_rate * 20 / 1000;
171
Benny Prijonoa8df6542006-03-23 14:20:42 +0000172 printf( "Opening device %d for %s: clockrate=%d, nchannel=%d, "
173 "bits=%d, nsamples=%d..\n",
174 dev_id, dirtype, clock_rate, nchannel, bits, nsamples);
Benny Prijono204ce5e2006-03-20 16:59:23 +0000175
Benny Prijonoa8df6542006-03-23 14:20:42 +0000176 if (dir == PJMEDIA_DIR_CAPTURE) {
177 status = pjmedia_snd_open_rec( dev_id, clock_rate, nchannel,
178 nsamples, bits, &rec_cb, NULL,
179 &strm);
180 } else if (dir == PJMEDIA_DIR_PLAYBACK) {
Benny Prijono204ce5e2006-03-20 16:59:23 +0000181 status = pjmedia_snd_open_player( dev_id, clock_rate, nchannel,
182 nsamples, bits, &play_cb, NULL,
183 &strm);
Benny Prijonoa8df6542006-03-23 14:20:42 +0000184 } else {
185 status = pjmedia_snd_open( dev_id, dev_id, clock_rate, nchannel,
186 nsamples, bits, &rec_cb, &play_cb, NULL,
187 &strm);
Benny Prijono204ce5e2006-03-20 16:59:23 +0000188 }
189
190 if (status != PJ_SUCCESS) {
Benny Prijonoa8df6542006-03-23 14:20:42 +0000191 app_perror("Unable to open device for capture", status);
192 return 1;
Benny Prijono204ce5e2006-03-20 16:59:23 +0000193 }
194
Benny Prijonoa8df6542006-03-23 14:20:42 +0000195 status = pjmedia_snd_stream_start(strm);
196 if (status != PJ_SUCCESS) {
197 app_perror("Unable to start capture stream", status);
198 return 1;
199 }
200
201 /* Let playback/capture runs for a while */
Benny Prijono5012da82006-04-25 10:02:40 +0000202 //pj_thread_sleep(1000);
203 puts("Press <ENTER> to stop");
204 fgets(tmp, sizeof(tmp), stdin);
205
Benny Prijonoa8df6542006-03-23 14:20:42 +0000206
Benny Prijono204ce5e2006-03-20 16:59:23 +0000207 pjmedia_snd_stream_close(strm);
Benny Prijonoa8df6542006-03-23 14:20:42 +0000208
209 if ((dir & PJMEDIA_DIR_CAPTURE) && rec_counter==0) {
210 printf("Error: capture stream was not running\n");
211 return 1;
212 }
213
214 if ((dir & PJMEDIA_DIR_PLAYBACK) && play_counter==0) {
215 printf("Error: playback stream was not running\n");
216 return 1;
217 }
218
219 puts("Success.");
Benny Prijonoe452dda2006-04-03 09:43:36 +0000220
221 printf("Delay: ");
222 for (i=0; i<play_counter; ++i)
223 printf("%d ", play_delays[i]);
224
225 puts("");
226 if (dir & PJMEDIA_DIR_PLAYBACK) {
227 printf("Callback interval: min interval=%d ms, max interval=%d ms\n",
228 min_delay, max_delay);
229 }
230
231
Benny Prijono204ce5e2006-03-20 16:59:23 +0000232 return 0;
233}
234
235
236int main(int argc, char *argv[])
237{
238 pj_caching_pool cp;
239 pjmedia_endpt *med_endpt;
240 pj_status_t status;
241
242 /* Init pjlib */
243 status = pj_init();
244 PJ_ASSERT_RETURN(status==PJ_SUCCESS, 1);
245
246 /* Must create a pool factory before we can allocate any memory. */
247 pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
248
249 /*
250 * Initialize media endpoint.
251 * This will implicitly initialize PJMEDIA too.
252 */
Benny Prijono275fd682006-03-22 11:59:11 +0000253 status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
Benny Prijono204ce5e2006-03-20 16:59:23 +0000254 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
255
256
257 if (argc == 1) {
258 enum_devices();
259 return 0;
260 } else if (argc == 6) {
261
262 int dev_id;
Benny Prijono15953012006-04-27 22:37:08 +0000263 pjmedia_dir dir = PJMEDIA_DIR_NONE;
Benny Prijono204ce5e2006-03-20 16:59:23 +0000264 int nchannel;
265 int bits;
266
267 dev_id = atoi(argv[1]);
Benny Prijonoa8df6542006-03-23 14:20:42 +0000268
269 if (strcmp(argv[2], "rec")==0)
270 dir = PJMEDIA_DIR_CAPTURE;
271 else if (strcmp(argv[2], "play")==0)
272 dir = PJMEDIA_DIR_PLAYBACK;
273 else if (strcmp(argv[2], "both")==0)
274 dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
275
Benny Prijono204ce5e2006-03-20 16:59:23 +0000276 clock_rate = atoi(argv[3]);
277 nchannel = atoi(argv[4]);
278 bits = atoi(argv[5]);
279
Benny Prijono5012da82006-04-25 10:02:40 +0000280 return open_device(dev_id, dir, nchannel, bits);
Benny Prijono204ce5e2006-03-20 16:59:23 +0000281
282 } else {
283 puts("Error: invalid arguments");
284 puts(desc);
285 return 1;
286 }
287
Benny Prijonoaf1bb1e2006-11-21 12:39:31 +0000288 /* Shutdown PJLIB */
289 pj_shutdown();
290
Benny Prijono204ce5e2006-03-20 16:59:23 +0000291 return 0;
292}
293
294