AXFER-TRANSFER(1)

πŸ“¦
version 1.2.16 Β· 2 versions
  • 1.2.16 Β· alpine 3.22, alpine 3.23, alpine 3.24, arch rolling, centos-stream 10, centos-stream 9, debian trixie, fedora 43, fedora 44, nixos 26.05, nixpkgs unstable, opensuse-leap 16.0, ubuntu noble, ubuntu questing, ubuntu resolute, ubuntu stonking (latest)
  • 1.2.8 Β· debian bookworm, ubuntu jammy
, in alpine 3.22, alpine 3.23, alpine 3.24, arch rolling, centos-stream 10, centos-stream 9, debian trixie, fedora 43, fedora 44, nixos 26.05, nixpkgs unstable, opensuse-leap 16.0, ubuntu noble, ubuntu questing, ubuntu resolute, ubuntu stonking

✨ AXFER-TRANSFER ✨

okay so bestie, welcome to axfer-transfer β€” the transferrer of audio data frame for sound devices and nodes. yes that's the whole name. it's from the General Commands Manual and it's iconic. πŸŽ€


πŸ¦‹ SYNOPSIS πŸ¦‹

axfer transfer direction [ common-options ] [ backend-options ] [ filepath ]

axfer transfer direction [ common-options ] [ backend-options ] -I | --separate-channels filepath ...

direction = capture | playback

common-options = ( read OPTIONS section )

backend-options = ( read OPTIONS section )

filepaths = ( read OPTIONS section )

that's the whole vibe check. direction goes either capture or playback, the common-options and backend-options live down in the OPTIONS section (scroll, babe, they're all there), and filepaths too. no cap. πŸ’…


🌸 DESCRIPTION 🌸

The transfer subcommand of axfer does the transmission of audio data frames for devices that are available in the supported backends. slay. Basically, this program was designed to use alsa-lib APIs (that's the libasound backend) to handle sound devices supported by the Linux sound subsystem (ALSA). πŸ¦‹


πŸŽ€ OPTIONS πŸŽ€

🌈 Direction 🌈

  • capture β€” operates for capture transmission. grabbing the sound out of the world, bestie. πŸŽ™οΈ
  • playback β€” operates for playback transmission. sending it back out into the world. πŸ”Š

πŸ“ Filepath πŸ“

So a filepath is handled as a path relative to the current working directory of run time β€” but only if it's not a full path from the root directory. iykyk.

The standard input or output is used if filepath is not specified, or if it's given as -. 🫢

For playback transmission, the container format of the given filepath is detected automatically, and that metadata gets used for the parameters of sample format, channels, rate, and duration. If nothing gets detected, then the content of the given file path is handled as raw data β€” and in that case, you gotta indicate the parameters as options yourself, bestie. πŸ’–

Multiple filepaths are allowed with the -I | --separate-channels option. But heads up: in that case, standard input and output is not available. And the same filepath is not allowed β€” except for these paths right here:

  • /dev/null
  • /dev/zero
  • /dev/full
  • /dev/random
  • /dev/urandom

(those five are the exceptions, periodt. everything else has to be unique.) ✨

⭐ Common options ⭐

  • -h, --help β€” prints help messages and finishes run time. the classic. πŸ’…
  • -q, --quiet β€” quiet mode. Suppresses messages. (not sound :)) 🀫
  • -v, --verbose β€” verbose mode. At runtime it dumps supplemental information according to the number of times this option is given on the command line. stack it up for more tea. 🍡
  • -d, --duration=# β€” interrupts after # seconds. A value of zero means infinity. The default is zero, so if this option is omitted then the transmission process will run until it is killed. Either -d or -s option is available exclusively. ⏱️
  • -s, --samples=# β€” interrupts after transmission of # number of data frames. A value of zero means infinity. The default is zero, so if this option is omitted then the transmission process will run until it is killed. Either -d or -s option is available exclusively. πŸ”’
  • -f, --format=FORMAT β€” indicates the format of the audio sample. This is required for capture transmission, or for playback transmission with files that include raw audio data. the available sample formats are listed right here:
    • [S8|U8|S16|U16|S32|U32][_LE|_BE]
    • [S24|U24][_LE|_BE]
    • FLOAT[_LE|_BE]
    • FLOAT64[_LE|_BE]
    • IEC958_SUBFRAME[_LE|_BE]
    • MU_LAW
    • A_LAW
    • [S20|U20][_LE|_BE]
    • [S24|U24][_3LE|_3BE]
    • [S20|U20][_3LE|_3BE]
    • [S18|U18][_3LE|_3BE]
    • DSD_U8
    • DSD_[U16|U32][_LE|_BE]

If endian-ness is omitted, host endian-ness is used. πŸ¦‹

Some special formats are available too, and they're giving convenience:

  • cd (16 bit little endian, 44100, stereo) [= -f S16_LE -c 2 -r 44100]
  • cdr (16 bit big endian, 44100, stereo) [= -f S16_BE -c 2 -f 44100]
  • dat (16 bit little endian, 48000, stereo) [= -f S16_LE -c 2 -r 48000]

If omitted, U8 is used as a default. Actual available formats are restricted by each transmission backend. ⭐

And now the unavailable sample format list β€” these formats have a size of data frame unaligned to byte unit: πŸ’€

  • IMA_ADPCM
  • MPEG
  • GSM
  • SPECIAL
  • G723_24
  • G723_24_1B
  • G723_40
  • G723_40_1B
  • -c, --channels=# β€” indicates the number of audio data samples per frame. This is required for capture transmission, or for playback transmission with files that include raw audio data. The value should be between 1 to 256. If omitted, 1 is used as a default. 🎚️
  • -r, --rate=# β€” indicates the number of audio data frame per second. This is required for capture transmission, or for playback transmission with files that include raw audio data. If the value is less than 1000, it's interpreted by kHz unit. The value should be between 2000 and 192000. If omitted, 8000 is used as a default. 🌊
  • -t, --file-type=TYPE β€” indicates the type of file. This is required for capture transmission. The available types are listed below:
    • wav: Microsoft/IBM RIFF/Wave format
    • au, sparc: Sparc AU format
    • voc: Creative Tech. voice format
    • raw: raw data

When nothing is indicated, for capture transmission, the type is decided according to the suffix of filepath, and raw type is used for fallback. πŸŽ€

  • -I, --separate-channels β€” indicate this option when several files are going to be handled. For capture transmission, if one filepath is given as filepath, a list of filepaths is generated in the formula '<filepath>-<sequential number>[.suffix]'. The suffix is omitted when raw format of container is used. πŸ—‚οΈ
  • --dump-hw-params β€” dumps hardware parameters and finishes run time, if the backend supports it. πŸ‘€
  • --xfer-backend=BACKEND β€” selects the backend of transmission from the list below. The default is libasound.
    • libasound
    • libffado (optional if compiled)

πŸ‘‘ Backend options for libasound πŸ‘‘

  • -D, --device=NODE

This option is used to select the PCM node in the libasound configuration space. Available nodes are listed by the pcm operation of the list subcommand. 🎯

  • -N, --nonblock

With this option, the PCM substream is opened in non-blocking mode. When an audio data frame is not available in the buffer of the PCM substream, the I/O operation immediately returns without blocking the process. This option implicitly uses the --waiter-type option as well, to prevent heavy consumption of CPU time. πŸ”₯

  • -M, --mmap

With this option, the audio data frame is processed directly in the buffer of the PCM substream, if the selected node supports this operation. Without the option, temporary buffers are used to copy the audio data frame for the buffer of the PCM substream. This option implicitly uses the --waiter-type option as well, to prevent heavy consumption of CPU time. πŸ”₯

  • -F, --period-size=#

This option configures the given value to the period_size hardware parameter of the PCM substream. The parameter indicates the number of audio data frame per period in the buffer of the PCM substream. Actual number is decided as a result of interaction between each implementation of the PCM plugin chained from the selected PCM node, and the in-kernel driver or PCM I/O plugins.

Ideally, the same amount of audio data frame as the value should be handled in one I/O operation. Actually, it is not, depending on implementation of the PCM plugins, the in-kernel driver, PCM I/O plugins and scheduling model. For the 'hw' PCM plugin in the 'irq' scheduling model, the value is used to decide the intervals of hardware interrupt, thus the same amount of audio data frame as the value is expected to be available for one I/O operation. πŸ“

  • --period-time=#

This option configures the given value to the period_time hardware parameter of the PCM substream. This option is similar to the --period-size option, however its unit is micro-second. ⏳

  • -B, --buffer-size=#

This option configures the given value to the buffer_size hardware parameter of the PCM substream. The parameter indicates the number of audio data frame in the buffer of the PCM substream. Actual number is decided as a result of interaction between each implementation of the PCM plugin chained from the selected PCM node, and the in-kernel driver or PCM I/O plugins.

Ideally, this is multiples of the number of audio data frame per period, thus the size of period. Actually, it is not, depending on implementation of the PCM plugins, the in-kernel driver and PCM I/O plugins. πŸ“

  • --buffer-time=#

This option configures the given value to the buffer_time hardware parameter of the PCM substream. This option is similar to the --buffer-size option, however its unit is micro-second. ⏳

  • --waiter-type=TYPE

This option indicates the type of waiter for event notification. At present, four types are available: default, select, poll and epoll. With the default type, 'snd_pcm_wait()' is used. With the select type, the 'select(2)' system call is used. With the poll type, the 'poll(2)' system call is used. With the epoll type, the Linux-specific 'epoll(7)' system call is used. πŸ‘‘

This option should correspond to one of the --nonblock or --mmap options, or the timer value of the --sched-model option. Neither this option nor --test-nowait is available at the same time. 🚫

  • --sched-model=MODEL

This option selects the scheduling model for the process of this program. One of irq or timer is available. In detail, please read the 'SCHEDULING MODEL' section. πŸ“š

When nothing is specified, the irq model is used. βš™οΈ

  • -A, --avail-min=#

This option configures the given value to the avail-min software parameter of the PCM substream. In blocking mode, the value is used as the threshold of the number of available audio data frames in the buffer of the PCM substream to wake up the process blocked by the I/O operation. In non-blocking mode, any I/O operation returns -EAGAIN until the available number of audio data frame reaches the threshold. πŸ›ŽοΈ

This option has an effect in cases where neither --mmap nor the timer value of the --sched-model option is used. πŸ’‘

  • -R, --start-delay=#

This option configures the given value to the start_threshold software parameter of the PCM substream. The value is used as a threshold to start the PCM substream automatically. At present, this option has an effect in cases where neither --mmap nor the timer value of the --sched-model option is used. πŸš€

For playback transmission, when the number of accumulated audio data frame in buffer of PCM substream to which this program writes out reaches the threshold, the PCM substream starts automatically without an explicit call of snd_pcm_start() to the PCM substream.

For capture transmission, this option is useless. The number of accumulated audio data frame is not increased without an explicit call of snd_pcm_start() to the PCM substream.

This option has an effect in cases neither --mmap nor timer value of --sched-model option is used.

  • -T, --stop-delay=# β€” sets the given value into the stop_threshold software parameter of the PCM substream πŸ’…

This value is used as the threshold to stop the PCM substream automatically. At present, this option has an effect in cases neither --mmap nor timer value of --sched-model option is used.

For capture transmission, when the number of accumulated audio data frame in buffer of PCM substream to which a driver or alsa-lib PCM plugins write reaches the threshold, the PCM substream stops automatically without an explicit call of snd_pcm_stop() to the PCM substream. This is a case that this program leaves the audio data frames without reading for a while.

For playback transmission, when the number available audio data frame in buffer of PCM substream from which a driver or alsa-lib PCM plugins read reaches the threshold, the PCM substream stops automatically without an explicit call of snd_pcm_stop() to the PCM substream. This is a case that this program leaves the audio data frames without writing for a while.

This option has an effect in cases neither --mmap nor timer value of --sched-model option is used.

  • --disable-resample β€” no resampling, bestie πŸŽ€ has an effect for 'plug' plugin in alsa-lib to suppress conversion of sampling rate for audio data frame.
  • --disable-channels β€” keeps your channels exactly where they are πŸ¦‹ has an effect for 'plug' plugin in alsa-lib to suppress conversion of channels for audio data frame.
  • --disable-format β€” format stays format, periodt ✨ has an effect for 'plug' plugin in alsa-lib to suppress conversion of sample format for audio data frame.
  • --disable-softvol β€” has an effect for 'softvol' plugin in alsa-lib to suppress conversion of samples for audio data frame via additional control element. no extra volume knob, we're being pure about it πŸ’œ
  • --fatal-errors β€” this one is giving absolutely no chill 😭 it suppresses recovery operation from XRUN state of running PCM substream, then process of this program is going to finish as usual.
  • --test-nowait β€” disables any waiter for I/O event notification. I/O operations are iterated till any of audio data frame is available. The option brings heavy load in consumption of CPU time.
⚠️ okay so heads up: --test-nowait is literally going to eat your CPU alive, that's not a vibe, that's a warning.

πŸ”₯ Backend options for libffado πŸ”₯

This backend is automatically available when configure script detects ffado_streaming_init() symbol in libffado shared object.

  • -p, --port=# β€” this option uses given value to decide which 1394 OHCI controller is used to communicate 🌸

When Linux system has two 1394 OHCI controllers, 0 or 1 are available. Neither this option nor -g is available at the same time. If nothing specified, libffado performs to communicate to units on IEEE 1394 bus managed by all of 1394 OHCI controller available in Linux system.

  • -n, --node=# β€” picks which unit is used to communicate πŸ’«

This option uses given value to decide which unit is used to communicate. This option requires -p option to indicate which 1394 OHCI controller is used to communicate to the specified unit.

  • -g, --guid=HEXADECIMAL β€” this option uses given value to decide a target unit to communicate πŸ”

The value should be prefixed with '0x' and consists of hexadecimal literal letters (0-9, a-f, A-F). Neither this option nor -p is available at the same time. If nothing specified, libffado performs to communicate to units on IEEE 1394 bus managed by all of 1394 OHCI controller available in Linux system.

  • --frames-per-period=# β€” this option uses given value to decide the number of audio data frame in one read/write operation. The operation is blocked till the number of available audio data frame exceeds the given value. As a default, 512 audio data frames is used.
  • --periods-per-buffer=# β€” this option uses given value to decide the size of intermediate buffer between this program and libffado. As a default, 2 periods per buffer is used.
  • --slave β€” allows this program to run slave mode πŸ‘‘

In this mode, libffado adds unit directory into configuration ROM of 1394 OHCI controller where Linux system runs. The unit directory can be found by the other node on the same bus. Linux system running on the node can transfer isochronous packet with audio data frame to the unit. This program can receive the packet and demultiplex the audio data frame.

  • --snoop β€” allows this program to run snoop mode πŸ•΅οΈ

In this mode, libffado listens isochronous channels to which device transfers isochronous packet. When isochronous communication starts by any unit on the same bus, the packets can be handled by this program.

  • --sched-priority=# β€” this option executes pthread_setschedparam() in a call of ffado_streaming_init() to configure scheduling policy and given value as its priority for threads related to isochronous communication. The given value should be within RLIMIT_RTPRIO parameter of process. Please read getrlimit(2) for details. πŸ“–

🚨 POSIX SIGNALS 🚨

During transmission, SIGINT and SIGTERM will close handled files and PCM substream to be going to finish run time. like, it's wrapping up, bestie, it said its goodbyes πŸ’–

SIGTSTP will suspend PCM substream and SIGCONT will resume it. No XRUNs are expected. With libffado backend, the suspend/resume is not supported and runtime is aborted immediately. so with libffado that's just a hard stop, no gentle pause, ok?? 😭

The other signals perform default behaviours.


🌈 EXAMPLES 🌈

okay these are the ones you're gonna actually use, let's gooo ✨

$ axfer transfer playback -d 1 something

The above will transfer audio data frame in 'something' file for playback during 1 second. The sample format is detected automatically as a result to parse 'something' as long as it's compliant to one of Microsoft/IBM RIFF/Wave, Sparc AU, Creative Tech. voice formats. If nothing detected, -r, -c and -f should be given, or -f should be given with special format.

$ axfer transfer playback -r 22050 -c 1 -f S16_LE -t raw something

The above will transfer audio data frame in 'something' file including no information of sample format, as sample format of 22050 Hz, monaural, signed 16 bit little endian PCM for playback. The transmission continues till catching SIGINT from keyboard or SIGTERM by kill(1) . so basically it goes forever until you Ctrl-C it πŸ‘

$ axfer transfer capture -d 10 -f cd something.wav

The above will transfer audio data frame to 'something.wav' file as sample format of 44.1 kHz, 2 channels, signed 16 bit little endian PCM, during 10 seconds. The file format is Microsoft/IBM RIFF/Wave according to suffix of the given filepath .

$ axfer transfer capture -s 1024 -r 48000 -c 2 -f S32_BE -I -t au channels

The above will transfer audio data frame as sample format of 48.0 kHz, 2 channels, signed 32 bit big endian PCM for 1,024 number of data frames to files named 'channels-1.au' and 'channels-2.au'. two files, split by channel, iconic behaviour fr πŸ’…

🎧 SCHEDULING MODEL 🎧

ok so here's the tea, bestie: in the design of the ALSA PCM core, the runtime of a PCM substream supports two modes β€” period-wakeup and no-period-wakeup. Two modes, two totally different scheduling models. Let's get into it πŸ’…


⏰ IRQ-based scheduling model ⏰

By default, period-wakeup mode is what you get. In this mode, in-kernel drivers should operate hardware to generate periodical notification for transmission of audio data frame. The interval of that notification is equivalent to the same amount of audio data frame as one period of buffer, against actual time. slay.

In a handler assigned to the notification, a helper function of ALSA PCM core gets called to update a position to head of hardware transmission, then compare it with a position to head of application operation to judge overrun/underrun (XRUN) and to wake up blocked processes. very much the main character of this whole flow.

For this purpose, hardware IRQ of controller for serial audio bus such as Inter-IC sound is typically used. In this case, the controller generates the IRQ according to transmission on the serial audio bus. And in the handler assigned to that IRQ, direct media access (DMA) transmission is requested between dedicated host memory and device memory. no cap.

If target hardware doesn't support this kind of mechanism, the periodical notification should be emulated by any timer; e.g. hrtimer, kernel timer. External PCM plugins generated by PCM plugin SDK in alsa-lib should also emulate the above behaviour. everyone pitches in πŸ’–

In this mode, PCM applications are programmed according to the typical way of I/O operations. They execute blocking system calls to read/write audio data frame in buffer of PCM substream, or blocking system calls to wait until any audio data frame is available. In axfer, this is called the IRQ-based scheduling model and it's the default behaviour. Users can explicitly configure this mode by usage of --sched-model option with irq value. iykyk.


πŸ¦‹ Timer-based scheduling model πŸ¦‹

The no-period-wakeup mode is an optional mode of runtime of PCM substream. The mode assumes a specific feature of hardware and assist of in-kernel driver and PCM applications. In this mode, in-kernel drivers don't operate hardware to generate periodical notification for transmission of audio data frame. The hardware should automatically continue transmission of audio data frame without periodical operation of the drivers; e.g. according to auto-triggered DMA transmission, a chain of registered descriptors. it's giving self-sufficient ✨

In this mode, nothing wakes up blocked processes, therefore PCM applications should be programmed without any blocking operation. For this reason, this mode is enabled when the PCM applications explicitly configure hardware parameter to runtime of PCM substream, to prevent disorder of existing applications. so polite of it.

Additionally, nothing maintains timing for transmission of audio data frame, therefore the PCM applications should voluntarily handle any timer to queue audio data frame in buffer of the PCM substream for lapse of time. Furthermore, instead of the driver, the PCM application should call a helper function of ALSA PCM core to update a position to head of hardware transmission and to check XRUN.

In axfer, this is called the timer-based scheduling model and it's available as long as hardware/driver assists no-period-wakeup runtime. Users should explicitly set this mode by usage of --sched-model option with timer value. literally just say the word.

In the scheduling model, PCM applications need to care of available space on PCM buffer by lapse of time, typically by yielding CPU and wait for rescheduling. For the yielding, timeout is calculated for preferable amount of PCM frames to process. This is convenient to a kind of applications, like sound servers β€” when an I/O thread of the server wait for the timeout, the other threads can process audio data frames for server clients. teamwork, we love to see it 🫢

Furthermore, with usage of rewinding/forwarding, applications can achieve low latency between transmission position and handling position even if they uses large size of PCM buffers. big buffers, small latency, bestie behavior.


🌈 Advantages and issues 🌈

Ideally, timer-based scheduling model has some advantages than IRQ-based scheduling model. Let's list the wins:

  1. At first, no interrupt context runs for PCM substream. The PCM substream is handled in any process context only. No need to care of race conditions between IRQ and process contexts. This reduces some concerns for some developers of drivers and applications. peace of mind fr.
  2. Secondary, CPU time is not used for handlers on the interrupt context. The CPU time can be dedicated for the other tasks. This is good in a point of Time Sharing System.
  3. Thirdly, hardware is not configured to generate interrupts. This is good in a point of reduction of overall power consumption possibly. save the planet, save the battery πŸ“
Now the caveat, and bestie this one matters: in either scheduling model, the hardware should allow drivers to read the number of audio data frame transferred between the dedicated memory and the device memory for audio serial bus. However, in timer-based scheduling model, fine granularity and accuracy of the value is important.

Actually hardware performs transmission between dedicated memory and device memory for a small batch of audio data frames or bytes. In a view of PCM applications, the granularity in current transmission is required to decide correct timeout for each I/O operation. And as of Linux kernel v4.21, ALSA PCM interface between kernel/userspace has no feature to report it. πŸ’€ so that's a whole thing.


πŸ’… COMPATIBILITY TO APLAY πŸ’…

The transfer subcommand of axfer is designed to keep compatibility to aplay(1). However some options below are not compatible due to several technical reasons. buckle up, here's the list πŸ‘‘

  • -I, --separate-channels β€” This option is supported just for files to store audio data frames corresponding to each channel. In aplay(1) implementation, this option has an additional effect to use PCM buffer aligned to non-interleaved order if a target device supports. As of 2018, PCM buffer of non-interleaved order is hardly used by sound devices.
  • -A, --avail-min=# β€” This option indicates threshold to wake up blocked process in a unit of audio data frame. Against aplay(1) implementation, this option has no effect with --mmap option as well as timer of --sched-model option.
  • -R, --start-delay=# β€” This option indicates threshold to start prepared PCM substream in a unit of audio data frame. Against aplay(1) implementation, this option has no effect with --mmap option as well as timer of --sched-model option.
  • -T, --stop-delay=# β€” This option indicates threshold to stop running PCM substream in a unit of audio data frame. Against aplay(1) implementation, this option has no effect with --mmap option as well as timer of --sched-model option.
  • --max-file-time=# β€” This option is unsupported. In aplay(1) implementation, the option has an effect for capture transmission to save files up to the same number of data frames as the given value by second unit, or the maximum number of data frames supported by used file format. When reaching to the limitation, used file is closed, then new file is opened and audio data frames are written. However, this option requires extra handling of files and shall increase complexity of main loop of axfer. not the vibe we're going for.
  • --use-strftime=FORMAT β€” This option is unsupported. In aplay(1) implementation, the option has an effect for capture transmission to generate file paths according to given format in which some extra formats are available as well as formats supported by strftime(3). However, this option requires extra string processing for file paths and it's bothersome if written in C language. πŸ’€
  • --process-id-file=FILEPATH β€” This option is unsupported. In aplay(1) implementation, the option has an effect to create a file for given value and write out process ID to it. This file allows users to get process ID and send any POSIX signal to aplay process. However, this idea has some troubles for file locking when multiple aplay processes run with the same file. messy, we don't do that.
  • -V, --vumeter=TYPE β€” This option is not supported at present. In aplay(1) implementation, this option has an effect to occupy stdout with some terminal control characters and display vumeter for monaural and stereo channels. However, some problems lay; this feature is just for audio data frames with PCM format, this feature brings disorder of terminal after aborting, stdout is not available for pipeline. yeah no πŸ™ˆ
  • -i, --interactive β€” This option is not supported at present. In aplay(1) implementation, this option has an effect to occupy stdin for key input and suspend/resume PCM substream according to pushed enter key. However, this feature requires an additional input handling in main loop and leave bothersome operation to maintain PCM substream.
  • -m, --chmap=CH1,CH2,... β€” ALSA PCM core and control core doesn't support this feature, therefore remapping should be done in userspace. This brings overhead to align audio data frames, especially for mmap operation. Furthermore, as of alsa-lib v1.1.8, some plugins don't support this feature expectedly, thus this option is a lack of transparent operation. At present, this option is not supported yet not to confuse users. protecting y'all from confusion, that's the job πŸŽ€
  • SIGTSTP, SIGCONT β€” This performs suspend/resume of PCM substream. In aplay(1) implementation, these operations bring XRUN state to the substream, and suspend/resume is done in interactive mode in the above. Some developers use the signal for recovery test from XRUN. At present, no alternative is supported for the test.
  • SIGUSR1 β€” This is not supported. In aplay(1) implementation, this signal is assigned to a handler to close a current file to store audio data frame and open a new file to continue processing. However, as well as --max-file-time option, this option should increase complexity of main loop of axfer.

🧩 DESIGN 🧩

okay bestie this is the part where we pop the hood and look at the ENGINE πŸ”₯ and honestly? it's giving gorgeous modular architecture, no cap.

πŸ› οΈ Modular structure

So the whole program is made of three modules: xfer, mapper and container. And every single one of them has an abstraction layer so the real implementation can be swapped in underneath, which is so clean of them honestly πŸ’…

           --------     ----------     -------------
device <-> | xfer | <-> | mapper | <-> | container | <-> file
           --------     ----------     -------------
            libasound    single         wav
            libffado     multiple       au
                                        voc
                                        raw
  • The xfer module is the one actually doing the transmission to devices and nodes, like it's the extrovert of the group 🫢. It can have several transmission backends. By default it uses the libasound backend to transmit via alsa-lib APIs. And here's the cute part: the module lets each backend parse its own command line options, so every backend gets to have main character energy with its own flags ✨
  • The container module reads/writes audio data frames through a descriptor for a file/stream of a multimedia container, or just raw data. It automatically detects the type of multimedia container and parses the parameters in that data header's metadata, like it just knows 🧚. At present three types of multimedia containers are supported: Microsoft/IBM RIFF/Wave (wav), Sparc AU (au) and Creative Technology voice (voc). Plus there's a special container prepped just for raw audio data (raw) 🌸
  • The mapper module handles buffer layout and alignment for transmission of audio data frames. It has two implementations: single and multiple. The single backend uses one container to construct the buffer, and the multiple backend uses several containers to construct it πŸ‘‘

πŸ“¦ Care of copying audio data frame

Between the xfer module and the mapper module, a pointer to a buffer containing audio data frames gets passed around. This buffer comes in two shapes: interleaved order and non-interleaved order πŸ’–

  • For interleaved, the pointer points to one buffer.
  • For non-interleaved, the pointer points to an array where each element points to one buffer.

Between the mapper module and the container module, a pointer to one buffer gets passed, because the supported media containers β€” including the raw type β€” store audio data frames in interleaved order. that's just the vibe πŸ¦‹

And when passing audio data frames between modules, axfer is programmed to avoid copying between one buffer and another as much as possible, because copying is lowkey wasteful and we simply do not do that here πŸ™ˆ

For example, in the scenarios below, no copying occurs between modules:

  • xfer(mmap/interleaved), mapper(single), container(any)
  • xfer(mmap/non-interleaved), mapper(multiple), containers(any)

zero copies, zero drama, iconic behavior fr fr ⭐

πŸ§ͺ Unit test

For each of the mapper and container modules, a unit test is available πŸŽ€ To run the tests, execute this command:

$ make test
⚠️ heads up bestie: each test iterates writing to file and reading from the file many times, so it takes a long time to finish. Please take care of the execution time if you're running on any CI environment 😭 the tests are thorough and they will absolutely eat your pipeline minutes.

πŸ‘€ SEE ALSO πŸ‘€

πŸ’œ AUTHOR πŸ’œ

Takashi Sakamoto <o-takashi@sakamocchi.jp>


and that's the whole page, bestie, we made it to the end πŸ₯ΉπŸ’– this beauty comes from alsa-utils, dated 28 November 2018, and it's AXFER-TRANSFER(1) β€” go forth and transfer some audio, you absolute legend πŸ‘‘βœ¨ slay 🫢