Saturday, March 18, 2017

Fixing Awful-Sounding ffmpeg Streaming Audio (Realtek ALC662)



Does Your ffmpeg MP3 Audio Sound Awful?  Mine Did!  But Not Now...

Terrible Quality Audio

Recently, I implemented an ffmpeg based streaming audio and video solution on silver, a $27.00 home theater computer that I brought back from the dead.  The solution worked pretty well, and aside from some minor ongoing issues with the Hauppage WinTV HVR-1110 card, I was pleased with my work except for the fact that I was plagued by terrible quality audio!

My Audio Setup

My audio setup is decent enough.  I have a pair of JBL Monitor 4206 speakers being driven by a Surround Sound Pioneer HTZ-77DV system set in stereo mode.  This combination is great, and here's why:  Because the JBL speakers are relatively small, they can't really produce audio all that well below 100Hz.  But the Pioneer System is based around a powered subwoofer, which takes care of reproducing sound at just those low frequencies.  That way, everything works out. But the ffmpeg streamed sound emanating from this otherwise great 2.1 sound system was simply atrocious.  No matter what I did with ffmpeg, it didn't get any better.  I tried a zillion things, including changing the encoder and dramatically raising the bitrate - nothing worked!

Awesome Frustration

It got to the point where I complained online about it, because I was certain that the "lossy" compression inherent in MP3 audio was the culprit, and libmp3lame was the instrument of my auditory torture:



A Bataan Death March of Audio

Because I was being dogged by terrible audio quality every morning and evening, I worked on this problem as I much as I could.  The terrible sound was killing me.  The one thing I knew for certain was that the audio signal was being badly distorted - but what component of the entire system was at fault?  Bedeviled by the audio coming out of my sound system, I continued to tinker on this problem, trying various different ffmpeg permutations and combinations...until I hit upon something strange. 

This was mostly due to me gradually turning away from treating this problem as an encoding (MP3) issue towards treating it as an audio amplification issue.  My ears were telling me it probably wasn't encoding because I wasn't hearing MP3 style audible artifacts.  What I was hearing were the hallmarks of a signal amplification problem, in particular "clipping".  I couldn't turn down the signal at source because it was being sent to silver at RCA line levels, so I looked for ways to reduce the incoming signal, or reduce how it was being treated on reception.  To do this, I sought out ways to reduce the volume level of the microphone input on silver.  I decided to used the amixer program to investigate where the levels were in the first place, so I could see if things needed to be turned down, and by how much.

Because it is a multimedia Home Theater PC, silver has a large number of audio controls.  This is due to the fact that it has a lot of audio inputs and outputs.  On its front panel, it has RCA Left, RCA Right, Composite Video, Line In, Microphone and Headphone.  On the back, it has the traditional trio of "normal" motherboard connectors; Line In, Microphone and Headphones.  It also has an expansion rail installed for its digital outputs; TOSLINK and Coaxial.   It also has a full complement of controls for its Surround Sound 5.1 outputs.  

Consequently, amixer produced the following output, which is quite long.  Fortunately, we need only concern ourselves with the last two entries:

root@silver:~# amixer
Simple mixer control 'Master',0
  Capabilities: pvolume pvolume-joined pswitch pswitch-joined
  Playback channels: Mono
  Limits: Playback 0 - 64
  Mono: Playback 48 [75%] [-16.00dB] [on]
Simple mixer control 'Headphone',0
  Capabilities: pswitch
  Playback channels: Front Left - Front Right
  Mono:
  Front Left: Playback [on]
  Front Right: Playback [on]
Simple mixer control 'PCM',0
  Capabilities: pvolume
  Playback channels: Front Left - Front Right
  Limits: Playback 0 - 255
  Mono:
  Front Left: Playback 179 [70%] [-15.20dB]
  Front Right: Playback 179 [70%] [-15.20dB]
Simple mixer control 'Front',0
  Capabilities: pvolume pswitch
  Playback channels: Front Left - Front Right
  Limits: Playback 0 - 64
  Mono:
  Front Left: Playback 48 [75%] [-16.00dB] [on]
  Front Right: Playback 48 [75%] [-16.00dB] [on]
Simple mixer control 'Front Mic',0
  Capabilities: pvolume pswitch
  Playback channels: Front Left - Front Right
  Limits: Playback 0 - 31
  Mono:
  Front Left: Playback 21 [68%] [-3.00dB] [off]
  Front Right: Playback 21 [68%] [-3.00dB] [off]
Simple mixer control 'Front Mic Boost',0
  Capabilities: volume
  Playback channels: Front Left - Front Right
  Capture channels: Front Left - Front Right
  Limits: 0 - 3
  Front Left: 0 [0%] [0.00dB]
  Front Right: 0 [0%] [0.00dB]
Simple mixer control 'Surround',0
  Capabilities: pvolume pswitch
  Playback channels: Front Left - Front Right
  Limits: Playback 0 - 64
  Mono:
  Front Left: Playback 48 [75%] [-16.00dB] [on]
  Front Right: Playback 48 [75%] [-16.00dB] [on]
Simple mixer control 'Center',0
  Capabilities: pvolume pvolume-joined pswitch pswitch-joined
  Playback channels: Mono
  Limits: Playback 0 - 64
  Mono: Playback 48 [75%] [-16.00dB] [on]
Simple mixer control 'LFE',0
  Capabilities: pvolume pvolume-joined pswitch pswitch-joined
  Playback channels: Mono
  Limits: Playback 0 - 64
  Mono: Playback 48 [75%] [-16.00dB] [on]
Simple mixer control 'Line',0
  Capabilities: pvolume pswitch
  Playback channels: Front Left - Front Right
  Limits: Playback 0 - 31
  Mono:
  Front Left: Playback 21 [68%] [-3.00dB] [off]
  Front Right: Playback 21 [68%] [-3.00dB] [off]
Simple mixer control 'IEC958',0
  Capabilities: pswitch pswitch-joined
  Playback channels: Mono
  Mono: Playback [on]
Simple mixer control 'IEC958 Default PCM',0
  Capabilities: pswitch pswitch-joined
  Playback channels: Mono
  Mono: Playback [on]
Simple mixer control 'Capture',0
  Capabilities: cvolume cswitch
  Capture channels: Front Left - Front Right
  Limits: Capture 0 - 31
  Front Left: Capture 10 [32%] [1.50dB] [on]
  Front Right: Capture 10 [32%] [1.50dB] [on]
Simple mixer control 'Capture',1
  Capabilities: cvolume cswitch
  Capture channels: Front Left - Front Right
  Limits: Capture 0 - 31
  Front Left: Capture 0 [0%] [-13.50dB] [off]
  Front Right: Capture 0 [0%] [-13.50dB] [off]
Simple mixer control 'Auto-Mute Mode',0
  Capabilities: enum
  Items: 'Disabled' 'Enabled'
  Item0: 'Enabled'
Simple mixer control 'Channel Mode',0
  Capabilities: enum
  Items: '2ch' '4ch' '6ch'
  Item0: '2ch'
Simple mixer control 'Input Source',0
  Capabilities: cenum
  Items: 'Front Mic' 'Rear Mic' 'Line'
  Item0: 'Rear Mic'
Simple mixer control 'Input Source',1
  Capabilities: cenum
  Items: 'Front Mic' 'Rear Mic' 'Line'
  Item0: 'Front Mic'
Simple mixer control 'Loopback Mixing',0
  Capabilities: enum
  Items: 'Disabled' 'Enabled'
  Item0: 'Enabled'
Simple mixer control 'Rear Mic',0
  Capabilities: pvolume pswitch
  Playback channels: Front Left - Front Right
  Limits: Playback 0 - 31
  Mono:
  Front Left: Playback 21 [68%] [-3.00dB] [off]
  Front Right: Playback 21 [68%] [-3.00dB] [off]

Simple mixer control 'Rear Mic Boost',0
  Capabilities: volume
  Playback channels: Front Left - Front Right
  Capture channels: Front Left - Front Right
  Limits: 0 - 3
  Front Left: 2 [67%] [20.00dB]
  Front Right: 2 [67%] [20.00dB
]

According to amixer, the 'Rear Mic' was operating at 68% of its total capacity.  This really didn't seem like a crazy setting to me.  Running at  -3.00dB is no big deal and it shouldn't be producing the distortion I was struggling with.  The thing that really caught my eye was the 'Rear Mic Boost' setting.  It was set at 67%, which was producing a 20.00dB gain on the microphone signal.  That's an amplifier at work.

I then used the program alsamixer to investigate further, because it can manipulate the inputs that are listed by amixer. I find the alsamixer program to be very useful because it offers a text-mode, curses based GUI, which makes manipulating the controls much faster and easier than typing in long command lines, and it doesn't require that you fire up an entire X-Windows session to do a little thing.  Besides, this entire project was done over SSH.

After starting the alsamixer program and pressing the right-arrow several times to navigate to the rightmost control, here's what I saw:


While it may not look like much, the rightmost control is what manipulates the 'Rear Mic Boost' setting, which controls how much amplification is applied to the 'Rear Mic' signal.    I used the down-arrow key to drop the 'Rear Mic Boost' setting to zero:


Lo!  My audio quality instantly improved!  So, in the end, the culprit proved to be the 'Rear Mic Boost' setting, which was getting an onboard amplifier to kick in, ruining everything.


So, I Was Barking up the Wrong Tree

In the end, the culprit wasn't ffmpeg or libmp3lame, it was upstream from them, and far more subtle than I originally thought.  The actual source of the problem was the onboard Surround Sound audio chip (ALC662) on the motherboard (FOXCONN G31MXP) in silver.  And the company responsible for my travails?  Realtek

As it turns out, the Realtek implementation of the Intel High Definiton Audio specification via that ALC662 chip was responsible for awesomely distorting the audio entering ffmpeg.  The signal was either "being clipped" or "noisy", producing audible garbage.  And, as we all know - when it comes to computers (and audio), "Garbage In, Garbage Out"! 

What is Clipping?

Clipping is a term for the circumstance where a digital amplifier is asked to boost a signal beyond its tolerances.  In this situation, a digital amplifier will simply give up and flat-line the output signal, basically to save itself from blowing up:




Clipping is good for amplifiers (no blown chips) but bad for speakers.  This is because speakers don't like flat line signals, which for them gets expressed as DC, which they are not built to handle.  Too much DC can cause excessive speaker extrusion, cone wear, voice coil damage and other bad stuff.

What is Noise?

Noise is a term for the circumstance where an amplifier somehow injects unwanted elements into a input signal.  This is often due to picked up Radio Frequency Interference (RFI) effects, or sometimes a bad connector.  Here's what a "noisy" signal looks like:

https://www.mathworks.com/matlabcentral/mlc-downloads/downloads/submissions/9554/versions/5/previews/numerical-tour/denoising_noise_models/index.html


By the way, amplifiers always inject "noise" into signals even when they are operating within their tolerances.  The amount of injected "noise" is what defines them as being either High Fidelity (hi-fi) or Low Fidelity (lo-fi).

Amplifier Classes

Another potential reason for the terrible audio could be that ALC662 has a really crappy amplifier circuit, like maybe a Class D.  Amplifiers come in classes ranging from Class A onwards, the further along the alphabet you go, the lower the quality of the output, but the better the efficiency.  Class A amplifiers sound great, but consume awesome amounts of power.  Class D amplifiers sound terrible, but consume very little power compared to their Class A brethren.  Here's a diagram of the classes of amplifier, what they do to signals, and their relative efficiency:





Anyway, problem solved.

No comments:

Post a Comment