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