Mercurial > mplayer.hg
annotate libao2/ao_sndio.c @ 37136:36638a3ccfe2
configure: add fma4 support to avoid breaking build
author | michael |
---|---|
date | Tue, 01 Jul 2014 23:53:51 +0000 |
parents | 38234a308fd3 |
children |
rev | line source |
---|---|
36463 | 1 /* |
2 * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> | |
3 * | |
4 * This file is part of MPlayer. | |
5 * | |
6 * MPlayer is free software; you can redistribute it and/or modify | |
7 * it under the terms of the GNU General Public License as published by | |
8 * the Free Software Foundation; either version 2 of the License, or | |
9 * (at your option) any later version. | |
10 * | |
11 * MPlayer is distributed in the hope that it will be useful, | |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 * GNU General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU General Public License along | |
17 * with MPlayer; if not, write to the Free Software Foundation, Inc., | |
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
19 */ | |
20 #include <sys/types.h> | |
21 #include <poll.h> | |
22 #include <errno.h> | |
23 #include <sndio.h> | |
24 #include <stdlib.h> | |
25 | |
26 #include "config.h" | |
27 #include "mp_msg.h" | |
28 #include "mixer.h" | |
29 #include "help_mp.h" | |
30 | |
31 #include "libaf/af_format.h" | |
32 | |
33 #include "audio_out.h" | |
34 #include "audio_out_internal.h" | |
35 | |
36 static ao_info_t info = { | |
37 "sndio audio output", | |
38 "sndio", | |
39 "Alexandre Ratchov <alex@caoua.org>", | |
40 "" | |
41 }; | |
42 | |
43 LIBAO_EXTERN(sndio) | |
44 | |
36465 | 45 static struct sio_hdl *hdl; |
46 static struct pollfd *pfds; | |
36463 | 47 static struct sio_par par; |
48 static int delay, vol, havevol; | |
49 static int prepause_delay; | |
50 | |
51 /* | |
52 * control misc parameters (only the volume for now) | |
53 */ | |
54 static int control(int cmd, void *arg) | |
55 { | |
56 ao_control_vol_t *ctl = arg; | |
57 | |
58 switch (cmd) { | |
59 case AOCONTROL_GET_VOLUME: | |
60 if (!havevol) | |
61 return CONTROL_FALSE; | |
62 ctl->left = ctl->right = vol * 100 / SIO_MAXVOL; | |
63 break; | |
64 case AOCONTROL_SET_VOLUME: | |
65 if (!havevol) | |
66 return CONTROL_FALSE; | |
67 sio_setvol(hdl, ctl->left * SIO_MAXVOL / 100); | |
68 break; | |
69 default: | |
70 return CONTROL_UNKNOWN; | |
71 } | |
72 return CONTROL_OK; | |
73 } | |
74 | |
75 /* | |
76 * call-back invoked whenever the the hardware position changes | |
77 */ | |
78 static void movecb(void *addr, int delta) | |
79 { | |
80 delay -= delta * (int)(par.bps * par.pchan); | |
81 } | |
82 | |
83 /* | |
84 * call-back invoked whenever the volume changes | |
85 */ | |
86 static void volcb(void *addr, unsigned newvol) | |
87 { | |
88 vol = newvol; | |
89 } | |
90 | |
91 /* | |
92 * open device and setup parameters | |
93 * return: 1 = success, 0 = failure | |
94 */ | |
95 static int init(int rate, int channels, int format, int flags) | |
96 { | |
97 int bpf; | |
98 | |
99 hdl = sio_open(SIO_DEVANY, SIO_PLAY, 0); | |
100 if (hdl == NULL) { | |
101 mp_msg(MSGT_AO, MSGL_ERR, "ao2: can't open sndio\n"); | |
102 return 0; | |
103 } | |
104 sio_initpar(&par); | |
105 par.bits = af_fmt2bits(format); | |
36897 | 106 par.bps = (par.bits + 7) >> 3; |
107 // normally bits == 8*bps so this makes no difference | |
108 // but we can support more formats for msb == 1, see "if" below | |
109 par.msb = 1; | |
36463 | 110 par.sig = (format & AF_FORMAT_SIGN_MASK) == AF_FORMAT_SI; |
111 if (par.bits > 8) | |
112 par.le = (format & AF_FORMAT_END_MASK) == AF_FORMAT_LE; | |
113 par.rate = rate; | |
114 par.pchan = channels; | |
115 par.appbufsz = par.rate * 250 / 1000; /* 250ms buffer */ | |
116 par.round = par.rate * 10 / 1000; /* 10ms block size */ | |
117 if (!sio_setpar(hdl, &par)) { | |
118 mp_msg(MSGT_AO, MSGL_ERR, "ao2: couldn't set params\n"); | |
36466 | 119 goto err_out; |
36463 | 120 } |
121 if (!sio_getpar(hdl, &par)) { | |
122 mp_msg(MSGT_AO, MSGL_ERR, "ao2: couldn't get params\n"); | |
36466 | 123 goto err_out; |
36463 | 124 } |
36897 | 125 // we do not care if LSBs are discarded |
126 if (par.bits < 8 * par.bps && !par.msb) { | |
36463 | 127 mp_msg(MSGT_AO, MSGL_ERR, "ao2: unsupported format\n"); |
36466 | 128 goto err_out; |
36463 | 129 } |
130 pfds = calloc(sio_nfds(hdl), sizeof(*pfds)); | |
131 if (pfds == NULL) { | |
132 mp_msg(MSGT_AO, MSGL_ERR, "ao2: couldn't allocate poll fds\n"); | |
36466 | 133 goto err_out; |
36463 | 134 } |
135 bpf = par.bps * par.pchan; | |
136 ao_data.format = af_bits2fmt(8 * par.bps); | |
137 ao_data.format |= par.sig ? AF_FORMAT_SI : AF_FORMAT_US; | |
36852
145057e3f0ed
ao_sndio: simplify, don't care about 8-bit endianness.
reimar
parents:
36467
diff
changeset
|
138 ao_data.format |= par.le ? AF_FORMAT_LE : AF_FORMAT_BE; |
36463 | 139 ao_data.channels = par.pchan; |
140 ao_data.bps = bpf * par.rate; | |
141 ao_data.buffersize = par.bufsz * bpf; | |
142 ao_data.outburst = par.round * bpf; | |
143 ao_data.samplerate = rate; | |
144 havevol = sio_onvol(hdl, volcb, NULL); | |
145 sio_onmove(hdl, movecb, NULL); | |
146 | |
147 /* | |
148 * prepare the device to start. It will start as soon there's enough | |
149 * data in the buffer to not underrun | |
150 */ | |
151 delay = 0; | |
152 if (!sio_start(hdl)) { | |
153 mp_msg(MSGT_AO, MSGL_ERR, "ao2: init: couldn't start\n"); | |
36466 | 154 goto err_out; |
36463 | 155 } |
156 return 1; | |
36466 | 157 err_out: |
36463 | 158 free(pfds); |
159 pfds = NULL; | |
160 sio_close(hdl); | |
161 hdl = NULL; | |
162 return 0; | |
163 } | |
164 | |
165 /* | |
166 * close device | |
167 */ | |
168 static void uninit(int immed) | |
169 { | |
170 if (hdl) | |
171 sio_close(hdl); | |
36466 | 172 hdl = NULL; |
173 free(pfds); | |
174 pfds = NULL; | |
36463 | 175 } |
176 | |
177 /* | |
178 * stop playing and prepare to restart | |
179 */ | |
180 static void reset(void) | |
181 { | |
182 if (!sio_stop(hdl)) | |
183 mp_msg(MSGT_AO, MSGL_ERR, "ao2: reset: couldn't stop\n"); | |
184 delay = 0; | |
185 if (!sio_start(hdl)) | |
186 mp_msg(MSGT_AO, MSGL_ERR, "ao2: reset: couldn't start\n"); | |
187 } | |
188 | |
189 /* | |
190 * refresh the "delay" counter: call sio_revents() which keeps track of | |
191 * the hardware position | |
192 */ | |
193 static void refresh(void) | |
194 { | |
36467 | 195 int n = sio_pollfd(hdl, pfds, POLLOUT); |
36463 | 196 while (poll(pfds, n, 0) < 0 && errno == EINTR) |
197 ; /* nothing */ | |
198 sio_revents(hdl, pfds); | |
199 } | |
200 | |
201 /* | |
202 * return the number of bytes available in the device buffer | |
203 */ | |
204 static int get_space(void) | |
205 { | |
206 refresh(); | |
207 return par.bufsz * par.pchan * par.bps - delay; | |
208 } | |
209 | |
210 /* | |
211 * delay in seconds between first and last sample in the buffer | |
212 */ | |
213 static float get_delay(void) | |
214 { | |
215 refresh(); | |
216 return (float)delay / (par.bps * par.pchan * par.rate); | |
217 } | |
218 | |
219 /* | |
220 * submit the given number of bytes to the device | |
221 */ | |
222 static int play(void *data, int len, int flags) | |
223 { | |
36467 | 224 int n = sio_write(hdl, data, len); |
36463 | 225 delay += n; |
226 return n; | |
227 } | |
228 | |
229 /* | |
230 * pause playing | |
231 */ | |
232 static void audio_pause(void) | |
233 { | |
234 /* | |
235 * sndio can't pause, so just stop | |
236 */ | |
237 prepause_delay = delay; | |
238 if (!sio_stop(hdl)) | |
239 mp_msg(MSGT_AO, MSGL_ERR, "ao2: pause: couldn't stop\n"); | |
240 delay = 0; | |
241 } | |
242 | |
243 /* | |
244 * resume playing after audio_pause() | |
245 */ | |
246 static void audio_resume(void) | |
247 { | |
248 /* | |
249 * prepare to start; then refill the buffer with the number of bytes | |
250 * audio_pause() consumed (this will trigger start) | |
251 */ | |
252 if (!sio_start(hdl)) | |
253 mp_msg(MSGT_AO, MSGL_ERR, "ao2: resume: couldn't start\n"); | |
254 mp_ao_resume_refill(&audio_out_sndio, | |
255 par.bufsz * par.pchan * par.bps - prepause_delay); | |
256 } |