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