1 /**
2 * \file pcm/pcm_generic.c
3 * \ingroup PCM
4 * \brief PCM Interface
5 * \author Jaroslav Kysela <perex@perex.cz>
6 * \date 2004
7 */
8 /*
9 * PCM - Common generic plugin code
10 * Copyright (c) 2004 by Jaroslav Kysela <perex@perex.cz>
11 *
12 *
13 * This library is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU Lesser General Public License as
15 * published by the Free Software Foundation; either version 2.1 of
16 * the License, or (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 *
27 */
28
29 #include <sys/ioctl.h>
30 #include <limits.h>
31 #include "pcm_local.h"
32 #include "pcm_generic.h"
33
34 #ifndef DOC_HIDDEN
35
snd_pcm_generic_close(snd_pcm_t * pcm)36 int snd_pcm_generic_close(snd_pcm_t *pcm)
37 {
38 snd_pcm_generic_t *generic = pcm->private_data;
39 int err = 0;
40 if (generic->close_slave)
41 err = snd_pcm_close(generic->slave);
42 free(generic);
43 return err;
44 }
45
snd_pcm_generic_nonblock(snd_pcm_t * pcm,int nonblock)46 int snd_pcm_generic_nonblock(snd_pcm_t *pcm, int nonblock)
47 {
48 snd_pcm_generic_t *generic = pcm->private_data;
49 return snd_pcm_nonblock(generic->slave, nonblock);
50 }
51
snd_pcm_generic_async(snd_pcm_t * pcm,int sig,pid_t pid)52 int snd_pcm_generic_async(snd_pcm_t *pcm, int sig, pid_t pid)
53 {
54 snd_pcm_generic_t *generic = pcm->private_data;
55 return snd_pcm_async(generic->slave, sig, pid);
56 }
57
snd_pcm_generic_poll_descriptors_count(snd_pcm_t * pcm)58 int snd_pcm_generic_poll_descriptors_count(snd_pcm_t *pcm)
59 {
60 snd_pcm_generic_t *generic = pcm->private_data;
61 return snd_pcm_poll_descriptors_count(generic->slave);
62 }
63
snd_pcm_generic_poll_descriptors(snd_pcm_t * pcm,struct pollfd * pfds,unsigned int space)64 int snd_pcm_generic_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space)
65 {
66 snd_pcm_generic_t *generic = pcm->private_data;
67 return snd_pcm_poll_descriptors(generic->slave, pfds, space);
68 }
69
snd_pcm_generic_poll_revents(snd_pcm_t * pcm,struct pollfd * pfds,unsigned int nfds,unsigned short * revents)70 int snd_pcm_generic_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
71 {
72 snd_pcm_generic_t *generic = pcm->private_data;
73 return snd_pcm_poll_descriptors_revents(generic->slave, pfds, nfds, revents);
74 }
75
snd_pcm_generic_info(snd_pcm_t * pcm,snd_pcm_info_t * info)76 int snd_pcm_generic_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
77 {
78 snd_pcm_generic_t *generic = pcm->private_data;
79 return snd_pcm_info(generic->slave, info);
80 }
81
snd_pcm_generic_hw_free(snd_pcm_t * pcm)82 int snd_pcm_generic_hw_free(snd_pcm_t *pcm)
83 {
84 snd_pcm_generic_t *generic = pcm->private_data;
85 return snd_pcm_hw_free(generic->slave);
86 }
87
snd_pcm_generic_sw_params(snd_pcm_t * pcm,snd_pcm_sw_params_t * params)88 int snd_pcm_generic_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
89 {
90 snd_pcm_generic_t *generic = pcm->private_data;
91 return snd_pcm_sw_params(generic->slave, params);
92 }
93
snd_pcm_generic_hw_refine(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)94 int snd_pcm_generic_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
95 {
96 snd_pcm_generic_t *generic = pcm->private_data;
97 return snd_pcm_hw_refine(generic->slave, params);
98 }
99
snd_pcm_generic_hw_params(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)100 int snd_pcm_generic_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
101 {
102 snd_pcm_generic_t *generic = pcm->private_data;
103 return _snd_pcm_hw_params_internal(generic->slave, params);
104 }
105
snd_pcm_generic_prepare(snd_pcm_t * pcm)106 int snd_pcm_generic_prepare(snd_pcm_t *pcm)
107 {
108 snd_pcm_generic_t *generic = pcm->private_data;
109 return snd_pcm_prepare(generic->slave);
110 }
111
snd_pcm_generic_channel_info(snd_pcm_t * pcm,snd_pcm_channel_info_t * info)112 int snd_pcm_generic_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
113 {
114 snd_pcm_generic_t *generic = pcm->private_data;
115 if (pcm->mmap_shadow) {
116 /* No own buffer is required - the plugin won't change
117 * the data on the buffer, or do safely on-the-place
118 * conversion
119 */
120 return snd_pcm_channel_info(generic->slave, info);
121 } else {
122 /* Allocate own buffer */
123 return snd_pcm_channel_info_shm(pcm, info, -1);
124 }
125 }
126
snd_pcm_generic_status(snd_pcm_t * pcm,snd_pcm_status_t * status)127 int snd_pcm_generic_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
128 {
129 snd_pcm_generic_t *generic = pcm->private_data;
130 return snd_pcm_status(generic->slave, status);
131 }
132
snd_pcm_generic_state(snd_pcm_t * pcm)133 snd_pcm_state_t snd_pcm_generic_state(snd_pcm_t *pcm)
134 {
135 snd_pcm_generic_t *generic = pcm->private_data;
136 return snd_pcm_state(generic->slave);
137 }
138
snd_pcm_generic_hwsync(snd_pcm_t * pcm)139 int snd_pcm_generic_hwsync(snd_pcm_t *pcm)
140 {
141 snd_pcm_generic_t *generic = pcm->private_data;
142 return snd_pcm_hwsync(generic->slave);
143 }
144
snd_pcm_generic_reset(snd_pcm_t * pcm)145 int snd_pcm_generic_reset(snd_pcm_t *pcm)
146 {
147 snd_pcm_generic_t *generic = pcm->private_data;
148 return snd_pcm_reset(generic->slave);
149 }
150
snd_pcm_generic_start(snd_pcm_t * pcm)151 int snd_pcm_generic_start(snd_pcm_t *pcm)
152 {
153 snd_pcm_generic_t *generic = pcm->private_data;
154 return snd_pcm_start(generic->slave);
155 }
156
snd_pcm_generic_drop(snd_pcm_t * pcm)157 int snd_pcm_generic_drop(snd_pcm_t *pcm)
158 {
159 snd_pcm_generic_t *generic = pcm->private_data;
160 return snd_pcm_drop(generic->slave);
161 }
162
snd_pcm_generic_drain(snd_pcm_t * pcm)163 int snd_pcm_generic_drain(snd_pcm_t *pcm)
164 {
165 snd_pcm_generic_t *generic = pcm->private_data;
166 return snd_pcm_drain(generic->slave);
167 }
168
snd_pcm_generic_pause(snd_pcm_t * pcm,int enable)169 int snd_pcm_generic_pause(snd_pcm_t *pcm, int enable)
170 {
171 snd_pcm_generic_t *generic = pcm->private_data;
172 return snd_pcm_pause(generic->slave, enable);
173 }
174
snd_pcm_generic_resume(snd_pcm_t * pcm)175 int snd_pcm_generic_resume(snd_pcm_t *pcm)
176 {
177 snd_pcm_generic_t *generic = pcm->private_data;
178 return snd_pcm_resume(generic->slave);
179 }
180
snd_pcm_generic_delay(snd_pcm_t * pcm,snd_pcm_sframes_t * delayp)181 int snd_pcm_generic_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
182 {
183 snd_pcm_generic_t *generic = pcm->private_data;
184 return snd_pcm_delay(generic->slave, delayp);
185 }
186
snd_pcm_generic_forwardable(snd_pcm_t * pcm)187 snd_pcm_sframes_t snd_pcm_generic_forwardable(snd_pcm_t *pcm)
188 {
189 snd_pcm_generic_t *generic = pcm->private_data;
190 return snd_pcm_forwardable(generic->slave);
191 }
192
snd_pcm_generic_forward(snd_pcm_t * pcm,snd_pcm_uframes_t frames)193 snd_pcm_sframes_t snd_pcm_generic_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
194 {
195 snd_pcm_generic_t *generic = pcm->private_data;
196 return INTERNAL(snd_pcm_forward)(generic->slave, frames);
197 }
198
snd_pcm_generic_rewindable(snd_pcm_t * pcm)199 snd_pcm_sframes_t snd_pcm_generic_rewindable(snd_pcm_t *pcm)
200 {
201 snd_pcm_generic_t *generic = pcm->private_data;
202 return snd_pcm_rewindable(generic->slave);
203 }
204
snd_pcm_generic_rewind(snd_pcm_t * pcm,snd_pcm_uframes_t frames)205 snd_pcm_sframes_t snd_pcm_generic_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
206 {
207 snd_pcm_generic_t *generic = pcm->private_data;
208 return snd_pcm_rewind(generic->slave, frames);
209 }
210
snd_pcm_generic_link(snd_pcm_t * pcm1,snd_pcm_t * pcm2)211 int snd_pcm_generic_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
212 {
213 snd_pcm_generic_t *generic = pcm1->private_data;
214 if (generic->slave->fast_ops->link)
215 return generic->slave->fast_ops->link(generic->slave->fast_op_arg, pcm2);
216 return -ENOSYS;
217 }
218
snd_pcm_generic_link_slaves(snd_pcm_t * pcm,snd_pcm_t * master)219 int snd_pcm_generic_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master)
220 {
221 snd_pcm_generic_t *generic = pcm->private_data;
222 if (generic->slave->fast_ops->link_slaves)
223 return generic->slave->fast_ops->link_slaves(generic->slave->fast_op_arg, master);
224 return -ENOSYS;
225 }
226
snd_pcm_generic_unlink(snd_pcm_t * pcm)227 int snd_pcm_generic_unlink(snd_pcm_t *pcm)
228 {
229 snd_pcm_generic_t *generic = pcm->private_data;
230 if (generic->slave->fast_ops->unlink)
231 return generic->slave->fast_ops->unlink(generic->slave->fast_op_arg);
232 return -ENOSYS;
233 }
234
snd_pcm_generic_writei(snd_pcm_t * pcm,const void * buffer,snd_pcm_uframes_t size)235 snd_pcm_sframes_t snd_pcm_generic_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
236 {
237 snd_pcm_generic_t *generic = pcm->private_data;
238 return _snd_pcm_writei(generic->slave, buffer, size);
239 }
240
snd_pcm_generic_writen(snd_pcm_t * pcm,void ** bufs,snd_pcm_uframes_t size)241 snd_pcm_sframes_t snd_pcm_generic_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
242 {
243 snd_pcm_generic_t *generic = pcm->private_data;
244 return _snd_pcm_writen(generic->slave, bufs, size);
245 }
246
snd_pcm_generic_readi(snd_pcm_t * pcm,void * buffer,snd_pcm_uframes_t size)247 snd_pcm_sframes_t snd_pcm_generic_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
248 {
249 snd_pcm_generic_t *generic = pcm->private_data;
250 return _snd_pcm_readi(generic->slave, buffer, size);
251 }
252
snd_pcm_generic_readn(snd_pcm_t * pcm,void ** bufs,snd_pcm_uframes_t size)253 snd_pcm_sframes_t snd_pcm_generic_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
254 {
255 snd_pcm_generic_t *generic = pcm->private_data;
256 return _snd_pcm_readn(generic->slave, bufs, size);
257 }
258
snd_pcm_generic_mmap_commit(snd_pcm_t * pcm,snd_pcm_uframes_t offset,snd_pcm_uframes_t size)259 snd_pcm_sframes_t snd_pcm_generic_mmap_commit(snd_pcm_t *pcm,
260 snd_pcm_uframes_t offset,
261 snd_pcm_uframes_t size)
262 {
263 snd_pcm_generic_t *generic = pcm->private_data;
264 return snd_pcm_mmap_commit(generic->slave, offset, size);
265 }
266
snd_pcm_generic_avail_update(snd_pcm_t * pcm)267 snd_pcm_sframes_t snd_pcm_generic_avail_update(snd_pcm_t *pcm)
268 {
269 snd_pcm_generic_t *generic = pcm->private_data;
270 return snd_pcm_avail_update(generic->slave);
271 }
272
snd_pcm_generic_htimestamp(snd_pcm_t * pcm,snd_pcm_uframes_t * avail,snd_htimestamp_t * tstamp)273 int snd_pcm_generic_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail,
274 snd_htimestamp_t *tstamp)
275 {
276 snd_pcm_generic_t *generic = pcm->private_data;
277 return snd_pcm_htimestamp(generic->slave, avail, tstamp);
278 }
279
280 /* stand-alone version - similar like snd_pcm_hw_htimestamp but
281 * taking the tstamp via gettimestamp().
282 */
snd_pcm_generic_real_htimestamp(snd_pcm_t * pcm,snd_pcm_uframes_t * avail,snd_htimestamp_t * tstamp)283 int snd_pcm_generic_real_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail,
284 snd_htimestamp_t *tstamp)
285 {
286 snd_pcm_sframes_t avail1;
287 int ok = 0;
288
289 while (1) {
290 avail1 = __snd_pcm_avail_update(pcm);
291 if (avail1 < 0)
292 return avail1;
293 if (ok && (snd_pcm_uframes_t)avail1 == *avail)
294 break;
295 *avail = avail1;
296 gettimestamp(tstamp, pcm->tstamp_type);
297 ok = 1;
298 }
299 return 0;
300 }
301
snd_pcm_generic_mmap(snd_pcm_t * pcm)302 int snd_pcm_generic_mmap(snd_pcm_t *pcm)
303 {
304 if (pcm->mmap_shadow) {
305 /* Copy the slave mmapped buffer data */
306 snd_pcm_generic_t *generic = pcm->private_data;
307 pcm->mmap_channels = generic->slave->mmap_channels;
308 pcm->running_areas = generic->slave->running_areas;
309 pcm->stopped_areas = generic->slave->stopped_areas;
310 }
311 return 0;
312 }
313
snd_pcm_generic_munmap(snd_pcm_t * pcm)314 int snd_pcm_generic_munmap(snd_pcm_t *pcm)
315 {
316 if (pcm->mmap_shadow) {
317 /* Clean up */
318 pcm->mmap_channels = NULL;
319 pcm->running_areas = NULL;
320 pcm->stopped_areas = NULL;
321 }
322 return 0;
323 }
324
snd_pcm_generic_query_chmaps(snd_pcm_t * pcm)325 snd_pcm_chmap_query_t **snd_pcm_generic_query_chmaps(snd_pcm_t *pcm)
326 {
327 snd_pcm_generic_t *generic = pcm->private_data;
328 return snd_pcm_query_chmaps(generic->slave);
329 }
330
snd_pcm_generic_get_chmap(snd_pcm_t * pcm)331 snd_pcm_chmap_t *snd_pcm_generic_get_chmap(snd_pcm_t *pcm)
332 {
333 snd_pcm_generic_t *generic = pcm->private_data;
334 return snd_pcm_get_chmap(generic->slave);
335 }
336
snd_pcm_generic_set_chmap(snd_pcm_t * pcm,const snd_pcm_chmap_t * map)337 int snd_pcm_generic_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
338 {
339 snd_pcm_generic_t *generic = pcm->private_data;
340 return snd_pcm_set_chmap(generic->slave, map);
341 }
342
snd_pcm_generic_may_wait_for_avail_min(snd_pcm_t * pcm,snd_pcm_uframes_t avail ATTRIBUTE_UNUSED)343 int snd_pcm_generic_may_wait_for_avail_min(snd_pcm_t *pcm, snd_pcm_uframes_t avail ATTRIBUTE_UNUSED)
344 {
345 snd_pcm_generic_t *generic = pcm->private_data;
346 return snd_pcm_may_wait_for_avail_min(generic->slave, snd_pcm_mmap_avail(generic->slave));
347 }
348
349 #endif /* DOC_HIDDEN */
350