Mercurial > mplayer.hg
annotate libao2/ao_sndio.c @ 36920:40ad45360c8a
Replace old item 'potmeter' by new item 'pimage'.
Recent versions of the X11/GTK GUI didn't allow to control a potmeter,
because that didn't seem to make any sense.
In order to get rid of the confusing potmeter that doesn't distinguish
from a hpotmeter and in order to allow the more useful behaviour recent
versions of the X11/GTK GUI have been utilized (and because we're still
supporting item 'potmeter' for reasons of compatibility with old skins),
introduce new item 'pimage' that reuses most of the current potmeter
code.
Additionally, remove remaining code and documentation of 'potmeter'.
author | ib |
---|---|
date | Mon, 17 Mar 2014 12:29:46 +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 } |