correct pcm audio format handling
[libav.git] / libav / audio.c
CommitLineData
de6d9b64
FB
1/*
2 * Linux audio play and grab interface
3 * Copyright (c) 2000, 2001 Gerard Lantau.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
8be1c656
FB
19#include "avformat.h"
20
de6d9b64
FB
21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24#include <linux/soundcard.h>
25#include <unistd.h>
26#include <fcntl.h>
27#include <sys/ioctl.h>
28#include <sys/mman.h>
de6d9b64
FB
29#include <sys/time.h>
30
de6d9b64
FB
31const char *audio_device = "/dev/dsp";
32
33typedef struct {
34 int fd;
35 int rate;
36 int channels;
37} AudioData;
38
39#define AUDIO_BLOCK_SIZE 4096
40
41/* audio read support */
42
43static int audio_read(URLContext *h, UINT8 *buf, int size)
44{
45 AudioData *s = h->priv_data;
46 int ret;
47
48 ret = read(s->fd, buf, size);
49 if (ret < 0)
50 return -errno;
51 else
52 return ret;
53}
54
55static int audio_write(URLContext *h, UINT8 *buf, int size)
56{
57 AudioData *s = h->priv_data;
58 int ret;
59
60 ret = write(s->fd, buf, size);
61 if (ret < 0)
62 return -errno;
63 else
64 return ret;
65}
66
67static int audio_get_format(URLContext *h, URLFormat *f)
68{
69 AudioData *s = h->priv_data;
70
71 strcpy(f->format_name, "pcm");
72 f->sample_rate = s->rate;
73 f->channels = s->channels;
74 return 0;
75}
76
77/* URI syntax: 'audio:[rate[,channels]]'
78 default: rate=44100, channels=2
79 */
80static int audio_open(URLContext *h, const char *uri, int flags)
81{
82 AudioData *s;
83 const char *p;
84 int freq, channels, audio_fd;
85 int tmp, err;
86
87 h->is_streamed = 1;
88 h->packet_size = AUDIO_BLOCK_SIZE;
89
90 s = malloc(sizeof(AudioData));
91 if (!s)
92 return -ENOMEM;
93 h->priv_data = s;
94
95 /* extract parameters */
96 p = uri;
97 strstart(p, "audio:", &p);
98 freq = strtol(p, (char **)&p, 0);
99 if (freq <= 0)
100 freq = 44100;
101 if (*p == ',')
102 p++;
103 channels = strtol(p, (char **)&p, 0);
104 if (channels <= 0)
105 channels = 2;
106 s->rate = freq;
107 s->channels = channels;
108
109 /* open linux audio device */
110 if (flags & URL_WRONLY)
111 audio_fd = open(audio_device,O_WRONLY);
112 else
113 audio_fd = open(audio_device,O_RDONLY);
114 if (audio_fd < 0) {
115 perror(audio_device);
116 return -EIO;
117 }
118
119 /* non blocking mode */
120 fcntl(audio_fd, F_SETFL, O_NONBLOCK);
121
122#if 0
123 tmp=(NB_FRAGMENTS << 16) | FRAGMENT_BITS;
124 err=ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &tmp);
125 if (err < 0) {
126 perror("SNDCTL_DSP_SETFRAGMENT");
127 }
128#endif
129
130 tmp=AFMT_S16_LE;
131 err=ioctl(audio_fd,SNDCTL_DSP_SETFMT,&tmp);
132 if (err < 0) {
133 perror("SNDCTL_DSP_SETFMT");
134 goto fail;
135 }
136
137 tmp= (channels == 2);
138 err=ioctl(audio_fd,SNDCTL_DSP_STEREO,&tmp);
139 if (err < 0) {
140 perror("SNDCTL_DSP_STEREO");
141 goto fail;
142 }
143
144 tmp = freq;
145 err=ioctl(audio_fd, SNDCTL_DSP_SPEED, &tmp);
146 if (err < 0) {
147 perror("SNDCTL_DSP_SPEED");
148 goto fail;
149 }
150
151 s->rate = tmp;
152 s->fd = audio_fd;
153
154 return 0;
155 fail:
156 close(audio_fd);
157 free(s);
158 return -EIO;
159}
160
161static int audio_close(URLContext *h)
162{
163 AudioData *s = h->priv_data;
164
165 close(s->fd);
166 free(s);
167 return 0;
168}
169
170URLProtocol audio_protocol = {
171 "audio",
172 audio_open,
173 audio_read,
174 audio_write,
175 NULL, /* seek */
176 audio_close,
177 audio_get_format,
178};