1/** 2 * \file pcm/pcm_multi.c 3 * \ingroup PCM_Plugins 4 * \brief PCM Multi Streams to One Conversion Plugin Interface 5 * \author Abramo Bagnara <abramo@alsa-project.org> 6 * \date 2000-2001 7 */ 8/* 9 * PCM - Multi 10 * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org> 11 * 12 * 13 * This library is free software; you can redistribute it and/or modify 14 * it under the terms of the GNU Lesser General Public License as 15 * published by the Free Software Foundation; either version 2.1 of 16 * the License, or (at your option) any later version. 17 * 18 * This program is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU Lesser General Public License for more details. 22 * 23 * You should have received a copy of the GNU Lesser General Public 24 * License along with this library; if not, write to the Free Software 25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 26 * 27 */ 28 29#include <stdio.h> 30#include <stdlib.h> 31#include <unistd.h> 32#include <string.h> 33#include <math.h> 34#include "pcm_local.h" 35#include "pcm_generic.h" 36 37#ifndef PIC 38/* entry for static linking */ 39const char *_snd_module_pcm_multi = ""; 40#endif 41 42#ifndef DOC_HIDDEN 43 44typedef struct { 45 snd_pcm_t *pcm; 46 unsigned int channels_count; 47 int close_slave; 48 snd_pcm_t *linked; 49} snd_pcm_multi_slave_t; 50 51typedef struct { 52 int slave_idx; 53 unsigned int slave_channel; 54} snd_pcm_multi_channel_t; 55 56typedef struct { 57 unsigned int slaves_count; 58 unsigned int master_slave; 59 snd_pcm_multi_slave_t *slaves; 60 unsigned int channels_count; 61 snd_pcm_multi_channel_t *channels; 62} snd_pcm_multi_t; 63 64#endif 65 66static int snd_pcm_multi_close(snd_pcm_t *pcm) 67{ 68 snd_pcm_multi_t *multi = pcm->private_data; 69 unsigned int i; 70 int ret = 0; 71 for (i = 0; i < multi->slaves_count; ++i) { 72 snd_pcm_multi_slave_t *slave = &multi->slaves[i]; 73 if (slave->close_slave) { 74 int err = snd_pcm_close(slave->pcm); 75 if (err < 0) 76 ret = err; 77 } 78 } 79 free(multi->slaves); 80 free(multi->channels); 81 free(multi); 82 return ret; 83} 84 85static int snd_pcm_multi_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED) 86{ 87 return 0; 88} 89 90static int snd_pcm_multi_async(snd_pcm_t *pcm, int sig, pid_t pid) 91{ 92 snd_pcm_multi_t *multi = pcm->private_data; 93 snd_pcm_t *slave_0 = multi->slaves[multi->master_slave].pcm; 94 return snd_pcm_async(slave_0, sig, pid); 95} 96 97static int snd_pcm_multi_poll_descriptors_count(snd_pcm_t *pcm) 98{ 99 snd_pcm_multi_t *multi = pcm->private_data; 100 snd_pcm_t *slave_0 = multi->slaves[multi->master_slave].pcm; 101 return snd_pcm_poll_descriptors_count(slave_0); 102} 103 104static int snd_pcm_multi_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space) 105{ 106 snd_pcm_multi_t *multi = pcm->private_data; 107 snd_pcm_t *slave; 108 snd_pcm_t *slave_0 = multi->slaves[multi->master_slave].pcm; 109 int err; 110 unsigned int i; 111 112 for (i = 0; i < multi->slaves_count; ++i) { 113 slave = multi->slaves[i].pcm; 114 if (slave == slave_0) 115 continue; 116 err = snd_pcm_poll_descriptors(slave, pfds, space); 117 if (err < 0) 118 return err; 119 } 120 /* finally overwrite with master's pfds */ 121 return snd_pcm_poll_descriptors(slave_0, pfds, space); 122} 123 124static int snd_pcm_multi_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) 125{ 126 snd_pcm_multi_t *multi = pcm->private_data; 127 snd_pcm_t *slave_0 = multi->slaves[multi->master_slave].pcm; 128 return snd_pcm_poll_descriptors_revents(slave_0, pfds, nfds, revents); 129} 130 131static int snd_pcm_multi_info(snd_pcm_t *pcm, snd_pcm_info_t *info) 132{ 133 snd_pcm_multi_t *multi = pcm->private_data; 134 int err, n; 135 assert(info->subdevice < multi->slaves_count); 136 n = info->subdevice; 137 info->subdevice = 0; 138 err = snd_pcm_info(multi->slaves[n].pcm, info); 139 if (err < 0) 140 return err; 141 info->subdevices_count = multi->slaves_count; 142 return 0; 143} 144 145static int snd_pcm_multi_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 146{ 147 snd_pcm_multi_t *multi = pcm->private_data; 148 snd_pcm_access_mask_t access_mask; 149 int err; 150 snd_pcm_access_mask_any(&access_mask); 151 snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED); 152 err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, 153 &access_mask); 154 if (err < 0) 155 return err; 156 err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS, 157 multi->channels_count, 0); 158 if (err < 0) 159 return err; 160 params->info = ~0U; 161 return 0; 162} 163 164static int snd_pcm_multi_hw_refine_sprepare(snd_pcm_t *pcm, unsigned int slave_idx, 165 snd_pcm_hw_params_t *sparams) 166{ 167 snd_pcm_multi_t *multi = pcm->private_data; 168 snd_pcm_multi_slave_t *slave = &multi->slaves[slave_idx]; 169 snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; 170 _snd_pcm_hw_params_any(sparams); 171 _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, 172 &saccess_mask); 173 _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_CHANNELS, 174 slave->channels_count, 0); 175 return 0; 176} 177 178static int snd_pcm_multi_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, 179 unsigned int slave_idx ATTRIBUTE_UNUSED, 180 snd_pcm_hw_params_t *params, 181 snd_pcm_hw_params_t *sparams) 182{ 183 int err; 184 unsigned int links = (SND_PCM_HW_PARBIT_FORMAT | 185 SND_PCM_HW_PARBIT_SUBFORMAT | 186 SND_PCM_HW_PARBIT_RATE | 187 SND_PCM_HW_PARBIT_PERIOD_SIZE | 188 SND_PCM_HW_PARBIT_PERIOD_TIME | 189 SND_PCM_HW_PARBIT_PERIODS | 190 SND_PCM_HW_PARBIT_BUFFER_SIZE | 191 SND_PCM_HW_PARBIT_BUFFER_TIME | 192 SND_PCM_HW_PARBIT_TICK_TIME); 193 const snd_pcm_access_mask_t *access_mask = snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS); 194 if (!snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) && 195 !snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED) && 196 !snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) { 197 snd_pcm_access_mask_t saccess_mask; 198 snd_pcm_access_mask_any(&saccess_mask); 199 snd_pcm_access_mask_reset(&saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); 200 err = _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, 201 &saccess_mask); 202 if (err < 0) 203 return err; 204 } 205 err = _snd_pcm_hw_params_refine(sparams, links, params); 206 if (err < 0) 207 return err; 208 return 0; 209} 210 211static int snd_pcm_multi_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, 212 unsigned int slave_idx ATTRIBUTE_UNUSED, 213 snd_pcm_hw_params_t *params, 214 snd_pcm_hw_params_t *sparams) 215{ 216 int err; 217 unsigned int links = (SND_PCM_HW_PARBIT_FORMAT | 218 SND_PCM_HW_PARBIT_SUBFORMAT | 219 SND_PCM_HW_PARBIT_RATE | 220 SND_PCM_HW_PARBIT_PERIOD_SIZE | 221 SND_PCM_HW_PARBIT_PERIOD_TIME | 222 SND_PCM_HW_PARBIT_PERIODS | 223 SND_PCM_HW_PARBIT_BUFFER_SIZE | 224 SND_PCM_HW_PARBIT_BUFFER_TIME | 225 SND_PCM_HW_PARBIT_TICK_TIME); 226 snd_pcm_access_mask_t access_mask; 227 const snd_pcm_access_mask_t *saccess_mask = snd_pcm_hw_param_get_mask(sparams, SND_PCM_HW_PARAM_ACCESS); 228 snd_pcm_access_mask_any(&access_mask); 229 snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED); 230 if (!snd_pcm_access_mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) 231 snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); 232 if (!snd_pcm_access_mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_COMPLEX) && 233 !snd_pcm_access_mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED)) 234 snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_COMPLEX); 235 err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, 236 &access_mask); 237 if (err < 0) 238 return err; 239 err = _snd_pcm_hw_params_refine(params, links, sparams); 240 if (err < 0) 241 return err; 242 params->info &= sparams->info; 243 return 0; 244} 245 246static int snd_pcm_multi_hw_refine_slave(snd_pcm_t *pcm, 247 unsigned int slave_idx, 248 snd_pcm_hw_params_t *sparams) 249{ 250 snd_pcm_multi_t *multi = pcm->private_data; 251 snd_pcm_t *slave = multi->slaves[slave_idx].pcm; 252 return snd_pcm_hw_refine(slave, sparams); 253} 254 255static int snd_pcm_multi_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 256{ 257 snd_pcm_multi_t *multi = pcm->private_data; 258 unsigned int k; 259 snd_pcm_hw_params_t sparams[multi->slaves_count]; 260 int err; 261 unsigned int cmask, changed; 262 err = snd_pcm_multi_hw_refine_cprepare(pcm, params); 263 if (err < 0) 264 return err; 265 for (k = 0; k < multi->slaves_count; ++k) { 266 err = snd_pcm_multi_hw_refine_sprepare(pcm, k, &sparams[k]); 267 if (err < 0) { 268 SNDERR("Slave PCM #%d not usable", k); 269 return err; 270 } 271 } 272 do { 273 cmask = params->cmask; 274 params->cmask = 0; 275 for (k = 0; k < multi->slaves_count; ++k) { 276 err = snd_pcm_multi_hw_refine_schange(pcm, k, params, &sparams[k]); 277 if (err >= 0) 278 err = snd_pcm_multi_hw_refine_slave(pcm, k, &sparams[k]); 279 if (err < 0) { 280 snd_pcm_multi_hw_refine_cchange(pcm, k, params, &sparams[k]); 281 return err; 282 } 283 err = snd_pcm_multi_hw_refine_cchange(pcm, k, params, &sparams[k]); 284 if (err < 0) 285 return err; 286 } 287 err = snd_pcm_hw_refine_soft(pcm, params); 288 changed = params->cmask; 289 params->cmask |= cmask; 290 if (err < 0) 291 return err; 292 } while (changed); 293 return 0; 294} 295 296static int snd_pcm_multi_hw_params_slave(snd_pcm_t *pcm, 297 unsigned int slave_idx, 298 snd_pcm_hw_params_t *sparams) 299{ 300 snd_pcm_multi_t *multi = pcm->private_data; 301 snd_pcm_t *slave = multi->slaves[slave_idx].pcm; 302 int err = snd_pcm_hw_params(slave, sparams); 303 if (err < 0) 304 return err; 305 err = snd_pcm_areas_silence(slave->running_areas, 0, slave->channels, slave->buffer_size, slave->format); 306 if (err < 0) 307 return err; 308 if (slave->stopped_areas) { 309 err = snd_pcm_areas_silence(slave->stopped_areas, 0, slave->channels, slave->buffer_size, slave->format); 310 if (err < 0) 311 return err; 312 } 313 return 0; 314} 315 316/* reset links to the normal state 317 * slave #0 = trigger master 318 * slave #1-(N-1) = trigger slaves, linked is set to #0 319 */ 320static void reset_links(snd_pcm_multi_t *multi) 321{ 322 unsigned int i; 323 324 for (i = 0; i < multi->slaves_count; ++i) { 325 if (multi->slaves[i].linked) 326 snd_pcm_unlink(multi->slaves[i].linked); 327 multi->slaves[0].linked = NULL; 328 if (! i) 329 continue; 330 if (snd_pcm_link(multi->slaves[0].pcm, multi->slaves[i].pcm) >= 0) 331 multi->slaves[i].linked = multi->slaves[0].pcm; 332 } 333} 334 335static int snd_pcm_multi_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 336{ 337 snd_pcm_multi_t *multi = pcm->private_data; 338 unsigned int i; 339 snd_pcm_hw_params_t sparams[multi->slaves_count]; 340 int err; 341 for (i = 0; i < multi->slaves_count; ++i) { 342 err = snd_pcm_multi_hw_refine_sprepare(pcm, i, &sparams[i]); 343 assert(err >= 0); 344 err = snd_pcm_multi_hw_refine_schange(pcm, i, params, &sparams[i]); 345 assert(err >= 0); 346 err = snd_pcm_multi_hw_params_slave(pcm, i, &sparams[i]); 347 if (err < 0) { 348 snd_pcm_multi_hw_refine_cchange(pcm, i, params, &sparams[i]); 349 return err; 350 } 351 } 352 reset_links(multi); 353 return 0; 354} 355 356static int snd_pcm_multi_hw_free(snd_pcm_t *pcm) 357{ 358 snd_pcm_multi_t *multi = pcm->private_data; 359 unsigned int i; 360 int err = 0; 361 for (i = 0; i < multi->slaves_count; ++i) { 362 snd_pcm_t *slave = multi->slaves[i].pcm; 363 int e = snd_pcm_hw_free(slave); 364 if (e < 0) 365 err = e; 366 if (!multi->slaves[i].linked) 367 continue; 368 e = snd_pcm_unlink(slave); 369 if (e < 0) 370 err = e; 371 multi->slaves[i].linked = NULL; 372 } 373 return err; 374} 375 376static int snd_pcm_multi_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params) 377{ 378 snd_pcm_multi_t *multi = pcm->private_data; 379 unsigned int i; 380 int err; 381 for (i = 0; i < multi->slaves_count; ++i) { 382 snd_pcm_t *slave = multi->slaves[i].pcm; 383 err = snd_pcm_sw_params(slave, params); 384 if (err < 0) 385 return err; 386 } 387 return 0; 388} 389 390static int snd_pcm_multi_status(snd_pcm_t *pcm, snd_pcm_status_t *status) 391{ 392 snd_pcm_multi_t *multi = pcm->private_data; 393 snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm; 394 return snd_pcm_status(slave, status); 395} 396 397static snd_pcm_state_t snd_pcm_multi_state(snd_pcm_t *pcm) 398{ 399 snd_pcm_multi_t *multi = pcm->private_data; 400 snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm; 401 return snd_pcm_state(slave); 402} 403 404static int snd_pcm_multi_hwsync(snd_pcm_t *pcm) 405{ 406 snd_pcm_multi_t *multi = pcm->private_data; 407 snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm; 408 return snd_pcm_hwsync(slave); 409} 410 411static int snd_pcm_multi_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) 412{ 413 snd_pcm_multi_t *multi = pcm->private_data; 414 snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm; 415 return snd_pcm_delay(slave, delayp); 416} 417 418static snd_pcm_sframes_t snd_pcm_multi_avail_update(snd_pcm_t *pcm) 419{ 420 snd_pcm_multi_t *multi = pcm->private_data; 421 snd_pcm_sframes_t ret = LONG_MAX; 422 unsigned int i; 423 for (i = 0; i < multi->slaves_count; ++i) { 424 snd_pcm_sframes_t avail; 425 avail = snd_pcm_avail_update(multi->slaves[i].pcm); 426 if (avail < 0) 427 return avail; 428 if (ret > avail) 429 ret = avail; 430 } 431 return ret; 432} 433 434static int snd_pcm_multi_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail, 435 snd_htimestamp_t *tstamp) 436{ 437 snd_pcm_multi_t *multi = pcm->private_data; 438 snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm; 439 return snd_pcm_htimestamp(slave, avail, tstamp); 440} 441 442static int snd_pcm_multi_prepare(snd_pcm_t *pcm) 443{ 444 snd_pcm_multi_t *multi = pcm->private_data; 445 int result = 0, err; 446 unsigned int i; 447 for (i = 0; i < multi->slaves_count; ++i) { 448 /* We call prepare to each slave even if it's linked. 449 * This is to make sure to sync non-mmaped control/status. 450 */ 451 err = snd_pcm_prepare(multi->slaves[i].pcm); 452 if (err < 0) 453 result = err; 454 } 455 return result; 456} 457 458static int snd_pcm_multi_reset(snd_pcm_t *pcm) 459{ 460 snd_pcm_multi_t *multi = pcm->private_data; 461 int result = 0, err; 462 unsigned int i; 463 for (i = 0; i < multi->slaves_count; ++i) { 464 /* Reset each slave, as well as in prepare */ 465 err = snd_pcm_reset(multi->slaves[i].pcm); 466 if (err < 0) 467 result = err; 468 } 469 return result; 470} 471 472/* when the first slave PCM is linked, it means that the whole multi 473 * plugin instance is linked manually to another PCM. in this case, 474 * we need to trigger the master. 475 */ 476static int snd_pcm_multi_start(snd_pcm_t *pcm) 477{ 478 snd_pcm_multi_t *multi = pcm->private_data; 479 int err = 0; 480 unsigned int i; 481 if (multi->slaves[0].linked) 482 return snd_pcm_start(multi->slaves[0].linked); 483 for (i = 0; i < multi->slaves_count; ++i) { 484 if (multi->slaves[i].linked) 485 continue; 486 err = snd_pcm_start(multi->slaves[i].pcm); 487 if (err < 0) 488 return err; 489 } 490 return err; 491} 492 493static int snd_pcm_multi_drop(snd_pcm_t *pcm) 494{ 495 snd_pcm_multi_t *multi = pcm->private_data; 496 int err = 0; 497 unsigned int i; 498 if (multi->slaves[0].linked) 499 return snd_pcm_drop(multi->slaves[0].linked); 500 for (i = 0; i < multi->slaves_count; ++i) { 501 if (multi->slaves[i].linked) 502 continue; 503 err = snd_pcm_drop(multi->slaves[i].pcm); 504 if (err < 0) 505 return err; 506 } 507 return err; 508} 509 510static int snd_pcm_multi_drain(snd_pcm_t *pcm) 511{ 512 snd_pcm_multi_t *multi = pcm->private_data; 513 int err = 0; 514 unsigned int i; 515 if (multi->slaves[0].linked) 516 return snd_pcm_drain(multi->slaves[0].linked); 517 for (i = 0; i < multi->slaves_count; ++i) { 518 if (multi->slaves[i].linked) 519 continue; 520 err = snd_pcm_drain(multi->slaves[i].pcm); 521 if (err < 0) 522 return err; 523 } 524 return err; 525} 526 527static int snd_pcm_multi_pause(snd_pcm_t *pcm, int enable) 528{ 529 snd_pcm_multi_t *multi = pcm->private_data; 530 int err = 0; 531 unsigned int i; 532 if (multi->slaves[0].linked) 533 return snd_pcm_pause(multi->slaves[0].linked, enable); 534 for (i = 0; i < multi->slaves_count; ++i) { 535 if (multi->slaves[i].linked) 536 continue; 537 err = snd_pcm_pause(multi->slaves[i].pcm, enable); 538 if (err < 0) 539 return err; 540 } 541 return err; 542} 543 544static int snd_pcm_multi_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info) 545{ 546 snd_pcm_multi_t *multi = pcm->private_data; 547 unsigned int channel = info->channel; 548 snd_pcm_multi_channel_t *c = &multi->channels[channel]; 549 int err; 550 if (c->slave_idx < 0) 551 return -ENXIO; 552 info->channel = c->slave_channel; 553 err = snd_pcm_channel_info(multi->slaves[c->slave_idx].pcm, info); 554 info->channel = channel; 555 return err; 556} 557 558static snd_pcm_sframes_t snd_pcm_multi_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 559{ 560 snd_pcm_multi_t *multi = pcm->private_data; 561 unsigned int i; 562 snd_pcm_uframes_t pos[multi->slaves_count]; 563 memset(pos, 0, sizeof(pos)); 564 for (i = 0; i < multi->slaves_count; ++i) { 565 snd_pcm_t *slave_i = multi->slaves[i].pcm; 566 snd_pcm_sframes_t f = snd_pcm_rewind(slave_i, frames); 567 if (f < 0) 568 return f; 569 pos[i] = f; 570 frames = f; 571 } 572 /* Realign the pointers */ 573 for (i = 0; i < multi->slaves_count; ++i) { 574 snd_pcm_t *slave_i = multi->slaves[i].pcm; 575 snd_pcm_uframes_t f = pos[i] - frames; 576 snd_pcm_sframes_t result; 577 if (f > 0) { 578 result = INTERNAL(snd_pcm_forward)(slave_i, f); 579 if (result < 0) 580 return result; 581 if ((snd_pcm_uframes_t)result != f) 582 return -EIO; 583 } 584 } 585 return frames; 586} 587 588static snd_pcm_sframes_t snd_pcm_multi_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 589{ 590 snd_pcm_multi_t *multi = pcm->private_data; 591 unsigned int i; 592 snd_pcm_uframes_t pos[multi->slaves_count]; 593 memset(pos, 0, sizeof(pos)); 594 for (i = 0; i < multi->slaves_count; ++i) { 595 snd_pcm_t *slave_i = multi->slaves[i].pcm; 596 snd_pcm_sframes_t f = INTERNAL(snd_pcm_forward)(slave_i, frames); 597 if (f < 0) 598 return f; 599 pos[i] = f; 600 frames = f; 601 } 602 /* Realign the pointers */ 603 for (i = 0; i < multi->slaves_count; ++i) { 604 snd_pcm_t *slave_i = multi->slaves[i].pcm; 605 snd_pcm_uframes_t f = pos[i] - frames; 606 snd_pcm_sframes_t result; 607 if (f > 0) { 608 result = snd_pcm_rewind(slave_i, f); 609 if (result < 0) 610 return result; 611 if ((snd_pcm_uframes_t)result != f) 612 return -EIO; 613 } 614 } 615 return frames; 616} 617 618static int snd_pcm_multi_resume(snd_pcm_t *pcm) 619{ 620 snd_pcm_multi_t *multi = pcm->private_data; 621 int err = 0; 622 unsigned int i; 623 if (multi->slaves[0].linked) 624 return snd_pcm_resume(multi->slaves[0].linked); 625 for (i = 0; i < multi->slaves_count; ++i) { 626 if (multi->slaves[i].linked) 627 continue; 628 err = snd_pcm_resume(multi->slaves[i].pcm); 629 if (err < 0) 630 return err; 631 } 632 return err; 633} 634 635/* if a multi plugin instance is linked as slaves, every slave PCMs 636 * including the first one has to be relinked to the given master. 637 */ 638static int snd_pcm_multi_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master) 639{ 640 snd_pcm_multi_t *multi = pcm->private_data; 641 unsigned int i; 642 int err; 643 644 for (i = 0; i < multi->slaves_count; ++i) { 645 snd_pcm_unlink(multi->slaves[i].pcm); 646 multi->slaves[i].linked = NULL; 647 err = snd_pcm_link(master, multi->slaves[i].pcm); 648 if (err < 0) { 649 reset_links(multi); 650 return err; 651 } 652 multi->slaves[i].linked = master; 653 } 654 return 0; 655} 656 657/* linking to a multi as a master is easy - simply link to the first 658 * slave element as its own slaves are already linked. 659 */ 660static int snd_pcm_multi_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2) 661{ 662 snd_pcm_multi_t *multi = pcm1->private_data; 663 if (multi->slaves[0].pcm->fast_ops->link) 664 return multi->slaves[0].pcm->fast_ops->link(multi->slaves[0].pcm, pcm2); 665 return -ENOSYS; 666} 667 668static int snd_pcm_multi_unlink(snd_pcm_t *pcm) 669{ 670 snd_pcm_multi_t *multi = pcm->private_data; 671 unsigned int i; 672 673 for (i = 0; i < multi->slaves_count; ++i) { 674 if (multi->slaves[i].linked) 675 snd_pcm_unlink(multi->slaves[i].linked); 676 multi->slaves[0].linked = NULL; 677 } 678 return 0; 679} 680 681static snd_pcm_sframes_t snd_pcm_multi_mmap_commit(snd_pcm_t *pcm, 682 snd_pcm_uframes_t offset, 683 snd_pcm_uframes_t size) 684{ 685 snd_pcm_multi_t *multi = pcm->private_data; 686 snd_pcm_t *slave; 687 unsigned int i; 688 snd_pcm_sframes_t result; 689 690 for (i = 0; i < multi->slaves_count; ++i) { 691 slave = multi->slaves[i].pcm; 692 result = snd_pcm_mmap_commit(slave, offset, size); 693 if (result < 0) 694 return result; 695 if ((snd_pcm_uframes_t)result != size) 696 return -EIO; 697 } 698 return size; 699} 700 701static int snd_pcm_multi_munmap(snd_pcm_t *pcm) 702{ 703 free(pcm->mmap_channels); 704 free(pcm->running_areas); 705 pcm->mmap_channels = NULL; 706 pcm->running_areas = NULL; 707 return 0; 708} 709 710static int snd_pcm_multi_mmap(snd_pcm_t *pcm) 711{ 712 snd_pcm_multi_t *multi = pcm->private_data; 713 unsigned int c; 714 715 pcm->mmap_channels = calloc(pcm->channels, 716 sizeof(pcm->mmap_channels[0])); 717 pcm->running_areas = calloc(pcm->channels, 718 sizeof(pcm->running_areas[0])); 719 if (!pcm->mmap_channels || !pcm->running_areas) { 720 snd_pcm_multi_munmap(pcm); 721 return -ENOMEM; 722 } 723 724 /* Copy the slave mmapped buffer data */ 725 for (c = 0; c < pcm->channels; c++) { 726 snd_pcm_multi_channel_t *chan = &multi->channels[c]; 727 snd_pcm_t *slave; 728 if (chan->slave_idx < 0) { 729 snd_pcm_multi_munmap(pcm); 730 return -ENXIO; 731 } 732 slave = multi->slaves[chan->slave_idx].pcm; 733 pcm->mmap_channels[c] = 734 slave->mmap_channels[chan->slave_channel]; 735 pcm->mmap_channels[c].channel = c; 736 pcm->running_areas[c] = 737 slave->running_areas[chan->slave_channel]; 738 } 739 return 0; 740} 741 742static void snd_pcm_multi_dump(snd_pcm_t *pcm, snd_output_t *out) 743{ 744 snd_pcm_multi_t *multi = pcm->private_data; 745 unsigned int k; 746 snd_output_printf(out, "Multi PCM\n"); 747 snd_output_printf(out, " Channel bindings:\n"); 748 for (k = 0; k < multi->channels_count; ++k) { 749 snd_pcm_multi_channel_t *c = &multi->channels[k]; 750 if (c->slave_idx < 0) 751 continue; 752 snd_output_printf(out, " %d: slave %d, channel %d\n", 753 k, c->slave_idx, c->slave_channel); 754 } 755 if (pcm->setup) { 756 snd_output_printf(out, "Its setup is:\n"); 757 snd_pcm_dump_setup(pcm, out); 758 } 759 for (k = 0; k < multi->slaves_count; ++k) { 760 snd_output_printf(out, "Slave #%d: ", k); 761 snd_pcm_dump(multi->slaves[k].pcm, out); 762 } 763} 764 765static const snd_pcm_ops_t snd_pcm_multi_ops = { 766 .close = snd_pcm_multi_close, 767 .info = snd_pcm_multi_info, 768 .hw_refine = snd_pcm_multi_hw_refine, 769 .hw_params = snd_pcm_multi_hw_params, 770 .hw_free = snd_pcm_multi_hw_free, 771 .sw_params = snd_pcm_multi_sw_params, 772 .channel_info = snd_pcm_multi_channel_info, 773 .dump = snd_pcm_multi_dump, 774 .nonblock = snd_pcm_multi_nonblock, 775 .async = snd_pcm_multi_async, 776 .mmap = snd_pcm_multi_mmap, 777 .munmap = snd_pcm_multi_munmap, 778}; 779 780static const snd_pcm_fast_ops_t snd_pcm_multi_fast_ops = { 781 .status = snd_pcm_multi_status, 782 .state = snd_pcm_multi_state, 783 .hwsync = snd_pcm_multi_hwsync, 784 .delay = snd_pcm_multi_delay, 785 .prepare = snd_pcm_multi_prepare, 786 .reset = snd_pcm_multi_reset, 787 .start = snd_pcm_multi_start, 788 .drop = snd_pcm_multi_drop, 789 .drain = snd_pcm_multi_drain, 790 .pause = snd_pcm_multi_pause, 791 .writei = snd_pcm_mmap_writei, 792 .writen = snd_pcm_mmap_writen, 793 .readi = snd_pcm_mmap_readi, 794 .readn = snd_pcm_mmap_readn, 795 .rewind = snd_pcm_multi_rewind, 796 .forward = snd_pcm_multi_forward, 797 .resume = snd_pcm_multi_resume, 798 .link = snd_pcm_multi_link, 799 .link_slaves = snd_pcm_multi_link_slaves, 800 .unlink = snd_pcm_multi_unlink, 801 .avail_update = snd_pcm_multi_avail_update, 802 .mmap_commit = snd_pcm_multi_mmap_commit, 803 .htimestamp = snd_pcm_multi_htimestamp, 804 .poll_descriptors_count = snd_pcm_multi_poll_descriptors_count, 805 .poll_descriptors = snd_pcm_multi_poll_descriptors, 806 .poll_revents = snd_pcm_multi_poll_revents, 807}; 808 809/** 810 * \brief Creates a new Multi PCM 811 * \param pcmp Returns created PCM handle 812 * \param name Name of PCM 813 * \param slaves_count Count of slaves 814 * \param master_slave Master slave number 815 * \param slaves_pcm Array with slave PCMs 816 * \param schannels_count Array with slave channel counts 817 * \param channels_count Count of channels 818 * \param sidxs Array with channels indexes to slaves 819 * \param schannels Array with slave channels 820 * \param close_slaves When set, the slave PCM handle is closed 821 * \retval zero on success otherwise a negative error code 822 * \warning Using of this function might be dangerous in the sense 823 * of compatibility reasons. The prototype might be freely 824 * changed in future. 825 */ 826int snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name, 827 unsigned int slaves_count, unsigned int master_slave, 828 snd_pcm_t **slaves_pcm, unsigned int *schannels_count, 829 unsigned int channels_count, 830 int *sidxs, unsigned int *schannels, 831 int close_slaves) 832{ 833 snd_pcm_t *pcm; 834 snd_pcm_multi_t *multi; 835 unsigned int i; 836 snd_pcm_stream_t stream; 837 char slave_map[64][64] = { { 0 } }; 838 int err; 839 840 assert(pcmp); 841 assert(slaves_count > 0 && slaves_pcm && schannels_count); 842 assert(channels_count > 0 && sidxs && schannels); 843 assert(master_slave < slaves_count); 844 845 multi = calloc(1, sizeof(snd_pcm_multi_t)); 846 if (!multi) { 847 return -ENOMEM; 848 } 849 850 stream = slaves_pcm[0]->stream; 851 852 multi->slaves_count = slaves_count; 853 multi->master_slave = master_slave; 854 multi->slaves = calloc(slaves_count, sizeof(*multi->slaves)); 855 if (!multi->slaves) { 856 free(multi); 857 return -ENOMEM; 858 } 859 multi->channels_count = channels_count; 860 multi->channels = calloc(channels_count, sizeof(*multi->channels)); 861 if (!multi->channels) { 862 free(multi->slaves); 863 free(multi); 864 return -ENOMEM; 865 } 866 for (i = 0; i < slaves_count; ++i) { 867 snd_pcm_multi_slave_t *slave = &multi->slaves[i]; 868 assert(slaves_pcm[i]->stream == stream); 869 slave->pcm = slaves_pcm[i]; 870 slave->channels_count = schannels_count[i]; 871 slave->close_slave = close_slaves; 872 } 873 for (i = 0; i < channels_count; ++i) { 874 snd_pcm_multi_channel_t *bind = &multi->channels[i]; 875 assert(sidxs[i] < (int)slaves_count); 876 assert(schannels[i] < schannels_count[sidxs[i]]); 877 bind->slave_idx = sidxs[i]; 878 bind->slave_channel = schannels[i]; 879 if (sidxs[i] < 0) 880 continue; 881 assert(!slave_map[sidxs[i]][schannels[i]]); 882 slave_map[sidxs[i]][schannels[i]] = 1; 883 } 884 multi->channels_count = channels_count; 885 886 err = snd_pcm_new(&pcm, SND_PCM_TYPE_MULTI, name, stream, 887 multi->slaves[0].pcm->mode); 888 if (err < 0) { 889 free(multi->slaves); 890 free(multi->channels); 891 free(multi); 892 return err; 893 } 894 pcm->mmap_rw = 1; 895 pcm->mmap_shadow = 1; /* has own mmap method */ 896 pcm->ops = &snd_pcm_multi_ops; 897 pcm->fast_ops = &snd_pcm_multi_fast_ops; 898 pcm->private_data = multi; 899 pcm->poll_fd = multi->slaves[master_slave].pcm->poll_fd; 900 pcm->poll_events = multi->slaves[master_slave].pcm->poll_events; 901 pcm->monotonic = multi->slaves[master_slave].pcm->monotonic; 902 snd_pcm_link_hw_ptr(pcm, multi->slaves[master_slave].pcm); 903 snd_pcm_link_appl_ptr(pcm, multi->slaves[master_slave].pcm); 904 *pcmp = pcm; 905 return 0; 906} 907 908/*! \page pcm_plugins 909 910\section pcm_plugins_multi Plugin: Multiple streams to One 911 912This plugin converts multiple streams to one. 913 914\code 915pcm.name { 916 type multi # Multiple streams conversion PCM 917 slaves { # Slaves definition 918 ID STR # Slave PCM name 919 # or 920 ID { 921 pcm STR # Slave PCM name 922 # or 923 pcm { } # Slave PCM definition 924 channels INT # Slave channels 925 } 926 } 927 bindings { # Bindings table 928 N { 929 slave STR # Slave key 930 channel INT # Slave channel 931 } 932 } 933 [master INT] # Define the master slave 934} 935\endcode 936 937For example, to bind two PCM streams with two-channel stereo (hw:0,0 and 938hw:0,1) as one 4-channel stereo PCM stream, define like this: 939\code 940pcm.quad { 941 type multi 942 943 slaves.a.pcm "hw:0,0" 944 slaves.a.channels 2 945 slaves.b.pcm "hw:0,1" 946 slaves.b.channels 2 947 948 bindings.0.slave a 949 bindings.0.channel 0 950 bindings.1.slave a 951 bindings.1.channel 1 952 bindings.2.slave b 953 bindings.2.channel 0 954 bindings.3.slave b 955 bindings.3.channel 1 956} 957\endcode 958Note that the resultant pcm "quad" is not in the interleaved format 959but in the "complex" format. Hence, it's not accessible by applications 960which can handle only the interleaved (or the non-interleaved) format. 961In such a case, wrap this PCM with \ref pcm_plugins_route "route" or 962\ref pcm_plugins_plug "plug" plugin. 963\code 964pcm.quad2 { 965 type route 966 slave.pcm "quad" 967 ttable.0.0 1 968 ttable.1.1 1 969 ttable.2.2 1 970 ttable.3.3 1 971} 972\endcode 973 974\subsection pcm_plugins_multi_funcref Function reference 975 976<UL> 977 <LI>snd_pcm_multi_open() 978 <LI>_snd_pcm_multi_open() 979</UL> 980 981*/ 982 983/** 984 * \brief Creates a new Multi PCM 985 * \param pcmp Returns created PCM handle 986 * \param name Name of PCM 987 * \param root Root configuration node 988 * \param conf Configuration node with Multi PCM description 989 * \param stream Stream type 990 * \param mode Stream mode 991 * \retval zero on success otherwise a negative error code 992 * \warning Using of this function might be dangerous in the sense 993 * of compatibility reasons. The prototype might be freely 994 * changed in future. 995 */ 996int _snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name, 997 snd_config_t *root, snd_config_t *conf, 998 snd_pcm_stream_t stream, int mode) 999{ 1000 snd_config_iterator_t i, inext, j, jnext; 1001 snd_config_t *slaves = NULL; 1002 snd_config_t *bindings = NULL; 1003 int err; 1004 unsigned int idx; 1005 const char **slaves_id = NULL; 1006 snd_config_t **slaves_conf = NULL; 1007 snd_pcm_t **slaves_pcm = NULL; 1008 unsigned int *slaves_channels = NULL; 1009 int *channels_sidx = NULL; 1010 unsigned int *channels_schannel = NULL; 1011 unsigned int slaves_count = 0; 1012 long master_slave = 0; 1013 unsigned int channels_count = 0; 1014 snd_config_for_each(i, inext, conf) { 1015 snd_config_t *n = snd_config_iterator_entry(i); 1016 const char *id; 1017 if (snd_config_get_id(n, &id) < 0) 1018 continue; 1019 if (snd_pcm_conf_generic_id(id)) 1020 continue; 1021 if (strcmp(id, "slaves") == 0) { 1022 if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { 1023 SNDERR("Invalid type for %s", id); 1024 return -EINVAL; 1025 } 1026 slaves = n; 1027 continue; 1028 } 1029 if (strcmp(id, "bindings") == 0) { 1030 if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { 1031 SNDERR("Invalid type for %s", id); 1032 return -EINVAL; 1033 } 1034 bindings = n; 1035 continue; 1036 } 1037 if (strcmp(id, "master") == 0) { 1038 if (snd_config_get_integer(n, &master_slave) < 0) { 1039 SNDERR("Invalid type for %s", id); 1040 return -EINVAL; 1041 } 1042 continue; 1043 } 1044 SNDERR("Unknown field %s", id); 1045 return -EINVAL; 1046 } 1047 if (!slaves) { 1048 SNDERR("slaves is not defined"); 1049 return -EINVAL; 1050 } 1051 if (!bindings) { 1052 SNDERR("bindings is not defined"); 1053 return -EINVAL; 1054 } 1055 snd_config_for_each(i, inext, slaves) { 1056 ++slaves_count; 1057 } 1058 if (master_slave < 0 || master_slave >= (long)slaves_count) { 1059 SNDERR("Master slave is out of range (0-%u)\n", slaves_count-1); 1060 return -EINVAL; 1061 } 1062 snd_config_for_each(i, inext, bindings) { 1063 long cchannel; 1064 snd_config_t *m = snd_config_iterator_entry(i); 1065 const char *id; 1066 if (snd_config_get_id(m, &id) < 0) 1067 continue; 1068 err = safe_strtol(id, &cchannel); 1069 if (err < 0 || cchannel < 0) { 1070 SNDERR("Invalid channel number: %s", id); 1071 return -EINVAL; 1072 } 1073 if ((unsigned long)cchannel >= channels_count) 1074 channels_count = cchannel + 1; 1075 } 1076 if (channels_count == 0) { 1077 SNDERR("No channels defined"); 1078 return -EINVAL; 1079 } 1080 slaves_id = calloc(slaves_count, sizeof(*slaves_id)); 1081 slaves_conf = calloc(slaves_count, sizeof(*slaves_conf)); 1082 slaves_pcm = calloc(slaves_count, sizeof(*slaves_pcm)); 1083 slaves_channels = calloc(slaves_count, sizeof(*slaves_channels)); 1084 channels_sidx = calloc(channels_count, sizeof(*channels_sidx)); 1085 channels_schannel = calloc(channels_count, sizeof(*channels_schannel)); 1086 if (!slaves_id || !slaves_conf || !slaves_pcm || !slaves_channels || 1087 !channels_sidx || !channels_schannel) { 1088 err = -ENOMEM; 1089 goto _free; 1090 } 1091 idx = 0; 1092 for (idx = 0; idx < channels_count; ++idx) 1093 channels_sidx[idx] = -1; 1094 idx = 0; 1095 snd_config_for_each(i, inext, slaves) { 1096 snd_config_t *m = snd_config_iterator_entry(i); 1097 const char *id; 1098 int channels; 1099 if (snd_config_get_id(m, &id) < 0) 1100 continue; 1101 slaves_id[idx] = id; 1102 err = snd_pcm_slave_conf(root, m, &slaves_conf[idx], 1, 1103 SND_PCM_HW_PARAM_CHANNELS, SCONF_MANDATORY, &channels); 1104 if (err < 0) 1105 goto _free; 1106 slaves_channels[idx] = channels; 1107 ++idx; 1108 } 1109 1110 snd_config_for_each(i, inext, bindings) { 1111 snd_config_t *m = snd_config_iterator_entry(i); 1112 long cchannel = -1; 1113 long schannel = -1; 1114 int slave = -1; 1115 long val; 1116 const char *str; 1117 const char *id; 1118 if (snd_config_get_id(m, &id) < 0) 1119 continue; 1120 err = safe_strtol(id, &cchannel); 1121 if (err < 0 || cchannel < 0) { 1122 SNDERR("Invalid channel number: %s", id); 1123 err = -EINVAL; 1124 goto _free; 1125 } 1126 snd_config_for_each(j, jnext, m) { 1127 snd_config_t *n = snd_config_iterator_entry(j); 1128 const char *id; 1129 if (snd_config_get_id(n, &id) < 0) 1130 continue; 1131 if (strcmp(id, "comment") == 0) 1132 continue; 1133 if (strcmp(id, "slave") == 0) { 1134 char buf[32]; 1135 unsigned int k; 1136 err = snd_config_get_string(n, &str); 1137 if (err < 0) { 1138 err = snd_config_get_integer(n, &val); 1139 if (err < 0) { 1140 SNDERR("Invalid value for %s", id); 1141 goto _free; 1142 } 1143 sprintf(buf, "%ld", val); 1144 str = buf; 1145 } 1146 for (k = 0; k < slaves_count; ++k) { 1147 if (strcmp(slaves_id[k], str) == 0) 1148 slave = k; 1149 } 1150 continue; 1151 } 1152 if (strcmp(id, "channel") == 0) { 1153 err = snd_config_get_integer(n, &schannel); 1154 if (err < 0) { 1155 SNDERR("Invalid type for %s", id); 1156 goto _free; 1157 } 1158 continue; 1159 } 1160 SNDERR("Unknown field %s", id); 1161 err = -EINVAL; 1162 goto _free; 1163 } 1164 if (slave < 0 || (unsigned int)slave >= slaves_count) { 1165 SNDERR("Invalid or missing sidx for channel %s", id); 1166 err = -EINVAL; 1167 goto _free; 1168 } 1169 if (schannel < 0 || 1170 (unsigned int) schannel >= slaves_channels[slave]) { 1171 SNDERR("Invalid or missing schannel for channel %s", id); 1172 err = -EINVAL; 1173 goto _free; 1174 } 1175 channels_sidx[cchannel] = slave; 1176 channels_schannel[cchannel] = schannel; 1177 } 1178 1179 for (idx = 0; idx < slaves_count; ++idx) { 1180 err = snd_pcm_open_slave(&slaves_pcm[idx], root, 1181 slaves_conf[idx], stream, mode, 1182 conf); 1183 if (err < 0) 1184 goto _free; 1185 snd_config_delete(slaves_conf[idx]); 1186 slaves_conf[idx] = NULL; 1187 } 1188 err = snd_pcm_multi_open(pcmp, name, slaves_count, master_slave, 1189 slaves_pcm, slaves_channels, 1190 channels_count, 1191 channels_sidx, channels_schannel, 1192 1); 1193_free: 1194 if (err < 0) { 1195 for (idx = 0; idx < slaves_count; ++idx) { 1196 if (slaves_pcm[idx]) 1197 snd_pcm_close(slaves_pcm[idx]); 1198 } 1199 } 1200 if (slaves_conf) { 1201 for (idx = 0; idx < slaves_count; ++idx) { 1202 if (slaves_conf[idx]) 1203 snd_config_delete(slaves_conf[idx]); 1204 } 1205 free(slaves_conf); 1206 } 1207 free(slaves_pcm); 1208 free(slaves_channels); 1209 free(channels_sidx); 1210 free(channels_schannel); 1211 free(slaves_id); 1212 return err; 1213} 1214#ifndef DOC_HIDDEN 1215SND_DLSYM_BUILD_VERSION(_snd_pcm_multi_open, SND_PCM_DLSYM_VERSION); 1216#endif 1217