September 5, 2014

The Podside Project: The Inevitable Roadblocks

This ended up being a very long post (I was on a roll) so there is a TL;DR at the bottom. PS sorry for the word wrapping issues, I don't know what's going on.

I named this blog Learning Through Failure which can mean a couple different things depending on one's perspective. I always defined 'Failure' in this context as hitting a roadblock which usually, in my experience, happens preventing any and all progress for a project, not necessarily a design flaw which would mean the existing progress should literally all be scrapped, but instead a vital feature, function, or step in the design cannot be completed due to lack of information, experience, patient issues, etc.

Right now I am facing three key roadblocks which are: audio device selection, multiple audio device selection, and MP3 encoding.

The main feature of this project is suppose to be capturing the audio from a microphone and the PC audio output to combine them into one audio stream, however, the first problem I encountered was of course one of the things I would have thought to be the easiest, capturing the PC audio output (link). What is very interesting about Java's handling of audio is although you can very easily find and display all of the PC's audio input and outputs (VSJQueryMixer.java code), you can only capture a single generic device of a specific type. As Matthias Pfisterer puts it, “Asking for a line is a rather tricky thing...first, we have to say which kind of line we want. The possibilities are: SourceDataLine (for playback), Clip (for repeated playback) and TargetDataLine (for recording)” (Source). The next step is to grab the audio from the TargetDataLine by calling:

TargetDataLine line;
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);  // format is an AudioFormat object
if (!AudioSystem.isLineSupported(info)) {
   // Handle the error.
   }
// Obtain and open the line.
try {
    line = (TargetDataLine) AudioSystem.getLine(info);
    line.open(format);
    } catch (LineUnavailableException ex) {
            // Handle the error.
            }
Although this code came from Java's tutorial site and is indeed a simple implementation it is the same implementation I continually find while looking for how to record audio with Java.  The problem with this is there is no way to specify a specific audio input or output to listen to or record from (aka 'info' contains the information of all audio I/O and using 'info[2]' to specify a specific I/O to listen/record from did not work for me, more below). This implementation confuses the hell out of me especially when you can use the code:
for(Mixer.Info mixInfo: mixInfos) {
    Mixer mixer = AudioSystem.getMixer(mixInfo);
    support = “, supports “; 
    if (mixer.isLineSupported(sourceDLInfo))
       support += “SourceDataLine “;
    if (mixer.isLineSupported(clipInfo))
       support += “Clip “;
    if (mixer.isLineSupported(targetDLInfo))
       support += “TargetDataLine “;
    if (mixer.isLineSupported(portInfo))
       support += “Port “;
    System.out.println(“Mixer: “ + mixInfo.getName() + support + “, “ + mixInfo.getDescription());
    }
(Source)
to clearly show all of the devices which in turn means Java can see them and yet you cannot pick a specific one. This is not an issue at all for most or at least simple programs which just want the microphone audio (the default input device) or the speakers for example, but this issue leads to the enviable problem for those more complex programs which want access to multiple inputs (which is what I am trying to do) or multiple outputs, or to record a specific device like the PC's audio output (again what I am trying to do). (I did something no one else has, link)
The third roadblock of MP3 encoding is a first for me. The MP3 codec is patented and therefore requires permission (aka $$$, MP3 Licensing Site *Side note: This site is pretty sketchy looking like it's from the 1990's.) to incorporate in a complied program. As most people (who know anything about audio file formats) would say the MP3 format is not only the most used format but also very space efficient, especially when compared to the WAVE format. However, because of the rules put in place by the patent holder Oracle is not allowed to include native MP3 support into Java unless they pay some form of fee. This of course  is good for the owner but of course makes it harder for developers and also results in less  code being shared due to avoiding patent lawsuits and people leaning toward free alternatives.
So basically I have had a very hard time finding a way to encode audio to the MP3 format but also legally implement MP3 encoding into my program, but it can be done.
TL;DR
Roadblocks can not only be speed bumps but obstacles which make us realize fundamental flaws in our logic or code design. For this project I have encountered 3 so far: audio device selection, multiple audio device selection, and MP3 encoding. The first two I never dreamed would be any kind of issue and MP3 licensing is a pain because it means Java does not have native support for it thus there is barely any example code and if you wish to use MP3 encoding in a commercial program you have to be creative to avoid patent infringement.

Epilogue: Stuff I found while writing this post which might be helpful in the near future.

No comments:

Post a Comment