1// SPDX-License-Identifier: GPL-2.0 2// 3// xfer-libffado.c - receive/transmit frames by libffado. 4// 5// Copyright (c) 2018 Takashi Sakamoto <o-takashi@sakamocchi.jp> 6// 7// Licensed under the terms of the GNU General Public License, version 2. 8 9#include "xfer.h" 10#include "misc.h" 11 12#include "frame-cache.h" 13 14#include <stdio.h> 15#include <sched.h> 16 17#include <libffado/ffado.h> 18 19struct libffado_state { 20 ffado_device_t *handle; 21 enum ffado_direction direction; 22 23 char *port_literal; 24 char *node_literal; 25 char *guid_literal; 26 unsigned int frames_per_period; 27 unsigned int periods_per_buffer; 28 unsigned int sched_priority; 29 bool slave_mode:1; 30 bool snoop_mode:1; 31 32 unsigned int data_ch_count; 33 ffado_streaming_stream_type *data_ch_map; 34 35 int (*process_frames)(struct xfer_context *xfer, 36 unsigned int *frame_count, 37 struct mapper_context *mapper, 38 struct container_context *cntrs); 39 40 struct frame_cache cache; 41}; 42 43enum no_short_opts { 44 OPT_FRAMES_PER_PERIOD = 200, 45 OPT_PERIODS_PER_BUFFER, 46 OPT_SLAVE_MODE, 47 OPT_SNOOP_MODE, 48 OPT_SCHED_PRIORITY, 49}; 50 51#define S_OPTS "p:n:g:" 52static const struct option l_opts[] = { 53 {"port", 1, 0, 'p'}, 54 {"node", 1, 0, 'n'}, 55 {"guid", 1, 0, 'g'}, 56 {"frames-per-period", 1, 0, OPT_FRAMES_PER_PERIOD}, 57 {"periods-per-buffer", 1, 0, OPT_PERIODS_PER_BUFFER}, 58 {"slave", 0, 0, OPT_SLAVE_MODE}, 59 {"snoop", 0, 0, OPT_SNOOP_MODE}, 60 {"sched-priority", 1, 0, OPT_SCHED_PRIORITY}, // to SCHED_FIFO 61}; 62 63static int xfer_libffado_init(struct xfer_context *xfer, 64 snd_pcm_stream_t direction) 65{ 66 struct libffado_state *state = xfer->private_data; 67 68 if (direction == SND_PCM_STREAM_CAPTURE) 69 state->direction = FFADO_CAPTURE; 70 else if (direction == SND_PCM_STREAM_PLAYBACK) 71 state->direction = FFADO_PLAYBACK; 72 else 73 return -EINVAL; 74 75 return 0; 76} 77 78static int xfer_libffado_parse_opt(struct xfer_context *xfer, int key, 79 const char *optarg) 80{ 81 struct libffado_state *state = xfer->private_data; 82 int err; 83 84 if (key == 'p') 85 state->port_literal = arg_duplicate_string(optarg, &err); 86 else if (key == 'n') 87 state->node_literal = arg_duplicate_string(optarg, &err); 88 else if (key == 'g') 89 state->guid_literal = arg_duplicate_string(optarg, &err); 90 else if (key == OPT_FRAMES_PER_PERIOD) 91 state->frames_per_period = arg_parse_decimal_num(optarg, &err); 92 else if (key == OPT_PERIODS_PER_BUFFER) 93 state->periods_per_buffer = arg_parse_decimal_num(optarg, &err); 94 else if (key == OPT_SLAVE_MODE) 95 state->slave_mode = true; 96 else if (key == OPT_SNOOP_MODE) 97 state->snoop_mode = true; 98 else if (key == OPT_SCHED_PRIORITY) 99 state->sched_priority = arg_parse_decimal_num(optarg, &err); 100 else 101 err = -ENXIO; 102 103 return err; 104} 105 106static int validate_sched_priority(struct libffado_state *state) 107{ 108 int val; 109 110 val = sched_get_priority_max(SCHED_FIFO); 111 if (val < 0) 112 return -errno; 113 if (state->sched_priority > val) 114 return -EINVAL; 115 116 val = sched_get_priority_min(SCHED_FIFO); 117 if (val < 0) 118 return -errno; 119 if (state->sched_priority < val) 120 return -EINVAL; 121 122 return 0; 123} 124 125static int xfer_libffado_validate_opts(struct xfer_context *xfer) 126{ 127 struct libffado_state *state = xfer->private_data; 128 int err; 129 130 if (state->node_literal != NULL) { 131 if (state->port_literal == NULL) { 132 fprintf(stderr, 133 "'n' option should correspond 'p' option.\n"); 134 return -EINVAL; 135 } 136 } 137 138 if (state->port_literal != NULL && state->guid_literal != NULL) { 139 fprintf(stderr, 140 "Neither 'p' option nor 'g' option is available at the " 141 "same time.\n"); 142 return -EINVAL; 143 } 144 145 if (state->guid_literal != NULL) { 146 if (strstr(state->guid_literal, "0x") != state->guid_literal) { 147 fprintf(stderr, 148 "A value of 'g' option should have '0x' as its " 149 "prefix for hexadecimal number.\n"); 150 return -EINVAL; 151 } 152 } 153 154 if (state->slave_mode && state->snoop_mode) { 155 fprintf(stderr, "Neither slave mode nor snoop mode is available" 156 "at the same time.\n"); 157 return -EINVAL; 158 } 159 160 if (state->sched_priority > 0) { 161 err = validate_sched_priority(state); 162 if (err < 0) 163 return err; 164 } 165 166 if (state->frames_per_period == 0) 167 state->frames_per_period = 512; 168 if (state->periods_per_buffer == 0) 169 state->periods_per_buffer = 2; 170 171 return 0; 172} 173 174static int r_process_frames(struct xfer_context *xfer, 175 unsigned int *frame_count, 176 struct mapper_context *mapper, 177 struct container_context *cntrs) 178{ 179 struct libffado_state *state = xfer->private_data; 180 unsigned int avail_count; 181 unsigned int bytes_per_frame; 182 unsigned int consumed_count; 183 int err; 184 185 // Trim up to expected frame count. 186 avail_count = state->frames_per_period; 187 if (*frame_count < avail_count) 188 avail_count = *frame_count; 189 190 // Cache required amount of frames. 191 if (avail_count > frame_cache_get_count(&state->cache)) { 192 int ch; 193 int pos; 194 195 // Register buffers. 196 pos = 0; 197 bytes_per_frame = state->cache.bytes_per_sample * 198 state->cache.samples_per_frame; 199 for (ch = 0; ch < state->data_ch_count; ++ch) { 200 char *buf; 201 202 if (state->data_ch_map[ch] != ffado_stream_type_audio) 203 continue; 204 205 buf = state->cache.buf_ptr; 206 buf += ch * bytes_per_frame; 207 if (ffado_streaming_set_capture_stream_buffer(state->handle, 208 ch, buf)) 209 return -EIO; 210 ++pos; 211 } 212 213 assert(pos == xfer->samples_per_frame); 214 215 // Move data to the buffer from intermediate buffer. 216 if (!ffado_streaming_transfer_buffers(state->handle)) 217 return -EIO; 218 219 frame_cache_increase_count(&state->cache, 220 state->frames_per_period); 221 } 222 223 // Write out to file descriptors. 224 consumed_count = frame_cache_get_count(&state->cache); 225 err = mapper_context_process_frames(mapper, state->cache.buf, 226 &consumed_count, cntrs); 227 if (err < 0) 228 return err; 229 230 frame_cache_reduce(&state->cache, consumed_count); 231 232 *frame_count = consumed_count; 233 234 return 0; 235} 236 237static int w_process_frames(struct xfer_context *xfer, 238 unsigned int *frame_count, 239 struct mapper_context *mapper, 240 struct container_context *cntrs) 241{ 242 struct libffado_state *state = xfer->private_data; 243 unsigned int avail_count; 244 int pos; 245 int ch; 246 unsigned int bytes_per_frame; 247 unsigned int consumed_count; 248 int err; 249 250 // Trim up to expected frame_count. 251 avail_count = state->frames_per_period; 252 if (*frame_count < avail_count) 253 avail_count = *frame_count; 254 255 // Cache required amount of frames. 256 if (avail_count > frame_cache_get_count(&state->cache)) { 257 avail_count -= frame_cache_get_count(&state->cache); 258 259 err = mapper_context_process_frames(mapper, state->cache.buf_ptr, 260 &avail_count, cntrs); 261 if (err < 0) 262 return err; 263 frame_cache_increase_count(&state->cache, avail_count); 264 avail_count = state->cache.remained_count; 265 } 266 267 // Register buffers. 268 pos = 0; 269 bytes_per_frame = state->cache.bytes_per_sample * 270 state->cache.samples_per_frame; 271 for (ch = 0; ch < state->data_ch_count; ++ch) { 272 char *buf; 273 274 if (state->data_ch_map[ch] != ffado_stream_type_audio) 275 continue; 276 277 buf = state->cache.buf; 278 buf += bytes_per_frame; 279 if (ffado_streaming_set_playback_stream_buffer(state->handle, 280 ch, buf)) 281 return -EIO; 282 ++pos; 283 } 284 285 assert(pos == xfer->samples_per_frame); 286 287 // Move data on the buffer for transmission. 288 if (!ffado_streaming_transfer_buffers(state->handle)) 289 return -EIO; 290 consumed_count = state->frames_per_period; 291 292 frame_cache_reduce(&state->cache, consumed_count); 293 294 *frame_count = consumed_count; 295 296 return 0; 297} 298 299static int open_handle(struct xfer_context *xfer, 300 unsigned int frames_per_second) 301{ 302 struct libffado_state *state = xfer->private_data; 303 ffado_options_t options = {0}; 304 ffado_device_info_t info = {0}; 305 306 char str[32] = {0}; 307 char *strings[1]; 308 309 // Set target unit if given. 310 if (state->port_literal != NULL) { 311 if (state->node_literal != NULL) { 312 snprintf(str, sizeof(str), "hw:%s,%s", 313 state->port_literal, state->node_literal); 314 } else { 315 snprintf(str, sizeof(str), "hw:%s", 316 state->port_literal); 317 } 318 } else if (state->guid_literal != NULL) { 319 snprintf(str, sizeof(str), "guid:%s", state->guid_literal); 320 } 321 if (str[0] != '\0') { 322 info.nb_device_spec_strings = 1; 323 strings[0] = str; 324 info.device_spec_strings = strings; 325 } 326 327 // Set common options. 328 options.sample_rate = frames_per_second; 329 options.period_size = state->frames_per_period; 330 options.nb_buffers = state->periods_per_buffer; 331 options.realtime = !!(state->sched_priority > 0); 332 options.packetizer_priority = state->sched_priority; 333 options.slave_mode = state->slave_mode; 334 options.snoop_mode = state->snoop_mode; 335 options.verbose = xfer->verbose; 336 337 state->handle = ffado_streaming_init(info, options); 338 if (state->handle == NULL) 339 return -EINVAL; 340 341 return 0; 342} 343 344static int enable_mbla_data_ch(struct libffado_state *state, 345 unsigned int *samples_per_frame) 346{ 347 int (*func_type)(ffado_device_t *handle, int pos); 348 int (*func_onoff)(ffado_device_t *handle, int pos, int on); 349 int count; 350 int ch; 351 352 if (state->direction == FFADO_CAPTURE) { 353 func_type = ffado_streaming_get_capture_stream_type; 354 func_onoff = ffado_streaming_capture_stream_onoff; 355 count = ffado_streaming_get_nb_capture_streams(state->handle); 356 } else { 357 func_type = ffado_streaming_get_playback_stream_type; 358 func_onoff = ffado_streaming_playback_stream_onoff; 359 count = ffado_streaming_get_nb_playback_streams(state->handle); 360 } 361 if (count <= 0) 362 return -EIO; 363 364 state->data_ch_map = calloc(count, sizeof(*state->data_ch_map)); 365 if (state->data_ch_map == NULL) 366 return -ENOMEM; 367 state->data_ch_count = count; 368 369 // When a data ch is off, data in the ch is truncated. This helps to 370 // align PCM frames in interleaved order. 371 *samples_per_frame = 0; 372 for (ch = 0; ch < count; ++ch) { 373 int on; 374 375 state->data_ch_map[ch] = func_type(state->handle, ch); 376 377 on = !!(state->data_ch_map[ch] == ffado_stream_type_audio); 378 if (func_onoff(state->handle, ch, on)) 379 return -EIO; 380 if (on) 381 ++(*samples_per_frame); 382 } 383 384 return 0; 385} 386 387static int xfer_libffado_pre_process(struct xfer_context *xfer, 388 snd_pcm_format_t *format, 389 unsigned int *samples_per_frame, 390 unsigned int *frames_per_second, 391 snd_pcm_access_t *access, 392 snd_pcm_uframes_t *frames_per_buffer) 393{ 394 struct libffado_state *state = xfer->private_data; 395 unsigned int channels; 396 int err; 397 398 // Supported format of sample is 24 bit multi bit linear audio in 399 // AM824 format or the others. 400 if (state->direction == FFADO_CAPTURE) { 401 if (*format == SND_PCM_FORMAT_UNKNOWN) 402 *format = SND_PCM_FORMAT_S24; 403 } 404 if (*format != SND_PCM_FORMAT_S24) { 405 fprintf(stderr, 406 "A libffado backend supports S24 only.\n"); 407 return -EINVAL; 408 } 409 410 // The backend requires the number of frames per second for its 411 // initialization. 412 if (state->direction == FFADO_CAPTURE) { 413 if (*frames_per_second == 0) 414 *frames_per_second = 48000; 415 } 416 if (*frames_per_second < 32000 || *frames_per_second > 192000) { 417 fprintf(stderr, 418 "A libffado backend supports sampling rate between " 419 "32000 and 192000, discretely.\n"); 420 return -EINVAL; 421 } 422 423 err = open_handle(xfer, *frames_per_second); 424 if (err < 0) 425 return err; 426 427 if (ffado_streaming_set_audio_datatype(state->handle, 428 ffado_audio_datatype_int24)) 429 return -EINVAL; 430 431 // Decide buffer layout. 432 err = enable_mbla_data_ch(state, &channels); 433 if (err < 0) 434 return err; 435 436 // This backend doesn't support resampling. 437 if (state->direction == FFADO_CAPTURE) { 438 if (*samples_per_frame == 0) 439 *samples_per_frame = channels; 440 } 441 if (*samples_per_frame != channels) { 442 fprintf(stderr, 443 "The number of samples per frame should be %u.\n", 444 channels); 445 return -EINVAL; 446 } 447 448 // A buffer has interleaved-aligned PCM frames. 449 *access = SND_PCM_ACCESS_RW_INTERLEAVED; 450 *frames_per_buffer = 451 state->frames_per_period * state->periods_per_buffer; 452 453 // Use cache for double number of frames per period. 454 err = frame_cache_init(&state->cache, *access, 455 snd_pcm_format_physical_width(*format) / 8, 456 *samples_per_frame, state->frames_per_period * 2); 457 if (err < 0) 458 return err; 459 460 if (state->direction == FFADO_CAPTURE) 461 state->process_frames = r_process_frames; 462 else 463 state->process_frames = w_process_frames; 464 465 if (ffado_streaming_prepare(state->handle)) 466 return -EIO; 467 468 if (ffado_streaming_start(state->handle)) 469 return -EIO; 470 471 return 0; 472} 473 474static int xfer_libffado_process_frames(struct xfer_context *xfer, 475 unsigned int *frame_count, 476 struct mapper_context *mapper, 477 struct container_context *cntrs) 478{ 479 struct libffado_state *state = xfer->private_data; 480 ffado_wait_response res; 481 int err; 482 483 res = ffado_streaming_wait(state->handle); 484 if (res == ffado_wait_shutdown || res == ffado_wait_error) { 485 err = -EIO; 486 } else if (res == ffado_wait_xrun) { 487 // No way to recover in this backend. 488 err = -EPIPE; 489 } else if (res == ffado_wait_ok) { 490 err = state->process_frames(xfer, frame_count, mapper, cntrs); 491 } else { 492 err = -ENXIO; 493 } 494 495 if (err < 0) 496 *frame_count = 0; 497 498 return err; 499} 500 501static void xfer_libffado_pause(struct xfer_context *xfer, bool enable) 502{ 503 struct libffado_state *state = xfer->private_data; 504 505 // This is an emergency avoidance because this backend doesn't support 506 // suspend/aresume operation. 507 if (enable) { 508 ffado_streaming_stop(state->handle); 509 ffado_streaming_finish(state->handle); 510 exit(EXIT_FAILURE); 511 } 512} 513 514static void xfer_libffado_post_process(struct xfer_context *xfer) 515{ 516 struct libffado_state *state = xfer->private_data; 517 518 if (state->handle != NULL) { 519 ffado_streaming_stop(state->handle); 520 ffado_streaming_finish(state->handle); 521 } 522 523 frame_cache_destroy(&state->cache); 524 free(state->data_ch_map); 525 state->data_ch_map = NULL; 526} 527 528static void xfer_libffado_destroy(struct xfer_context *xfer) 529{ 530 struct libffado_state *state = xfer->private_data; 531 532 free(state->port_literal); 533 free(state->node_literal); 534 free(state->guid_literal); 535 state->port_literal = NULL; 536 state->node_literal = NULL; 537 state->guid_literal = NULL; 538} 539 540static void xfer_libffado_help(struct xfer_context *xfer) 541{ 542 printf( 543" -p, --port decimal ID of port to decide 1394 OHCI controller for communication on IEEE 1394 bus\n" 544" -n, --node decimal ID of node to decide unit on IEEE 1394 bus for transmission of audio data frame\n" 545" -g, --guid hexadecimal ID for node on IEEE 1394 bus for transmission of audio data frame\n" 546" --frames-per-period the number of audio data frame to handle one operation (frame unit)\n" 547" --periods-per-bufer the number of periods in intermediate buffer between libffado (frame unit)\n" 548" --slave receive frames from the other Linux system on IEEE 1394 bus running with libffado.\n" 549" --snoop receive frames on packets of all isochronous channels.\n" 550" --sched-priority set SCHED_FIFO with given priority. see RLIMIT_RTPRIO in getrlimit(2).\n" 551 ); 552} 553 554const struct xfer_data xfer_libffado = { 555 .s_opts = S_OPTS, 556 .l_opts = l_opts, 557 .l_opts_count = ARRAY_SIZE(l_opts), 558 .ops = { 559 .init = xfer_libffado_init, 560 .parse_opt = xfer_libffado_parse_opt, 561 .validate_opts = xfer_libffado_validate_opts, 562 .pre_process = xfer_libffado_pre_process, 563 .process_frames = xfer_libffado_process_frames, 564 .pause = xfer_libffado_pause, 565 .post_process = xfer_libffado_post_process, 566 .destroy = xfer_libffado_destroy, 567 .help = xfer_libffado_help, 568 }, 569 .private_size = sizeof(struct libffado_state), 570}; 571