/* * parse the format type I and III descriptors */ static int parse_audio_format_i(struct snd_usb_audio *chip, struct audioformat *fp, unsigned int format, struct uac_format_type_i_continuous_descriptor *fmt) { snd_pcm_format_t pcm_format; int ret; if (fmt->bFormatType == UAC_FORMAT_TYPE_III) { /* FIXME: the format type is really IECxxx * but we give normal PCM format to get the existing * apps working... */ switch (chip->usb_id) { case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ if (chip->setup == 0x00 && fp->altsetting == 6) pcm_format = SNDRV_PCM_FORMAT_S16_BE; else pcm_format = SNDRV_PCM_FORMAT_S16_LE; break; default: pcm_format = SNDRV_PCM_FORMAT_S16_LE; } fp->formats = pcm_format_to_bits(pcm_format); } else { fp->formats = parse_audio_format_i_type(chip, fp, format, fmt); if (!fp->formats) return -EINVAL; } /* gather possible sample rates */ /* audio class v1 reports possible sample rates as part of the * proprietary class specific descriptor. * audio class v2 uses class specific EP0 range requests for that. */ switch (fp->protocol) { default: case UAC_VERSION_1: fp->channels = fmt->bNrChannels; ret = parse_audio_format_rates_v1(chip, fp, (unsigned char *) fmt, 7); break; case UAC_VERSION_2: /* fp->channels is already set in this case */ ret = parse_audio_format_rates_v2(chip, fp); break; } if (fp->channels < 1) { usb_audio_err(chip, "%u:%d : invalid channels %d\n", fp->iface, fp->altsetting, fp->channels); return -EINVAL; } return ret; }
unsigned int capture_sample(FILE *file, unsigned int card, unsigned int device, unsigned int channels, unsigned int rate, enum pcm_format format, unsigned int period_size, unsigned int period_count) { struct pcm_config config; struct pcm *pcm; char *buffer; unsigned int size; unsigned int bytes_read = 0; memset(&config, 0, sizeof(config)); config.channels = channels; config.rate = rate; config.period_size = period_size; config.period_count = period_count; config.format = format; config.start_threshold = 0; config.stop_threshold = 0; config.silence_threshold = 0; pcm = pcm_open(card, device, PCM_IN, &config); if (!pcm || !pcm_is_ready(pcm)) { fprintf(stderr, "Unable to open PCM device (%s)\n", pcm_get_error(pcm)); return 0; } size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm)); buffer = malloc(size); if (!buffer) { fprintf(stderr, "Unable to allocate %d bytes\n", size); free(buffer); pcm_close(pcm); return 0; } printf("Capturing sample: %u ch, %u hz, %u bit\n", channels, rate, pcm_format_to_bits(format)); while (capturing && !pcm_read(pcm, buffer, size)) { if (fwrite(buffer, 1, size, file) != size) { fprintf(stderr,"Error capturing sample\n"); break; } bytes_read += size; } free(buffer); pcm_close(pcm); return pcm_bytes_to_frames(pcm, bytes_read); }
static void params_change(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct loopback_pcm *dpcm = runtime->private_data; struct loopback_cable *cable = dpcm->cable; cable->hw.formats = pcm_format_to_bits(runtime->format); cable->hw.rate_min = runtime->rate; cable->hw.rate_max = runtime->rate; cable->hw.channels_min = runtime->channels; cable->hw.channels_max = runtime->channels; params_change_substream(cable->streams[SNDRV_PCM_STREAM_PLAYBACK], runtime); params_change_substream(cable->streams[SNDRV_PCM_STREAM_CAPTURE], runtime); }
static int atmel_ac97c_capture_open(struct snd_pcm_substream *substream) { struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; mutex_lock(&opened_mutex); chip->opened++; runtime->hw = atmel_ac97c_hw; if (chip->cur_rate) { runtime->hw.rate_min = chip->cur_rate; runtime->hw.rate_max = chip->cur_rate; } if (chip->cur_format) runtime->hw.formats = pcm_format_to_bits(chip->cur_format); mutex_unlock(&opened_mutex); chip->capture_substream = substream; return 0; }
int main(int argc, char **argv) { FILE *file; struct wav_header header; unsigned int card = 0; unsigned int device = 0; unsigned int channels = 2; unsigned int rate = 44100; unsigned int bits = 16; unsigned int frames; unsigned int period_size = 1024; unsigned int period_count = 4; enum pcm_format format; if (argc < 2) { fprintf(stderr, "Usage: %s file.wav [-D card] [-d device] [-c channels] " "[-r rate] [-b bits] [-p period_size] [-n n_periods]\n", argv[0]); return 1; } file = fopen(argv[1], "wb"); if (!file) { fprintf(stderr, "Unable to create file '%s'\n", argv[1]); return 1; } /* parse command line arguments */ argv += 2; while (*argv) { if (strcmp(*argv, "-d") == 0) { argv++; if (*argv) device = atoi(*argv); } else if (strcmp(*argv, "-c") == 0) { argv++; if (*argv) channels = atoi(*argv); } else if (strcmp(*argv, "-r") == 0) { argv++; if (*argv) rate = atoi(*argv); } else if (strcmp(*argv, "-b") == 0) { argv++; if (*argv) bits = atoi(*argv); } else if (strcmp(*argv, "-D") == 0) { argv++; if (*argv) card = atoi(*argv); } else if (strcmp(*argv, "-p") == 0) { argv++; if (*argv) period_size = atoi(*argv); } else if (strcmp(*argv, "-n") == 0) { argv++; if (*argv) period_count = atoi(*argv); } if (*argv) argv++; } header.riff_id = ID_RIFF; header.riff_sz = 0; header.riff_fmt = ID_WAVE; header.fmt_id = ID_FMT; header.fmt_sz = 16; header.audio_format = FORMAT_PCM; header.num_channels = channels; header.sample_rate = rate; switch (bits) { case 32: format = PCM_FORMAT_S32_LE; break; case 24: format = PCM_FORMAT_S24_LE; break; case 16: format = PCM_FORMAT_S16_LE; break; default: fprintf(stderr, "%d bits is not supported.\n", bits); return 1; } header.bits_per_sample = pcm_format_to_bits(format); header.byte_rate = (header.bits_per_sample / 8) * channels * rate; header.block_align = channels * (header.bits_per_sample / 8); header.data_id = ID_DATA; /* leave enough room for header */ fseek(file, sizeof(struct wav_header), SEEK_SET); /* install signal handler and begin capturing */ signal(SIGINT, sigint_handler); frames = capture_sample(file, card, device, header.num_channels, header.sample_rate, format, period_size, period_count); printf("Captured %d frames\n", frames); /* write header now all information is known */ header.data_sz = frames * header.block_align; header.riff_sz = header.data_sz + sizeof(header) - 8; fseek(file, 0, SEEK_SET); fwrite(&header, sizeof(struct wav_header), 1, file); fclose(file); return 0; }