summaryrefslogtreecommitdiffstats
path: root/libaudio/aplay.c
diff options
context:
space:
mode:
Diffstat (limited to 'libaudio/aplay.c')
-rw-r--r--libaudio/aplay.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/libaudio/aplay.c b/libaudio/aplay.c
new file mode 100644
index 0000000..0ac0ac0
--- /dev/null
+++ b/libaudio/aplay.c
@@ -0,0 +1,140 @@
+/*
+** Copyright 2010, The Android Open-Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "alsa_audio.h"
+
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT 0x20746d66
+#define ID_DATA 0x61746164
+
+#define FORMAT_PCM 1
+
+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; /* sample_rate * num_channels * bps / 8 */
+ uint16_t block_align; /* num_channels * bps / 8 */
+ uint16_t bits_per_sample;
+ uint32_t data_id;
+ uint32_t data_sz;
+};
+
+int play_file(unsigned rate, unsigned channels, int fd, unsigned count)
+{
+ struct pcm *pcm;
+ struct mixer *mixer;
+ struct pcm_ctl *ctl = NULL;
+ unsigned bufsize;
+ char *data;
+ unsigned flags = PCM_OUT;
+
+ if (channels == 1)
+ flags |= PCM_MONO;
+ else
+ flags |= PCM_STEREO;
+
+ pcm = pcm_open(flags);
+ if (!pcm_ready(pcm)) {
+ pcm_close(pcm);
+ return -1;
+ }
+
+ mixer = mixer_open();
+ if (mixer)
+ ctl = mixer_get_control(mixer,"Playback Path", 0);
+
+ bufsize = pcm_buffer_size(pcm);
+ data = malloc(bufsize);
+ if (!data) {
+ fprintf(stderr,"could not allocate %d bytes\n", count);
+ return -1;
+ }
+
+ while (read(fd, data, bufsize) == bufsize) {
+ if (pcm_write(pcm, data, bufsize))
+ break;
+
+ /* HACK: remove */
+ if (ctl) {
+ //mixer_ctl_select(ctl, "SPK");
+ ctl = 0;
+ }
+ }
+ pcm_close(pcm);
+ return 0;
+}
+
+int play_wav(const char *fn)
+{
+ struct wav_header hdr;
+ unsigned rate, channels;
+ int fd;
+ fd = open(fn, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "aplay: cannot open '%s'\n", fn);
+ return -1;
+ }
+ if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+ fprintf(stderr, "aplay: cannot read header\n");
+ return -1;
+ }
+ fprintf(stderr,"aplay: %d ch, %d hz, %d bit, %s\n",
+ hdr.num_channels, hdr.sample_rate, hdr.bits_per_sample,
+ hdr.audio_format == FORMAT_PCM ? "PCM" : "unknown");
+
+ if ((hdr.riff_id != ID_RIFF) ||
+ (hdr.riff_fmt != ID_WAVE) ||
+ (hdr.fmt_id != ID_FMT)) {
+ fprintf(stderr, "aplay: '%s' is not a riff/wave file\n", fn);
+ return -1;
+ }
+ if ((hdr.audio_format != FORMAT_PCM) ||
+ (hdr.fmt_sz != 16)) {
+ fprintf(stderr, "aplay: '%s' is not pcm format\n", fn);
+ return -1;
+ }
+ if (hdr.bits_per_sample != 16) {
+ fprintf(stderr, "aplay: '%s' is not 16bit per sample\n", fn);
+ return -1;
+ }
+
+ return play_file(hdr.sample_rate, hdr.num_channels, fd, hdr.data_sz);
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 2) {
+ fprintf(stderr,"usage: aplay <file>\n");
+ return -1;
+ }
+
+ return play_wav(argv[1]);
+}
+