📄 aplay.c
字号:
return 1; } break; case 'd': timelimit = strtol(optarg, NULL, 0); break; case 'N': nonblock = 1; open_mode |= SND_PCM_NONBLOCK; break; case 'F': period_time = strtol(optarg, NULL, 0); break; case 'B': buffer_time = strtol(optarg, NULL, 0); break; case OPT_PERIOD_SIZE: period_frames = strtol(optarg, NULL, 0); break; case OPT_BUFFER_SIZE: buffer_frames = strtol(optarg, NULL, 0); break; case 'A': avail_min = strtol(optarg, NULL, 0); break; case 'R': start_delay = strtol(optarg, NULL, 0); break; case 'T': stop_delay = strtol(optarg, NULL, 0); break; case 'v': verbose++; if (verbose > 1 && !vumeter) vumeter = VUMETER_MONO; break; case 'V': if (*optarg == 's') vumeter = VUMETER_STEREO; else if (*optarg == 'm') vumeter = VUMETER_MONO; else vumeter = VUMETER_NONE; break; case 'M': mmap_flag = 1; break; case 'I': interleaved = 0; break; case 'P': stream = SND_PCM_STREAM_PLAYBACK; command = "aplay"; break; case 'C': stream = SND_PCM_STREAM_CAPTURE; command = "arecord"; start_delay = 1; if (file_type == FORMAT_DEFAULT) file_type = FORMAT_WAVE; break; case OPT_DISABLE_RESAMPLE: open_mode |= SND_PCM_NO_AUTO_RESAMPLE; break; case OPT_DISABLE_CHANNELS: open_mode |= SND_PCM_NO_AUTO_CHANNELS; break; case OPT_DISABLE_FORMAT: open_mode |= SND_PCM_NO_AUTO_FORMAT; break; case OPT_DISABLE_SOFTVOL: open_mode |= SND_PCM_NO_SOFTVOL; break; case OPT_TEST_POSITION: test_position = 1; break; default: fprintf(stderr, _("Try `%s --help' for more information.\n"), command); return 1; } } if (do_device_list) { if (do_pcm_list) pcm_list(); device_list(); goto __end; } else if (do_pcm_list) { pcm_list(); goto __end; } err = snd_pcm_open(&handle, pcm_name, stream, open_mode); if (err < 0) { error(_("audio open error: %s"), snd_strerror(err)); return 1; } if ((err = snd_pcm_info(handle, info)) < 0) { error(_("info error: %s"), snd_strerror(err)); return 1; } if (nonblock) { err = snd_pcm_nonblock(handle, 1); if (err < 0) { error(_("nonblock setting error: %s"), snd_strerror(err)); return 1; } } chunk_size = 1024; hwparams = rhwparams; audiobuf = (u_char *)malloc(1024); if (audiobuf == NULL) { error(_("not enough memory")); return 1; } if (mmap_flag) { writei_func = snd_pcm_mmap_writei; readi_func = snd_pcm_mmap_readi; writen_func = snd_pcm_mmap_writen; readn_func = snd_pcm_mmap_readn; } else { writei_func = snd_pcm_writei; readi_func = snd_pcm_readi; writen_func = snd_pcm_writen; readn_func = snd_pcm_readn; } signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGABRT, signal_handler); if (interleaved) { if (optind > argc - 1) { if (stream == SND_PCM_STREAM_PLAYBACK) playback(NULL); else capture(NULL); } else { while (optind <= argc - 1) { if (stream == SND_PCM_STREAM_PLAYBACK) playback(argv[optind++]); else capture(argv[optind++]); } } } else { if (stream == SND_PCM_STREAM_PLAYBACK) playbackv(&argv[optind], argc - optind); else capturev(&argv[optind], argc - optind); } if (verbose==2) putchar('\n'); snd_pcm_close(handle); free(audiobuf); __end: snd_output_close(log); snd_config_update_free_global(); return EXIT_SUCCESS;}/* * Safe read (for pipes) */ static ssize_t safe_read(int fd, void *buf, size_t count){ ssize_t result = 0, res; while (count > 0) { if ((res = read(fd, buf, count)) == 0) break; if (res < 0) return result > 0 ? result : res; count -= res; result += res; buf = (char *)buf + res; } return result;}/* * Test, if it is a .VOC file and return >=0 if ok (this is the length of rest) * < 0 if not */static int test_vocfile(void *buffer){ VocHeader *vp = buffer; if (!memcmp(vp->magic, VOC_MAGIC_STRING, 20)) { vocminor = LE_SHORT(vp->version) & 0xFF; vocmajor = LE_SHORT(vp->version) / 256; if (LE_SHORT(vp->version) != (0x1233 - LE_SHORT(vp->coded_ver))) return -2; /* coded version mismatch */ return LE_SHORT(vp->headerlen) - sizeof(VocHeader); /* 0 mostly */ } return -1; /* magic string fail */}/* * helper for test_wavefile */static size_t test_wavefile_read(int fd, u_char *buffer, size_t *size, size_t reqsize, int line){ if (*size >= reqsize) return *size; if ((size_t)safe_read(fd, buffer + *size, reqsize - *size) != reqsize - *size) { error(_("read error (called from line %i)"), line); exit(EXIT_FAILURE); } return *size = reqsize;}#define check_wavefile_space(buffer, len, blimit) \ if (len > blimit) { \ blimit = len; \ if ((buffer = realloc(buffer, blimit)) == NULL) { \ error(_("not enough memory")); \ exit(EXIT_FAILURE); \ } \ }/* * test, if it's a .WAV file, > 0 if ok (and set the speed, stereo etc.) * == 0 if not * Value returned is bytes to be discarded. */static ssize_t test_wavefile(int fd, u_char *_buffer, size_t size){ WaveHeader *h = (WaveHeader *)_buffer; u_char *buffer = NULL; size_t blimit = 0; WaveFmtBody *f; WaveChunkHeader *c; u_int type, len; if (size < sizeof(WaveHeader)) return -1; if (h->magic != WAV_RIFF || h->type != WAV_WAVE) return -1; if (size > sizeof(WaveHeader)) { check_wavefile_space(buffer, size - sizeof(WaveHeader), blimit); memcpy(buffer, _buffer + sizeof(WaveHeader), size - sizeof(WaveHeader)); } size -= sizeof(WaveHeader); while (1) { check_wavefile_space(buffer, sizeof(WaveChunkHeader), blimit); test_wavefile_read(fd, buffer, &size, sizeof(WaveChunkHeader), __LINE__); c = (WaveChunkHeader*)buffer; type = c->type; len = LE_INT(c->length); len += len % 2; if (size > sizeof(WaveChunkHeader)) memmove(buffer, buffer + sizeof(WaveChunkHeader), size - sizeof(WaveChunkHeader)); size -= sizeof(WaveChunkHeader); if (type == WAV_FMT) break; check_wavefile_space(buffer, len, blimit); test_wavefile_read(fd, buffer, &size, len, __LINE__); if (size > len) memmove(buffer, buffer + len, size - len); size -= len; } if (len < sizeof(WaveFmtBody)) { error(_("unknown length of 'fmt ' chunk (read %u, should be %u at least)"), len, (u_int)sizeof(WaveFmtBody)); exit(EXIT_FAILURE); } check_wavefile_space(buffer, len, blimit); test_wavefile_read(fd, buffer, &size, len, __LINE__); f = (WaveFmtBody*) buffer; if (LE_SHORT(f->format) == WAV_FMT_EXTENSIBLE) { WaveFmtExtensibleBody *fe = (WaveFmtExtensibleBody*)buffer; if (len < sizeof(WaveFmtExtensibleBody)) { error(_("unknown length of extensible 'fmt ' chunk (read %u, should be %u at least)"), len, (u_int)sizeof(WaveFmtExtensibleBody)); exit(EXIT_FAILURE); } if (memcmp(fe->guid_tag, WAV_GUID_TAG, 14) != 0) { error(_("wrong format tag in extensible 'fmt ' chunk")); exit(EXIT_FAILURE); } f->format = fe->guid_format; } if (LE_SHORT(f->format) != WAV_FMT_PCM && LE_SHORT(f->format) != WAV_FMT_IEEE_FLOAT) { error(_("can't play WAVE-file format 0x%04x which is not PCM or FLOAT encoded"), LE_SHORT(f->format)); exit(EXIT_FAILURE); } if (LE_SHORT(f->channels) < 1) { error(_("can't play WAVE-files with %d tracks"), LE_SHORT(f->channels)); exit(EXIT_FAILURE); } hwparams.channels = LE_SHORT(f->channels); switch (LE_SHORT(f->bit_p_spl)) { case 8: if (hwparams.format != DEFAULT_FORMAT && hwparams.format != SND_PCM_FORMAT_U8) fprintf(stderr, _("Warning: format is changed to U8\n")); hwparams.format = SND_PCM_FORMAT_U8; break; case 16: if (hwparams.format != DEFAULT_FORMAT && hwparams.format != SND_PCM_FORMAT_S16_LE) fprintf(stderr, _("Warning: format is changed to S16_LE\n")); hwparams.format = SND_PCM_FORMAT_S16_LE; break; case 24: switch (LE_SHORT(f->byte_p_spl) / hwparams.channels) { case 3: if (hwparams.format != DEFAULT_FORMAT && hwparams.format != SND_PCM_FORMAT_S24_3LE) fprintf(stderr, _("Warning: format is changed to S24_3LE\n")); hwparams.format = SND_PCM_FORMAT_S24_3LE; break; case 4: if (hwparams.format != DEFAULT_FORMAT && hwparams.format != SND_PCM_FORMAT_S24_LE) fprintf(stderr, _("Warning: format is changed to S24_LE\n")); hwparams.format = SND_PCM_FORMAT_S24_LE; break; default: error(_(" can't play WAVE-files with sample %d bits in %d bytes wide (%d channels)"), LE_SHORT(f->bit_p_spl), LE_SHORT(f->byte_p_spl), hwparams.channels); exit(EXIT_FAILURE); } break; case 32: if (LE_SHORT(f->format) == WAV_FMT_PCM) hwparams.format = SND_PCM_FORMAT_S32_LE; else if (LE_SHORT(f->format) == WAV_FMT_IEEE_FLOAT) hwparams.format = SND_PCM_FORMAT_FLOAT_LE; break; default: error(_(" can't play WAVE-files with sample %d bits wide"), LE_SHORT(f->bit_p_spl)); exit(EXIT_FAILURE); } hwparams.rate = LE_INT(f->sample_fq); if (size > len) memmove(buffer, buffer + len, size - len); size -= len; while (1) { u_int type, len; check_wavefile_space(buffer, sizeof(WaveChunkHeader), blimit); test_wavefile_read(fd, buffer, &size, sizeof(WaveChunkHeader), __LINE__); c = (WaveChunkHeader*)buffer; type = c->type; len = LE_INT(c->length); if (size > sizeof(WaveChunkHeader)) memmove(buffer, buffer + sizeof(WaveChunkHeader), size - sizeof(WaveChunkHeader)); size -= sizeof(WaveChunkHeader); if (type == WAV_DATA) { if (len < pbrec_count && len < 0x7ffffffe) pbrec_count = len; if (size > 0) memcpy(_buffer, buffer, size); free(buffer); return size; } len += len % 2; check_wavefile_space(buffer, len, blimit); test_wavefile_read(fd, buffer, &size, len, __LINE__); if (size > len) memmove(buffer, buffer + len, size - len); size -= len; } /* shouldn't be reached */ return -1;}/* */static int test_au(int fd, void *buffer){ AuHeader *ap = buffer; if (ap->magic != AU_MAGIC) return -1; if (BE_INT(ap->hdr_size) > 128 || BE_INT(ap->hdr_size) < 24) return -1; pbrec_count = BE_INT(ap->data_size); switch (BE_INT(ap->encoding)) { case AU_FMT_ULAW: if (hwparams.format != DEFAULT_FORMAT && hwparams.format != SND_PCM_FORMAT_MU_LAW) fprintf(stderr, _("Warning: format is changed to MU_LAW\n")); hwparams.format = SND_PCM_FORMAT_MU_LAW; break; case AU_FMT_LIN8: if (hwparams.format != DEFAULT_FORMAT && hwparams.format != SND_PCM_FORMAT_U8) fprintf(stderr, _("Warning: format is changed to U8\n")); hwparams.format = SND_PCM_FORMAT_U8; break; case AU_FMT_LIN16: if (hwparams.format != DEFAULT_FORMAT && hwparams.format != SND_PCM_FORMAT_S16_BE) fprintf(stderr, _("Warning: format is changed to S16_BE\n")); hwparams.format = SND_PCM_FORMAT_S16_BE; break; default: return -1; } hwparams.rate = BE_INT(ap->sample_rate); if (hwparams.rate < 2000 || hwparams.rate > 256000) return -1; hwparams.channels = BE_INT(ap->channels); if (hwparams.channels < 1 || hwparams.channels > 128) return -1; if ((size_t)safe_read(fd, buffer + sizeof(AuHeader), BE_INT(ap->hdr_size) - sizeof(AuHeader)) != BE_INT(ap->hdr_size) - sizeof(AuHeader)) { error(_("read error")); exit(EXIT_FAILURE); } return 0;}static void set_params(void){ snd_pcm_hw_params_t *params; snd_pcm_sw_params_t *swparams; snd_pcm_uframes_t buffer_size; int err; size_t n; unsigned int rate; snd_pcm_uframes_t start_threshold, stop_threshold; snd_pcm_hw_params_alloca(¶ms); snd_pcm_sw_params_alloca(&swparams); err = snd_pcm_hw_params_any(handle, params); if (err < 0) { error(_("Broken configuration for this PCM: no configurations available")); exit(EXIT_FAILURE); } if (mmap_flag) { snd_pcm_access_mask_t *mask = alloca(snd_pcm_access_mask_sizeof()); snd_pcm_access_mask_none(mask); snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED); snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_COMPLEX); err = snd_pcm_hw_params_set_access_mask(handle, params, mask); } else if (interleaved) err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); else err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_NONINTERLEAVED); if (err < 0) { error(_("Access type not available")); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_format(handle, params, hwparams.format); if (err < 0) { error(_("Sample format non available")); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_channels(handle, params, hwparams.channels); if (err < 0) { error(_("Channels count non available")); exit(EXIT_FAILURE); }#if 0 err = snd_pcm_hw_params_set_periods_min(handle, params, 2); assert(err >= 0);#endif rate = hwparams.rate; err = snd_pcm_hw_params_set_rate_near(handle, params, &hwparams.rate, 0); assert(err >= 0); if ((float)rate * 1.05 < hwparams.rate || (float)rate * 0.95 > hwparams.rate) { if (!quiet_mode) { char plugex[64]; const char *pcmname = snd_pcm_name(handle); fprintf(stderr, _("Warning: rate is not accurate (requested = %iHz, got = %iHz)\n"), rate, hwparams.rate); if (! pcmname || strchr(snd_pcm_name(handle), ':')) *plugex = 0; else snprintf(plugex, sizeof(plugex), "(-Dplug:%s)", snd_pcm_name(handle)); fprintf(stderr, _(" please, try the plug plugin %s\n"), plugex); } } rate = hwparams.rate; if (buffer_time == 0 && buffer_frames == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -