00001
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #define _GNU_SOURCE
00036 #include <stdio.h>
00037 #include <malloc.h>
00038 #include <unistd.h>
00039 #include <stdlib.h>
00040 #include <string.h>
00041 #include <getopt.h>
00042 #include <fcntl.h>
00043 #include <ctype.h>
00044 #include <errno.h>
00045 #include <limits.h>
00046 #include <locale.h>
00047 #include <alsa/asoundlib.h>
00048 #include <assert.h>
00049 #include <sys/types.h>
00050 #include <sys/poll.h>
00051 #include <sys/uio.h>
00052 #include <sys/time.h>
00053 #include <sys/signal.h>
00054 #include <sys/socket.h>
00055 #include <netinet/in.h>
00056 #include <arpa/inet.h>
00057 #include <asm/byteorder.h>
00058
00059 #if 0
00060 #include "aconfig.h"
00061 #include "gettext.h"
00062 #include "formats.h"
00063 #include "version.h"
00064 #endif
00065
00066
00067
00068 #ifndef LLONG_MAX
00069 #define LLONG_MAX 9223372036854775807LL
00070 #endif
00071
00072 #define DEFAULT_FORMAT SND_PCM_FORMAT_U8
00073 #define DEFAULT_SPEED 4000
00074
00075 #define FORMAT_DEFAULT -1
00076 #define FORMAT_RAW 0
00077 #define FORMAT_VOC 1
00078 #define FORMAT_WAVE 2
00079 #define FORMAT_AU 3
00080
00081
00082 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
00083 #define error(...) do {\
00084 fprintf(stderr, "%s: %s:%d: ", command, __FUNCTION__, __LINE__); \
00085 fprintf(stderr, __VA_ARGS__); \
00086 putc('\n', stderr); \
00087 } while (0)
00088 #else
00089 #define error(args...) do {\
00090 fprintf(stderr, "%s: %s:%d: ", command, __FUNCTION__, __LINE__); \
00091 fprintf(stderr, ##args); \
00092 putc('\n', stderr); \
00093 } while (0)
00094 #endif
00095
00096
00097
00098 static snd_pcm_sframes_t (*readi_func)(snd_pcm_t *handle, void *buffer, snd_pcm_uframes_t size);
00099
00100 static char *command;
00101 static snd_pcm_t *handle;
00102 static struct {
00103 snd_pcm_format_t format;
00104 unsigned int channels;
00105 unsigned int rate;
00106 } hwparams, rhwparams;
00107 static int timelimit = 10;
00108 static int quiet_mode = 0;
00109 static int file_type = FORMAT_RAW;
00110 static unsigned int sleep_min = 0;
00111 static int open_mode = 0;
00112 static snd_pcm_stream_t stream = SND_PCM_STREAM_CAPTURE;
00113 static int mmap_flag = 0;
00114 static int interleaved = 1;
00115 static int nonblock = 0;
00116 static snd_pcm_uframes_t chunk_size = 0;
00117 static unsigned period_time = 0;
00118 static unsigned buffer_time = 0;
00119 static snd_pcm_uframes_t period_frames = 0;
00120 static snd_pcm_uframes_t buffer_frames = 0;
00121 static int avail_min = -1;
00122 static int start_delay = 0;
00123 static int stop_delay = 0;
00124 static int verbose = 0;
00125 static size_t bits_per_sample, bits_per_frame;
00126 static size_t chunk_bytes;
00127 static snd_output_t *log;
00128 struct timeval ttime;
00129 snd_pcm_info_t *info;
00130 static off64_t pbrec_count = LLONG_MAX;
00131 char *pcm_name = "default";
00132
00133
00134
00135 static size_t set_params(void)
00136 {
00137 snd_pcm_hw_params_t *params;
00138 snd_pcm_sw_params_t *swparams;
00139 snd_pcm_uframes_t buffer_size;
00140 int err;
00141 size_t n;
00142 snd_pcm_uframes_t xfer_align;
00143 unsigned int rate;
00144 snd_pcm_uframes_t start_threshold, stop_threshold;
00145 snd_pcm_hw_params_alloca(¶ms);
00146 snd_pcm_sw_params_alloca(&swparams);
00147 err = snd_pcm_hw_params_any(handle, params);
00148 if (err < 0) {
00149 error("Broken configuration for this PCM: no configurations available");
00150 exit(EXIT_FAILURE);
00151 }
00152 if (mmap_flag) {
00153 snd_pcm_access_mask_t *mask = alloca(snd_pcm_access_mask_sizeof());
00154 snd_pcm_access_mask_none(mask);
00155 snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
00156 snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
00157 snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_COMPLEX);
00158 err = snd_pcm_hw_params_set_access_mask(handle, params, mask);
00159 } else if (interleaved)
00160 err = snd_pcm_hw_params_set_access(handle, params,
00161 SND_PCM_ACCESS_RW_INTERLEAVED);
00162 else
00163 err = snd_pcm_hw_params_set_access(handle, params,
00164 SND_PCM_ACCESS_RW_NONINTERLEAVED);
00165 if (err < 0) {
00166 error("Access type not available");
00167 exit(EXIT_FAILURE);
00168 }
00169 err = snd_pcm_hw_params_set_format(handle, params, hwparams.format);
00170 if (err < 0) {
00171 error("Sample format non available");
00172 exit(EXIT_FAILURE);
00173 }
00174 err = snd_pcm_hw_params_set_channels(handle, params, hwparams.channels);
00175 if (err < 0) {
00176 error("Channels count non available");
00177 exit(EXIT_FAILURE);
00178 }
00179
00180 #if 0
00181 err = snd_pcm_hw_params_set_periods_min(handle, params, 2);
00182 assert(err >= 0);
00183 #endif
00184 rate = hwparams.rate;
00185 err = snd_pcm_hw_params_set_rate_near(handle, params, &hwparams.rate, 0);
00186 assert(err >= 0);
00187 if ((float)rate * 1.05 < hwparams.rate || (float)rate * 0.95 > hwparams.rate) {
00188 if (!quiet_mode) {
00189 char plugex[64];
00190 const char *pcmname = snd_pcm_name(handle);
00191 fprintf(stderr, "Warning: rate is not accurate (requested = %iHz, got = %iHz)\n", rate, hwparams.rate);
00192 if (! pcmname || strchr(snd_pcm_name(handle), ':'))
00193 *plugex = 0;
00194 else
00195 snprintf(plugex, sizeof(plugex), "(-Dplug:%s)",
00196 snd_pcm_name(handle));
00197 fprintf(stderr, " please, try the plug plugin %s\n",
00198 plugex);
00199 }
00200 }
00201 rate = hwparams.rate;
00202 if (buffer_time == 0 && buffer_frames == 0) {
00203 err = snd_pcm_hw_params_get_buffer_time_max(params,
00204 &buffer_time, 0);
00205 assert(err >= 0);
00206 if (buffer_time > 500000)
00207 buffer_time = 500000;
00208 }
00209 if (period_time == 0 && period_frames == 0) {
00210 if (buffer_time > 0)
00211 period_time = buffer_time / 4;
00212
00213 else
00214 period_frames = buffer_frames / 4;
00215
00216 }
00217 if (period_time > 0)
00218 err = snd_pcm_hw_params_set_period_time_near(handle, params,
00219 &period_time, 0);
00220 else
00221 err = snd_pcm_hw_params_set_period_size_near(handle, params,
00222 &period_frames, 0);
00223 assert(err >= 0);
00224 if (buffer_time > 0) {
00225 err = snd_pcm_hw_params_set_buffer_time_near(handle, params,
00226 &buffer_time, 0);
00227 } else {
00228 err = snd_pcm_hw_params_set_buffer_size_near(handle, params,
00229 &buffer_frames);
00230 }
00231 assert(err >= 0);
00232 err = snd_pcm_hw_params(handle, params);
00233 if (err < 0) {
00234 error("Unable to install hw params:");
00235 snd_pcm_hw_params_dump(params, log);
00236 exit(EXIT_FAILURE);
00237 }
00238 snd_pcm_hw_params_get_period_size(params, &chunk_size, 0);
00239 snd_pcm_hw_params_get_buffer_size(params, &buffer_size);
00240 if (chunk_size == buffer_size) {
00241 error("Can't use period equal to buffer size (%lu == %lu)",
00242 chunk_size, buffer_size);
00243 exit(EXIT_FAILURE);
00244 }
00245 snd_pcm_sw_params_current(handle, swparams);
00246 err = snd_pcm_sw_params_get_xfer_align(swparams, &xfer_align);
00247 if (err < 0) {
00248 error("Unable to obtain xfer align\n");
00249 exit(EXIT_FAILURE);
00250 }
00251 if (sleep_min)
00252 xfer_align = 1;
00253 err = snd_pcm_sw_params_set_sleep_min(handle, swparams,
00254 sleep_min);
00255 assert(err >= 0);
00256 if (avail_min < 0)
00257 n = chunk_size;
00258 else
00259 n = (double) rate * avail_min / 1000000;
00260 err = snd_pcm_sw_params_set_avail_min(handle, swparams, n);
00261
00262
00263 n = (buffer_size / xfer_align) * xfer_align;
00264 if (start_delay <= 0) {
00265 start_threshold = n + (double) rate * start_delay / 1000000;
00266 } else
00267 start_threshold = (double) rate * start_delay / 1000000;
00268 if (start_threshold < 1)
00269 start_threshold = 1;
00270 if (start_threshold > n)
00271 start_threshold = n;
00272 err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold);
00273 assert(err >= 0);
00274 if (stop_delay <= 0)
00275 stop_threshold = buffer_size + (double) rate * stop_delay / 1000000;
00276 else
00277 stop_threshold = (double) rate * stop_delay / 1000000;
00278 err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold);
00279 assert(err >= 0);
00280
00281 err = snd_pcm_sw_params_set_xfer_align(handle, swparams, xfer_align);
00282 assert(err >= 0);
00283
00284 if (snd_pcm_sw_params(handle, swparams) < 0) {
00285 error("unable to install sw params:");
00286 snd_pcm_sw_params_dump(swparams, log);
00287 exit(EXIT_FAILURE);
00288 }
00289
00290 if (verbose)
00291 snd_pcm_dump(handle, log);
00292
00293 bits_per_sample = snd_pcm_format_physical_width(hwparams.format);
00294 bits_per_frame = bits_per_sample * hwparams.channels;
00295 chunk_bytes = chunk_size * bits_per_frame / 8;
00296 return chunk_bytes;
00297 }
00298
00299
00300 int audio_open(void)
00301 {
00302 int error;
00303
00304 snd_pcm_info_alloca(&info);
00305
00306 error = snd_output_stdio_attach(&log, stderr, 0);
00307 assert(error >= 0);
00308
00309 file_type = FORMAT_RAW;
00310 start_delay=1;
00311
00312 chunk_size = -1;
00313 rhwparams.format = SND_PCM_FORMAT_U16_LE;
00314 rhwparams.rate = DEFAULT_SPEED;
00315 rhwparams.channels = 1;
00316
00317 if ((error = snd_pcm_open(&handle, pcm_name, stream, open_mode)) < 0)
00318 error("audio open error: %s", snd_strerror(error));
00319
00320 if ((error = snd_pcm_info(handle, info)) < 0)
00321 error("info error: %s", snd_strerror(error));
00322
00323 if (nonblock) {
00324 if ((error = snd_pcm_nonblock(handle, 1)) < 0)
00325 error("nonblock setting error: %s",
00326 snd_strerror(error));
00327 }
00328
00329 chunk_size = 1024;
00330 hwparams = rhwparams;
00331
00332 if (mmap_flag) {
00333 readi_func = snd_pcm_mmap_readi;
00334 } else {
00335 readi_func = snd_pcm_readi;
00336 }
00337
00338 return set_params();
00339 }
00340
00341
00342 void audio_close(void)
00343 {
00344 snd_pcm_close(handle);
00345 snd_output_close(log);
00346 snd_config_update_free_global();
00347 }
00348
00349
00350
00351
00352
00353
00354
00355 #if 0
00356 ssize_t safe_read(int fd, void *buf, size_t count)
00357 {
00358 ssize_t result = 0, res;
00359
00360 while (count > 0) {
00361 if ((res = read(fd, buf, count)) == 0)
00362 break;
00363 if (res < 0)
00364 return result > 0 ? result : res;
00365 count -= res;
00366 result += res;
00367 buf = (char *)buf + res;
00368 }
00369 return result;
00370 }
00371 #endif
00372
00373
00374 #ifndef timersub
00375 #define timersub(a, b, result) \
00376 do { \
00377 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
00378 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
00379 if ((result)->tv_usec < 0) { \
00380 --(result)->tv_sec; \
00381 (result)->tv_usec += 1000000; \
00382 } \
00383 } while (0)
00384 #endif
00385
00386
00387
00388 static void xrun(void)
00389 {
00390 snd_pcm_status_t *status;
00391 int res;
00392
00393 snd_pcm_status_alloca(&status);
00394 if ((res = snd_pcm_status(handle, status))<0) {
00395 error("status error: %s", snd_strerror(res));
00396 exit(EXIT_FAILURE);
00397 }
00398 if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) {
00399 struct timeval now, diff, tstamp;
00400 gettimeofday(&now, 0);
00401 snd_pcm_status_get_trigger_tstamp(status, &tstamp);
00402 timersub(&now, &tstamp, &diff);
00403 fprintf(stderr, "%s!!! (at least %.3f ms long)\n",
00404 stream == SND_PCM_STREAM_PLAYBACK ? "underrun" : "overrun",
00405 diff.tv_sec * 1000 + diff.tv_usec / 1000.0);
00406 if (verbose) {
00407 fprintf(stderr, "Status:\n");
00408 snd_pcm_status_dump(status, log);
00409 }
00410 if ((res = snd_pcm_prepare(handle))<0) {
00411 error("xrun: prepare error: %s", snd_strerror(res));
00412 exit(EXIT_FAILURE);
00413 }
00414 return;
00415 } if (snd_pcm_status_get_state(status) == SND_PCM_STATE_DRAINING) {
00416 if (verbose) {
00417 fprintf(stderr, "Status(DRAINING):\n");
00418 snd_pcm_status_dump(status, log);
00419 }
00420 if (stream == SND_PCM_STREAM_CAPTURE) {
00421 fprintf(stderr, "capture stream format change? attempting recover...\n");
00422 if ((res = snd_pcm_prepare(handle))<0) {
00423 error("xrun(DRAINING): prepare error: %s", snd_strerror(res));
00424 exit(EXIT_FAILURE);
00425 }
00426 return;
00427 }
00428 }
00429 if (verbose) {
00430 fprintf(stderr, "Status(R/W):\n");
00431 snd_pcm_status_dump(status, log);
00432 }
00433 error("read/write error, state = %s", snd_pcm_state_name(snd_pcm_status_get_state(status)));
00434 exit(EXIT_FAILURE);
00435 }
00436
00437
00438 static void suspend(void)
00439 {
00440 int res;
00441
00442 if (!quiet_mode)
00443 fprintf(stderr, "Suspended. Trying resume. "); fflush(stderr);
00444 while ((res = snd_pcm_resume(handle)) == -EAGAIN)
00445 sleep(1);
00446 if (res < 0) {
00447 if (!quiet_mode)
00448 fprintf(stderr, "Failed. Restarting stream. "); fflush(stderr);
00449 if ((res = snd_pcm_prepare(handle)) < 0) {
00450 error("suspend: prepare error: %s", snd_strerror(res));
00451 exit(EXIT_FAILURE);
00452 }
00453 }
00454 if (!quiet_mode)
00455 fprintf(stderr, "Done.\n");
00456 }
00457
00458
00459
00460
00461
00462
00463 static void compute_max_peak(u_char *data, size_t count)
00464 {
00465 signed int val, max, max_peak = 0, perc;
00466 static int run = 0;
00467 int format_little_endian = snd_pcm_format_little_endian(hwparams.format);
00468
00469 switch (bits_per_sample) {
00470 case 8: {
00471 signed char *valp = (signed char *)data;
00472 signed char mask = snd_pcm_format_silence(hwparams.format);
00473 while (count-- > 0) {
00474 val = *valp++ ^ mask;
00475 val = abs(val);
00476 if (max_peak < val)
00477 max_peak = val;
00478 }
00479 break;
00480 }
00481 case 16: {
00482 signed short *valp = (signed short *)data;
00483 signed short mask = snd_pcm_format_silence_16(hwparams.format);
00484 signed short sval;
00485
00486 count /= 2;
00487 while (count-- > 0) {
00488 if (format_little_endian)
00489 sval = __le16_to_cpu(*valp);
00490 else sval = __be16_to_cpu(*valp);
00491 sval = abs(sval) ^ mask;
00492 if (max_peak < sval)
00493 max_peak = sval;
00494 valp++;
00495 }
00496 break;
00497 }
00498 case 24: {
00499 unsigned char *valp = data;
00500 signed int mask = snd_pcm_format_silence_32(hwparams.format);
00501
00502 count /= 3;
00503 while (count-- > 0) {
00504 if (format_little_endian) {
00505 val = valp[0] | (valp[1]<<8) | (valp[2]<<16);
00506 } else {
00507 val = (valp[0]<<16) | (valp[1]<<8) | valp[2];
00508 }
00509
00510 if (val & (1<<(bits_per_sample-1))) {
00511 val |= 0xff<<24;
00512 }
00513 val = abs(val) ^ mask;
00514 if (max_peak < val)
00515 max_peak = val;
00516 valp += 3;
00517 }
00518 break;
00519 }
00520 case 32: {
00521 signed int *valp = (signed int *)data;
00522 signed int mask = snd_pcm_format_silence_32(hwparams.format);
00523 count /= 4;
00524 while (count-- > 0) {
00525 if (format_little_endian)
00526 val = __le32_to_cpu(*valp);
00527 else val = __be32_to_cpu(*valp);
00528 val = abs(val) ^ mask;
00529 if (max_peak < val)
00530 max_peak = val;
00531 valp++;
00532 }
00533 break;
00534 }
00535 default:
00536 if (run == 0) {
00537 run = 1;
00538 }
00539 return;
00540 }
00541 max = 1 << (bits_per_sample-1);
00542 if (max <= 0)
00543 max = 0x7fffffff;
00544
00545 if (bits_per_sample > 16)
00546 perc = max_peak / (max / 100);
00547 else
00548 perc = max_peak * 100 / max;
00549
00550 }
00551
00552
00553 int consume_audio(u_char *data, size_t rcount)
00554 {
00555 ssize_t r;
00556 size_t result = 0;
00557 size_t count = rcount;
00558
00559 if (sleep_min == 0 &&
00560 count != chunk_size) {
00561 count = chunk_size;
00562 }
00563
00564 while (count > 0) {
00565 r = readi_func(handle, data, count);
00566 if (r == -EAGAIN || (r >= 0 && (size_t)r < count)) {
00567 snd_pcm_wait(handle, 1000);
00568 } else if (r == -EPIPE) {
00569 xrun();
00570 } else if (r == -ESTRPIPE) {
00571 suspend();
00572 } else if (r < 0) {
00573 error("read error: %s", snd_strerror(r));
00574 exit(EXIT_FAILURE);
00575 }
00576 if (r > 0) {
00577 if (verbose > 1)
00578 compute_max_peak(data, r * hwparams.channels);
00579 result += r;
00580 count -= r;
00581 data += r * bits_per_frame / 8;
00582 }
00583 }
00584 return rcount;
00585 }
00586
00587
00588
00589 static off64_t calc_count(void)
00590 {
00591 off64_t count;
00592
00593 if (timelimit == 0) {
00594 count = pbrec_count;
00595 } else {
00596 count = snd_pcm_format_size(hwparams.format, hwparams.rate * hwparams.channels);
00597 count *= (off64_t)timelimit;
00598 }
00599 return count < pbrec_count ? count : pbrec_count;
00600 }
00601
00602