zte's code,first commit
Change-Id: I9a04da59e459a9bc0d67f101f700d9d7dc8d681b
diff --git a/ap/lib/libtinyalsa/alsatest.c b/ap/lib/libtinyalsa/alsatest.c
new file mode 100644
index 0000000..e599fff
--- /dev/null
+++ b/ap/lib/libtinyalsa/alsatest.c
@@ -0,0 +1,764 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+//#include <stdlib.h>
+//#include "pthread.h"
+//#include "alsatest.h"
+//#include <stdbool.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <tinyalsa/asoundlib.h>
+#include <sound/asound.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT 0x20746d66
+#define ID_DATA 0x61746164
+
+#define FORMAT_PCM 1
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
+
+
+struct riff_wave_header {
+ uint32_t riff_id;
+ uint32_t riff_sz;
+ uint32_t wave_id;
+};
+
+struct chunk_header {
+ uint32_t id;
+ uint32_t sz;
+};
+
+struct chunk_fmt {
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate;
+ uint16_t block_align;
+ uint16_t bits_per_sample;
+};
+struct wav_header {
+ uint32_t riff_id;
+ uint32_t riff_sz;
+ uint32_t riff_fmt;
+ uint32_t fmt_id;
+ uint32_t fmt_sz;
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate;
+ uint16_t block_align;
+ uint16_t bits_per_sample;
+ uint32_t data_id;
+ uint32_t data_sz;
+};
+
+enum t_output_path{
+ T_OUTPUT_RECEIVER,
+ T_OUTPUT_SPEAKER,
+ T_OUTPUT_HEADSET,
+};
+
+enum t_input_path{
+ T_INPUT_MICLP,
+ T_INPUT_MICRP,
+};
+
+enum t_output_vol{
+ T_OUTPUT_VOL_MINUS_63_5DB = 0,
+ T_OUTPUT_VOL_MINUS_63DB = 1,
+ T_OUTPUT_VOL_MINUS_6DB = 115,
+ T_OUTPUT_VOL_MINUS_3DB = 121,
+ T_OUTPUT_VOL_MINUS_2DB = 123,
+ T_OUTPUT_VOL_MINUS_1DB = 125,
+ T_OUTPUT_VOL_0DB = 127,
+ T_OUTPUT_VOL_1DB = 129,
+ T_OUTPUT_VOL_2DB = 131,
+ T_OUTPUT_VOL_3DB = 133,
+ T_OUTPUT_VOL_6DB = 139,
+ T_OUTPUT_VOL_9DB = 145,
+ T_OUTPUT_VOL_12DB = 151,
+ T_OUTPUT_VOL_24DB = 175,
+};
+
+enum t_input_vol{
+ T_INPUT_VOL_MINUS_12DB = 0,
+ T_INPUT_VOL_MINUS_3DB = 18,
+ T_INPUT_VOL_MINUS_2DB = 20,
+ T_INPUT_VOL_MINUS_1DB = 22,
+ T_INPUT_VOL_0DB = 24,
+ T_INPUT_VOL_1DB = 26,
+ T_INPUT_VOL_2DB = 28,
+ T_INPUT_VOL_3DB = 30,
+ T_INPUT_VOL_20DB = 64,
+};
+
+struct audio_para_conf {
+ const char *control;
+ char *values[2];
+};
+
+static struct audio_para_conf common_out_para_audio[] = { //¶ÔÓ¦¹«¹²²¿·Ö
+ {"Speaker Analog Playback Volume",{"127"}},
+ {"Speaker Driver Playback Switch",{"1"}},
+ {"DAC Left Input",{"Mono"}},
+ {"DAC Right Input",{"Mono"}},
+ {"Output Right From Right DAC",{"1"}},
+ {"Output Left From Left DAC",{"1"}},
+ {"HP Analog Playback Volume",{"127","127"}},
+ {"HP Driver Playback Switch",{"1","1"}}, //7dB
+
+};
+
+static struct audio_para_conf common_in_para_audio[] = { //¶ÔÓ¦¹«¹²²¿·Ö
+ {"Mic PGA Capture Volume",{"40"}},
+ {"ADC Capture Switch",{"1"}},
+ {"ADC Fine Capture Volume",{"0"}},
+
+};
+
+static struct audio_para_conf hp_outpath_para_audio[] = { //¶ÔÓ¦ÓÚHpÊä³öͨµÀ
+ {"Speaker Switch",{"0"}},
+ {"HP Left Switch",{"1"}},
+ {"HP Right Switch",{"1"}},
+ {"HP Driver Playback Volume",{"0","0"}},
+};
+
+static struct audio_para_conf spk_outpath_para_audio[] = { //¶ÔÓ¦ÓÚSpkÊä³öͨµÀ
+ {"Speaker Switch",{"1"}},
+ {"Speaker Driver Playback Volume",{"2"}}, //18dB
+ {"HP Left Switch",{"0"}},
+ {"HP Right Switch",{"0"}},
+};
+
+static struct audio_para_conf mic1lp_mc1lm_inpath_para_audio[] = { //¶ÔÓ¦ÓÚMic1lp_Mic1lmÊäÈëͨµÀ
+ {"MIC1LM P-Terminal",{"Off"}},
+ {"MIC1RP P-Terminal",{"Off"}},
+ {"MIC1LP P-Terminal",{"FFR 10 Ohm"}},
+ {"MIC1LM M-Terminal",{"FFR 10 Ohm"}},
+
+};
+
+static struct audio_para_conf mic1rp_inpath_para_audio[] = {//¶ÔÓ¦ÓÚMic1rpÊäÈëͨµÀ
+ {"MIC1LM P-Terminal",{"Off"}},
+ {"MIC1RP P-Terminal",{"FFR 10 Ohm"}},
+ {"MIC1LP P-Terminal",{"Off"}},
+ {"MIC1LM M-Terminal",{"Off"}},
+};
+
+static struct audio_para_conf handset_inoutpath_para_voice[] = { //¶ÔÓ¦ÓÚHpÊä³öͨµÀMic1lp_Mic1lmÊäÈëͨµÀ
+ {"Speaker Switch",{"0"}},
+ {"DAC Playback Volume",{"129","129"}},
+ {"HP Left Switch",{"1"}},
+ {"HP Right Switch",{"1"}},
+ {"HP Driver Playback Volume",{"7","7"}},
+ {"MIC1LM P-Terminal",{"Off"}},
+ {"MIC1RP P-Terminal",{"Off"}},
+ {"MIC1LP P-Terminal",{"FFR 10 Ohm"}},
+ {"MIC1LM M-Terminal",{"FFR 10 Ohm"}},
+ {"ADC Capture Volume",{"24"}},
+ {"voice processing path select",{"handset"}},
+
+};
+static struct audio_para_conf headset_inoutpath_para_voice[] = { //¶ÔÓ¦ÓÚHpÊä³öͨµÀ Mic1rpÊäÈëͨµÀ
+ {"Speaker Switch",{"0"}},
+ {"DAC Playback Volume ",{"129","129"}},
+ {"HP Left Switch",{"1"}},
+ {"HP Right Switch",{"1"}},
+ {"HP Driver Playback Switch",{"7","7"}}, //7dB
+ {"MIC1LM P-Terminal",{"Off"}},
+ {"MIC1RP P-Terminal",{"FFR 10 Ohm"}},
+ {"MIC1LP P-Terminal",{"Off"}},
+ {"MIC1LM M-Terminal",{"Off"}},
+ {"ADC Capture Volume",{"24"}},
+ {"voice processing select",{"headset"}},
+};
+
+static struct audio_para_conf spk_inoutpath_para_voice[] = { //¶ÔÓ¦ÓÚSpkÊä³öͨµÀMic1lp_Mic1lmÊäÈëͨµÀ
+
+ {"DAC Playback Volume",{"124","124"}}, //-1.5dB
+ {"Speaker Switch",{"1"}},
+ {"Speaker Driver Playback Volume",{"2"}}, //18dB
+ {"HP Left Switch",{"0"}},
+ {"HP Right Switch",{"0"}},
+ {"MIC1LM P-Terminal",{"Off"}},
+ {"MIC1RP P-Terminal",{"Off"}},
+ {"MIC1LP P-Terminal",{"FFR 10 Ohm"}},
+ {"MIC1LM M-Terminal",{"FFR 10 Ohm"}},
+ {"ADC Capture Volume",{"24"}},
+ {"voice processing path select",{"speak"}},
+};
+
+static struct audio_para_conf output_dac_vol = {"DAC Playback Volume",{"24"}};
+
+static struct audio_para_conf input_adc_vol = {"ADC Capture Volume",{"129","129"}};
+
+static int sig_close = 1;
+
+static int s_outpath = T_OUTPUT_SPEAKER;
+static int s_inpath = T_INPUT_MICLP;
+static int s_invol = T_INPUT_VOL_0DB;
+static int s_outvol = T_OUTPUT_VOL_0DB;
+
+void stream_close(int sig)
+{
+ /* allow the stream to be closed gracefully */
+ signal(sig, SIG_IGN);
+ sig_close = 0;
+}
+
+static void tinymix_set_value_test(struct mixer *mixer, const char *control,
+ char **values)
+{
+ struct mixer_ctl *ctl;
+ enum mixer_ctl_type type;
+ unsigned int num_ctl_values;
+ unsigned int i;
+
+ if (isdigit(control[0]))
+ ctl = mixer_get_ctl(mixer, atoi(control));
+ else
+ ctl = mixer_get_ctl_by_name(mixer, control);
+
+ if (!ctl) {
+ fprintf(stderr, "Invalid mixer control\n");
+ return;
+ }
+
+ type = mixer_ctl_get_type(ctl);
+ num_ctl_values = mixer_ctl_get_num_values(ctl);
+
+ if (isdigit(values[0][0])) {
+
+ for (i = 0; i < num_ctl_values; i++) {
+ if (mixer_ctl_set_value(ctl, i, atoi(values[i]))) {
+ fprintf(stderr, "Error: invalid value for index %d\n", i);
+ return;
+ }
+ }
+
+ } else {
+ if (type == MIXER_CTL_TYPE_ENUM) {
+ /*if (num_values != 1) {
+ fprintf(stderr, "Enclose strings in quotes and try again\n");
+ return;
+ }*/
+ if (mixer_ctl_set_enum_by_string(ctl, values[0]))
+ fprintf(stderr, "Error: invalid enum value\n");
+ } else {
+ fprintf(stderr, "Error: only enum types can be set with strings\n");
+ }
+ }
+}
+
+int mix_set_outputpath(struct mixer *mixer, int path)
+{
+ int i;
+ for(i = 0;i<ARRAY_SIZE(common_out_para_audio);i++)
+ {
+ tinymix_set_value_test(mixer,common_out_para_audio[i].control,common_out_para_audio[i].values);
+ }
+ switch(path)
+ {
+ case T_OUTPUT_RECEIVER:
+ for(i = 0;i<ARRAY_SIZE(hp_outpath_para_audio);i++)
+ {
+ tinymix_set_value_test(mixer,hp_outpath_para_audio[i].control,hp_outpath_para_audio[i].values);
+ }
+ break;
+ case T_OUTPUT_SPEAKER:
+ for(i = 0;i<ARRAY_SIZE(spk_outpath_para_audio);i++)
+ {
+ tinymix_set_value_test(mixer,spk_outpath_para_audio[i].control,spk_outpath_para_audio[i].values);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int mix_set_inputpath(struct mixer *mixer, int path)
+{
+ int i;
+ for(i = 0;i<ARRAY_SIZE(common_in_para_audio);i++)
+ {
+ tinymix_set_value_test(mixer,common_in_para_audio[i].control,common_in_para_audio[i].values);
+ }
+ switch(path)
+ {
+ case T_INPUT_MICLP:
+ for(i = 0;i<ARRAY_SIZE(mic1lp_mc1lm_inpath_para_audio);i++)
+ {
+ tinymix_set_value_test(mixer,mic1lp_mc1lm_inpath_para_audio[i].control,mic1lp_mc1lm_inpath_para_audio[i].values);
+ }
+ break;
+ case T_INPUT_MICRP:
+ for(i = 0;i<ARRAY_SIZE(mic1rp_inpath_para_audio);i++)
+ {
+ tinymix_set_value_test(mixer,mic1rp_inpath_para_audio[i].control,mic1rp_inpath_para_audio[i].values);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int mix_set_inputvol(struct mixer *mixer, int volume)
+{
+
+ struct mixer_ctl *ctl = input_adc_vol.control;
+ enum mixer_ctl_type type;
+ unsigned int num_ctl_values;
+ unsigned int i;
+
+ ctl = mixer_get_ctl_by_name(mixer, ctl);
+ if (!ctl) {
+ fprintf(stderr, "Invalid mixer control\n");
+ return;
+ }
+
+// int value = atoi(input_adc_vol.values[0]);
+// mixer_ctl_set_value(ctl, 0, value);
+ mixer_ctl_set_value(ctl, 0, volume);
+
+ return 0;
+}
+
+int mix_set_outputvol(struct mixer *mixer, int volume)
+{
+ struct mixer_ctl *ctl = output_dac_vol.control;
+ enum mixer_ctl_type type;
+ unsigned int i;
+
+ ctl = mixer_get_ctl_by_name(mixer, ctl);
+ if (!ctl) {
+ fprintf(stderr, "Invalid mixer control\n");
+ return;
+ }
+
+ mixer_ctl_set_value(ctl, 0, volume);
+ mixer_ctl_set_value(ctl, 1, volume);
+// int value = atoi(output_dac_vol.values[0]);
+// mixer_ctl_set_value(ctl, 0, value);
+// value = atoi(output_dac_vol.values[1]);
+// mixer_ctl_set_value(ctl, 1, value);
+
+ return 0;
+}
+
+int mix_set_output_mute(struct mixer *mixer, bool enable)
+{
+ struct mixer_ctl *ctl = "DAC Mute";
+ enum mixer_ctl_type type;
+ unsigned int i;
+ printf("mix_set_output_mute %d\n",enable);
+
+ ctl = mixer_get_ctl_by_name(mixer, ctl);
+ if (!ctl) {
+ fprintf(stderr, "Invalid mixer control\n");
+ return;
+ }
+ mixer_ctl_set_value(ctl, 0, enable);
+ mixer_ctl_set_value(ctl, 1, enable);
+}
+
+int mix_set_input_mute(struct mixer *mixer, bool enable)
+{
+ struct mixer_ctl *ctl = "ADC Capture Switch";
+ enum mixer_ctl_type type;
+ unsigned int i;
+
+ ctl = mixer_get_ctl_by_name(mixer, ctl);
+ if (!ctl) {
+ fprintf(stderr, "Invalid mixer control\n");
+ return;
+ }
+
+ mixer_ctl_set_value(ctl, 0, !enable);
+}
+
+int check_param(struct pcm_params *params, unsigned int param, unsigned int value,
+ char *param_name, char *param_unit)
+{
+ unsigned int min;
+ unsigned int max;
+ int is_within_bounds = 1;
+
+ min = pcm_params_get_min(params, param);
+ if (value < min) {
+ fprintf(stderr, "%s is %u%s, device only supports >= %u%s\n", param_name, value,
+ param_unit, min, param_unit);
+ is_within_bounds = 0;
+ }
+
+ max = pcm_params_get_max(params, param);
+ if (value > max) {
+ fprintf(stderr, "%s is %u%s, device only supports <= %u%s\n", param_name, value,
+ param_unit, max, param_unit);
+ is_within_bounds = 0;
+ }
+
+ return is_within_bounds;
+}
+
+int sample_is_playable(unsigned int card, unsigned int device, unsigned int channels,
+ unsigned int rate, unsigned int bits, unsigned int period_size,
+ unsigned int period_count)
+{
+ struct pcm_params *params;
+ int can_play;
+
+ params = pcm_params_get(card, device, PCM_OUT);
+ if (params == NULL) {
+ fprintf(stderr, "Unable to open PCM device %u.\n", device);
+ return 0;
+ }
+
+ can_play = check_param(params, PCM_PARAM_RATE, rate, "Sample rate", "Hz");
+ can_play &= check_param(params, PCM_PARAM_CHANNELS, channels, "Sample", " channels");
+ can_play &= check_param(params, PCM_PARAM_SAMPLE_BITS, bits, "Bitrate", " bits");
+ can_play &= check_param(params, PCM_PARAM_PERIOD_SIZE, period_size, "Period size", "Hz");
+ can_play &= check_param(params, PCM_PARAM_PERIODS, period_count, "Period count", "Hz");
+
+ pcm_params_free(params);
+
+ return can_play;
+}
+
+void play_sample(FILE *file, unsigned int card, unsigned int device, unsigned int channels,
+ unsigned int rate, unsigned int bits, unsigned int period_size,
+ unsigned int period_count)
+{
+ struct pcm_config config;
+ struct pcm *pcm;
+ char *buffer;
+ int size;
+ int num_read;
+
+ memset(&config, 0, sizeof(config));
+ config.channels = channels;
+ config.rate = rate;
+ config.period_size = period_size;
+ config.period_count = period_count;
+ if (bits == 32)
+ config.format = PCM_FORMAT_S32_LE;
+ else if (bits == 16)
+ config.format = PCM_FORMAT_S16_LE;
+ config.start_threshold = 0;
+ config.stop_threshold = 0;
+ config.silence_threshold = 0;
+
+ if (!sample_is_playable(card, device, channels, rate, bits, period_size, period_count)) {
+ return;
+ }
+
+ pcm = pcm_open(card, device, PCM_OUT, &config);
+ if (!pcm || !pcm_is_ready(pcm)) {
+ fprintf(stderr, "Unable to open PCM device %u (%s)\n",
+ device, pcm_get_error(pcm));
+ return;
+ }
+
+ 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;
+ }
+
+ printf("Playing sample: %u ch, %u hz, %u bit\n", channels, rate, bits);
+
+ /* catch ctrl-c to shutdown cleanly */
+ signal(SIGINT, stream_close);
+
+ do {
+ num_read = fread(buffer, 1, size, file);
+ if (num_read > 0) {
+ if (pcm_write(pcm, buffer, num_read)) {
+ fprintf(stderr, "Error playing sample\n");
+ break;
+ }
+ }
+ } while (sig_close && num_read > 0);
+
+ free(buffer);
+ pcm_close(pcm);
+}
+
+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 (sig_close && !pcm_read(pcm, buffer, size)) {
+ if (fwrite(buffer, 1, size, file) != size) {
+ fprintf(stderr,"Error capturing sample\n");
+ break;
+ }
+ bytes_read += size;
+ if (bytes_read>=300000)
+ break;
+ }
+
+ free(buffer);
+ pcm_close(pcm);
+ return pcm_bytes_to_frames(pcm, bytes_read);
+}
+
+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;
+
+ struct riff_wave_header riff_wave_header;
+ struct chunk_header chunk_header;
+ struct chunk_fmt chunk_fmt;
+ char *filename;
+ int more_chunks = 1;
+ struct mixer *mixer;
+
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s cap file.wav [-D card] [-d device] [-c channels] "
+ "[-r rate] [-b bits] [-p period_size] [-n n_periods]\n", argv[0]);
+ fprintf(stderr, "Usage: %s play file.wav [-D card] [-d device] [-p period_size]"
+ " [-n n_periods] \n", argv[0]);
+ return 1;
+ }
+
+ if (strcmp(argv[1], "play") == 0) {
+ mixer = mixer_open(card);
+ if (!mixer) {
+ fprintf(stderr, "Failed to open mixer\n");
+ return -1;
+ }
+ mix_set_outputpath(mixer, T_OUTPUT_SPEAKER);
+ mix_set_outputvol(mixer, T_OUTPUT_VOL_0DB);
+ // mix_set_output_mute(mixer,false);
+ mixer_close(mixer);
+
+ filename = argv[2];
+ file = fopen(filename, "rb");
+ if (!file) {
+ fprintf(stderr, "Unable to open file '%s'\n", filename);
+ return 1;
+ }
+
+ fread(&riff_wave_header, sizeof(riff_wave_header), 1, file);
+ if ((riff_wave_header.riff_id != ID_RIFF) ||
+ (riff_wave_header.wave_id != ID_WAVE)) {
+ fprintf(stderr, "Error: '%s' is not a riff/wave file\n", filename);
+ fclose(file);
+ return 1;
+ }
+
+ do {
+ fread(&chunk_header, sizeof(chunk_header), 1, file);
+
+ switch (chunk_header.id) {
+ case ID_FMT:
+ fread(&chunk_fmt, sizeof(chunk_fmt), 1, file);
+ /* If the format header is larger, skip the rest */
+ if (chunk_header.sz > sizeof(chunk_fmt))
+ fseek(file, chunk_header.sz - sizeof(chunk_fmt), SEEK_CUR);
+ break;
+ case ID_DATA:
+ /* Stop looking for chunks */
+ more_chunks = 0;
+ break;
+ default:
+ /* Unknown chunk, skip bytes */
+ fseek(file, chunk_header.sz, SEEK_CUR);
+ }
+ } while (more_chunks);
+
+ /* parse command line arguments */
+ argv += 3;
+ while (*argv) {
+ if (strcmp(*argv, "-d") == 0) {
+ argv++;
+ if (*argv)
+ device = atoi(*argv);
+ }
+ if (strcmp(*argv, "-p") == 0) {
+ argv++;
+ if (*argv)
+ period_size = atoi(*argv);
+ }
+ if (strcmp(*argv, "-n") == 0) {
+ argv++;
+ if (*argv)
+ period_count = atoi(*argv);
+ }
+ if (strcmp(*argv, "-D") == 0) {
+ argv++;
+ if (*argv)
+ card = atoi(*argv);
+ }
+ if (*argv)
+ argv++;
+ }
+
+ play_sample(file, card, device, chunk_fmt.num_channels, chunk_fmt.sample_rate,
+ chunk_fmt.bits_per_sample, period_size, period_count);
+
+ fclose(file);
+
+ }else if(strcmp(argv[1], "cap") == 0) {
+ mixer = mixer_open(card);
+ if (!mixer) {
+ fprintf(stderr, "Failed to open mixer\n");
+ return -1;
+ }
+ mix_set_inputpath(mixer, T_INPUT_MICLP);
+ mix_set_inputvol(mixer, T_INPUT_VOL_0DB);
+ mixer_close(mixer);
+
+ file = fopen(argv[2], "wb");
+ if (!file) {
+ fprintf(stderr, "Unable to create file '%s'\n", argv[1]);
+ return 1;
+ }
+
+ /* parse command line arguments */
+ argv += 3;
+ 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, stream_close);
+ 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;
+}