Initial Import
[profile/ivi/alsa-lib.git] / src / pcm / pcm_shm.c
1 /**
2  * \file pcm/pcm_shm.c
3  * \ingroup PCM_Plugins
4  * \brief PCM Shared Memory Plugin Interface
5  * \author Abramo Bagnara <abramo@alsa-project.org>
6  * \date 2000-2001
7  */
8 /*
9  *  PCM - Shared Memory Client
10  *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
26  *
27  */
28   
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stddef.h>
32 #include <limits.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <fcntl.h>
36 #include <sys/ioctl.h>
37 #include <sys/shm.h>
38 #include <sys/socket.h>
39 #include <sys/poll.h>
40 #include <sys/un.h>
41 #include <sys/mman.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #include <net/if.h>
45 #include <netdb.h>
46 #include "aserver.h"
47
48 #ifndef PIC
49 /* entry for static linking */
50 const char *_snd_module_pcm_shm = "";
51 #endif
52
53 #ifndef DOC_HIDDEN
54 typedef struct {
55         int socket;
56         volatile snd_pcm_shm_ctrl_t *ctrl;
57 } snd_pcm_shm_t;
58 #endif
59
60 static long snd_pcm_shm_action_fd0(snd_pcm_t *pcm, int *fd)
61 {
62         snd_pcm_shm_t *shm = pcm->private_data;
63         int err;
64         char buf[1];
65         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
66
67         err = write(shm->socket, buf, 1);
68         if (err != 1)
69                 return -EBADFD;
70         err = snd_receive_fd(shm->socket, buf, 1, fd);
71         if (err != 1)
72                 return -EBADFD;
73         if (ctrl->cmd) {
74                 SNDERR("Server has not done the cmd");
75                 return -EBADFD;
76         }
77         return ctrl->result;
78 }
79
80 static int snd_pcm_shm_new_rbptr(snd_pcm_t *pcm, snd_pcm_shm_t *shm,
81                                  snd_pcm_rbptr_t *rbptr, volatile snd_pcm_shm_rbptr_t *shm_rbptr)
82 {
83         if (!shm_rbptr->use_mmap) {
84                 if (&pcm->hw == rbptr)
85                         snd_pcm_set_hw_ptr(pcm, &shm_rbptr->ptr, -1, 0);
86                 else
87                         snd_pcm_set_appl_ptr(pcm, &shm_rbptr->ptr, -1, 0);
88         } else {
89                 void *ptr;
90                 size_t mmap_size, mmap_offset, offset;
91                 int fd;
92                 long result;
93                 
94                 shm->ctrl->cmd = &pcm->hw == rbptr ? SND_PCM_IOCTL_HW_PTR_FD : SND_PCM_IOCTL_APPL_PTR_FD;
95                 result = snd_pcm_shm_action_fd0(pcm, &fd);
96                 if (result < 0)
97                         return result;
98                 mmap_size = page_ptr(shm_rbptr->offset, sizeof(snd_pcm_uframes_t), &offset, &mmap_offset);
99                 ptr = mmap(NULL, mmap_size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, mmap_offset);
100                 if (ptr == MAP_FAILED || ptr == NULL) {
101                         SYSERR("shm rbptr mmap failed");
102                         return -errno;
103                 }
104                 if (&pcm->hw == rbptr)
105                         snd_pcm_set_hw_ptr(pcm, (snd_pcm_uframes_t *)((char *)ptr + offset), fd, shm_rbptr->offset);
106                 else
107                         snd_pcm_set_appl_ptr(pcm, (snd_pcm_uframes_t *)((char *)ptr + offset), fd, shm_rbptr->offset);
108         }
109         return 0;
110 }
111
112 static long snd_pcm_shm_action(snd_pcm_t *pcm)
113 {
114         snd_pcm_shm_t *shm = pcm->private_data;
115         int err, result;
116         char buf[1];
117         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
118
119         if (ctrl->hw.changed || ctrl->appl.changed)
120                 return -EBADFD;
121         err = write(shm->socket, buf, 1);
122         if (err != 1)
123                 return -EBADFD;
124         err = read(shm->socket, buf, 1);
125         if (err != 1)
126                 return -EBADFD;
127         if (ctrl->cmd) {
128                 SNDERR("Server has not done the cmd");
129                 return -EBADFD;
130         }
131         result = ctrl->result;
132         if (ctrl->hw.changed) {
133                 err = snd_pcm_shm_new_rbptr(pcm, shm, &pcm->hw, &ctrl->hw);
134                 if (err < 0)
135                         return err;
136                 ctrl->hw.changed = 0;
137         }
138         if (ctrl->appl.changed) {
139                 err = snd_pcm_shm_new_rbptr(pcm, shm, &pcm->appl, &ctrl->appl);
140                 if (err < 0)
141                         return err;
142                 ctrl->appl.changed = 0;
143         }
144         return result;
145 }
146
147 static long snd_pcm_shm_action_fd(snd_pcm_t *pcm, int *fd)
148 {
149         snd_pcm_shm_t *shm = pcm->private_data;
150         int err;
151         char buf[1];
152         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
153
154         if (ctrl->hw.changed || ctrl->appl.changed)
155                 return -EBADFD;
156         err = write(shm->socket, buf, 1);
157         if (err != 1)
158                 return -EBADFD;
159         err = snd_receive_fd(shm->socket, buf, 1, fd);
160         if (err != 1)
161                 return -EBADFD;
162         if (ctrl->cmd) {
163                 SNDERR("Server has not done the cmd");
164                 return -EBADFD;
165         }
166         if (ctrl->hw.changed) {
167                 err = snd_pcm_shm_new_rbptr(pcm, shm, &pcm->hw, &ctrl->hw);
168                 if (err < 0)
169                         return err;
170                 ctrl->hw.changed = 0;
171         }
172         if (ctrl->appl.changed) {
173                 err = snd_pcm_shm_new_rbptr(pcm, shm, &pcm->appl, &ctrl->appl);
174                 if (err < 0)
175                         return err;
176                 ctrl->appl.changed = 0;
177         }
178         return ctrl->result;
179 }
180
181 static int snd_pcm_shm_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED)
182 {
183         return 0;
184 }
185
186 static int snd_pcm_shm_async(snd_pcm_t *pcm, int sig, pid_t pid)
187 {
188         snd_pcm_shm_t *shm = pcm->private_data;
189         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
190         ctrl->cmd = SND_PCM_IOCTL_ASYNC;
191         ctrl->u.async.sig = sig;
192         ctrl->u.async.pid = pid;
193         return snd_pcm_shm_action(pcm);
194 }
195
196 static int snd_pcm_shm_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
197 {
198         snd_pcm_shm_t *shm = pcm->private_data;
199         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
200         int err;
201 //      ctrl->u.info = *info;
202         ctrl->cmd = SNDRV_PCM_IOCTL_INFO;
203         err = snd_pcm_shm_action(pcm);
204         if (err < 0)
205                 return err;
206         *info = ctrl->u.info;
207         return err;
208 }
209
210 static int snd_pcm_shm_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED)
211 {
212         return 0;
213 }
214
215 static int snd_pcm_shm_hw_refine_sprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *sparams)
216 {
217         snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP };
218         _snd_pcm_hw_params_any(sparams);
219         _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
220                                    &saccess_mask);
221         return 0;
222 }
223
224 static int snd_pcm_shm_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
225                                           snd_pcm_hw_params_t *sparams)
226 {
227         int err;
228         unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS;
229         const snd_pcm_access_mask_t *access_mask = snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS);
230         if (!snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) &&
231             !snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED)) {
232                 err = _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
233                                              access_mask);
234                 if (err < 0)
235                         return err;
236         }
237         err = _snd_pcm_hw_params_refine(sparams, links, params);
238         if (err < 0)
239                 return err;
240         return 0;
241 }
242         
243 static int snd_pcm_shm_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
244                                           snd_pcm_hw_params_t *sparams)
245 {
246         int err;
247         unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS;
248         snd_pcm_access_mask_t access_mask;
249         snd_mask_copy(&access_mask, snd_pcm_hw_param_get_mask(sparams, SND_PCM_HW_PARAM_ACCESS));
250         snd_pcm_access_mask_set(&access_mask, SND_PCM_ACCESS_RW_INTERLEAVED);
251         snd_pcm_access_mask_set(&access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED);
252         err = _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
253                                          &access_mask);
254         if (err < 0)
255                 return err;
256         err = _snd_pcm_hw_params_refine(params, links, sparams);
257         if (err < 0)
258                 return err;
259         return 0;
260 }
261
262 static int snd_pcm_shm_hw_refine_slave(snd_pcm_t *pcm,
263                                        snd_pcm_hw_params_t *params)
264 {
265         snd_pcm_shm_t *shm = pcm->private_data;
266         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
267         int err;
268         ctrl->u.hw_refine = *params;
269         ctrl->cmd = SNDRV_PCM_IOCTL_HW_REFINE;
270         err = snd_pcm_shm_action(pcm);
271         *params = ctrl->u.hw_refine;
272         return err;
273 }
274
275 static int snd_pcm_shm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
276 {
277         return snd_pcm_hw_refine_slave(pcm, params,
278                                        snd_pcm_shm_hw_refine_cprepare,
279                                        snd_pcm_shm_hw_refine_cchange,
280                                        snd_pcm_shm_hw_refine_sprepare,
281                                        snd_pcm_shm_hw_refine_schange,
282                                        snd_pcm_shm_hw_refine_slave);
283 }
284
285 static int snd_pcm_shm_hw_params_slave(snd_pcm_t *pcm, 
286                                        snd_pcm_hw_params_t *params)
287 {
288         snd_pcm_shm_t *shm = pcm->private_data;
289         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
290         int err;
291         params->flags |= SND_PCM_HW_PARAMS_EXPORT_BUFFER;
292         ctrl->cmd = SNDRV_PCM_IOCTL_HW_PARAMS;
293         ctrl->u.hw_params = *params;
294         err = snd_pcm_shm_action(pcm);
295         *params = ctrl->u.hw_params;
296         return err;
297 }
298
299 static int snd_pcm_shm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
300 {
301         return snd_pcm_hw_params_slave(pcm, params,
302                                        snd_pcm_shm_hw_refine_cchange,
303                                        snd_pcm_shm_hw_refine_sprepare,
304                                        snd_pcm_shm_hw_refine_schange,
305                                        snd_pcm_shm_hw_params_slave);
306 }
307
308 static int snd_pcm_shm_hw_free(snd_pcm_t *pcm)
309 {
310         snd_pcm_shm_t *shm = pcm->private_data;
311         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
312         ctrl->cmd = SNDRV_PCM_IOCTL_HW_FREE;
313         return snd_pcm_shm_action(pcm);
314 }
315
316 static int snd_pcm_shm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
317 {
318         snd_pcm_shm_t *shm = pcm->private_data;
319         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
320         int err;
321         ctrl->cmd = SNDRV_PCM_IOCTL_SW_PARAMS;
322         ctrl->u.sw_params = *params;
323         err = snd_pcm_shm_action(pcm);
324         *params = ctrl->u.sw_params;
325         if (err < 0)
326                 return err;
327         return err;
328 }
329
330 static int snd_pcm_shm_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
331 {
332         return 0;
333 }
334
335 static int snd_pcm_shm_munmap(snd_pcm_t *pcm)
336 {
337         unsigned int c;
338         for (c = 0; c < pcm->channels; ++c) {
339                 snd_pcm_channel_info_t *i = &pcm->mmap_channels[c];
340                 unsigned int c1;
341                 int err;
342                 if (i->type != SND_PCM_AREA_MMAP)
343                         continue;
344                 if (i->u.mmap.fd < 0)
345                         continue;
346                 for (c1 = c + 1; c1 < pcm->channels; ++c1) {
347                         snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
348                         if (i1->type != SND_PCM_AREA_MMAP)
349                                 continue;
350                         if (i1->u.mmap.fd != i->u.mmap.fd)
351                                 continue;
352                         i1->u.mmap.fd = -1;
353                 }
354                 err = close(i->u.mmap.fd);
355                 if (err < 0) {
356                         SYSERR("close failed");
357                         return -errno;
358                 }
359         }
360         return 0;
361 }
362
363 static int snd_pcm_shm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
364 {
365         snd_pcm_shm_t *shm = pcm->private_data;
366         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
367         int err;
368         int fd;
369         ctrl->cmd = SNDRV_PCM_IOCTL_CHANNEL_INFO;
370         ctrl->u.channel_info = *info;
371         err = snd_pcm_shm_action_fd(pcm, &fd);
372         if (err < 0)
373                 return err;
374         *info = ctrl->u.channel_info;
375         info->addr = 0;
376         switch (info->type) {
377         case SND_PCM_AREA_MMAP:
378                 info->u.mmap.fd = fd;
379                 break;
380         case SND_PCM_AREA_SHM:
381                 break;
382         default:
383                 assert(0);
384                 break;
385         }
386         return err;
387 }
388
389 static int snd_pcm_shm_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
390 {
391         snd_pcm_shm_t *shm = pcm->private_data;
392         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
393         int err;
394         ctrl->cmd = SNDRV_PCM_IOCTL_STATUS;
395         // ctrl->u.status = *status;
396         err = snd_pcm_shm_action(pcm);
397         if (err < 0)
398                 return err;
399         *status = ctrl->u.status;
400         return err;
401 }
402
403 static snd_pcm_state_t snd_pcm_shm_state(snd_pcm_t *pcm)
404 {
405         snd_pcm_shm_t *shm = pcm->private_data;
406         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
407         ctrl->cmd = SND_PCM_IOCTL_STATE;
408         return snd_pcm_shm_action(pcm);
409 }
410
411 static int snd_pcm_shm_hwsync(snd_pcm_t *pcm)
412 {
413         snd_pcm_shm_t *shm = pcm->private_data;
414         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
415         ctrl->cmd = SND_PCM_IOCTL_HWSYNC;
416         return snd_pcm_shm_action(pcm);
417 }
418
419 static int snd_pcm_shm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
420 {
421         snd_pcm_shm_t *shm = pcm->private_data;
422         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
423         int err;
424         ctrl->cmd = SNDRV_PCM_IOCTL_DELAY;
425         err = snd_pcm_shm_action(pcm);
426         if (err < 0)
427                 return err;
428         *delayp = ctrl->u.delay.frames;
429         return err;
430 }
431
432 static snd_pcm_sframes_t snd_pcm_shm_avail_update(snd_pcm_t *pcm)
433 {
434         snd_pcm_shm_t *shm = pcm->private_data;
435         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
436         int err;
437         ctrl->cmd = SND_PCM_IOCTL_AVAIL_UPDATE;
438         err = snd_pcm_shm_action(pcm);
439         if (err < 0)
440                 return err;
441         return err;
442 }
443
444 static int snd_pcm_shm_htimestamp(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
445                                   snd_pcm_uframes_t *avail ATTRIBUTE_UNUSED,
446                                   snd_htimestamp_t *tstamp ATTRIBUTE_UNUSED)
447 {
448         return -EIO;    /* not implemented yet */
449 }
450
451 static int snd_pcm_shm_prepare(snd_pcm_t *pcm)
452 {
453         snd_pcm_shm_t *shm = pcm->private_data;
454         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
455         ctrl->cmd = SNDRV_PCM_IOCTL_PREPARE;
456         return snd_pcm_shm_action(pcm);
457 }
458
459 static int snd_pcm_shm_reset(snd_pcm_t *pcm)
460 {
461         snd_pcm_shm_t *shm = pcm->private_data;
462         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
463         ctrl->cmd = SNDRV_PCM_IOCTL_RESET;
464         return snd_pcm_shm_action(pcm);
465 }
466
467 static int snd_pcm_shm_start(snd_pcm_t *pcm)
468 {
469         snd_pcm_shm_t *shm = pcm->private_data;
470         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
471         ctrl->cmd = SNDRV_PCM_IOCTL_START;
472         return snd_pcm_shm_action(pcm);
473 }
474
475 static int snd_pcm_shm_drop(snd_pcm_t *pcm)
476 {
477         snd_pcm_shm_t *shm = pcm->private_data;
478         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
479         ctrl->cmd = SNDRV_PCM_IOCTL_DROP;
480         return snd_pcm_shm_action(pcm);
481 }
482
483 static int snd_pcm_shm_drain(snd_pcm_t *pcm)
484 {
485         snd_pcm_shm_t *shm = pcm->private_data;
486         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
487         int err;
488         do {
489                 ctrl->cmd = SNDRV_PCM_IOCTL_DRAIN;
490                 err = snd_pcm_shm_action(pcm);
491                 if (err != -EAGAIN)
492                         break;
493                 usleep(10000);
494         } while (1);
495         if (err < 0)
496                 return err;
497         if (!(pcm->mode & SND_PCM_NONBLOCK))
498                 snd_pcm_wait(pcm, -1);
499         return err;
500 }
501
502 static int snd_pcm_shm_pause(snd_pcm_t *pcm, int enable)
503 {
504         snd_pcm_shm_t *shm = pcm->private_data;
505         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
506         ctrl->cmd = SNDRV_PCM_IOCTL_PAUSE;
507         ctrl->u.pause.enable = enable;
508         return snd_pcm_shm_action(pcm);
509 }
510
511 static snd_pcm_sframes_t snd_pcm_shm_rewindable(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
512 {
513         return 0;       /* FIX ME */
514 }
515
516 static snd_pcm_sframes_t snd_pcm_shm_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
517 {
518         snd_pcm_shm_t *shm = pcm->private_data;
519         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
520         ctrl->cmd = SNDRV_PCM_IOCTL_REWIND;
521         ctrl->u.rewind.frames = frames;
522         return snd_pcm_shm_action(pcm);
523 }
524
525 static snd_pcm_sframes_t snd_pcm_shm_forwardable(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
526 {
527         return 0;       /* FIX ME */
528 }
529
530 static snd_pcm_sframes_t snd_pcm_shm_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
531 {
532         snd_pcm_shm_t *shm = pcm->private_data;
533         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
534         ctrl->cmd = SND_PCM_IOCTL_FORWARD;
535         ctrl->u.forward.frames = frames;
536         return snd_pcm_shm_action(pcm);
537 }
538
539 static int snd_pcm_shm_resume(snd_pcm_t *pcm)
540 {
541         snd_pcm_shm_t *shm = pcm->private_data;
542         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
543         ctrl->cmd = SNDRV_PCM_IOCTL_RESUME;
544         return snd_pcm_shm_action(pcm);
545 }
546
547 static snd_pcm_sframes_t snd_pcm_shm_mmap_commit(snd_pcm_t *pcm,
548                                                  snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
549                                                  snd_pcm_uframes_t size)
550 {
551         snd_pcm_shm_t *shm = pcm->private_data;
552         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
553         ctrl->cmd = SND_PCM_IOCTL_MMAP_COMMIT;
554         ctrl->u.mmap_commit.offset = offset;
555         ctrl->u.mmap_commit.frames = size;
556         return snd_pcm_shm_action(pcm);
557 }
558
559 static int snd_pcm_shm_poll_descriptor(snd_pcm_t *pcm)
560 {
561         snd_pcm_shm_t *shm = pcm->private_data;
562         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
563         int fd, err;
564         ctrl->cmd = SND_PCM_IOCTL_POLL_DESCRIPTOR;
565         err = snd_pcm_shm_action_fd(pcm, &fd);
566         if (err < 0)
567                 return err;
568         return fd;
569 }
570
571 static int snd_pcm_shm_close(snd_pcm_t *pcm)
572 {
573         snd_pcm_shm_t *shm = pcm->private_data;
574         volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
575         int result;
576         ctrl->cmd = SND_PCM_IOCTL_CLOSE;
577         result = snd_pcm_shm_action(pcm);
578         shmdt((void *)ctrl);
579         close(shm->socket);
580         close(pcm->poll_fd);
581         free(shm);
582         return result;
583 }
584
585 static void snd_pcm_shm_dump(snd_pcm_t *pcm, snd_output_t *out)
586 {
587         snd_output_printf(out, "Shm PCM\n");
588         if (pcm->setup) {
589                 snd_output_printf(out, "Its setup is:\n");
590                 snd_pcm_dump_setup(pcm, out);
591         }
592 }
593
594 static const snd_pcm_ops_t snd_pcm_shm_ops = {
595         .close = snd_pcm_shm_close,
596         .info = snd_pcm_shm_info,
597         .hw_refine = snd_pcm_shm_hw_refine,
598         .hw_params = snd_pcm_shm_hw_params,
599         .hw_free = snd_pcm_shm_hw_free,
600         .sw_params = snd_pcm_shm_sw_params,
601         .channel_info = snd_pcm_shm_channel_info,
602         .dump = snd_pcm_shm_dump,
603         .nonblock = snd_pcm_shm_nonblock,
604         .async = snd_pcm_shm_async,
605         .mmap = snd_pcm_shm_mmap,
606         .munmap = snd_pcm_shm_munmap,
607 };
608
609 static const snd_pcm_fast_ops_t snd_pcm_shm_fast_ops = {
610         .status = snd_pcm_shm_status,
611         .state = snd_pcm_shm_state,
612         .hwsync = snd_pcm_shm_hwsync,
613         .delay = snd_pcm_shm_delay,
614         .prepare = snd_pcm_shm_prepare,
615         .reset = snd_pcm_shm_reset,
616         .start = snd_pcm_shm_start,
617         .drop = snd_pcm_shm_drop,
618         .drain = snd_pcm_shm_drain,
619         .pause = snd_pcm_shm_pause,
620         .rewindable = snd_pcm_shm_rewindable,
621         .rewind = snd_pcm_shm_rewind,
622         .forwardable = snd_pcm_shm_forwardable,
623         .forward = snd_pcm_shm_forward,
624         .resume = snd_pcm_shm_resume,
625         .writei = snd_pcm_mmap_writei,
626         .writen = snd_pcm_mmap_writen,
627         .readi = snd_pcm_mmap_readi,
628         .readn = snd_pcm_mmap_readn,
629         .avail_update = snd_pcm_shm_avail_update,
630         .mmap_commit = snd_pcm_shm_mmap_commit,
631         .htimestamp = snd_pcm_shm_htimestamp,
632 };
633
634 static int make_local_socket(const char *filename)
635 {
636         size_t l = strlen(filename);
637         size_t size = offsetof(struct sockaddr_un, sun_path) + l;
638         struct sockaddr_un *addr = alloca(size);
639         int sock;
640
641         sock = socket(PF_LOCAL, SOCK_STREAM, 0);
642         if (sock < 0) {
643                 SYSERR("socket failed");
644                 return -errno;
645         }
646         
647         addr->sun_family = AF_LOCAL;
648         memcpy(addr->sun_path, filename, l);
649
650         if (connect(sock, (struct sockaddr *) addr, size) < 0) {
651                 SYSERR("connect failed");
652                 return -errno;
653         }
654         return sock;
655 }
656
657 #if 0
658 static int make_inet_socket(const char *host, int port)
659 {
660         struct sockaddr_in addr;
661         int sock;
662         struct hostent *h = gethostbyname(host);
663         if (!h)
664                 return -ENOENT;
665
666         sock = socket(PF_INET, SOCK_STREAM, 0);
667         if (sock < 0) {
668                 SYSERR("socket failed");
669                 return -errno;
670         }
671         
672         addr.sin_family = AF_INET;
673         addr.sin_port = htons(port);
674         memcpy(&addr.sin_addr, h->h_addr_list[0], sizeof(struct in_addr));
675
676         if (connect(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
677                 SYSERR("connect failed");
678                 return -errno;
679         }
680         return sock;
681 }
682 #endif
683
684 /**
685  * \brief Creates a new shared memory PCM
686  * \param pcmp Returns created PCM handle
687  * \param name Name of PCM
688  * \param sockname Unix socket name
689  * \param sname Server name
690  * \param stream PCM Stream
691  * \param mode PCM Mode
692  * \retval zero on success otherwise a negative error code
693  * \warning Using of this function might be dangerous in the sense
694  *          of compatibility reasons. The prototype might be freely
695  *          changed in future.
696  */
697 int snd_pcm_shm_open(snd_pcm_t **pcmp, const char *name,
698                      const char *sockname, const char *sname,
699                      snd_pcm_stream_t stream, int mode)
700 {
701         snd_pcm_t *pcm;
702         snd_pcm_shm_t *shm = NULL;
703         snd_client_open_request_t *req;
704         snd_client_open_answer_t ans;
705         size_t snamelen, reqlen;
706         int err;
707         int result;
708         snd_pcm_shm_ctrl_t *ctrl = NULL;
709         int sock = -1;
710         snamelen = strlen(sname);
711         if (snamelen > 255)
712                 return -EINVAL;
713
714         result = make_local_socket(sockname);
715         if (result < 0) {
716                 SNDERR("server for socket %s is not running", sockname);
717                 goto _err;
718         }
719         sock = result;
720
721         reqlen = sizeof(*req) + snamelen;
722         req = alloca(reqlen);
723         memcpy(req->name, sname, snamelen);
724         req->dev_type = SND_DEV_TYPE_PCM;
725         req->transport_type = SND_TRANSPORT_TYPE_SHM;
726         req->stream = stream;
727         req->mode = mode;
728         req->namelen = snamelen;
729         err = write(sock, req, reqlen);
730         if (err < 0) {
731                 SYSERR("write error");
732                 result = -errno;
733                 goto _err;
734         }
735         if ((size_t) err != reqlen) {
736                 SNDERR("write size error");
737                 result = -EINVAL;
738                 goto _err;
739         }
740         err = read(sock, &ans, sizeof(ans));
741         if (err < 0) {
742                 SYSERR("read error");
743                 result = -errno;
744                 goto _err;
745         }
746         if (err != sizeof(ans)) {
747                 SNDERR("read size error");
748                 result = -EINVAL;
749                 goto _err;
750         }
751         result = ans.result;
752         if (result < 0)
753                 goto _err;
754
755         ctrl = shmat(ans.cookie, 0, 0);
756         if (!ctrl) {
757                 SYSERR("shmat error");
758                 result = -errno;
759                 goto _err;
760         }
761                 
762         shm = calloc(1, sizeof(snd_pcm_shm_t));
763         if (!shm) {
764                 result = -ENOMEM;
765                 goto _err;
766         }
767
768         shm->socket = sock;
769         shm->ctrl = ctrl;
770
771         err = snd_pcm_new(&pcm, SND_PCM_TYPE_SHM, name, stream, mode);
772         if (err < 0) {
773                 result = err;
774                 goto _err;
775         }
776         pcm->mmap_rw = 1;
777         pcm->ops = &snd_pcm_shm_ops;
778         pcm->fast_ops = &snd_pcm_shm_fast_ops;
779         pcm->private_data = shm;
780         err = snd_pcm_shm_poll_descriptor(pcm);
781         if (err < 0) {
782                 snd_pcm_close(pcm);
783                 return err;
784         }
785         pcm->poll_fd = err;
786         pcm->poll_events = stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
787         snd_pcm_set_hw_ptr(pcm, &ctrl->hw.ptr, -1, 0);
788         snd_pcm_set_appl_ptr(pcm, &ctrl->appl.ptr, -1, 0);
789         *pcmp = pcm;
790         return 0;
791
792  _err:
793         close(sock);
794         if (ctrl)
795                 shmdt(ctrl);
796         free(shm);
797         return result;
798 }
799
800 /*! \page pcm_plugins
801
802 \section pcm_plugins_shm Plugin: shm
803
804 This plugin communicates with aserver via shared memory. It is a raw
805 communication without any conversions, but it can be expected worse
806 performance.
807
808 \code
809 pcm.name {
810         type shm                # Shared memory PCM
811         server STR              # Server name
812         pcm STR                 # PCM name
813 }
814 \endcode
815
816 \subsection pcm_plugins_shm_funcref Function reference
817
818 <UL>
819   <LI>snd_pcm_shm_open()
820   <LI>_snd_pcm_shm_open()
821 </UL>
822
823 */
824
825 /**
826  * \brief Creates a new shm PCM
827  * \param pcmp Returns created PCM handle
828  * \param name Name of PCM
829  * \param root Root configuration node
830  * \param conf Configuration node with hw PCM description
831  * \param stream PCM Stream
832  * \param mode PCM Mode
833  * \warning Using of this function might be dangerous in the sense
834  *          of compatibility reasons. The prototype might be freely
835  *          changed in future.
836  */
837 int _snd_pcm_shm_open(snd_pcm_t **pcmp, const char *name,
838                       snd_config_t *root, snd_config_t *conf,
839                       snd_pcm_stream_t stream, int mode)
840 {
841         snd_config_iterator_t i, next;
842         const char *server = NULL;
843         const char *pcm_name = NULL;
844         snd_config_t *sconfig;
845         const char *host = NULL;
846         const char *sockname = NULL;
847         long port = -1;
848         int err;
849         int local;
850         struct hostent *h;
851         snd_config_for_each(i, next, conf) {
852                 snd_config_t *n = snd_config_iterator_entry(i);
853                 const char *id;
854                 if (snd_config_get_id(n, &id) < 0)
855                         continue;
856                 if (snd_pcm_conf_generic_id(id))
857                         continue;
858                 if (strcmp(id, "server") == 0) {
859                         err = snd_config_get_string(n, &server);
860                         if (err < 0) {
861                                 SNDERR("Invalid type for %s", id);
862                                 return -EINVAL;
863                         }
864                         continue;
865                 }
866                 if (strcmp(id, "pcm") == 0) {
867                         err = snd_config_get_string(n, &pcm_name);
868                         if (err < 0) {
869                                 SNDERR("Invalid type for %s", id);
870                                 return -EINVAL;
871                         }
872                         continue;
873                 }
874                 SNDERR("Unknown field %s", id);
875                 return -EINVAL;
876         }
877         if (!pcm_name) {
878                 SNDERR("pcm is not defined");
879                 return -EINVAL;
880         }
881         if (!server) {
882                 SNDERR("server is not defined");
883                 return -EINVAL;
884         }
885         err = snd_config_search_definition(root, "server", server, &sconfig);
886         if (err < 0) {
887                 SNDERR("Unknown server %s", server);
888                 return -EINVAL;
889         }
890         if (snd_config_get_type(sconfig) != SND_CONFIG_TYPE_COMPOUND) {
891                 SNDERR("Invalid type for server %s definition", server);
892                 goto _err;
893         }
894         snd_config_for_each(i, next, sconfig) {
895                 snd_config_t *n = snd_config_iterator_entry(i);
896                 const char *id;
897                 if (snd_config_get_id(n, &id) < 0)
898                         continue;
899                 if (strcmp(id, "comment") == 0)
900                         continue;
901                 if (strcmp(id, "host") == 0) {
902                         err = snd_config_get_string(n, &host);
903                         if (err < 0) {
904                                 SNDERR("Invalid type for %s", id);
905                                 goto _err;
906                         }
907                         continue;
908                 }
909                 if (strcmp(id, "socket") == 0) {
910                         err = snd_config_get_string(n, &sockname);
911                         if (err < 0) {
912                                 SNDERR("Invalid type for %s", id);
913                                 goto _err;
914                         }
915                         continue;
916                 }
917                 if (strcmp(id, "port") == 0) {
918                         err = snd_config_get_integer(n, &port);
919                         if (err < 0) {
920                                 SNDERR("Invalid type for %s", id);
921                                 goto _err;
922                         }
923                         continue;
924                 }
925                 SNDERR("Unknown field %s", id);
926                _err:
927                 err = -EINVAL;
928                 goto __error;
929         }
930
931         if (!host) {
932                 SNDERR("host is not defined");
933                 goto _err;
934         }
935         if (!sockname) {
936                 SNDERR("socket is not defined");
937                 goto _err;
938         }
939         h = gethostbyname(host);
940         if (!h) {
941                 SNDERR("Cannot resolve %s", host);
942                 goto _err;
943         }
944         local = snd_is_local(h);
945         if (!local) {
946                 SNDERR("%s is not the local host", host);
947                 goto _err;
948         }
949         err = snd_pcm_shm_open(pcmp, name, sockname, pcm_name, stream, mode);
950       __error:
951         snd_config_delete(sconfig);
952         return err;
953 }
954 #ifndef DOC_HIDDEN
955 SND_DLSYM_BUILD_VERSION(_snd_pcm_shm_open, SND_PCM_DLSYM_VERSION);
956 #endif