1/** 2 * \file pcm/pcm_ioplug.c 3 * \ingroup Plugin_SDK 4 * \brief I/O Plugin SDK 5 * \author Takashi Iwai <tiwai@suse.de> 6 * \date 2005 7 */ 8/* 9 * PCM - External I/O Plugin SDK 10 * Copyright (c) 2005 by Takashi Iwai <tiwai@suse.de> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 26 * 27 */ 28 29#include "pcm_local.h" 30#include "pcm_ioplug.h" 31#include "pcm_ext_parm.h" 32#include "pcm_generic.h" 33 34#ifndef PIC 35/* entry for static linking */ 36const char *_snd_module_pcm_ioplug = ""; 37#endif 38 39#ifndef DOC_HIDDEN 40 41/* hw_params */ 42typedef struct snd_pcm_ioplug_priv { 43 snd_pcm_ioplug_t *data; 44 struct snd_ext_parm params[SND_PCM_IOPLUG_HW_PARAMS]; 45 snd_pcm_uframes_t last_hw; 46 snd_pcm_uframes_t avail_max; 47 snd_htimestamp_t trigger_tstamp; 48} ioplug_priv_t; 49 50static int snd_pcm_ioplug_drop(snd_pcm_t *pcm); 51static int snd_pcm_ioplug_poll_descriptors_count(snd_pcm_t *pcm); 52static int snd_pcm_ioplug_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space); 53static int snd_pcm_ioplug_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); 54 55/* update the hw pointer */ 56/* called in lock */ 57static void snd_pcm_ioplug_hw_ptr_update(snd_pcm_t *pcm) 58{ 59 ioplug_priv_t *io = pcm->private_data; 60 snd_pcm_sframes_t hw; 61 62 hw = io->data->callback->pointer(io->data); 63 if (hw >= 0) { 64 snd_pcm_uframes_t delta; 65 snd_pcm_uframes_t avail; 66 67 if ((snd_pcm_uframes_t)hw >= io->last_hw) 68 delta = hw - io->last_hw; 69 else { 70 const snd_pcm_uframes_t wrap_point = 71 (io->data->flags & SND_PCM_IOPLUG_FLAG_BOUNDARY_WA) ? 72 pcm->boundary : pcm->buffer_size; 73 delta = wrap_point + hw - io->last_hw; 74 } 75 snd_pcm_mmap_hw_forward(io->data->pcm, delta); 76 /* stop the stream if all samples are drained */ 77 if (io->data->state == SND_PCM_STATE_DRAINING) { 78 avail = snd_pcm_mmap_avail(pcm); 79 if (avail >= pcm->buffer_size) 80 snd_pcm_ioplug_drop(pcm); 81 } 82 io->last_hw = (snd_pcm_uframes_t)hw; 83 } else { 84 if (io->data->state == SND_PCM_STATE_DRAINING) 85 snd_pcm_ioplug_drop(pcm); 86 else 87 io->data->state = SNDRV_PCM_STATE_XRUN; 88 } 89} 90 91static int snd_pcm_ioplug_info(snd_pcm_t *pcm, snd_pcm_info_t *info) 92{ 93 memset(info, 0, sizeof(*info)); 94 info->stream = pcm->stream; 95 info->card = -1; 96 if (pcm->name) { 97 snd_strlcpy((char *)info->id, pcm->name, sizeof(info->id)); 98 snd_strlcpy((char *)info->name, pcm->name, sizeof(info->name)); 99 snd_strlcpy((char *)info->subname, pcm->name, sizeof(info->subname)); 100 } 101 info->subdevices_count = 1; 102 return 0; 103} 104 105static int snd_pcm_ioplug_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info) 106{ 107 return snd_pcm_channel_info_shm(pcm, info, -1); 108} 109 110static int snd_pcm_ioplug_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) 111{ 112 ioplug_priv_t *io = pcm->private_data; 113 114 if (io->data->version >= 0x010001 && 115 io->data->callback->delay) 116 return io->data->callback->delay(io->data, delayp); 117 else { 118 snd_pcm_ioplug_hw_ptr_update(pcm); 119 *delayp = snd_pcm_mmap_delay(pcm); 120 } 121 return 0; 122} 123 124static int snd_pcm_ioplug_status(snd_pcm_t *pcm, snd_pcm_status_t * status) 125{ 126 ioplug_priv_t *io = pcm->private_data; 127 snd_pcm_sframes_t sd; 128 129 memset(status, 0, sizeof(*status)); 130 snd_pcm_ioplug_hw_ptr_update(pcm); 131 status->state = io->data->state; 132 status->trigger_tstamp = io->trigger_tstamp; 133 gettimestamp(&status->tstamp, pcm->tstamp_type); 134 status->avail = snd_pcm_mmap_avail(pcm); 135 status->avail_max = io->avail_max; 136 status->appl_ptr = *pcm->appl.ptr; 137 status->hw_ptr = *pcm->hw.ptr; 138 if (snd_pcm_ioplug_delay(pcm, &sd) < 0) 139 sd = snd_pcm_mmap_delay(pcm); 140 status->delay = sd; 141 return 0; 142} 143 144static snd_pcm_state_t snd_pcm_ioplug_state(snd_pcm_t *pcm) 145{ 146 ioplug_priv_t *io = pcm->private_data; 147 return io->data->state; 148} 149 150static int snd_pcm_ioplug_hwsync(snd_pcm_t *pcm) 151{ 152 snd_pcm_ioplug_hw_ptr_update(pcm); 153 return 0; 154} 155 156static int snd_pcm_ioplug_reset(snd_pcm_t *pcm) 157{ 158 ioplug_priv_t *io = pcm->private_data; 159 160 io->data->appl_ptr = 0; 161 io->data->hw_ptr = 0; 162 io->last_hw = 0; 163 io->avail_max = 0; 164 return 0; 165} 166 167static int snd_pcm_ioplug_prepare(snd_pcm_t *pcm) 168{ 169 ioplug_priv_t *io = pcm->private_data; 170 int err = 0; 171 172 snd_pcm_ioplug_reset(pcm); 173 if (io->data->callback->prepare) { 174 snd_pcm_unlock(pcm); /* to avoid deadlock */ 175 err = io->data->callback->prepare(io->data); 176 snd_pcm_lock(pcm); 177 } 178 if (err < 0) 179 return err; 180 181 io->data->state = SND_PCM_STATE_PREPARED; 182 return err; 183} 184 185static const int hw_params_type[SND_PCM_IOPLUG_HW_PARAMS] = { 186 [SND_PCM_IOPLUG_HW_ACCESS] = SND_PCM_HW_PARAM_ACCESS, 187 [SND_PCM_IOPLUG_HW_FORMAT] = SND_PCM_HW_PARAM_FORMAT, 188 [SND_PCM_IOPLUG_HW_CHANNELS] = SND_PCM_HW_PARAM_CHANNELS, 189 [SND_PCM_IOPLUG_HW_RATE] = SND_PCM_HW_PARAM_RATE, 190 [SND_PCM_IOPLUG_HW_PERIOD_BYTES] = SND_PCM_HW_PARAM_PERIOD_BYTES, 191 [SND_PCM_IOPLUG_HW_BUFFER_BYTES] = SND_PCM_HW_PARAM_BUFFER_BYTES, 192 [SND_PCM_IOPLUG_HW_PERIODS] = SND_PCM_HW_PARAM_PERIODS, 193}; 194 195/* x = a * b */ 196static int rule_mul(snd_pcm_hw_params_t *params, int x, int a, int b) 197{ 198 snd_interval_t t; 199 200 snd_interval_mul(hw_param_interval(params, a), 201 hw_param_interval(params, b), &t); 202 return snd_interval_refine(hw_param_interval(params, x), &t); 203} 204 205/* x = a / b */ 206static int rule_div(snd_pcm_hw_params_t *params, int x, int a, int b) 207{ 208 snd_interval_t t; 209 210 snd_interval_div(hw_param_interval(params, a), 211 hw_param_interval(params, b), &t); 212 return snd_interval_refine(hw_param_interval(params, x), &t); 213} 214 215/* x = a * b / k */ 216static int rule_muldivk(snd_pcm_hw_params_t *params, int x, int a, int b, int k) 217{ 218 snd_interval_t t; 219 220 snd_interval_muldivk(hw_param_interval(params, a), 221 hw_param_interval(params, b), k, &t); 222 return snd_interval_refine(hw_param_interval(params, x), &t); 223} 224 225/* x = a * k / b */ 226static int rule_mulkdiv(snd_pcm_hw_params_t *params, int x, int a, int k, int b) 227{ 228 snd_interval_t t; 229 230 snd_interval_mulkdiv(hw_param_interval(params, a), k, 231 hw_param_interval(params, b), &t); 232 return snd_interval_refine(hw_param_interval(params, x), &t); 233} 234 235#if 0 236static void dump_parm(snd_pcm_hw_params_t *params) 237{ 238 snd_output_t *log; 239 snd_output_stdio_attach(&log, stderr, 0); 240 snd_pcm_hw_params_dump(params, log); 241 snd_output_close(log); 242} 243#endif 244 245/* refine *_TIME and *_SIZE, then update *_BYTES */ 246static int refine_time_and_size(snd_pcm_hw_params_t *params, 247 int time, int size, int bytes) 248{ 249 int err, change1 = 0; 250 251 /* size = time * rate / 1000000 */ 252 err = rule_muldivk(params, size, time, 253 SND_PCM_HW_PARAM_RATE, 1000000); 254 if (err < 0) 255 return err; 256 change1 |= err; 257 258 /* bytes = size * framebits / 8 */ 259 err = rule_muldivk(params, bytes, size, 260 SND_PCM_HW_PARAM_FRAME_BITS, 8); 261 if (err < 0) 262 return err; 263 change1 |= err; 264 return change1; 265} 266 267/* refine *_TIME and *_SIZE from *_BYTES */ 268static int refine_back_time_and_size(snd_pcm_hw_params_t *params, 269 int time, int size, int bytes) 270{ 271 int err; 272 273 /* size = bytes * 8 / framebits */ 274 err = rule_mulkdiv(params, size, bytes, 8, SND_PCM_HW_PARAM_FRAME_BITS); 275 if (err < 0) 276 return err; 277 /* time = size * 1000000 / rate */ 278 err = rule_mulkdiv(params, time, size, 1000000, SND_PCM_HW_PARAM_RATE); 279 if (err < 0) 280 return err; 281 return 0; 282} 283 284 285static int snd_pcm_ioplug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 286{ 287 int change = 0, change1, change2, err; 288 ioplug_priv_t *io = pcm->private_data; 289 struct snd_ext_parm *p; 290 unsigned int i; 291 292 /* access, format */ 293 for (i = SND_PCM_IOPLUG_HW_ACCESS; i <= SND_PCM_IOPLUG_HW_FORMAT; i++) { 294 err = snd_ext_parm_mask_refine(hw_param_mask(params, hw_params_type[i]), 295 io->params, i); 296 if (err < 0) 297 return err; 298 change |= err; 299 } 300 /* channels, rate */ 301 for (; i <= SND_PCM_IOPLUG_HW_RATE; i++) { 302 err = snd_ext_parm_interval_refine(hw_param_interval(params, hw_params_type[i]), 303 io->params, i); 304 if (err < 0) 305 return err; 306 change |= err; 307 } 308 309 if (params->rmask & ((1 << SND_PCM_HW_PARAM_ACCESS) | 310 (1 << SND_PCM_HW_PARAM_FORMAT) | 311 (1 << SND_PCM_HW_PARAM_SUBFORMAT) | 312 (1 << SND_PCM_HW_PARAM_CHANNELS) | 313 (1 << SND_PCM_HW_PARAM_RATE))) { 314 err = snd_pcm_hw_refine_soft(pcm, params); 315 if (err < 0) 316 return err; 317 change |= err; 318 } 319 320 change1 = refine_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME, 321 SND_PCM_HW_PARAM_PERIOD_SIZE, 322 SND_PCM_HW_PARAM_PERIOD_BYTES); 323 if (change1 < 0) 324 return change1; 325 err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_BYTES), 326 io->params, SND_PCM_IOPLUG_HW_PERIOD_BYTES); 327 if (err < 0) 328 return err; 329 change1 |= err; 330 if (change1) { 331 change |= change1; 332 err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME, 333 SND_PCM_HW_PARAM_PERIOD_SIZE, 334 SND_PCM_HW_PARAM_PERIOD_BYTES); 335 if (err < 0) 336 return err; 337 } 338 339 change1 = refine_time_and_size(params, SND_PCM_HW_PARAM_BUFFER_TIME, 340 SND_PCM_HW_PARAM_BUFFER_SIZE, 341 SND_PCM_HW_PARAM_BUFFER_BYTES); 342 if (change1 < 0) 343 return change1; 344 change |= change1; 345 346 do { 347 change2 = 0; 348 err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_BUFFER_BYTES), 349 io->params, SND_PCM_IOPLUG_HW_BUFFER_BYTES); 350 if (err < 0) 351 return err; 352 change2 |= err; 353 /* periods = buffer_bytes / period_bytes */ 354 err = rule_div(params, SND_PCM_HW_PARAM_PERIODS, 355 SND_PCM_HW_PARAM_BUFFER_BYTES, 356 SND_PCM_HW_PARAM_PERIOD_BYTES); 357 if (err < 0) 358 return err; 359 change2 |= err; 360 err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIODS), 361 io->params, SND_PCM_IOPLUG_HW_PERIODS); 362 if (err < 0) 363 return err; 364 change2 |= err; 365 /* buffer_bytes = periods * period_bytes */ 366 err = rule_mul(params, SND_PCM_HW_PARAM_BUFFER_BYTES, 367 SND_PCM_HW_PARAM_PERIOD_BYTES, 368 SND_PCM_HW_PARAM_PERIODS); 369 if (err < 0) 370 return err; 371 change2 |= err; 372 change1 |= change2; 373 } while (change2); 374 change |= change1; 375 376 if (change1) { 377 err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_BUFFER_TIME, 378 SND_PCM_HW_PARAM_BUFFER_SIZE, 379 SND_PCM_HW_PARAM_BUFFER_BYTES); 380 if (err < 0) 381 return err; 382 } 383 384 /* period_bytes = buffer_bytes / periods */ 385 err = rule_div(params, SND_PCM_HW_PARAM_PERIOD_BYTES, 386 SND_PCM_HW_PARAM_BUFFER_BYTES, 387 SND_PCM_HW_PARAM_PERIODS); 388 if (err < 0) 389 return err; 390 if (err) { 391 /* update period_size and period_time */ 392 change |= err; 393 err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_BYTES), 394 io->params, SND_PCM_IOPLUG_HW_PERIOD_BYTES); 395 if (err < 0) 396 return err; 397 err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME, 398 SND_PCM_HW_PARAM_PERIOD_SIZE, 399 SND_PCM_HW_PARAM_PERIOD_BYTES); 400 if (err < 0) 401 return err; 402 } 403 404 params->info = SND_PCM_INFO_BLOCK_TRANSFER; 405 p = &io->params[SND_PCM_IOPLUG_HW_ACCESS]; 406 if (p->active) { 407 for (i = 0; i < p->num_list; i++) 408 switch (p->list[i]) { 409 case SND_PCM_ACCESS_MMAP_INTERLEAVED: 410 case SND_PCM_ACCESS_RW_INTERLEAVED: 411 params->info |= SND_PCM_INFO_INTERLEAVED; 412 break; 413 case SND_PCM_ACCESS_MMAP_NONINTERLEAVED: 414 case SND_PCM_ACCESS_RW_NONINTERLEAVED: 415 params->info |= SND_PCM_INFO_NONINTERLEAVED; 416 break; 417 } 418 } 419 if (io->data->callback->pause) 420 params->info |= SND_PCM_INFO_PAUSE; 421 if (io->data->callback->resume) 422 params->info |= SND_PCM_INFO_RESUME; 423 424#if 0 425 fprintf(stderr, "XXX\n"); 426 dump_parm(params); 427#endif 428 return change; 429} 430 431static int snd_pcm_ioplug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 432{ 433 ioplug_priv_t *io = pcm->private_data; 434 int err; 435 436 INTERNAL(snd_pcm_hw_params_get_access)(params, &io->data->access); 437 INTERNAL(snd_pcm_hw_params_get_format)(params, &io->data->format); 438 INTERNAL(snd_pcm_hw_params_get_channels)(params, &io->data->channels); 439 INTERNAL(snd_pcm_hw_params_get_rate)(params, &io->data->rate, 0); 440 INTERNAL(snd_pcm_hw_params_get_period_size)(params, &io->data->period_size, 0); 441 INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &io->data->buffer_size); 442 if (io->data->callback->hw_params) { 443 err = io->data->callback->hw_params(io->data, params); 444 if (err < 0) 445 return err; 446 INTERNAL(snd_pcm_hw_params_get_access)(params, &io->data->access); 447 INTERNAL(snd_pcm_hw_params_get_format)(params, &io->data->format); 448 INTERNAL(snd_pcm_hw_params_get_channels)(params, &io->data->channels); 449 INTERNAL(snd_pcm_hw_params_get_rate)(params, &io->data->rate, 0); 450 INTERNAL(snd_pcm_hw_params_get_period_size)(params, &io->data->period_size, 0); 451 INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &io->data->buffer_size); 452 } 453 return 0; 454} 455 456static int snd_pcm_ioplug_hw_free(snd_pcm_t *pcm) 457{ 458 ioplug_priv_t *io = pcm->private_data; 459 460 if (io->data->callback->hw_free) 461 return io->data->callback->hw_free(io->data); 462 return 0; 463} 464 465static int snd_pcm_ioplug_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params) 466{ 467 ioplug_priv_t *io = pcm->private_data; 468 int err; 469 470 if (!io->data->callback->sw_params) 471 return 0; 472 473 snd_pcm_unlock(pcm); /* to avoid deadlock */ 474 err = io->data->callback->sw_params(io->data, params); 475 snd_pcm_lock(pcm); 476 477 return err; 478} 479 480 481static int snd_pcm_ioplug_start(snd_pcm_t *pcm) 482{ 483 ioplug_priv_t *io = pcm->private_data; 484 int err; 485 486 if (io->data->state != SND_PCM_STATE_PREPARED) 487 return -EBADFD; 488 489 err = io->data->callback->start(io->data); 490 if (err < 0) 491 return err; 492 493 gettimestamp(&io->trigger_tstamp, pcm->tstamp_type); 494 io->data->state = SND_PCM_STATE_RUNNING; 495 496 return 0; 497} 498 499static int snd_pcm_ioplug_drop(snd_pcm_t *pcm) 500{ 501 ioplug_priv_t *io = pcm->private_data; 502 503 if (io->data->state == SND_PCM_STATE_OPEN) 504 return -EBADFD; 505 506 io->data->callback->stop(io->data); 507 508 gettimestamp(&io->trigger_tstamp, pcm->tstamp_type); 509 io->data->state = SND_PCM_STATE_SETUP; 510 511 return 0; 512} 513 514static int ioplug_drain_via_poll(snd_pcm_t *pcm) 515{ 516 ioplug_priv_t *io = pcm->private_data; 517 518 while (io->data->state == SND_PCM_STATE_DRAINING) { 519 snd_pcm_ioplug_hw_ptr_update(pcm); 520 if (io->data->state != SND_PCM_STATE_DRAINING) 521 break; 522 /* in non-blocking mode, let application to poll() by itself */ 523 if (io->data->nonblock) 524 return -EAGAIN; 525 if (snd_pcm_wait_nocheck(pcm, SND_PCM_WAIT_DRAIN) < 0) 526 break; 527 } 528 529 return 0; /* force to drop at error */ 530} 531 532/* need own locking */ 533static int snd_pcm_ioplug_drain(snd_pcm_t *pcm) 534{ 535 ioplug_priv_t *io = pcm->private_data; 536 int err = 0; 537 538 snd_pcm_lock(pcm); 539 switch (io->data->state) { 540 case SND_PCM_STATE_OPEN: 541 case SND_PCM_STATE_DISCONNECTED: 542 case SND_PCM_STATE_SUSPENDED: 543 snd_pcm_unlock(pcm); 544 return -EBADFD; 545 case SND_PCM_STATE_PREPARED: 546 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { 547 if (!io->data->callback->drain) { 548 err = snd_pcm_ioplug_start(pcm); 549 if (err < 0) 550 goto unlock; 551 } 552 io->data->state = SND_PCM_STATE_DRAINING; 553 } 554 break; 555 case SND_PCM_STATE_RUNNING: 556 io->data->state = SND_PCM_STATE_DRAINING; 557 break; 558 default: 559 break; 560 } 561 562 if (io->data->state == SND_PCM_STATE_DRAINING) { 563 if (io->data->callback->drain) { 564 snd_pcm_unlock(pcm); /* let plugin own locking */ 565 err = io->data->callback->drain(io->data); 566 snd_pcm_lock(pcm); 567 } else { 568 err = ioplug_drain_via_poll(pcm); 569 } 570 } 571 572 unlock: 573 if (!err && io->data->state != SND_PCM_STATE_SETUP) 574 snd_pcm_ioplug_drop(pcm); 575 snd_pcm_unlock(pcm); 576 return err; 577} 578 579static int snd_pcm_ioplug_pause(snd_pcm_t *pcm, int enable) 580{ 581 ioplug_priv_t *io = pcm->private_data; 582 static const snd_pcm_state_t states[2] = { 583 SND_PCM_STATE_RUNNING, SND_PCM_STATE_PAUSED 584 }; 585 int prev, err; 586 587 prev = !enable; 588 enable = !prev; 589 if (io->data->state != states[prev]) 590 return -EBADFD; 591 if (io->data->callback->pause) { 592 err = io->data->callback->pause(io->data, enable); 593 if (err < 0) 594 return err; 595 } 596 io->data->state = states[enable]; 597 return 0; 598} 599 600static snd_pcm_sframes_t snd_pcm_ioplug_rewindable(snd_pcm_t *pcm) 601{ 602 return snd_pcm_mmap_hw_rewindable(pcm); 603} 604 605static snd_pcm_sframes_t snd_pcm_ioplug_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 606{ 607 snd_pcm_mmap_appl_backward(pcm, frames); 608 return frames; 609} 610 611static snd_pcm_sframes_t snd_pcm_ioplug_forwardable(snd_pcm_t *pcm) 612{ 613 return snd_pcm_mmap_avail(pcm); 614} 615 616static snd_pcm_sframes_t snd_pcm_ioplug_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 617{ 618 snd_pcm_mmap_appl_forward(pcm, frames); 619 return frames; 620} 621 622/* need own locking */ 623static int snd_pcm_ioplug_resume(snd_pcm_t *pcm) 624{ 625 ioplug_priv_t *io = pcm->private_data; 626 627 if (io->data->callback->resume) 628 io->data->callback->resume(io->data); 629 return 0; 630} 631 632/* called in lock */ 633static snd_pcm_sframes_t ioplug_priv_transfer_areas(snd_pcm_t *pcm, 634 const snd_pcm_channel_area_t *areas, 635 snd_pcm_uframes_t offset, 636 snd_pcm_uframes_t size) 637{ 638 ioplug_priv_t *io = pcm->private_data; 639 snd_pcm_sframes_t result; 640 641 if (! size) 642 return 0; 643 if (io->data->callback->transfer) 644 result = io->data->callback->transfer(io->data, areas, offset, size); 645 else 646 result = size; 647 if (result > 0) 648 snd_pcm_mmap_appl_forward(pcm, result); 649 return result; 650} 651 652static snd_pcm_sframes_t snd_pcm_ioplug_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size) 653{ 654 if (pcm->mmap_rw) 655 return snd_pcm_mmap_writei(pcm, buffer, size); 656 else { 657 snd_pcm_channel_area_t areas[pcm->channels]; 658 snd_pcm_areas_from_buf(pcm, areas, (void*)buffer); 659 return snd_pcm_write_areas(pcm, areas, 0, size, 660 ioplug_priv_transfer_areas); 661 } 662} 663 664static snd_pcm_sframes_t snd_pcm_ioplug_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) 665{ 666 if (pcm->mmap_rw) 667 return snd_pcm_mmap_writen(pcm, bufs, size); 668 else { 669 snd_pcm_channel_area_t areas[pcm->channels]; 670 snd_pcm_areas_from_bufs(pcm, areas, bufs); 671 return snd_pcm_write_areas(pcm, areas, 0, size, 672 ioplug_priv_transfer_areas); 673 } 674} 675 676static snd_pcm_sframes_t snd_pcm_ioplug_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size) 677{ 678 if (pcm->mmap_rw) 679 return snd_pcm_mmap_readi(pcm, buffer, size); 680 else { 681 snd_pcm_channel_area_t areas[pcm->channels]; 682 snd_pcm_areas_from_buf(pcm, areas, buffer); 683 return snd_pcm_read_areas(pcm, areas, 0, size, 684 ioplug_priv_transfer_areas); 685 } 686} 687 688static snd_pcm_sframes_t snd_pcm_ioplug_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) 689{ 690 if (pcm->mmap_rw) 691 return snd_pcm_mmap_readn(pcm, bufs, size); 692 else { 693 snd_pcm_channel_area_t areas[pcm->channels]; 694 snd_pcm_areas_from_bufs(pcm, areas, bufs); 695 return snd_pcm_read_areas(pcm, areas, 0, size, 696 ioplug_priv_transfer_areas); 697 } 698} 699 700static int snd_pcm_ioplug_mmap_begin_capture(snd_pcm_t *pcm, 701 const snd_pcm_channel_area_t **areas, 702 snd_pcm_uframes_t *offset, 703 snd_pcm_uframes_t *frames) 704{ 705 ioplug_priv_t *io = pcm->private_data; 706 int err; 707 708 err = __snd_pcm_mmap_begin_generic(pcm, areas, offset, frames); 709 if (err < 0) 710 return err; 711 712 if (io->data->callback->transfer && 713 pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED && 714 pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) { 715 snd_pcm_sframes_t result; 716 result = io->data->callback->transfer(io->data, *areas, *offset, *frames); 717 if (result < 0) 718 return result; 719 } 720 721 return err; 722} 723 724static int snd_pcm_ioplug_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, 725 snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames) 726{ 727 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) 728 return __snd_pcm_mmap_begin_generic(pcm, areas, offset, frames); 729 return snd_pcm_ioplug_mmap_begin_capture(pcm, areas, offset, frames); 730} 731 732static snd_pcm_sframes_t snd_pcm_ioplug_mmap_commit(snd_pcm_t *pcm, 733 snd_pcm_uframes_t offset, 734 snd_pcm_uframes_t size) 735{ 736 if (pcm->stream == SND_PCM_STREAM_PLAYBACK && 737 pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED && 738 pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) { 739 const snd_pcm_channel_area_t *areas; 740 snd_pcm_uframes_t ofs, frames = size; 741 742 __snd_pcm_mmap_begin_generic(pcm, &areas, &ofs, &frames); 743 if (ofs != offset) 744 return -EIO; 745 return ioplug_priv_transfer_areas(pcm, areas, offset, frames); 746 } 747 748 snd_pcm_mmap_appl_forward(pcm, size); 749 return size; 750} 751 752static snd_pcm_sframes_t snd_pcm_ioplug_avail_update(snd_pcm_t *pcm) 753{ 754 ioplug_priv_t *io = pcm->private_data; 755 snd_pcm_uframes_t avail; 756 757 snd_pcm_ioplug_hw_ptr_update(pcm); 758 if (io->data->state == SND_PCM_STATE_XRUN) 759 return -EPIPE; 760 761 avail = snd_pcm_mmap_avail(pcm); 762 if (avail > io->avail_max) 763 io->avail_max = avail; 764 return (snd_pcm_sframes_t)avail; 765} 766 767static int snd_pcm_ioplug_nonblock(snd_pcm_t *pcm, int nonblock) 768{ 769 ioplug_priv_t *io = pcm->private_data; 770 771 io->data->nonblock = nonblock; 772 return 0; 773} 774 775static int snd_pcm_ioplug_poll_descriptors_count(snd_pcm_t *pcm) 776{ 777 ioplug_priv_t *io = pcm->private_data; 778 int err = 1; 779 780 if (io->data->callback->poll_descriptors_count) { 781 snd_pcm_unlock(pcm); /* to avoid deadlock */ 782 err = io->data->callback->poll_descriptors_count(io->data); 783 snd_pcm_lock(pcm); 784 } 785 return err; 786} 787 788static int snd_pcm_ioplug_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space) 789{ 790 ioplug_priv_t *io = pcm->private_data; 791 int err; 792 793 if (io->data->callback->poll_descriptors) { 794 snd_pcm_unlock(pcm); /* to avoid deadlock */ 795 err = io->data->callback->poll_descriptors(io->data, pfds, space); 796 snd_pcm_lock(pcm); 797 return err; 798 } 799 if (pcm->poll_fd < 0) 800 return -EIO; 801 if (space >= 1 && pfds) { 802 pfds->fd = pcm->poll_fd; 803 pfds->events = pcm->poll_events | POLLERR | POLLNVAL; 804 } else { 805 return 0; 806 } 807 return 1; 808} 809 810static int snd_pcm_ioplug_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) 811{ 812 ioplug_priv_t *io = pcm->private_data; 813 int err; 814 815 if (io->data->callback->poll_revents) { 816 snd_pcm_unlock(pcm); /* to avoid deadlock */ 817 err = io->data->callback->poll_revents(io->data, pfds, nfds, revents); 818 snd_pcm_lock(pcm); 819 } else { 820 *revents = pfds->revents; 821 err = 0; 822 } 823 return err; 824} 825 826static int snd_pcm_ioplug_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) 827{ 828 return 0; 829} 830 831static int snd_pcm_ioplug_async(snd_pcm_t *pcm ATTRIBUTE_UNUSED, 832 int sig ATTRIBUTE_UNUSED, 833 pid_t pid ATTRIBUTE_UNUSED) 834{ 835 return -ENOSYS; 836} 837 838static int snd_pcm_ioplug_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) 839{ 840 return 0; 841} 842 843static snd_pcm_chmap_query_t **snd_pcm_ioplug_query_chmaps(snd_pcm_t *pcm) 844{ 845 ioplug_priv_t *io = pcm->private_data; 846 847 if (io->data->version >= 0x010002 && 848 io->data->callback->query_chmaps) 849 return io->data->callback->query_chmaps(io->data); 850 return NULL; 851} 852 853static snd_pcm_chmap_t *snd_pcm_ioplug_get_chmap(snd_pcm_t *pcm) 854{ 855 ioplug_priv_t *io = pcm->private_data; 856 857 if (io->data->version >= 0x010002 && 858 io->data->callback->get_chmap) 859 return io->data->callback->get_chmap(io->data); 860 return NULL; 861} 862 863static int snd_pcm_ioplug_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map) 864{ 865 ioplug_priv_t *io = pcm->private_data; 866 867 if (io->data->version >= 0x010002 && 868 io->data->callback->set_chmap) 869 return io->data->callback->set_chmap(io->data, map); 870 return -ENXIO; 871} 872 873static void snd_pcm_ioplug_dump(snd_pcm_t *pcm, snd_output_t *out) 874{ 875 ioplug_priv_t *io = pcm->private_data; 876 877 if (io->data->callback->dump) 878 io->data->callback->dump(io->data, out); 879 else { 880 if (io->data->name) 881 snd_output_printf(out, "%s\n", io->data->name); 882 else 883 snd_output_printf(out, "IO-PCM Plugin\n"); 884 if (pcm->setup) { 885 snd_output_printf(out, "Its setup is:\n"); 886 snd_pcm_dump_setup(pcm, out); 887 } 888 } 889} 890 891static void clear_io_params(ioplug_priv_t *io) 892{ 893 int i; 894 for (i = 0; i < SND_PCM_IOPLUG_HW_PARAMS; i++) 895 snd_ext_parm_clear(&io->params[i]); 896} 897 898static int snd_pcm_ioplug_close(snd_pcm_t *pcm) 899{ 900 ioplug_priv_t *io = pcm->private_data; 901 902 clear_io_params(io); 903 if (io->data->callback->close) 904 io->data->callback->close(io->data); 905 free(io); 906 907 return 0; 908} 909 910static const snd_pcm_ops_t snd_pcm_ioplug_ops = { 911 .close = snd_pcm_ioplug_close, 912 .nonblock = snd_pcm_ioplug_nonblock, 913 .async = snd_pcm_ioplug_async, 914 .info = snd_pcm_ioplug_info, 915 .hw_refine = snd_pcm_ioplug_hw_refine, 916 .hw_params = snd_pcm_ioplug_hw_params, 917 .hw_free = snd_pcm_ioplug_hw_free, 918 .sw_params = snd_pcm_ioplug_sw_params, 919 .channel_info = snd_pcm_ioplug_channel_info, 920 .dump = snd_pcm_ioplug_dump, 921 .mmap = snd_pcm_ioplug_mmap, 922 .munmap = snd_pcm_ioplug_munmap, 923 .query_chmaps = snd_pcm_ioplug_query_chmaps, 924 .get_chmap = snd_pcm_ioplug_get_chmap, 925 .set_chmap = snd_pcm_ioplug_set_chmap, 926}; 927 928static const snd_pcm_fast_ops_t snd_pcm_ioplug_fast_ops = { 929 .status = snd_pcm_ioplug_status, 930 .prepare = snd_pcm_ioplug_prepare, 931 .reset = snd_pcm_ioplug_reset, 932 .start = snd_pcm_ioplug_start, 933 .drop = snd_pcm_ioplug_drop, 934 .drain = snd_pcm_ioplug_drain, 935 .pause = snd_pcm_ioplug_pause, 936 .state = snd_pcm_ioplug_state, 937 .hwsync = snd_pcm_ioplug_hwsync, 938 .delay = snd_pcm_ioplug_delay, 939 .resume = snd_pcm_ioplug_resume, 940 .link = NULL, 941 .link_slaves = NULL, 942 .unlink = NULL, 943 .rewindable = snd_pcm_ioplug_rewindable, 944 .rewind = snd_pcm_ioplug_rewind, 945 .forwardable = snd_pcm_ioplug_forwardable, 946 .forward = snd_pcm_ioplug_forward, 947 .writei = snd_pcm_ioplug_writei, 948 .writen = snd_pcm_ioplug_writen, 949 .readi = snd_pcm_ioplug_readi, 950 .readn = snd_pcm_ioplug_readn, 951 .avail_update = snd_pcm_ioplug_avail_update, 952 .mmap_commit = snd_pcm_ioplug_mmap_commit, 953 .htimestamp = snd_pcm_generic_real_htimestamp, 954 .poll_descriptors_count = snd_pcm_ioplug_poll_descriptors_count, 955 .poll_descriptors = snd_pcm_ioplug_poll_descriptors, 956 .poll_revents = snd_pcm_ioplug_poll_revents, 957 .mmap_begin = snd_pcm_ioplug_mmap_begin, 958}; 959 960#endif /* !DOC_HIDDEN */ 961 962/* 963 * Exported functions 964 */ 965 966/*! \page pcm_external_plugins PCM External Plugin SDK 967 968\section pcm_ioplug External Plugin: I/O Plugin 969 970The I/O-type plugin is a PCM plugin to work as the input or output terminal point, 971i.e. as a user-space PCM driver. 972 973The new plugin is created via #snd_pcm_ioplug_create() function. 974The first argument is a pointer of the pluging information. Some of 975this struct must be initialized in prior to call 976#snd_pcm_ioplug_create(). Then the function fills other fields in 977return. The rest arguments, name, stream and mode, are usually 978identical with the values passed from the ALSA plugin constructor. 979 980The following fields are mandatory: version, name, callback. 981Otherfields are optional and should be initialized with zero. 982 983The constant #SND_PCM_IOPLUG_VERSION must be passed to the version 984field for the version check in alsa-lib. A non-NULL ASCII string 985has to be passed to the name field. The callback field contains the 986table of callback functions for this plugin (defined as 987#snd_pcm_ioplug_callback_t). 988 989flags field specifies the optional bit-flags. poll_fd and poll_events 990specify the poll file descriptor and the corresponding poll events 991(POLLIN, POLLOUT) for the plugin. If the plugin requires multiple 992poll descriptors or poll descriptor(s) dynamically varying, set 993poll_descriptors and poll_descriptors_count callbacks to the callback 994table. Then the poll_fd and poll_events field are ignored. 995 996mmap_rw specifies whether the plugin behaves in the pseudo mmap mode. 997When this value is set to 1, the plugin creates always a local buffer 998and performs read/write calls using this buffer as if it's mmapped. 999The address of local buffer can be obtained via 1000#snd_pcm_ioplug_mmap_areas() function. 1001When poll_fd, poll_events and mmap_rw fields are changed after 1002#snd_pcm_ioplug_create(), call #snd_pcm_ioplug_reinit_status() to 1003reflect the changes. 1004 1005The driver can set an arbitrary value (pointer) to private_data 1006field to refer its own data in the callbacks. 1007 1008The rest fields are filled by #snd_pcm_ioplug_create(). The pcm field 1009is the resultant PCM handle. The others are the current status of the 1010PCM. 1011 1012The callback functions in #snd_pcm_ioplug_callback_t define the real 1013behavior of the driver. 1014At least, start, stop and pointer callbacks must be given. Other 1015callbacks are optional. The start and stop callbacks are called when 1016the PCM stream is started and stopped, repsectively. The pointer 1017callback returns the current DMA position, which may be called at any 1018time. 1019 1020The transfer callback is called when any data transfer happens. It 1021receives the area array, offset and the size to transfer. The area 1022array contains the array of snd_pcm_channel_area_t with the elements 1023of number of channels. 1024 1025When the PCM is closed, close callback is called. If the driver 1026allocates any internal buffers, they should be released in this 1027callback. The hw_params and hw_free callbacks are called when 1028hw_params are set and reset, respectively. Note that they may be 1029called multiple times according to the application. Similarly, 1030sw_params callback is called when sw_params is set or changed. 1031 1032The prepare, drain, pause and resume callbacks are called when 1033#snd_pcm_prepare(), #snd_pcm_drain(), #snd_pcm_pause(), and 1034#snd_pcm_resume() are called. The poll_descriptors_count and 1035poll_descriptors callbacks are used to return the multiple or dynamic 1036poll descriptors as mentioned above. The poll_revents callback is 1037used to modify poll events. If the driver needs to mangle the native 1038poll events to proper poll events for PCM, you can do it in this 1039callback. 1040 1041Finally, the dump callback is used to print the status of the plugin. 1042 1043Note that some callbacks (start, stop, pointer, transfer and pause) 1044may be called inside the internal pthread mutex, and they shouldn't 1045call the PCM functions again unnecessarily from the callback itself; 1046otherwise it may lead to a deadlock. 1047 1048The hw_params constraints can be defined via either 1049#snd_pcm_ioplug_set_param_minmax() and #snd_pcm_ioplug_set_param_list() 1050functions after calling #snd_pcm_ioplug_create(). 1051The former defines the minimal and maximal acceptable values for the 1052given hw_params parameter (SND_PCM_IOPLUG_HW_XXX). 1053This function can't be used for the format parameter. The latter 1054function specifies the available parameter values as the list. 1055 1056To clear the parameter constraints, call #snd_pcm_ioplug_params_reset() function. 1057 1058*/ 1059 1060/** 1061 * \brief Create an ioplug instance 1062 * \param ioplug the ioplug handle 1063 * \param name name of PCM 1064 * \param stream stream direction 1065 * \param mode PCM open mode 1066 * \return 0 if successful, or a negative error code 1067 * 1068 * Creates the ioplug instance. 1069 * 1070 * The callback is the mandatory field of ioplug handle. At least, start, stop and 1071 * pointer callbacks must be set before calling this function. 1072 * 1073 */ 1074int snd_pcm_ioplug_create(snd_pcm_ioplug_t *ioplug, const char *name, 1075 snd_pcm_stream_t stream, int mode) 1076{ 1077 ioplug_priv_t *io; 1078 int err; 1079 snd_pcm_t *pcm; 1080 1081 assert(ioplug && ioplug->callback); 1082 assert(ioplug->callback->start && 1083 ioplug->callback->stop && 1084 ioplug->callback->pointer); 1085 1086 /* We support 1.0.0 to current */ 1087 if (ioplug->version < 0x010000 || 1088 ioplug->version > SND_PCM_IOPLUG_VERSION) { 1089 SNDERR("ioplug: Plugin version mismatch: 0x%x", 1090 ioplug->version); 1091 return -ENXIO; 1092 } 1093 1094 io = calloc(1, sizeof(*io)); 1095 if (! io) 1096 return -ENOMEM; 1097 1098 io->data = ioplug; 1099 ioplug->state = SND_PCM_STATE_OPEN; 1100 ioplug->stream = stream; 1101 1102 err = snd_pcm_new(&pcm, SND_PCM_TYPE_IOPLUG, name, stream, mode); 1103 if (err < 0) { 1104 free(io); 1105 return err; 1106 } 1107 1108 ioplug->pcm = pcm; 1109 pcm->ops = &snd_pcm_ioplug_ops; 1110 pcm->fast_ops = &snd_pcm_ioplug_fast_ops; 1111 pcm->private_data = io; 1112 1113 snd_pcm_set_hw_ptr(pcm, &ioplug->hw_ptr, -1, 0); 1114 snd_pcm_set_appl_ptr(pcm, &ioplug->appl_ptr, -1, 0); 1115 1116 snd_pcm_ioplug_reinit_status(ioplug); 1117 1118 return 0; 1119} 1120 1121/** 1122 * \brief Delete the ioplug instance 1123 * \param ioplug the ioplug handle 1124 * \return 0 if successful, or a negative error code 1125 */ 1126int snd_pcm_ioplug_delete(snd_pcm_ioplug_t *ioplug) 1127{ 1128 return snd_pcm_close(ioplug->pcm); 1129} 1130 1131 1132/** 1133 * \brief Reset ioplug parameters 1134 * \param ioplug the ioplug handle 1135 * 1136 * Resets the all parameters for the given ioplug handle. 1137 */ 1138void snd_pcm_ioplug_params_reset(snd_pcm_ioplug_t *ioplug) 1139{ 1140 ioplug_priv_t *io = ioplug->pcm->private_data; 1141 clear_io_params(io); 1142} 1143 1144/** 1145 * \brief Set parameter as the list 1146 * \param ioplug the ioplug handle 1147 * \param type parameter type 1148 * \param num_list number of available values 1149 * \param list the list of available values 1150 * \return 0 if successful, or a negative error code 1151 * 1152 * Sets the parameter as the list. 1153 * The available values of the given parameter type is restricted to the ones of the given list. 1154 */ 1155int snd_pcm_ioplug_set_param_list(snd_pcm_ioplug_t *ioplug, int type, unsigned int num_list, const unsigned int *list) 1156{ 1157 ioplug_priv_t *io = ioplug->pcm->private_data; 1158 if (type < 0 || type >= SND_PCM_IOPLUG_HW_PARAMS) { 1159 SNDERR("IOPLUG: invalid parameter type %d", type); 1160 return -EINVAL; 1161 } 1162 if (type == SND_PCM_IOPLUG_HW_PERIODS) 1163 io->params[type].integer = 1; 1164 return snd_ext_parm_set_list(&io->params[type], num_list, list); 1165} 1166 1167/** 1168 * \brief Set parameter as the min/max values 1169 * \param ioplug the ioplug handle 1170 * \param type parameter type 1171 * \param min the minimum value 1172 * \param max the maximum value 1173 * \return 0 if successful, or a negative error code 1174 * 1175 * Sets the parameter as the min/max values. 1176 * The available values of the given parameter type is restricted between the given 1177 * minimum and maximum values. 1178 */ 1179int snd_pcm_ioplug_set_param_minmax(snd_pcm_ioplug_t *ioplug, int type, unsigned int min, unsigned int max) 1180{ 1181 ioplug_priv_t *io = ioplug->pcm->private_data; 1182 if (type < 0 || type >= SND_PCM_IOPLUG_HW_PARAMS) { 1183 SNDERR("IOPLUG: invalid parameter type %d", type); 1184 return -EINVAL; 1185 } 1186 if (type == SND_PCM_IOPLUG_HW_ACCESS || type == SND_PCM_IOPLUG_HW_FORMAT) { 1187 SNDERR("IOPLUG: invalid parameter type %d", type); 1188 return -EINVAL; 1189 } 1190 if (type == SND_PCM_IOPLUG_HW_PERIODS) 1191 io->params[type].integer = 1; 1192 return snd_ext_parm_set_minmax(&io->params[type], min, max); 1193} 1194 1195/** 1196 * \brief Reinitialize the poll and mmap status 1197 * \param ioplug the ioplug handle 1198 * \return 0 if successful, or a negative error code 1199 * 1200 * Reinitializes the poll and the mmap status of the PCM. 1201 * Call this function to propagate the status change in the ioplug instance to 1202 * its PCM internals. 1203 */ 1204int snd_pcm_ioplug_reinit_status(snd_pcm_ioplug_t *ioplug) 1205{ 1206 ioplug->pcm->poll_fd = ioplug->poll_fd; 1207 ioplug->pcm->poll_events = ioplug->poll_events; 1208 if (ioplug->flags & SND_PCM_IOPLUG_FLAG_MONOTONIC) 1209 ioplug->pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC; 1210 else 1211 ioplug->pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY; 1212 ioplug->pcm->mmap_rw = ioplug->mmap_rw; 1213 return 0; 1214} 1215 1216/** 1217 * \brief Get mmap area of ioplug 1218 * \param ioplug the ioplug handle 1219 * \return the mmap channel areas if available, or NULL 1220 * 1221 * Returns the mmap channel areas if available. When mmap_rw field is not set, 1222 * this function always returns NULL. 1223 */ 1224const snd_pcm_channel_area_t *snd_pcm_ioplug_mmap_areas(snd_pcm_ioplug_t *ioplug) 1225{ 1226 if (ioplug->mmap_rw) 1227 return snd_pcm_mmap_areas(ioplug->pcm); 1228 return NULL; 1229} 1230 1231/** 1232 * \brief Change the ioplug PCM status 1233 * \param ioplug the ioplug handle 1234 * \param state the PCM status 1235 * \return zero if successful or a negative error code 1236 * 1237 * Changes the PCM status of the ioplug to the given value. 1238 * This function can be used for external plugins to notify the status 1239 * change, e.g. XRUN. 1240 */ 1241int snd_pcm_ioplug_set_state(snd_pcm_ioplug_t *ioplug, snd_pcm_state_t state) 1242{ 1243 ioplug->state = state; 1244 return 0; 1245} 1246 1247/** 1248 * \brief Get the available frames. This function can be used to calculate the 1249 * the available frames before calling #snd_pcm_avail_update() 1250 * \param ioplug the ioplug handle 1251 * \param hw_ptr hardware pointer in frames 1252 * \param appl_ptr application pointer in frames 1253 * \return available frames for the application 1254 */ 1255snd_pcm_uframes_t snd_pcm_ioplug_avail(const snd_pcm_ioplug_t * const ioplug, 1256 const snd_pcm_uframes_t hw_ptr, 1257 const snd_pcm_uframes_t appl_ptr) 1258{ 1259 return __snd_pcm_avail(ioplug->pcm, hw_ptr, appl_ptr); 1260} 1261 1262/** 1263 * \brief Get the available frames. This function can be used to calculate the 1264 * the available frames before calling #snd_pcm_avail_update() 1265 * \param ioplug the ioplug handle 1266 * \param hw_ptr hardware pointer in frames 1267 * \param appl_ptr application pointer in frames 1268 * \return available frames for the hardware 1269 */ 1270snd_pcm_uframes_t snd_pcm_ioplug_hw_avail(const snd_pcm_ioplug_t * const ioplug, 1271 const snd_pcm_uframes_t hw_ptr, 1272 const snd_pcm_uframes_t appl_ptr) 1273{ 1274 /* available data/space which can be transferred by the user 1275 * application 1276 */ 1277 const snd_pcm_uframes_t user_avail = snd_pcm_ioplug_avail(ioplug, 1278 hw_ptr, 1279 appl_ptr); 1280 1281 if (user_avail > ioplug->pcm->buffer_size) { 1282 /* there was an Xrun */ 1283 return 0; 1284 } 1285 /* available data/space which can be transferred by the DMA */ 1286 return ioplug->pcm->buffer_size - user_avail; 1287} 1288