1/** 2 * \file pcm/pcm_dmix.c 3 * \ingroup PCM_Plugins 4 * \brief PCM Direct Stream Mixing (dmix) Plugin Interface 5 * \author Jaroslav Kysela <perex@perex.cz> 6 * \date 2003 7 */ 8/* 9 * PCM - Direct Stream Mixing 10 * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz> 11 * 12 * 13 * This library is free software; you can redistribute it and/or modify 14 * it under the terms of the GNU Lesser General Public License as 15 * published by the Free Software Foundation; either version 2.1 of 16 * the License, or (at your option) any later version. 17 * 18 * This program is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU Lesser General Public License for more details. 22 * 23 * You should have received a copy of the GNU Lesser General Public 24 * License along with this library; if not, write to the Free Software 25 * Foundation, Inc., 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 <unistd.h> 33#include <signal.h> 34#include <string.h> 35#include <fcntl.h> 36#include <ctype.h> 37#include <grp.h> 38#include <sys/ioctl.h> 39#include <sys/mman.h> 40#include <sys/shm.h> 41#include <sys/sem.h> 42#include <sys/wait.h> 43#include <sys/socket.h> 44#include <sys/un.h> 45#include <sys/mman.h> 46#include "pcm_direct.h" 47 48#ifndef PIC 49/* entry for static linking */ 50const char *_snd_module_pcm_dmix = ""; 51#endif 52 53#ifndef DOC_HIDDEN 54/* start is pending - this state happens when rate plugin does a delayed commit */ 55#define STATE_RUN_PENDING 1024 56#endif 57 58/* 59 * 60 */ 61 62static int shm_sum_discard(snd_pcm_direct_t *dmix); 63 64/* 65 * sum ring buffer shared memory area 66 */ 67static int shm_sum_create_or_connect(snd_pcm_direct_t *dmix) 68{ 69 struct shmid_ds buf; 70 int tmpid, err; 71 size_t size; 72 73 size = dmix->shmptr->s.channels * 74 dmix->shmptr->s.buffer_size * 75 sizeof(signed int); 76retryshm: 77 dmix->u.dmix.shmid_sum = shmget(dmix->ipc_key + 1, size, 78 IPC_CREAT | dmix->ipc_perm); 79 err = -errno; 80 if (dmix->u.dmix.shmid_sum < 0) { 81 if (errno == EINVAL) 82 if ((tmpid = shmget(dmix->ipc_key + 1, 0, dmix->ipc_perm)) != -1) 83 if (!shmctl(tmpid, IPC_STAT, &buf)) 84 if (!buf.shm_nattch) 85 /* no users so destroy the segment */ 86 if (!shmctl(tmpid, IPC_RMID, NULL)) 87 goto retryshm; 88 return err; 89 } 90 if (shmctl(dmix->u.dmix.shmid_sum, IPC_STAT, &buf) < 0) { 91 err = -errno; 92 shm_sum_discard(dmix); 93 return err; 94 } 95 if (dmix->ipc_gid >= 0) { 96 buf.shm_perm.gid = dmix->ipc_gid; 97 shmctl(dmix->u.dmix.shmid_sum, IPC_SET, &buf); 98 } 99 dmix->u.dmix.sum_buffer = shmat(dmix->u.dmix.shmid_sum, 0, 0); 100 if (dmix->u.dmix.sum_buffer == (void *) -1) { 101 err = -errno; 102 shm_sum_discard(dmix); 103 return err; 104 } 105 mlock(dmix->u.dmix.sum_buffer, size); 106 return 0; 107} 108 109static int shm_sum_discard(snd_pcm_direct_t *dmix) 110{ 111 struct shmid_ds buf; 112 int ret = 0; 113 114 if (dmix->u.dmix.shmid_sum < 0) 115 return -EINVAL; 116 if (dmix->u.dmix.sum_buffer != (void *) -1 && shmdt(dmix->u.dmix.sum_buffer) < 0) 117 return -errno; 118 dmix->u.dmix.sum_buffer = (void *) -1; 119 if (shmctl(dmix->u.dmix.shmid_sum, IPC_STAT, &buf) < 0) 120 return -errno; 121 if (buf.shm_nattch == 0) { /* we're the last user, destroy the segment */ 122 if (shmctl(dmix->u.dmix.shmid_sum, IPC_RMID, NULL) < 0) 123 return -errno; 124 ret = 1; 125 } 126 dmix->u.dmix.shmid_sum = -1; 127 return ret; 128} 129 130static void dmix_server_free(snd_pcm_direct_t *dmix) 131{ 132 /* remove the memory region */ 133 shm_sum_create_or_connect(dmix); 134 shm_sum_discard(dmix); 135} 136 137/* 138 * the main function of this plugin: mixing 139 * FIXME: optimize it for different architectures 140 */ 141 142#include "pcm_dmix_generic.c" 143#if defined(__i386__) 144#include "pcm_dmix_i386.c" 145#elif defined(__x86_64__) 146#include "pcm_dmix_x86_64.c" 147#else 148#ifndef DOC_HIDDEN 149#define mix_select_callbacks(x) generic_mix_select_callbacks(x) 150#define dmix_supported_format generic_dmix_supported_format 151#endif 152#endif 153 154static void mix_areas(snd_pcm_direct_t *dmix, 155 const snd_pcm_channel_area_t *src_areas, 156 const snd_pcm_channel_area_t *dst_areas, 157 snd_pcm_uframes_t src_ofs, 158 snd_pcm_uframes_t dst_ofs, 159 snd_pcm_uframes_t size) 160{ 161 unsigned int src_step, dst_step; 162 unsigned int chn, dchn, channels, sample_size; 163 mix_areas_t *do_mix_areas; 164 165 channels = dmix->channels; 166 switch (dmix->shmptr->s.format) { 167 case SND_PCM_FORMAT_S16_LE: 168 case SND_PCM_FORMAT_S16_BE: 169 sample_size = 2; 170 do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_16; 171 break; 172 case SND_PCM_FORMAT_S32_LE: 173 case SND_PCM_FORMAT_S32_BE: 174 sample_size = 4; 175 do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_32; 176 break; 177 case SND_PCM_FORMAT_S24_LE: 178 sample_size = 4; 179 do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_24; 180 break; 181 case SND_PCM_FORMAT_S24_3LE: 182 sample_size = 3; 183 do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_24; 184 break; 185 case SND_PCM_FORMAT_U8: 186 sample_size = 1; 187 do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_u8; 188 break; 189 default: 190 return; 191 } 192 if (dmix->interleaved) { 193 /* 194 * process all areas in one loop 195 * it optimizes the memory accesses for this case 196 */ 197 do_mix_areas(size * channels, 198 (unsigned char *)dst_areas[0].addr + sample_size * dst_ofs * channels, 199 (unsigned char *)src_areas[0].addr + sample_size * src_ofs * channels, 200 dmix->u.dmix.sum_buffer + dst_ofs * channels, 201 sample_size, 202 sample_size, 203 sizeof(signed int)); 204 return; 205 } 206 for (chn = 0; chn < channels; chn++) { 207 dchn = dmix->bindings ? dmix->bindings[chn] : chn; 208 if (dchn >= dmix->shmptr->s.channels) 209 continue; 210 src_step = src_areas[chn].step / 8; 211 dst_step = dst_areas[dchn].step / 8; 212 do_mix_areas(size, 213 ((unsigned char *)dst_areas[dchn].addr + dst_areas[dchn].first / 8) + dst_ofs * dst_step, 214 ((unsigned char *)src_areas[chn].addr + src_areas[chn].first / 8) + src_ofs * src_step, 215 dmix->u.dmix.sum_buffer + channels * dst_ofs + chn, 216 dst_step, 217 src_step, 218 channels * sizeof(signed int)); 219 } 220} 221 222static void remix_areas(snd_pcm_direct_t *dmix, 223 const snd_pcm_channel_area_t *src_areas, 224 const snd_pcm_channel_area_t *dst_areas, 225 snd_pcm_uframes_t src_ofs, 226 snd_pcm_uframes_t dst_ofs, 227 snd_pcm_uframes_t size) 228{ 229 unsigned int src_step, dst_step; 230 unsigned int chn, dchn, channels, sample_size; 231 mix_areas_t *do_remix_areas; 232 233 channels = dmix->channels; 234 switch (dmix->shmptr->s.format) { 235 case SND_PCM_FORMAT_S16_LE: 236 case SND_PCM_FORMAT_S16_BE: 237 sample_size = 2; 238 do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_16; 239 break; 240 case SND_PCM_FORMAT_S32_LE: 241 case SND_PCM_FORMAT_S32_BE: 242 sample_size = 4; 243 do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_32; 244 break; 245 case SND_PCM_FORMAT_S24_LE: 246 sample_size = 4; 247 do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_24; 248 break; 249 case SND_PCM_FORMAT_S24_3LE: 250 sample_size = 3; 251 do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_24; 252 break; 253 case SND_PCM_FORMAT_U8: 254 sample_size = 1; 255 do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_u8; 256 break; 257 default: 258 return; 259 } 260 if (dmix->interleaved) { 261 /* 262 * process all areas in one loop 263 * it optimizes the memory accesses for this case 264 */ 265 do_remix_areas(size * channels, 266 (unsigned char *)dst_areas[0].addr + sample_size * dst_ofs * channels, 267 (unsigned char *)src_areas[0].addr + sample_size * src_ofs * channels, 268 dmix->u.dmix.sum_buffer + dst_ofs * channels, 269 sample_size, 270 sample_size, 271 sizeof(signed int)); 272 return; 273 } 274 for (chn = 0; chn < channels; chn++) { 275 dchn = dmix->bindings ? dmix->bindings[chn] : chn; 276 if (dchn >= dmix->shmptr->s.channels) 277 continue; 278 src_step = src_areas[chn].step / 8; 279 dst_step = dst_areas[dchn].step / 8; 280 do_remix_areas(size, 281 ((unsigned char *)dst_areas[dchn].addr + dst_areas[dchn].first / 8) + dst_ofs * dst_step, 282 ((unsigned char *)src_areas[chn].addr + src_areas[chn].first / 8) + src_ofs * src_step, 283 dmix->u.dmix.sum_buffer + channels * dst_ofs + chn, 284 dst_step, 285 src_step, 286 channels * sizeof(signed int)); 287 } 288} 289 290/* 291 * if no concurrent access is allowed in the mixing routines, we need to protect 292 * the area via semaphore 293 */ 294#ifndef DOC_HIDDEN 295#ifdef NO_CONCURRENT_ACCESS 296#define dmix_down_sem(dmix) snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT) 297#define dmix_up_sem(dmix) snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT) 298#else 299#define dmix_down_sem(dmix) 300#define dmix_up_sem(dmix) 301#endif 302#endif 303 304/* 305 * synchronize shm ring buffer with hardware 306 */ 307static void snd_pcm_dmix_sync_area(snd_pcm_t *pcm) 308{ 309 snd_pcm_direct_t *dmix = pcm->private_data; 310 snd_pcm_uframes_t slave_hw_ptr, slave_appl_ptr, slave_size; 311 snd_pcm_uframes_t appl_ptr, size, transfer; 312 const snd_pcm_channel_area_t *src_areas, *dst_areas; 313 314 /* calculate the size to transfer */ 315 /* check the available size in the local buffer 316 * last_appl_ptr keeps the last updated position 317 */ 318 size = dmix->appl_ptr - dmix->last_appl_ptr; 319 if (! size) 320 return; 321 if (size >= pcm->boundary / 2) 322 size = pcm->boundary - size; 323 324 /* the slave_app_ptr can be far behind the slave_hw_ptr */ 325 /* reduce mixing and errors here - just skip not catched writes */ 326 if (dmix->slave_hw_ptr <= dmix->slave_appl_ptr) 327 slave_size = dmix->slave_appl_ptr - dmix->slave_hw_ptr; 328 else 329 slave_size = dmix->slave_appl_ptr + (dmix->slave_boundary - dmix->slave_hw_ptr); 330 if (slave_size > dmix->slave_buffer_size) { 331 transfer = dmix->slave_buffer_size - slave_size; 332 if (transfer > size) 333 transfer = size; 334 dmix->last_appl_ptr += transfer; 335 dmix->last_appl_ptr %= pcm->boundary; 336 dmix->slave_appl_ptr += transfer; 337 dmix->slave_appl_ptr %= dmix->slave_boundary; 338 size = dmix->appl_ptr - dmix->last_appl_ptr; 339 if (! size) 340 return; 341 if (size >= pcm->boundary / 2) 342 size = pcm->boundary - size; 343 } 344 345 /* check the available size in the slave PCM buffer */ 346 slave_hw_ptr = dmix->slave_hw_ptr; 347 /* don't write on the last active period - this area may be cleared 348 * by the driver during mix operation... 349 */ 350 slave_hw_ptr -= slave_hw_ptr % dmix->slave_period_size; 351 slave_hw_ptr += dmix->slave_buffer_size; 352 if (slave_hw_ptr >= dmix->slave_boundary) 353 slave_hw_ptr -= dmix->slave_boundary; 354 if (slave_hw_ptr < dmix->slave_appl_ptr) 355 slave_size = slave_hw_ptr + (dmix->slave_boundary - dmix->slave_appl_ptr); 356 else 357 slave_size = slave_hw_ptr - dmix->slave_appl_ptr; 358 if (slave_size < size) 359 size = slave_size; 360 if (! size) 361 return; 362 363 /* add sample areas here */ 364 src_areas = snd_pcm_mmap_areas(pcm); 365 dst_areas = snd_pcm_mmap_areas(dmix->spcm); 366 appl_ptr = dmix->last_appl_ptr % pcm->buffer_size; 367 dmix->last_appl_ptr += size; 368 dmix->last_appl_ptr %= pcm->boundary; 369 slave_appl_ptr = dmix->slave_appl_ptr % dmix->slave_buffer_size; 370 dmix->slave_appl_ptr += size; 371 dmix->slave_appl_ptr %= dmix->slave_boundary; 372 dmix_down_sem(dmix); 373 for (;;) { 374 transfer = size; 375 if (appl_ptr + transfer > pcm->buffer_size) 376 transfer = pcm->buffer_size - appl_ptr; 377 if (slave_appl_ptr + transfer > dmix->slave_buffer_size) 378 transfer = dmix->slave_buffer_size - slave_appl_ptr; 379 mix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer); 380 size -= transfer; 381 if (! size) 382 break; 383 slave_appl_ptr += transfer; 384 slave_appl_ptr %= dmix->slave_buffer_size; 385 appl_ptr += transfer; 386 appl_ptr %= pcm->buffer_size; 387 } 388 dmix_up_sem(dmix); 389} 390 391/* 392 * synchronize hardware pointer (hw_ptr) with ours 393 */ 394static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm) 395{ 396 snd_pcm_direct_t *dmix = pcm->private_data; 397 snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail; 398 snd_pcm_sframes_t diff; 399 400 switch (snd_pcm_state(dmix->spcm)) { 401 case SND_PCM_STATE_DISCONNECTED: 402 dmix->state = SND_PCM_STATE_DISCONNECTED; 403 return -ENODEV; 404 default: 405 break; 406 } 407 if (dmix->slowptr) 408 snd_pcm_hwsync(dmix->spcm); 409 old_slave_hw_ptr = dmix->slave_hw_ptr; 410 slave_hw_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr; 411 diff = slave_hw_ptr - old_slave_hw_ptr; 412 if (diff == 0) /* fast path */ 413 return 0; 414 if (dmix->state != SND_PCM_STATE_RUNNING && 415 dmix->state != SND_PCM_STATE_DRAINING) 416 /* not really started yet - don't update hw_ptr */ 417 return 0; 418 if (diff < 0) { 419 slave_hw_ptr += dmix->slave_boundary; 420 diff = slave_hw_ptr - old_slave_hw_ptr; 421 } 422 dmix->hw_ptr += diff; 423 dmix->hw_ptr %= pcm->boundary; 424 if (pcm->stop_threshold >= pcm->boundary) /* don't care */ 425 return 0; 426 avail = snd_pcm_mmap_playback_avail(pcm); 427 if (avail > dmix->avail_max) 428 dmix->avail_max = avail; 429 if (avail >= pcm->stop_threshold) { 430 snd_timer_stop(dmix->timer); 431 gettimestamp(&dmix->trigger_tstamp, pcm->monotonic); 432 if (dmix->state == SND_PCM_STATE_RUNNING) { 433 dmix->state = SND_PCM_STATE_XRUN; 434 return -EPIPE; 435 } 436 dmix->state = SND_PCM_STATE_SETUP; 437 /* clear queue to remove pending poll events */ 438 snd_pcm_direct_clear_timer_queue(dmix); 439 } 440 return 0; 441} 442 443/* 444 * plugin implementation 445 */ 446 447static snd_pcm_state_t snd_pcm_dmix_state(snd_pcm_t *pcm) 448{ 449 snd_pcm_direct_t *dmix = pcm->private_data; 450 snd_pcm_state_t state; 451 state = snd_pcm_state(dmix->spcm); 452 switch (state) { 453 case SND_PCM_STATE_SUSPENDED: 454 return state; 455 case SND_PCM_STATE_DISCONNECTED: 456 return state; 457 default: 458 break; 459 } 460 if (dmix->state == STATE_RUN_PENDING) 461 return SNDRV_PCM_STATE_RUNNING; 462 return dmix->state; 463} 464 465static int snd_pcm_dmix_status(snd_pcm_t *pcm, snd_pcm_status_t * status) 466{ 467 snd_pcm_direct_t *dmix = pcm->private_data; 468 469 switch (dmix->state) { 470 case SNDRV_PCM_STATE_DRAINING: 471 case SNDRV_PCM_STATE_RUNNING: 472 snd_pcm_dmix_sync_ptr(pcm); 473 break; 474 default: 475 break; 476 } 477 memset(status, 0, sizeof(*status)); 478 status->state = snd_pcm_dmix_state(pcm); 479 status->trigger_tstamp = dmix->trigger_tstamp; 480 gettimestamp(&status->tstamp, pcm->monotonic); 481 status->avail = snd_pcm_mmap_playback_avail(pcm); 482 status->avail_max = status->avail > dmix->avail_max ? status->avail : dmix->avail_max; 483 dmix->avail_max = 0; 484 return 0; 485} 486 487static int snd_pcm_dmix_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) 488{ 489 snd_pcm_direct_t *dmix = pcm->private_data; 490 int err; 491 492 switch(dmix->state) { 493 case SNDRV_PCM_STATE_DRAINING: 494 case SNDRV_PCM_STATE_RUNNING: 495 err = snd_pcm_dmix_sync_ptr(pcm); 496 if (err < 0) 497 return err; 498 /* fallthru */ 499 case SNDRV_PCM_STATE_PREPARED: 500 case SNDRV_PCM_STATE_SUSPENDED: 501 case STATE_RUN_PENDING: 502 *delayp = snd_pcm_mmap_playback_hw_avail(pcm); 503 return 0; 504 case SNDRV_PCM_STATE_XRUN: 505 return -EPIPE; 506 case SNDRV_PCM_STATE_DISCONNECTED: 507 return -ENODEV; 508 default: 509 return -EBADFD; 510 } 511} 512 513static int snd_pcm_dmix_hwsync(snd_pcm_t *pcm) 514{ 515 snd_pcm_direct_t *dmix = pcm->private_data; 516 517 switch(dmix->state) { 518 case SNDRV_PCM_STATE_DRAINING: 519 case SNDRV_PCM_STATE_RUNNING: 520 /* sync slave PCM */ 521 return snd_pcm_dmix_sync_ptr(pcm); 522 case SNDRV_PCM_STATE_PREPARED: 523 case SNDRV_PCM_STATE_SUSPENDED: 524 case STATE_RUN_PENDING: 525 return 0; 526 case SNDRV_PCM_STATE_XRUN: 527 return -EPIPE; 528 case SNDRV_PCM_STATE_DISCONNECTED: 529 return -ENODEV; 530 default: 531 return -EBADFD; 532 } 533} 534 535static int snd_pcm_dmix_prepare(snd_pcm_t *pcm) 536{ 537 snd_pcm_direct_t *dmix = pcm->private_data; 538 539 snd_pcm_direct_check_interleave(dmix, pcm); 540 dmix->state = SND_PCM_STATE_PREPARED; 541 dmix->appl_ptr = dmix->last_appl_ptr = 0; 542 dmix->hw_ptr = 0; 543 return snd_pcm_direct_set_timer_params(dmix); 544} 545 546static void reset_slave_ptr(snd_pcm_t *pcm, snd_pcm_direct_t *dmix) 547{ 548 dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr; 549 if (pcm->buffer_size > pcm->period_size * 2) 550 return; 551 /* If we have too litte periods, better to align the start position 552 * to the period boundary so that the interrupt can be handled properly 553 * at the right time. 554 */ 555 dmix->slave_appl_ptr = ((dmix->slave_appl_ptr + dmix->slave_period_size - 1) 556 / dmix->slave_period_size) * dmix->slave_period_size; 557} 558 559static int snd_pcm_dmix_reset(snd_pcm_t *pcm) 560{ 561 snd_pcm_direct_t *dmix = pcm->private_data; 562 dmix->hw_ptr %= pcm->period_size; 563 dmix->appl_ptr = dmix->last_appl_ptr = dmix->hw_ptr; 564 reset_slave_ptr(pcm, dmix); 565 return 0; 566} 567 568static int snd_pcm_dmix_start_timer(snd_pcm_t *pcm, snd_pcm_direct_t *dmix) 569{ 570 int err; 571 572 snd_pcm_hwsync(dmix->spcm); 573 reset_slave_ptr(pcm, dmix); 574 err = snd_timer_start(dmix->timer); 575 if (err < 0) 576 return err; 577 dmix->state = SND_PCM_STATE_RUNNING; 578 return 0; 579} 580 581static int snd_pcm_dmix_start(snd_pcm_t *pcm) 582{ 583 snd_pcm_direct_t *dmix = pcm->private_data; 584 snd_pcm_sframes_t avail; 585 int err; 586 587 if (dmix->state != SND_PCM_STATE_PREPARED) 588 return -EBADFD; 589 avail = snd_pcm_mmap_playback_hw_avail(pcm); 590 if (avail == 0) 591 dmix->state = STATE_RUN_PENDING; 592 else if (avail < 0) 593 return 0; 594 else { 595 if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0) 596 return err; 597 snd_pcm_dmix_sync_area(pcm); 598 } 599 gettimestamp(&dmix->trigger_tstamp, pcm->monotonic); 600 return 0; 601} 602 603static int snd_pcm_dmix_drop(snd_pcm_t *pcm) 604{ 605 snd_pcm_direct_t *dmix = pcm->private_data; 606 if (dmix->state == SND_PCM_STATE_OPEN) 607 return -EBADFD; 608 dmix->state = SND_PCM_STATE_SETUP; 609 snd_pcm_direct_timer_stop(dmix); 610 return 0; 611} 612 613static int snd_pcm_dmix_drain(snd_pcm_t *pcm) 614{ 615 snd_pcm_direct_t *dmix = pcm->private_data; 616 snd_pcm_uframes_t stop_threshold; 617 int err; 618 619 if (dmix->state == SND_PCM_STATE_OPEN) 620 return -EBADFD; 621 if (pcm->mode & SND_PCM_NONBLOCK) 622 return -EAGAIN; 623 if (dmix->state == SND_PCM_STATE_PREPARED) { 624 if (snd_pcm_mmap_playback_hw_avail(pcm) > 0) 625 snd_pcm_dmix_start(pcm); 626 else { 627 snd_pcm_dmix_drop(pcm); 628 return 0; 629 } 630 } 631 632 if (dmix->state == SND_PCM_STATE_XRUN) { 633 snd_pcm_dmix_drop(pcm); 634 return 0; 635 } 636 637 stop_threshold = pcm->stop_threshold; 638 if (pcm->stop_threshold > pcm->buffer_size) 639 pcm->stop_threshold = pcm->buffer_size; 640 dmix->state = SND_PCM_STATE_DRAINING; 641 do { 642 err = snd_pcm_dmix_sync_ptr(pcm); 643 if (err < 0) { 644 snd_pcm_dmix_drop(pcm); 645 return err; 646 } 647 if (dmix->state == SND_PCM_STATE_DRAINING) { 648 snd_pcm_dmix_sync_area(pcm); 649 snd_pcm_wait_nocheck(pcm, -1); 650 snd_pcm_direct_clear_timer_queue(dmix); /* force poll to wait */ 651 } 652 } while (dmix->state == SND_PCM_STATE_DRAINING); 653 pcm->stop_threshold = stop_threshold; 654 return 0; 655} 656 657static int snd_pcm_dmix_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED) 658{ 659 return -EIO; 660} 661 662static snd_pcm_sframes_t snd_pcm_dmix_rewindable(snd_pcm_t *pcm) 663{ 664 return snd_pcm_mmap_hw_avail(pcm); 665} 666 667static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 668{ 669 snd_pcm_direct_t *dmix = pcm->private_data; 670 snd_pcm_uframes_t slave_appl_ptr, slave_size; 671 snd_pcm_uframes_t appl_ptr, size, transfer, result; 672 const snd_pcm_channel_area_t *src_areas, *dst_areas; 673 674 if (dmix->state == SND_PCM_STATE_RUNNING || 675 dmix->state == SND_PCM_STATE_DRAINING) 676 return snd_pcm_dmix_hwsync(pcm); 677 678 if (dmix->last_appl_ptr < dmix->appl_ptr) 679 size = dmix->appl_ptr - dmix->last_appl_ptr; 680 else 681 size = dmix->appl_ptr + (pcm->boundary - dmix->last_appl_ptr); 682 if (frames < size) 683 size = frames; 684 snd_pcm_mmap_appl_backward(pcm, size); 685 frames -= size; 686 if (!frames) 687 return size; 688 result = size; 689 690 if (dmix->hw_ptr < dmix->appl_ptr) 691 size = dmix->appl_ptr - dmix->hw_ptr; 692 else 693 size = dmix->appl_ptr + (pcm->boundary - dmix->hw_ptr); 694 if (size > frames) 695 size = frames; 696 if (dmix->slave_hw_ptr < dmix->slave_appl_ptr) 697 slave_size = dmix->slave_appl_ptr - dmix->slave_hw_ptr; 698 else 699 slave_size = dmix->slave_appl_ptr + (pcm->boundary - dmix->slave_hw_ptr); 700 if (slave_size < size) 701 size = slave_size; 702 frames -= size; 703 result += size; 704 705 /* add sample areas here */ 706 src_areas = snd_pcm_mmap_areas(pcm); 707 dst_areas = snd_pcm_mmap_areas(dmix->spcm); 708 dmix->last_appl_ptr -= size; 709 dmix->last_appl_ptr %= pcm->boundary; 710 appl_ptr = dmix->last_appl_ptr % pcm->buffer_size; 711 dmix->slave_appl_ptr -= size; 712 dmix->slave_appl_ptr %= dmix->slave_boundary; 713 slave_appl_ptr = dmix->slave_appl_ptr % dmix->slave_buffer_size; 714 dmix_down_sem(dmix); 715 for (;;) { 716 transfer = size; 717 if (appl_ptr + transfer > pcm->buffer_size) 718 transfer = pcm->buffer_size - appl_ptr; 719 if (slave_appl_ptr + transfer > dmix->slave_buffer_size) 720 transfer = dmix->slave_buffer_size - slave_appl_ptr; 721 remix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer); 722 size -= transfer; 723 if (! size) 724 break; 725 slave_appl_ptr += transfer; 726 slave_appl_ptr %= dmix->slave_buffer_size; 727 appl_ptr += transfer; 728 appl_ptr %= pcm->buffer_size; 729 } 730 dmix->last_appl_ptr -= frames; 731 dmix->last_appl_ptr %= pcm->boundary; 732 dmix->slave_appl_ptr -= frames; 733 dmix->slave_appl_ptr %= dmix->slave_boundary; 734 dmix_up_sem(dmix); 735 736 snd_pcm_mmap_appl_backward(pcm, frames); 737 738 return result + frames; 739} 740 741static snd_pcm_sframes_t snd_pcm_dmix_forwardable(snd_pcm_t *pcm) 742{ 743 return snd_pcm_mmap_avail(pcm); 744} 745 746static snd_pcm_sframes_t snd_pcm_dmix_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 747{ 748 snd_pcm_sframes_t avail; 749 750 avail = snd_pcm_mmap_playback_avail(pcm); 751 if (avail < 0) 752 return 0; 753 if (frames > (snd_pcm_uframes_t)avail) 754 frames = avail; 755 snd_pcm_mmap_appl_forward(pcm, frames); 756 return frames; 757} 758 759static snd_pcm_sframes_t snd_pcm_dmix_readi(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED) 760{ 761 return -ENODEV; 762} 763 764static snd_pcm_sframes_t snd_pcm_dmix_readn(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED) 765{ 766 return -ENODEV; 767} 768 769static int snd_pcm_dmix_close(snd_pcm_t *pcm) 770{ 771 snd_pcm_direct_t *dmix = pcm->private_data; 772 773 if (dmix->timer) 774 snd_timer_close(dmix->timer); 775 snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT); 776 snd_pcm_close(dmix->spcm); 777 if (dmix->server) 778 snd_pcm_direct_server_discard(dmix); 779 if (dmix->client) 780 snd_pcm_direct_client_discard(dmix); 781 shm_sum_discard(dmix); 782 if (snd_pcm_direct_shm_discard(dmix)) { 783 if (snd_pcm_direct_semaphore_discard(dmix)) 784 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); 785 } else 786 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); 787 free(dmix->bindings); 788 pcm->private_data = NULL; 789 free(dmix); 790 return 0; 791} 792 793static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm, 794 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, 795 snd_pcm_uframes_t size) 796{ 797 snd_pcm_direct_t *dmix = pcm->private_data; 798 int err; 799 800 switch (snd_pcm_state(dmix->spcm)) { 801 case SND_PCM_STATE_XRUN: 802 return -EPIPE; 803 case SND_PCM_STATE_SUSPENDED: 804 return -ESTRPIPE; 805 default: 806 break; 807 } 808 if (! size) 809 return 0; 810 snd_pcm_mmap_appl_forward(pcm, size); 811 if (dmix->state == STATE_RUN_PENDING) { 812 if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0) 813 return err; 814 } else if (dmix->state == SND_PCM_STATE_RUNNING || 815 dmix->state == SND_PCM_STATE_DRAINING) 816 snd_pcm_dmix_sync_ptr(pcm); 817 if (dmix->state == SND_PCM_STATE_RUNNING || 818 dmix->state == SND_PCM_STATE_DRAINING) { 819 /* ok, we commit the changes after the validation of area */ 820 /* it's intended, although the result might be crappy */ 821 snd_pcm_dmix_sync_area(pcm); 822 /* clear timer queue to avoid a bogus return from poll */ 823 if (snd_pcm_mmap_playback_avail(pcm) < pcm->avail_min) 824 snd_pcm_direct_clear_timer_queue(dmix); 825 } 826 return size; 827} 828 829static snd_pcm_sframes_t snd_pcm_dmix_avail_update(snd_pcm_t *pcm) 830{ 831 snd_pcm_direct_t *dmix = pcm->private_data; 832 833 if (dmix->state == SND_PCM_STATE_RUNNING || 834 dmix->state == SND_PCM_STATE_DRAINING) 835 snd_pcm_dmix_sync_ptr(pcm); 836 return snd_pcm_mmap_playback_avail(pcm); 837} 838 839static int snd_pcm_dmix_htimestamp(snd_pcm_t *pcm, 840 snd_pcm_uframes_t *avail, 841 snd_htimestamp_t *tstamp) 842{ 843 snd_pcm_direct_t *dmix = pcm->private_data; 844 snd_pcm_uframes_t avail1; 845 int ok = 0; 846 847 while (1) { 848 if (dmix->state == SND_PCM_STATE_RUNNING || 849 dmix->state == SND_PCM_STATE_DRAINING) 850 snd_pcm_dmix_sync_ptr(pcm); 851 avail1 = snd_pcm_mmap_playback_avail(pcm); 852 if (ok && *avail == avail1) 853 break; 854 *avail = avail1; 855 *tstamp = snd_pcm_hw_fast_tstamp(dmix->spcm); 856 } 857 return 0; 858} 859 860static int snd_pcm_dmix_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) 861{ 862 snd_pcm_direct_t *dmix = pcm->private_data; 863 if (dmix->state == SND_PCM_STATE_RUNNING) 864 snd_pcm_dmix_sync_area(pcm); 865 return snd_pcm_direct_poll_revents(pcm, pfds, nfds, revents); 866} 867 868 869static void snd_pcm_dmix_dump(snd_pcm_t *pcm, snd_output_t *out) 870{ 871 snd_pcm_direct_t *dmix = pcm->private_data; 872 873 snd_output_printf(out, "Direct Stream Mixing PCM\n"); 874 if (pcm->setup) { 875 snd_output_printf(out, "Its setup is:\n"); 876 snd_pcm_dump_setup(pcm, out); 877 } 878 if (dmix->spcm) 879 snd_pcm_dump(dmix->spcm, out); 880} 881 882static const snd_pcm_ops_t snd_pcm_dmix_ops = { 883 .close = snd_pcm_dmix_close, 884 .info = snd_pcm_direct_info, 885 .hw_refine = snd_pcm_direct_hw_refine, 886 .hw_params = snd_pcm_direct_hw_params, 887 .hw_free = snd_pcm_direct_hw_free, 888 .sw_params = snd_pcm_direct_sw_params, 889 .channel_info = snd_pcm_direct_channel_info, 890 .dump = snd_pcm_dmix_dump, 891 .nonblock = snd_pcm_direct_nonblock, 892 .async = snd_pcm_direct_async, 893 .mmap = snd_pcm_direct_mmap, 894 .munmap = snd_pcm_direct_munmap, 895}; 896 897static const snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = { 898 .status = snd_pcm_dmix_status, 899 .state = snd_pcm_dmix_state, 900 .hwsync = snd_pcm_dmix_hwsync, 901 .delay = snd_pcm_dmix_delay, 902 .prepare = snd_pcm_dmix_prepare, 903 .reset = snd_pcm_dmix_reset, 904 .start = snd_pcm_dmix_start, 905 .drop = snd_pcm_dmix_drop, 906 .drain = snd_pcm_dmix_drain, 907 .pause = snd_pcm_dmix_pause, 908 .rewindable = snd_pcm_dmix_rewindable, 909 .rewind = snd_pcm_dmix_rewind, 910 .forwardable = snd_pcm_dmix_forwardable, 911 .forward = snd_pcm_dmix_forward, 912 .resume = snd_pcm_direct_resume, 913 .link = NULL, 914 .link_slaves = NULL, 915 .unlink = NULL, 916 .writei = snd_pcm_mmap_writei, 917 .writen = snd_pcm_mmap_writen, 918 .readi = snd_pcm_dmix_readi, 919 .readn = snd_pcm_dmix_readn, 920 .avail_update = snd_pcm_dmix_avail_update, 921 .mmap_commit = snd_pcm_dmix_mmap_commit, 922 .htimestamp = snd_pcm_dmix_htimestamp, 923 .poll_descriptors = NULL, 924 .poll_descriptors_count = NULL, 925 .poll_revents = snd_pcm_dmix_poll_revents, 926}; 927 928/** 929 * \brief Creates a new dmix PCM 930 * \param pcmp Returns created PCM handle 931 * \param name Name of PCM 932 * \param opts Direct PCM configurations 933 * \param params Parameters for slave 934 * \param root Configuration root 935 * \param sconf Slave configuration 936 * \param stream PCM Direction (stream) 937 * \param mode PCM Mode 938 * \retval zero on success otherwise a negative error code 939 * \warning Using of this function might be dangerous in the sense 940 * of compatibility reasons. The prototype might be freely 941 * changed in future. 942 */ 943int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, 944 struct snd_pcm_direct_open_conf *opts, 945 struct slave_params *params, 946 snd_config_t *root, snd_config_t *sconf, 947 snd_pcm_stream_t stream, int mode) 948{ 949 snd_pcm_t *pcm = NULL, *spcm = NULL; 950 snd_pcm_direct_t *dmix = NULL; 951 int ret, first_instance; 952 int fail_sem_loop = 10; 953 954 assert(pcmp); 955 956 if (stream != SND_PCM_STREAM_PLAYBACK) { 957 SNDERR("The dmix plugin supports only playback stream"); 958 return -EINVAL; 959 } 960 961 dmix = calloc(1, sizeof(snd_pcm_direct_t)); 962 if (!dmix) { 963 ret = -ENOMEM; 964 goto _err_nosem; 965 } 966 967 ret = snd_pcm_direct_parse_bindings(dmix, params, opts->bindings); 968 if (ret < 0) 969 goto _err_nosem; 970 971 dmix->ipc_key = opts->ipc_key; 972 dmix->ipc_perm = opts->ipc_perm; 973 dmix->ipc_gid = opts->ipc_gid; 974 dmix->semid = -1; 975 dmix->shmid = -1; 976 977 ret = snd_pcm_new(&pcm, dmix->type = SND_PCM_TYPE_DMIX, name, stream, mode); 978 if (ret < 0) 979 goto _err; 980 981 982 while (1) { 983 ret = snd_pcm_direct_semaphore_create_or_connect(dmix); 984 if (ret < 0) { 985 SNDERR("unable to create IPC semaphore"); 986 goto _err_nosem; 987 } 988 ret = snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT); 989 if (ret < 0) { 990 snd_pcm_direct_semaphore_discard(dmix); 991 if (--fail_sem_loop <= 0) 992 goto _err_nosem; 993 continue; 994 } 995 break; 996 } 997 998 first_instance = ret = snd_pcm_direct_shm_create_or_connect(dmix); 999 if (ret < 0) { 1000 SNDERR("unable to create IPC shm instance"); 1001 goto _err; 1002 } 1003 1004 pcm->ops = &snd_pcm_dmix_ops; 1005 pcm->fast_ops = &snd_pcm_dmix_fast_ops; 1006 pcm->private_data = dmix; 1007 dmix->state = SND_PCM_STATE_OPEN; 1008 dmix->slowptr = opts->slowptr; 1009 dmix->max_periods = opts->max_periods; 1010 dmix->sync_ptr = snd_pcm_dmix_sync_ptr; 1011 1012 if (first_instance) { 1013 /* recursion is already checked in 1014 snd_pcm_direct_get_slave_ipc_offset() */ 1015 ret = snd_pcm_open_slave(&spcm, root, sconf, stream, 1016 mode | SND_PCM_NONBLOCK, NULL); 1017 if (ret < 0) { 1018 SNDERR("unable to open slave"); 1019 goto _err; 1020 } 1021 1022 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) { 1023 SNDERR("dmix plugin can be only connected to hw plugin"); 1024 ret = -EINVAL; 1025 goto _err; 1026 } 1027 1028 ret = snd_pcm_direct_initialize_slave(dmix, spcm, params); 1029 if (ret < 0) { 1030 SNDERR("unable to initialize slave"); 1031 goto _err; 1032 } 1033 1034 dmix->spcm = spcm; 1035 1036 if (dmix->shmptr->use_server) { 1037 dmix->server_free = dmix_server_free; 1038 1039 ret = snd_pcm_direct_server_create(dmix); 1040 if (ret < 0) { 1041 SNDERR("unable to create server"); 1042 goto _err; 1043 } 1044 } 1045 1046 dmix->shmptr->type = spcm->type; 1047 } else { 1048 if (dmix->shmptr->use_server) { 1049 /* up semaphore to avoid deadlock */ 1050 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); 1051 ret = snd_pcm_direct_client_connect(dmix); 1052 if (ret < 0) { 1053 SNDERR("unable to connect client"); 1054 goto _err_nosem; 1055 } 1056 1057 snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT); 1058 ret = snd_pcm_direct_open_secondary_client(&spcm, dmix, "dmix_client"); 1059 if (ret < 0) 1060 goto _err; 1061 } else { 1062 1063 ret = snd_pcm_open_slave(&spcm, root, sconf, stream, 1064 mode | SND_PCM_NONBLOCK | 1065 SND_PCM_APPEND, 1066 NULL); 1067 if (ret < 0) { 1068 SNDERR("unable to open slave"); 1069 goto _err; 1070 } 1071 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) { 1072 SNDERR("dmix plugin can be only connected to hw plugin"); 1073 ret = -EINVAL; 1074 goto _err; 1075 } 1076 1077 ret = snd_pcm_direct_initialize_secondary_slave(dmix, spcm, params); 1078 if (ret < 0) { 1079 SNDERR("unable to initialize slave"); 1080 goto _err; 1081 } 1082 } 1083 1084 dmix->spcm = spcm; 1085 } 1086 1087 ret = shm_sum_create_or_connect(dmix); 1088 if (ret < 0) { 1089 SNDERR("unable to initialize sum ring buffer"); 1090 goto _err; 1091 } 1092 1093 ret = snd_pcm_direct_initialize_poll_fd(dmix); 1094 if (ret < 0) { 1095 SNDERR("unable to initialize poll_fd"); 1096 goto _err; 1097 } 1098 1099 mix_select_callbacks(dmix); 1100 1101 pcm->poll_fd = dmix->poll_fd; 1102 pcm->poll_events = POLLIN; /* it's different than other plugins */ 1103 1104 pcm->mmap_rw = 1; 1105 snd_pcm_set_hw_ptr(pcm, &dmix->hw_ptr, -1, 0); 1106 snd_pcm_set_appl_ptr(pcm, &dmix->appl_ptr, -1, 0); 1107 1108 if (dmix->channels == UINT_MAX) 1109 dmix->channels = dmix->shmptr->s.channels; 1110 1111 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); 1112 1113 *pcmp = pcm; 1114 return 0; 1115 1116 _err: 1117 if (dmix->timer) 1118 snd_timer_close(dmix->timer); 1119 if (dmix->server) 1120 snd_pcm_direct_server_discard(dmix); 1121 if (dmix->client) 1122 snd_pcm_direct_client_discard(dmix); 1123 if (spcm) 1124 snd_pcm_close(spcm); 1125 if (dmix->u.dmix.shmid_sum >= 0) 1126 shm_sum_discard(dmix); 1127 if (dmix->shmid >= 0) 1128 snd_pcm_direct_shm_discard(dmix); 1129 if (snd_pcm_direct_semaphore_discard(dmix) < 0) 1130 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); 1131 _err_nosem: 1132 if (dmix) { 1133 free(dmix->bindings); 1134 free(dmix); 1135 } 1136 if (pcm) 1137 snd_pcm_free(pcm); 1138 return ret; 1139} 1140 1141/*! \page pcm_plugins 1142 1143\section pcm_plugins_dmix Plugin: dmix 1144 1145This plugin provides direct mixing of multiple streams. The resolution 1146for 32-bit mixing is only 24-bit. The low significant byte is filled with 1147zeros. The extra 8 bits are used for the saturation. 1148 1149\code 1150pcm.name { 1151 type dmix # Direct mix 1152 ipc_key INT # unique IPC key 1153 ipc_key_add_uid BOOL # add current uid to unique IPC key 1154 ipc_perm INT # IPC permissions (octal, default 0600) 1155 slave STR 1156 # or 1157 slave { # Slave definition 1158 pcm STR # slave PCM name 1159 # or 1160 pcm { } # slave PCM definition 1161 format STR # format definition 1162 rate INT # rate definition 1163 channels INT 1164 period_time INT # in usec 1165 # or 1166 period_size INT # in bytes 1167 buffer_time INT # in usec 1168 # or 1169 buffer_size INT # in bytes 1170 periods INT # when buffer_size or buffer_time is not specified 1171 } 1172 bindings { # note: this is client independent!!! 1173 N INT # maps slave channel to client channel N 1174 } 1175 slowptr BOOL # slow but more precise pointer updates 1176} 1177\endcode 1178 1179<code>ipc_key</code> specfies the unique IPC key in integer. 1180This number must be unique for each different dmix definition, 1181since the shared memory is created with this key number. 1182When <code>ipc_key_add_uid</code> is set true, the uid value is 1183added to the value set in <code>ipc_key</code>. This will 1184avoid the confliction of the same IPC key with different users 1185concurrently. 1186 1187Note that the dmix plugin itself supports only a single configuration. 1188That is, it supports only the fixed rate (default 48000), format 1189(\c S16), channels (2), and period_time (125000). 1190For using other configuration, you have to set the value explicitly 1191in the slave PCM definition. The rate, format and channels can be 1192covered by an additional \ref pcm_plugins_dmix "plug plugin", 1193but there is only one base configuration, anyway. 1194 1195An example configuration for setting 44100 Hz, \c S32_LE format 1196as the slave PCM of "hw:0" is like below: 1197\code 1198pcm.dmix_44 { 1199 type dmix 1200 ipc_key 321456 # any unique value 1201 ipc_key_add_uid true 1202 slave { 1203 pcm "hw:0" 1204 format S32_LE 1205 rate 44100 1206 } 1207} 1208\endcode 1209You can hear 48000 Hz samples still using this dmix pcm via plug plugin 1210like: 1211\code 1212% aplay -Dplug:dmix_44 foo_48k.wav 1213\endcode 1214 1215For using the dmix plugin for OSS emulation device, you have to set 1216the period and the buffer sizes in power of two. For example, 1217\code 1218pcm.dmixoss { 1219 type dmix 1220 ipc_key 321456 # any unique value 1221 ipc_key_add_uid true 1222 slave { 1223 pcm "hw:0" 1224 period_time 0 1225 period_size 1024 # must be power of 2 1226 buffer_size 8192 # ditto 1227 } 1228} 1229\endcode 1230<code>period_time 0</code> must be set, too, for resetting the 1231default value. In the case of soundcards with multi-channel IO, 1232adding the bindings would help 1233\code 1234pcm.dmixoss { 1235 ... 1236 bindings { 1237 0 0 # map from 0 to 0 1238 1 1 # map from 1 to 1 1239 } 1240} 1241\endcode 1242so that only the first two channels are used by dmix. 1243Also, note that ICE1712 have the limited buffer size, 5513 frames 1244(corresponding to 640 kB). In this case, reduce the buffer_size 1245to 4096. 1246 1247\subsection pcm_plugins_dmix_funcref Function reference 1248 1249<UL> 1250 <LI>snd_pcm_dmix_open() 1251 <LI>_snd_pcm_dmix_open() 1252</UL> 1253 1254*/ 1255 1256/** 1257 * \brief Creates a new dmix PCM 1258 * \param pcmp Returns created PCM handle 1259 * \param name Name of PCM 1260 * \param root Root configuration node 1261 * \param conf Configuration node with dmix PCM description 1262 * \param stream PCM Stream 1263 * \param mode PCM Mode 1264 * \warning Using of this function might be dangerous in the sense 1265 * of compatibility reasons. The prototype might be freely 1266 * changed in future. 1267 */ 1268int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, 1269 snd_config_t *root, snd_config_t *conf, 1270 snd_pcm_stream_t stream, int mode) 1271{ 1272 snd_config_t *sconf; 1273 struct slave_params params; 1274 struct snd_pcm_direct_open_conf dopen; 1275 int bsize, psize; 1276 int err; 1277 1278 err = snd_pcm_direct_parse_open_conf(root, conf, stream, &dopen); 1279 if (err < 0) 1280 return err; 1281 1282 /* the default settings, it might be invalid for some hardware */ 1283 params.format = SND_PCM_FORMAT_S16; 1284 params.rate = 48000; 1285 params.channels = 2; 1286 params.period_time = -1; 1287 params.buffer_time = -1; 1288 bsize = psize = -1; 1289 params.periods = 3; 1290 1291 err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8, 1292 SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, ¶ms.format, 1293 SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate, 1294 SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels, 1295 SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time, 1296 SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time, 1297 SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize, 1298 SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize, 1299 SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods); 1300 if (err < 0) 1301 return err; 1302 1303 /* set a reasonable default */ 1304 if (psize == -1 && params.period_time == -1) 1305 params.period_time = 125000; /* 0.125 seconds */ 1306 1307 if (params.format == -2) 1308 params.format = SND_PCM_FORMAT_UNKNOWN; 1309 else if (!(dmix_supported_format & (1ULL << params.format))) { 1310 /* sorry, limited features */ 1311 SNDERR("Unsupported format"); 1312 snd_config_delete(sconf); 1313 return -EINVAL; 1314 } 1315 1316 params.period_size = psize; 1317 params.buffer_size = bsize; 1318 1319 err = snd_pcm_dmix_open(pcmp, name, &dopen, ¶ms, 1320 root, sconf, stream, mode); 1321 snd_config_delete(sconf); 1322 return err; 1323} 1324#ifndef DOC_HIDDEN 1325SND_DLSYM_BUILD_VERSION(_snd_pcm_dmix_open, SND_PCM_DLSYM_VERSION); 1326#endif 1327