1041
|
1 #include <stdio.h>
|
|
2 #include <stdlib.h>
|
|
3
|
|
4 #include <sys/ioctl.h>
|
|
5 #include <unistd.h>
|
|
6 #include <sys/time.h>
|
|
7 #include <sys/types.h>
|
|
8 #include <sys/stat.h>
|
|
9 #include <fcntl.h>
|
|
10 #include <sys/audioio.h>
|
|
11 #ifdef __svr4__
|
|
12 #include <stropts.h>
|
|
13 #endif
|
|
14
|
|
15 #include "../config.h"
|
|
16
|
|
17 #include "audio_out.h"
|
|
18 #include "audio_out_internal.h"
|
1058
|
19 #include "afmt.h"
|
1041
|
20
|
|
21 static ao_info_t info =
|
|
22 {
|
|
23 "Sun audio output",
|
|
24 "sun",
|
|
25 "jk@tools.de",
|
|
26 ""
|
|
27 };
|
|
28
|
|
29 LIBAO_EXTERN(sun)
|
|
30
|
|
31
|
|
32 #ifndef AUDIO_PRECISION_8
|
|
33 #define AUDIO_PRECISION_8 8
|
|
34 #define AUDIO_PRECISION_16 16
|
|
35 #endif
|
|
36
|
|
37
|
|
38 // there are some globals:
|
|
39 // ao_samplerate
|
|
40 // ao_channels
|
|
41 // ao_format
|
|
42 // ao_bps
|
|
43 // ao_outburst
|
|
44 // ao_buffersize
|
|
45
|
|
46 static char *dsp="/dev/audio";
|
|
47 static int queued_bursts = 0;
|
|
48 static int audio_fd=-1;
|
|
49
|
1058
|
50 // convert an OSS audio format specification into a sun audio encoding
|
|
51 static int oss2sunfmt(int oss_format)
|
|
52 {
|
|
53 switch (oss_format){
|
|
54 case AFMT_MU_LAW:
|
|
55 return AUDIO_ENCODING_ULAW;
|
|
56 case AFMT_A_LAW:
|
|
57 return AUDIO_ENCODING_ALAW;
|
|
58 case AFMT_S16_LE:
|
|
59 return AUDIO_ENCODING_LINEAR;
|
|
60 case AFMT_U8:
|
|
61 return AUDIO_ENCODING_LINEAR8;
|
|
62 #ifdef AUDIO_ENCODING_DVI // Missing on NetBSD...
|
|
63 case AFMT_IMA_ADPCM:
|
|
64 return AUDIO_ENCODING_DVI;
|
|
65 #endif
|
|
66 default:
|
|
67 return AUDIO_ENCODING_NONE;
|
|
68 }
|
|
69 }
|
|
70
|
1041
|
71 // to set/get/query special features/parameters
|
|
72 static int control(int cmd,int arg){
|
|
73 switch(cmd){
|
|
74 case AOCONTROL_SET_DEVICE:
|
|
75 dsp=(char*)arg;
|
|
76 return CONTROL_OK;
|
|
77 case AOCONTROL_QUERY_FORMAT:
|
|
78 return CONTROL_TRUE;
|
|
79 }
|
|
80 return CONTROL_UNKNOWN;
|
|
81 }
|
|
82
|
|
83 // open & setup audio device
|
|
84 // return: 1=success 0=fail
|
|
85 static int init(int rate,int channels,int format,int flags){
|
|
86
|
|
87 audio_info_t info;
|
|
88 int byte_per_sec;
|
|
89
|
|
90 printf("ao2: %d Hz %d chans 0x%X\n",rate,channels,format);
|
|
91
|
|
92 audio_fd=open(dsp, O_WRONLY);
|
|
93 if(audio_fd<0){
|
|
94 printf("Can't open audio device %s -> nosound\n",dsp);
|
|
95 return 0;
|
|
96 }
|
|
97
|
|
98 ioctl(audio_fd, AUDIO_DRAIN, 0);
|
|
99
|
|
100 AUDIO_INITINFO(&info);
|
1058
|
101 info.play.encoding = oss2sunfmt(ao_format = format);
|
|
102 info.play.precision = (format==AFMT_S16_LE? AUDIO_PRECISION_16:AUDIO_PRECISION_8);
|
1041
|
103 info.play.channels = ao_channels = channels;
|
|
104 --ao_channels;
|
|
105 info.play.sample_rate = ao_samplerate = rate;
|
|
106 info.play.samples = 0;
|
|
107 info.play.eof = 0;
|
|
108 if(ioctl (audio_fd, AUDIO_SETINFO, &info)<0)
|
1058
|
109 printf("audio_setup: your card doesn't support %d channel, %s, %d Hz samplerate\n",channels,audio_out_format_name(format),rate);
|
|
110 byte_per_sec = (channels * info.play.precision * rate);
|
1041
|
111 ao_outburst=byte_per_sec > 100000 ? 16384 : 8192;
|
|
112 queued_bursts = 0;
|
|
113
|
|
114 if(ao_buffersize==-1){
|
|
115 // Measuring buffer size:
|
|
116 void* data;
|
|
117 ao_buffersize=0;
|
|
118 #ifdef HAVE_AUDIO_SELECT
|
|
119 data=malloc(ao_outburst); memset(data,0,ao_outburst);
|
|
120 while(ao_buffersize<0x40000){
|
|
121 fd_set rfds;
|
|
122 struct timeval tv;
|
|
123 FD_ZERO(&rfds); FD_SET(audio_fd,&rfds);
|
|
124 tv.tv_sec=0; tv.tv_usec = 0;
|
|
125 if(!select(audio_fd+1, NULL, &rfds, NULL, &tv)) break;
|
|
126 write(audio_fd,data,ao_outburst);
|
|
127 ao_buffersize+=ao_outburst;
|
|
128 }
|
|
129 free(data);
|
|
130 if(ao_buffersize==0){
|
|
131 printf("\n *** Your audio driver DOES NOT support select() ***\n");
|
|
132 printf("Recompile mplayer with #undef HAVE_AUDIO_SELECT in config.h !\n\n");
|
|
133 return 0;
|
|
134 }
|
|
135 #ifdef __svr4__
|
1058
|
136 // remove the 0 bytes from the above ao_buffersize measurement from the
|
|
137 // audio driver's STREAMS queue
|
1041
|
138 ioctl(audio_fd, I_FLUSH, FLUSHW);
|
|
139 #endif
|
|
140 ioctl(audio_fd, AUDIO_DRAIN, 0);
|
|
141 #endif
|
|
142 }
|
|
143
|
|
144 return 1;
|
|
145 }
|
|
146
|
|
147 // close audio device
|
|
148 static void uninit(){
|
|
149 close(audio_fd);
|
|
150 }
|
|
151
|
|
152 // stop playing and empty buffers (for seeking/pause)
|
|
153 static void reset(){
|
|
154 audio_info_t info;
|
|
155
|
|
156 #ifdef __svr4__
|
1058
|
157 // throw away buffered data in the audio driver's STREAMS queue
|
1041
|
158 ioctl(audio_fd, I_FLUSH, FLUSHW);
|
|
159 #endif
|
|
160 uninit();
|
|
161 audio_fd=open(dsp, O_WRONLY);
|
|
162 if(audio_fd<0){
|
|
163 printf("\nFatal error: *** CANNOT RE-OPEN / RESET AUDIO DEVICE ***\n");
|
|
164 return;
|
|
165 }
|
|
166
|
|
167 ioctl(audio_fd, AUDIO_DRAIN, 0);
|
|
168
|
|
169 AUDIO_INITINFO(&info);
|
1058
|
170 info.play.encoding = oss2sunfmt(ao_format);
|
|
171 info.play.precision = (ao_format==AFMT_S16_LE? AUDIO_PRECISION_16:AUDIO_PRECISION_8);
|
1041
|
172 info.play.channels = ao_channels+1;
|
|
173 info.play.sample_rate = ao_samplerate;
|
|
174 info.play.samples = 0;
|
|
175 info.play.eof = 0;
|
|
176 ioctl (audio_fd, AUDIO_SETINFO, &info);
|
|
177 queued_bursts = 0;
|
|
178 }
|
|
179
|
|
180 // stop playing, keep buffers (for pause)
|
|
181 static void audio_pause()
|
|
182 {
|
|
183 struct audio_info info;
|
|
184 AUDIO_INITINFO(&info);
|
|
185 info.play.pause = 1;
|
|
186 ioctl(audio_fd, AUDIO_SETINFO, &info);
|
|
187 }
|
|
188
|
|
189 // resume playing, after audio_pause()
|
|
190 static void audio_resume()
|
|
191 {
|
|
192 struct audio_info info;
|
|
193 AUDIO_INITINFO(&info);
|
|
194 info.play.pause = 0;
|
|
195 ioctl(audio_fd, AUDIO_SETINFO, &info);
|
|
196 }
|
|
197
|
|
198
|
|
199 // return: how many bytes can be played without blocking
|
|
200 static int get_space(){
|
|
201 int playsize=ao_outburst;
|
|
202
|
|
203 // check buffer
|
|
204 #ifdef HAVE_AUDIO_SELECT
|
|
205 { fd_set rfds;
|
|
206 struct timeval tv;
|
|
207 FD_ZERO(&rfds);
|
|
208 FD_SET(audio_fd, &rfds);
|
|
209 tv.tv_sec = 0;
|
|
210 tv.tv_usec = 0;
|
|
211 if(!select(audio_fd+1, NULL, &rfds, NULL, &tv)) return 0; // not block!
|
|
212 }
|
|
213 #endif
|
|
214
|
|
215 {
|
|
216 audio_info_t info;
|
|
217 ioctl(audio_fd, AUDIO_GETINFO, &info);
|
|
218 if(queued_bursts - info.play.eof > 2)
|
|
219 return 0;
|
|
220 }
|
|
221 return ao_outburst;
|
|
222 }
|
|
223
|
|
224 // plays 'len' bytes of 'data'
|
|
225 // it should round it down to outburst*n
|
|
226 // return: number of bytes played
|
|
227 static int play(void* data,int len,int flags){
|
|
228 len/=ao_outburst;
|
|
229 len=write(audio_fd,data,len*ao_outburst);
|
|
230 if(len>0) {
|
|
231 queued_bursts ++;
|
|
232 write(audio_fd,data,0);
|
|
233 }
|
|
234 return len;
|
|
235 }
|
|
236
|
|
237 static int audio_delay_method=2;
|
|
238
|
|
239 // return: how many unplayed bytes are in the buffer
|
|
240 static int get_delay(){
|
|
241 int q;
|
|
242 audio_info_t info;
|
|
243 ioctl(audio_fd, AUDIO_GETINFO, &info);
|
|
244 return (queued_bursts - info.play.eof) * ao_outburst;
|
|
245 }
|
|
246
|