NihAV: towards an audio player

So after weeks of doing nothing and looking at lossless audio codecs (in no particular order) I’m going back to developing NihAV and more particularly an audio player.

The main problem with nihav-player concept is that 1) it’s primarily video player 2) it’s based on outdated SDL1 instead of SDL2 3) the SDL1 wrapper especially in audio area was incomplete and my shim implementation for audio callback as a trait is not good enough so it deadlocks time from time. So I’ve finally installed SDL2 and started to write a new audio-only player based on it (well, considering that I’m not trying to write a cross-platform player an ALSA wrapper would do but I’d rather avoid it). It turns out that SDL2 has its own audio queue interface which simplifies my life (at least for now)—instead of NIHing it and encountering deadlocks I can now simply send data to the queue, check how many samples are still there to be played and add more when I want to. Maybe later when I need more advanced processing I’ll implement proper callback-based audio processing pipeline but for my current needs this is enough.

And now I’d like to complain about the crates I use and don’t use. This is not a fault of Rust programming language but rather a downside created by modern approach to programming and enabled by all those package managers like Cargo and most famously npm.js (which is the synonym with the bloated library dependencies).

First of all I need tcgetattr()/tcsetattr() for reading commands from the terminal. If I simply use libc crate it does what I want it to do, but if I’d use suggested “friendly” wrapper for it called nix it’ll try to pull additional two or three crates and will fail to build with rustc 1.33 that I still have no reason to migrate from. SDL2 wrappers are even worse. sdl2-sys that provides just bindings to the library depends on cfg-if and libc crates which is reasonable. sdl2 crate though is a bloated beast pulling a dozen of dependencies with some of them being duplicate (before version 0.33 it pulled rand crate by default which pulled a dozen of other crates, some of them depending on different rand_core version from the others; and the saddest thing is that it was required just to allow generating random pixel values). And I can’t compile that version because it depends on TryFrom trait instead of num-traits crate and you need a compiler at least two months younger to support it. The older version should work just fine though.

The rant is over, back to the NihAV matters.

Now my player can play various formats supported by NihAV, pause/resume playback, seek forward and backward. Essentially it’s good enough for everyday music needs. I’m still considering whether I should not support MP3 or definitely not support it.

And for achieving that I had to fix some bugs, add a seeking for FLAC files without seektable (which seems to be virtually all FLAC files out there), make demuxers report duration (either as a container or a stream property) plus some optimisations in Monkey’s Audio decoder.

The optimisations was a funny thing. At first I tried SSE intrinsics provided by the compiler and it turned out that loop unrolling by 16 leads to wrong results in one of the sum registers. But unrolling it by 8 worked fine—except that auto-vectorisation in the compiler did even better job on the same code turned into a standalone function with iterators. Plus IMO x86 intrinsics look ugly with their _mm_operation_epi32. Maybe if I ever get to writing H.264 decoder for my own viewing needs I’ll try standalone assembly or inline one if asm!() syntax will be stabilised by then.

So for my player I think I’ll need just to add volume control and print name of the file currently being played and not just current time. But this should not be that hard…

One Response to “NihAV: towards an audio player”

  1. […] Kostya's Rants around Multimedia « NihAV: towards an audio player […]