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_empeg.c,v 1.16 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 <unistd.h>
29 # include <fcntl.h>
30 # include <sys/ioctl.h>
31 # include <sys/soundcard.h>
32 # include <errno.h>
33 # include <string.h>
34 # include <mad.h>
35 
36 # include "audio.h"
37 
38 # define AUDIO_DEVICE	"/dev/dsp"
39 # define AUDIO_FILLSZ	4608
40 
41 static int sfd;
42 
43 static
init(struct audio_init * init)44 int init(struct audio_init *init)
45 {
46   if (init->path == 0)
47     init->path = AUDIO_DEVICE;
48 
49   sfd = open(init->path, O_WRONLY);
50   if (sfd == -1) {
51     audio_error = ":";
52     return -1;
53   }
54 
55   return 0;
56 }
57 
58 static
config(struct audio_config * config)59 int config(struct audio_config *config)
60 {
61   /*
62    * The empeg-car's audio device is locked at 44100 Hz stereo 16-bit
63    * signed little-endian; no configuration is necessary or possible,
64    * but we may need to resample the output and/or convert to stereo.
65    */
66 
67   config->channels  = 2;
68   config->speed     = 44100;
69   config->precision = 16;
70 
71   return 0;
72 }
73 
74 static
output(unsigned char const * ptr,unsigned int len)75 int output(unsigned char const *ptr, unsigned int len)
76 {
77   while (len) {
78     int wrote;
79 
80     wrote = write(sfd, ptr, len);
81     if (wrote == -1) {
82       if (errno == EINTR)
83 	continue;
84       else {
85 	audio_error = ":write";
86 	return -1;
87       }
88     }
89 
90     ptr += wrote;
91     len -= wrote;
92   }
93 
94   return 0;
95 }
96 
97 static
buffer(unsigned char const * ptr,unsigned int len)98 int buffer(unsigned char const *ptr, unsigned int len)
99 {
100   static unsigned char hold[AUDIO_FILLSZ];
101   static unsigned int held;
102   unsigned int left, grab;
103 
104   if (len == 0) {
105     if (held) {
106       memset(&hold[held], 0, sizeof(hold) - held);
107       held = 0;
108 
109       return output(hold, sizeof(hold));
110     }
111 
112     return 0;
113   }
114 
115   if (held == 0 && len == sizeof(hold))
116     return output(ptr, len);
117 
118   left = sizeof(hold) - held;
119 
120   while (len) {
121     grab = len < left ? len : left;
122 
123     memcpy(&hold[held], ptr, grab);
124     held += grab;
125     left -= grab;
126 
127     ptr  += grab;
128     len  -= grab;
129 
130     if (left == 0) {
131       if (output(hold, sizeof(hold)) == -1)
132 	return -1;
133 
134       held = 0;
135       left = sizeof(hold);
136     }
137   }
138 
139   return 0;
140 }
141 
142 # define drain()  buffer(0, 0)
143 
144 static
play(struct audio_play * play)145 int play(struct audio_play *play)
146 {
147   unsigned char data[MAX_NSAMPLES * 2 * 2];
148   unsigned int len;
149 
150   len = audio_pcm_s16le(data, play->nsamples,
151 			play->samples[0], play->samples[1],
152 			play->mode, play->stats);
153 
154   return buffer(data, len);
155 }
156 
157 static
stop(struct audio_stop * stop)158 int stop(struct audio_stop *stop)
159 {
160   return 0;
161 }
162 
163 static
finish(struct audio_finish * finish)164 int finish(struct audio_finish *finish)
165 {
166   int result = 0;
167 
168   if (drain() == -1)
169     result = -1;
170 
171   if (close(sfd) == -1 && result == 0) {
172     audio_error = ":close";
173     result = -1;
174   }
175 
176   return result;
177 }
178 
audio_empeg(union audio_control * control)179 int audio_empeg(union audio_control *control)
180 {
181   audio_error = 0;
182 
183   switch (control->command) {
184   case AUDIO_COMMAND_INIT:
185     return init(&control->init);
186 
187   case AUDIO_COMMAND_CONFIG:
188     return config(&control->config);
189 
190   case AUDIO_COMMAND_PLAY:
191     return play(&control->play);
192 
193   case AUDIO_COMMAND_STOP:
194     return stop(&control->stop);
195 
196   case AUDIO_COMMAND_FINISH:
197     return finish(&control->finish);
198   }
199 
200   return 0;
201 }
202