Home | History | Annotate | Download | only in pcm
      1 /**
      2  * \file pcm/pcm_shm.c
      3  * \ingroup PCM_Plugins
      4  * \brief PCM Shared Memory Plugin Interface
      5  * \author Abramo Bagnara <abramo (at) alsa-project.org>
      6  * \date 2000-2001
      7  */
      8 /*
      9  *  PCM - Shared Memory Client
     10  *  Copyright (c) 2000 by Abramo Bagnara <abramo (at) 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
    957