Closed timjosten closed 8 years ago
The corruption is a noise appended to sound. I can clearly hear it in quiet passages, for example, I have one track which starts with electronic piano, it is clean when listening on local device (pc or phone), but on Shairport it is crackling like vinyl record. Not loud too.
It's not a bug, it's the "Sounds-like-good-old-vinyl"-feature :smile:
But seriously, very interesting! I've a patch in mind which I find at a fork of the orginal shairport: https://github.com/yenchee1970/shairport/commit/387fa01f2318f6502f77a07747d1ef5b693b1c9b
I'm not sure if it somehow related or if the patch from @yenchee1970 really fixes something. Do you mind to test it with this patch applied again?
I am struggling with setting up OpenWrt build environment on a netbook. Have to wait an eternity if something fails to build.
I see!
Just for clarification: shairport does stuffing by inserting or deleting frames. You can turn this almost of if you set drift
to a large value, eg 65535
.
Which version of shairport-sync did you used for testing?
2.1.15-1
What about original shairport, or shairport for windows? Do they stuff too? They are affected too
Of course, you're right! I just want to be sure that no stuffing is done at all.
I hexdumped both files and compared at which positions the four bytes are dropped: 0x5b8
0xd90
0x1042
. So they are not dropped at a regular interval...
Maybe @mikebrady has an idea...
Which command line settings did you used for testing?
I used nothing for the command line options. I simply haven't found anything interesting there to try (except for stuffing, which resulted in heavy cpu load if soxr is enabled).
Off topic: sometimes, the root of such problems (when something is incomplete) is when using incorrect comparator inside for() or while() cycles. For example < instead of <=. Or ++i instead of i++.
Thanks for the posts. I'll have a look at the files and that patch, though it doesn't look like it could be the case of the problem. One thing that is completely unaltered in Shairport Sync is the code that decompressed the incoming Apple Lossless data. It wold be really nice to see if that is the cause of the glitches.
Well, for my application I need no stuffing at all. So that patch in a stuff_buffer function is a good hint (yay!). I can even binary patch the code to not bother with recompiling. But... The problem for other users is there anyway. There's corruption even if streaming from localhost to localhost. For example, I tried Airfoil streaming to Shairport4w on the very same system, and there's corruption. There couldn't be any delays in transmission on localhost. :)
Hi there @timjosten. Would there be possibility of reposting those two files please?
[Update] It's okay, thanks – I've got em.
Different question for you, @timjosten, please: how did you generate the "original" audio file?
Hi @mikebrady! The original audio file is just a FLAC decompressed to WAV, then converted to RAW. I know what stuffing is, it is needed of course because different systems tend to playback audio at slightly different speeds (hardware timers are not atomic precision). But why stuffing is there when capturing and playing on localhost? I have enabled soxr and I don't hear any noises anymore.
P.S. Are two separate computers are so out of sync in terms of timers that Shairport is stuffing so often? I thought it should stuff several samples in each 10-20 seconds to be in sync. But it is doing it thousands of times per second (so it is hearable)!
Hello again. There are a number of things in your post, so I'll deal with them separately.
stdout
backend to a file. My experiments show that the two decoders produce identical results – bit for bit, the outputs are identical.
I haven't yet found a way to generate the raw audio from the source in a way that I can be sure is accurate, but the fact that the two decoders generate exactly the same output suggests that they are both working according to specification. An alternative explanation is that they are both faulty in an identical way, but that is implausible, I think.localhost
– I've never really figured it out. It may be that the DAC is running on a separate clock, or the DAC clock is inaccurate (this is a known issue with some sound cards, BTW).[Update] I finally figured out how to do this end-to-end checking reliably.
First, the source machine is a Mac running OS X 10.11.5, i.e. the latest El Capitan, with the latest iTunes, 14.4.1.6. iTunes is running with all "Playback Preferences" unselected – so "Crossfade", "Sound Enhancer" and "Sound Check" are all unselected.
The source track is a regular CD track stored in a WAV file. The Mac utility afinfo
reports its properties:
File: <filepath>
File type ID: WAVE
Num Tracks: 1
----
Data format: 2 ch, 44100 Hz, 'lpcm' (0x0000000C) 16-bit little-endian signed integer
no channel layout.
estimated duration: 282.866667 sec
audio bytes: 49897680
audio packets: 12474420
bit rate: 1411200 bits per second
packet size upper bound: 4
maximum packet size: 4
audio data file offset: 44
optimized
source bit depth: I16
----
Note that this is how the source track is stored in iTunes. My understanding of AirPlay is that the source audio is losslessly compressed to ALAC and sent over the network to the AirPlay device where it is expanded, again losslessly, and sent to the audio output.
The only special setting at the Shairport Sync end is that the general
ignore_volume_control
setting is set to "yes"
. As mentioned before, I'm using the stdout
back end, which sends the audio to standard output rather than an audio device. No "stuffing" or interpolation takes place. The command I used to invoke "Shairport Sync" was
./shairport-sync -v -o stdout > ~/Desktop/hammerton_sample.bin
In this case, Shairport Sync was picking up settings from the configuration file, but was then directing its output to stdout
, which was piped, as indicated, to the file.
The track was played in iTunes to the Shairport Sync device, and Shairport Sync was terminated after the Player thread exit
debug message came up. This closed the output file.
Overall, what I expected to happen was that the output from Shairport Sync would be bit-for-bit identical to the audio in the original source track.
There are slight issues with finding the start and end of the audio. The audio data file offset
figure allows us to skip the first 44 bytes of metadata in the source track file, so I simply looked for the first non-zero byte thereafter.
To skip the approximately two seconds of silence introduced by Shairport Sync at the start of playback, I similarly searched for the first non-zero byte in the Shairport Sync output. At the end of the track, we could similarly expect extra silence to be added, but silence would be represented by all zeros.
Having synchronized the start of the source file's audio to the start of the Shairport Sync file's audio as described above, I found that the audio output from Shairport Sync is indeed bit-for-bit identical with the audio content of the source file. This is all using the standard decoder in Shairport Sync, written by David Hammerton. There is a trailer of an extra few hundred bytes of silence at the end of the Shairport Sync file, as expected.
So, overall, I'm thinking that the problems you have are caused by something else...
@mikebrady you're awesome! :) I did almost the same procedure a year ago. But there was stuffing involved. I don't remember if I used the pipe output from Shairport Sync... My "real" question was why was it stuffing so often? The sound was constantly distorted noticeably, like a person singing with troubled throat :))
Have you binary compared those raw files I have attached in the beginning? In my case it was skipping 4 bytes each ~1500 bytes. This turns to - each ~375 samples. So each 8 milliseconds one sample is skipped. Pretty much significant!
I did indeed compare the two files and it did show bytes missing but also bytes inserted.
As to why it's stuffing so often, I'm afraid I don't know. You'd have to do a thorough investigation using known-good components, at least temporarily, to isolate the issues.
Is it okay to close this issue? I think the main topic is resolved.
Yeah, close it. The 'basic' stuffing is the cause - it is so simple that it causes some distortion. If timers are bad, it will stuff more often, resulting in bad sound. SOXR stuffing is the cure.
I made up a version of Shairport Sync that allows you to choose one decoder or the other.
Can you provide a branch for this, please? I would like to test the Apple decoder with HTC Connect to further investigate this issue: #338
Apparently, there's long standing bug in most Shairport forks. Be it the old Shairport, or Shairport-sync, or even Shairport4w, all of them are affected. I have tested them all on different platforms and experienced the same audio corruption. If I use any other receiver (like Airfoil), there's no corruption. The corruption is a noise appended to sound. I can clearly hear it in quiet passages, for example, I have one track which starts with electronic piano, it is clean when listening on local device (pc or phone), but on Shairport it is crackling like vinyl record. Not loud too. I did some data dumps and figured out what is causing the corruption. When going thru Shairport, audio data is corrupted. Every few kilobytes there are 4 bytes lost. I compared the original raw audio and the one outputted by shairport. Interestingly, it is always 4 bytes which get lost (1 stereo sample). They just drop out from the stream. This is causing slight but hearable "rales". It happens each 1-2 kilobytes. What is wrong? Any thoughts?
I have attached 2 audio dumps, they are renamed to GIFs as this forum doesn't allow other file types. The first one is original audio, the second is dumped from shairport pipe output. Open both in hex editor and compare page by page. You will see those 4 bytes gets dropped on each page.