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_sun.c,v 1.32 2004/01/23 09:41:31 rob Exp $
20  */
21 
22 # ifdef HAVE_CONFIG_H
23 #  include "config.h"
24 # endif
25 
26 # include "global.h"
27 
28 # include <stdlib.h>
29 # include <unistd.h>
30 # include <fcntl.h>
31 # include <sys/ioctl.h>
32 # include <sys/audioio.h>
33 # include <string.h>
34 # include <errno.h>
35 # include <sys/types.h>
36 
37 # ifdef HAVE_STROPTS_H
38 #  include <stropts.h>
39 # endif
40 
41 # include <sys/conf.h>
42 # include <mad.h>
43 
44 # include "gettext.h"
45 
46 # include "audio.h"
47 
48 # if defined(WORDS_BIGENDIAN)
49 #  define audio_pcm_s32  audio_pcm_s32be
50 #  define audio_pcm_s24  audio_pcm_s24be
51 #  define audio_pcm_s16  audio_pcm_s16be
52 # else
53 #  define audio_pcm_s32  audio_pcm_s32le
54 #  define audio_pcm_s24  audio_pcm_s24le
55 #  define audio_pcm_s16  audio_pcm_s16le
56 # endif
57 
58 # define AUDIO_DEVICE	"/dev/audio"
59 
60 static int sfd;
61 static audio_pcmfunc_t *audio_pcm;
62 
63 static
init(struct audio_init * init)64 int init(struct audio_init *init)
65 {
66   if (init->path == 0)
67     init->path = getenv("AUDIODEV");
68 
69   if (init->path == 0)
70     init->path = AUDIO_DEVICE;
71 
72   sfd = open(init->path, O_WRONLY);
73   if (sfd == -1) {
74     audio_error = ":";
75     return -1;
76   }
77 
78   return 0;
79 }
80 
81 static
set_pause(int flag)82 int set_pause(int flag)
83 {
84   static int paused;
85   audio_info_t info;
86 
87   if (flag != paused) {
88     paused = 0;
89 
90     AUDIO_INITINFO(&info);
91     info.play.pause = flag;
92 
93     if (ioctl(sfd, AUDIO_SETINFO, &info) == -1) {
94       audio_error = ":ioctl(AUDIO_SETINFO)";
95       return -1;
96     }
97 
98     paused = flag;
99   }
100 
101   return 0;
102 }
103 
104 static
config(struct audio_config * config)105 int config(struct audio_config *config)
106 {
107   unsigned int bitdepth;
108   audio_info_t info;
109 
110   bitdepth = config->precision & ~7;
111   if (bitdepth == 0)
112     bitdepth = 16;
113   else if (bitdepth > 32)
114     bitdepth = 32;
115 
116   set_pause(0);
117 
118   if (ioctl(sfd, AUDIO_DRAIN, 0) == -1) {
119     audio_error = ":ioctl(AUDIO_DRAIN)";
120     return -1;
121   }
122 
123   AUDIO_INITINFO(&info);
124 
125   info.play.sample_rate = config->speed;
126   info.play.channels    = config->channels;
127   info.play.precision   = bitdepth;
128   info.play.encoding    = AUDIO_ENCODING_LINEAR;
129 
130   if (ioctl(sfd, AUDIO_SETINFO, &info) == -1) {
131     audio_error = ":ioctl(AUDIO_SETINFO)";
132     return -1;
133   }
134 
135   /* validate settings */
136 
137   if (ioctl(sfd, AUDIO_GETINFO, &info) == -1) {
138     audio_error = ":ioctl(AUDIO_GETINFO)";
139     return -1;
140   }
141 
142   config->channels  = info.play.channels;
143   config->speed     = info.play.sample_rate;
144   bitdepth          = info.play.precision;
145 
146   switch (bitdepth) {
147   case 8:
148     audio_pcm = audio_pcm_u8;
149     break;
150 
151   case 16:
152     audio_pcm = audio_pcm_s16;
153     break;
154 
155   case 24:
156     audio_pcm = audio_pcm_s24;
157     break;
158 
159   case 32:
160     audio_pcm = audio_pcm_s32;
161     break;
162 
163   default:
164     audio_error = _("unsupported bit depth");
165     return -1;
166   }
167 
168   config->precision = bitdepth;
169 
170   return 0;
171 }
172 
173 static
output(unsigned char const * ptr,unsigned int len)174 int output(unsigned char const *ptr, unsigned int len)
175 {
176   while (len) {
177     int wrote;
178 
179     wrote = write(sfd, ptr, len);
180     if (wrote == -1) {
181       if (errno == EINTR)
182 	continue;
183       else {
184 	audio_error = ":write";
185 	return -1;
186       }
187     }
188 
189     ptr += wrote;
190     len -= wrote;
191   }
192 
193   return 0;
194 }
195 
196 static
play(struct audio_play * play)197 int play(struct audio_play *play)
198 {
199   unsigned char data[MAX_NSAMPLES * 4 * 2];
200   unsigned int len;
201 
202   set_pause(0);
203 
204   len = audio_pcm(data, play->nsamples, play->samples[0], play->samples[1],
205 		  play->mode, play->stats);
206 
207   return output(data, len);
208 }
209 
210 static
flush(void)211 int flush(void)
212 {
213 # if defined(I_FLUSH)
214   if (ioctl(sfd, I_FLUSH, FLUSHW) == -1) {
215     audio_error = ":ioctl(I_FLUSH)";
216     return -1;
217   }
218 # elif defined(AUDIO_FLUSH)
219   if (ioctl(sfd, AUDIO_FLUSH) == -1) {
220     audio_error = ":ioctl(AUDIO_FLUSH)";
221     return -1;
222   }
223 # endif
224 
225   return 0;
226 }
227 
228 static
stop(struct audio_stop * stop)229 int stop(struct audio_stop *stop)
230 {
231   int result;
232 
233   result = set_pause(1);
234 
235   if (result == 0 && stop->flush && flush() == -1)
236     result = -1;
237 
238   return result;
239 }
240 
241 static
finish(struct audio_finish * finish)242 int finish(struct audio_finish *finish)
243 {
244   int result;
245 
246   result = set_pause(0);
247 
248   if (close(sfd) == -1 && result == 0) {
249     audio_error = ":close";
250     result = -1;
251   }
252 
253   return result;
254 }
255 
audio_sun(union audio_control * control)256 int audio_sun(union audio_control *control)
257 {
258   audio_error = 0;
259 
260   switch (control->command) {
261   case AUDIO_COMMAND_INIT:
262     return init(&control->init);
263 
264   case AUDIO_COMMAND_CONFIG:
265     return config(&control->config);
266 
267   case AUDIO_COMMAND_PLAY:
268     return play(&control->play);
269 
270   case AUDIO_COMMAND_STOP:
271     return stop(&control->stop);
272 
273   case AUDIO_COMMAND_FINISH:
274     return finish(&control->finish);
275   }
276 
277   return 0;
278 }
279