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