1 /*
2 * madplay - MPEG audio decoder and player
3 * Copyright (C) 2000-2004 Robert Leslie
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * $Id: audio_nas.c,v 1.8 2004/01/23 09:41:31 rob Exp $
20 */
21
22 /* N.B. this audio module is buggy and unfinished */
23
24 # ifdef HAVE_CONFIG_H
25 # include "config.h"
26 # endif
27
28 # include "global.h"
29
30 # include <audio/audiolib.h>
31 # include <mad.h>
32
33 # include "gettext.h"
34
35 # include "audio.h"
36
37 static AuServer *server;
38 static AuFlowID flow;
39 static audio_pcmfunc_t *audio_pcm;
40
41 static struct {
42 unsigned char *data;
43 unsigned int len;
44 } buffer;
45
46 static
init(struct audio_init * init)47 int init(struct audio_init *init)
48 {
49 char const *servername;
50 char *message;
51
52 servername = init->path;
53 if (servername && *servername == 0)
54 servername = 0;
55
56 server = AuOpenServer(servername, 0, 0, 0, 0, &message);
57 if (server == 0) {
58 audio_error = message ? message : _("AuOpenServer() failed");
59 /* N.B. AuFree(message) never called */
60 return -1;
61 }
62
63 flow = AuCreateFlow(server, 0);
64 if (flow == 0) {
65 AuCloseServer(server);
66 audio_error = _("could not create flow");
67 return -1;
68 }
69
70 return 0;
71 }
72
73 static
getdevice(AuServer const * server,unsigned int * channels)74 AuDeviceID getdevice(AuServer const *server, unsigned int *channels)
75 {
76 AuDeviceID device = AuNone;
77 int i;
78
79 for (i = 0; i < AuServerNumDevices(server); ++i) {
80 if (AuDeviceKind(AuServerDevice(server, i)) ==
81 AuComponentKindPhysicalOutput &&
82 AuDeviceNumTracks(AuServerDevice(server, i)) == *channels) {
83 device = AuDeviceIdentifier(AuServerDevice(server, i));
84 break;
85 }
86 }
87
88 if (device == AuNone) {
89 /* try a device with a different number of channels */
90
91 for (i = 0; i < AuServerNumDevices(server); ++i) {
92 if (AuDeviceKind(AuServerDevice(server, i)) ==
93 AuComponentKindPhysicalOutput &&
94 AuDeviceNumTracks(AuServerDevice(server, i)) >= 1 &&
95 AuDeviceNumTracks(AuServerDevice(server, i)) <= 2) {
96 device = AuDeviceIdentifier(AuServerDevice(server, i));
97 *channels = AuDeviceNumTracks(AuServerDevice(server, i));
98 break;
99 }
100 }
101 }
102
103 return device;
104 }
105
106 static
send(unsigned int len)107 void send(unsigned int len)
108 {
109 if (len > buffer.len)
110 len = buffer.len;
111
112 AuWriteElement(server, flow, 0, len, buffer.data, AuFalse, 0);
113 # if defined(DEBUG)
114 fprintf(stderr, "AuWriteElement(..., %u, ...)\n", len);
115 # endif
116
117 buffer.data += len;
118 buffer.len -= len;
119 }
120
121 static
eventhandler(AuServer * server,AuEvent * event,AuEventHandlerRec * handler)122 AuBool eventhandler(AuServer *server, AuEvent *event,
123 AuEventHandlerRec *handler)
124 {
125 AuElementNotifyEvent *notifyevent;
126
127 switch (event->type) {
128 case AuEventTypeElementNotify:
129 # if defined(DEBUG)
130 fprintf(stderr, "AuEventTypeElementNotify: ");
131 # endif
132 notifyevent = (AuElementNotifyEvent *) event;
133
134 switch (notifyevent->kind) {
135 case AuElementNotifyKindLowWater:
136 # if defined(DEBUG)
137 fprintf(stderr, "AuElementNotifyKindLowWater\n");
138 # endif
139 send(notifyevent->num_bytes);
140 break;
141
142 case AuElementNotifyKindState:
143 # if defined(DEBUG)
144 fprintf(stderr, "AuElementNotifyKindState: ");
145 # endif
146 switch (notifyevent->cur_state) {
147 case AuStatePause:
148 # if defined(DEBUG)
149 fprintf(stderr, "AuStatePause\n");
150 # endif
151 if (notifyevent->reason != AuReasonUser)
152 send(notifyevent->num_bytes);
153 break;
154
155 default:
156 # if defined(DEBUG)
157 fprintf(stderr, "other\n");
158 # endif
159 }
160 break;
161
162 default:
163 # if defined(DEBUG)
164 fprintf(stderr, "other\n");
165 # endif
166 }
167 break;
168
169 default:
170 # if defined(DEBUG)
171 fprintf(stderr, "other\n");
172 # endif
173 }
174
175 return AuTrue;
176 }
177
178 static
config(struct audio_config * config)179 int config(struct audio_config *config)
180 {
181 unsigned int bitdepth;
182 int format = 0;
183 AuDeviceID device;
184 AuElement elements[2];
185
186 bitdepth = config->precision & ~7;
187 if (bitdepth == 0 || bitdepth > 16)
188 bitdepth = 16;
189
190 switch (config->precision = bitdepth) {
191 case 8:
192 format = AuFormatLinearSigned8;
193 audio_pcm = audio_pcm_s8;
194 break;
195
196 case 16:
197 # if defined(WORDS_BIGENDIAN)
198 format = AuFormatLinearSigned16MSB;
199 audio_pcm = audio_pcm_s16be;
200 # else
201 format = AuFormatLinearSigned16LSB;
202 audio_pcm = audio_pcm_s16le;
203 # endif
204 break;
205 }
206
207 device = getdevice(server, &config->channels);
208 if (device == AuNone) {
209 audio_error = _("could not find an output device");
210 return -1;
211 }
212
213 AuMakeElementImportClient(&elements[0], config->speed, format,
214 config->channels, AuTrue,
215 config->speed * 2, config->speed, 0, 0);
216 AuMakeElementExportDevice(&elements[1], 0, device, config->speed,
217 AuUnlimitedSamples, 0, 0);
218 AuSetElements(server, flow, AuTrue, 2, elements, 0);
219
220 AuRegisterEventHandler(server, AuEventHandlerIDMask, 0, flow,
221 eventhandler, 0);
222
223 AuStartFlow(server, flow, 0);
224
225 return 0;
226 }
227
228 static
play(struct audio_play * play)229 int play(struct audio_play *play)
230 {
231 unsigned char data[MAX_NSAMPLES * 4 * 2];
232 unsigned int len;
233
234 len = audio_pcm(data, play->nsamples, play->samples[0], play->samples[1],
235 play->mode, play->stats);
236
237 buffer.data = data;
238 buffer.len = len;
239
240 while (buffer.len)
241 AuHandleEvents(server);
242
243 return 0;
244 }
245
246 static
stop(struct audio_stop * stop)247 int stop(struct audio_stop *stop)
248 {
249 return 0;
250 }
251
252 static
finish(struct audio_finish * finish)253 int finish(struct audio_finish *finish)
254 {
255 AuCloseServer(server);
256
257 return 0;
258 }
259
audio_nas(union audio_control * control)260 int audio_nas(union audio_control *control)
261 {
262 audio_error = 0;
263
264 switch (control->command) {
265 case AUDIO_COMMAND_INIT:
266 return init(&control->init);
267
268 case AUDIO_COMMAND_CONFIG:
269 return config(&control->config);
270
271 case AUDIO_COMMAND_PLAY:
272 return play(&control->play);
273
274 case AUDIO_COMMAND_STOP:
275 return stop(&control->stop);
276
277 case AUDIO_COMMAND_FINISH:
278 return finish(&control->finish);
279 }
280
281 return 0;
282 }
283