2009-11-28

XBMC over Jack (Revisited)

I updated my ubuntu to karmic (9.10) lately, which works great, though my hacked version of XBMC cannot compile, after some hacks, it compiles fine, though gave me segment fault when starting. So I decided to take some time to install the current version of XBMC and apply my jack patch on it.

This time I decide to use the version in PPA's karmic release instead the svn version (the previous one on svn was not very stable, crash now and then), first add xbmc and nvidia-vdpau repositories (xbmc depends on nvidia-190-libvdpau-dev, though I am still using 185 since the 190 version crash with tv-out, might goes to another post)
sudo add-apt-repository ppa:team-xbmc/ppa
sudo add-apt-repository ppa:nvidia-vdpau/ppa

You still need to add the source part into apt source list, (add-apt-repository can get the key for you, which is convenient, wish it can support an option to add the source part too). Add this line to /etc/apt/sources.list.d/team-xbmc-ppa-karmic.list

deb-src http://ppa.launchpad.net/team-xbmc/ppa/ubuntu karmic main

Then install the needed libraries for building xbmc, and download the source codes.

sudo apt-get build-dep xbmc
apt-get source xbmc
sudo apt-get install libbio2jack0-dev libjack-dev libjack0.100.0-dev libjackasyn-dev


You should have the source codes ready after a while. As a comments in my previews post said, the audio interface was changed a little bit in the new xbmc source, though fortunately it's not a big change, so the previous patch can works just fine after some minor changes. get the patch from this address.
* https://sites.google.com/site/yjpark/downloads (xbmc-9.11~beta1-jack.patch)

patch -p0 < xbmc-9.11~beta1-jack.patch

Then do the normal configure, before make, please add "-ljack" into Makefile, (search the line LIBS=..., add it to the end of the line will be fine), after that make should work.

One important thing to note, to make the audio matching video, you probably should change the delay constant in xbmc/cores/AudioRenderers/JackDirectSound.cpp.

float CJackDirectSound::GetDelay()
{
Update();

return m_timePerPacket * (float)m_packetsSent + 0.4;
}


Just play an correct video file, adjust audio delay to make it sync, then add the value you used into the end of the return line will be ok (ahead means plus)

Note: C++ library for Jack is from Jack_CPP (http://x37v.info/jack_cpp/doc/index.html) (by Alex Norman, with pretty good documetation and examples, thanks again), I included the needed files in the patch, though suggest you to look at the documents on his site for more information.

What's next

Currently this is not working if enabling real time support in jackd, probably will do some research on this part.

Also plan to find a way to deal with the ugly delay part, ideally can calculate the delay, if too hard, probably will retrieve the value from config, then won't need rebuild for it.

And make the library detecting with the proper way, both in code and also in configure process (not a c/cpp programmer, so might need some time), then no manual change needed.

If I can finish all these, then will try to commit the patch to xbmc.

2009-11-18

Install SVN 1.6.5 in Debain Etch

We still need to use Debian Etch for our project, I am running it through chroot on ubuntu, and also vmware on osx. it's default svn is 1.4, which cannot access the shared svn source folder (1.6.5 on both ubuntu 9.10 and osx 10.6.2), so here is the steps to install svn 1.6.5 on etch (sqlite in etch is too old to be used to compile svn 1.6.5, also I am not running svn repository in the chroot, so just ignore the warning of Berkeley DB)
wget http://www.sqlite.org/sqlite-amalgamation-3.6.13.tar.gz
tar xzf sqlite-amalgamation-3.6.13.tar.gz
wget http://subversion.tigris.org/downloads/subversion-1.6.5.tar.bz2
tar xjf subversion-1.6.5.tar.bz2
sudo apt-get install build-essential
sudo apt-get install libapr1-dev
sudo apt-get install libaprutil1-dev
sudo apt-get install libneon26-dev
cd subversion-1.6.5
mkdir sqlite-amalgamation
cp ../sqlite-3.6.13/sqlite3.c sqlite-amalgamation/
./configure
make
sudo make install
You may also want to upgrade pysvn to pysvn-1.7.1
wget http://pysvn.barrys-emacs.org/source_kits/pysvn-1.7.1.tar.gz
tar xzf pysvn-1.7.1.tar.gz
cd pysvn-1.7.1/Source/
python setup.py backport
python setup.py configure
make
sudo cp pysvn/* /usr/lib/python2.4/site-packages/pysvn/

2009-07-31

XBMC over JACK

I have a XBox, which I use it watching video mostly, by installing XBMC (http://xbmc.org), it's the best media player IMO, though the very aged CPU cannot take H.264 or X.264 decode, it can only support MPEG2 HD, so after a while, I found out that it's not as useful as before.

While now the XBMC is available on most platform: Windows, OS/X (Plex is better IMO, which is based on XBMC, http://www.plexapp.com/), and Linux.

XBMC works fine on ubuntu through ALSA, though I am using JACK (http://jackaudio.org/) for better sound quality, so I have to stop JACK before start XBMC which is quite annoying.

After some research on the web, I decide to implement JACK audio bridge for XBMC, which is quite easy, here is how I did it:

First, get the source code

* http://xbmc.org/development/svn/

XBMC already has a flexible structure to support different audio interfaces, under linuxport/XBMC/xbmc/cores/AudioRenderers, there are a bunch of supported interfaces: ALSA, PulseAudio, Windows Direct sound.

Seconds, get the library

JACK comes with C library, it's asynchronus and need some time to learn it, did some research, found out there is a good C++ library at http://x37v.info/jack_cpp/doc/index.html (by Alex Norman, with pretty good documetation and examples, thanks a lot)

Now, link them together

To make it simple, I just put all the files from jackcpp under AudioRenderers, then write a simple wrapper to let them talk with each other.

There is a NullDirectSound.cpp there, which is a very good example to learn how to write a new interface.

In AudioRendererFactory.cpp, a quick hacky way to use the JACK interface:

--- AudioRendererFactory.cpp (revision 19572)
+++ AudioRendererFactory.cpp (working copy)
@@ -22,6 +22,7 @@
#include "stdafx.h"
#include "AudioRendererFactory.h"
#include "NullDirectSound.h"
+#include "JackDirectSound.h"

#ifdef HAS_PULSEAUDIO
#include "PulseAudioDirectSound.h"
@@ -59,10 +60,14 @@
{
IAudioRenderer* audioSink = NULL;

+//For Jack
+ audioSink = new CJackDirectSound();
+ ReturnOnValidInitialize();
+


Then create JackDirectSound.cpp and JackDirectSound.h (I just copied from NullDirectSound.cpp and NullDirectSound.h)

if you see the diff from JackDirectSound.cpp and NullDirectSound.cpp, you will find out most of them are same except for the change of name, the only logic I added are these lines (full version below):

In Initialize():


jackBuffer = new JackCpp::BlockingAudioIO("XBMC.Jack", iChannels, iChannels);
jackBuffer->start();
for(int i = 0; i <>connectToPhysical(i,i);
}
m_uiChannels = iChannels;

I am using blocking interface here, since it's very simple to use.

In Deinitialize():


if (jackBuffer) {
for(int i = 0; i <>disconnectOutPort(i);
}
jackBuffer->close();
//TODO: Cannot delete jackBuffer, otherwise will crash.
//delete jackBuffer;
}
jackBuffer = 0;


And in AddPackets():



CLog::Log(LOGERROR,"Jack.AddPackets() len=%d, add=%d", len, add);

if (jackBuffer){
short* pSamples = (short*)data;
for (int i=0; i< j =" 0;">write(j, (float) pSamples[i*m_uiChannels + j] / 32768.0);
}
}
}


The logic to convert the data chunks here cause me some trouble, had to do some search and experiments before get the sound right, but before that some result sound were quite interesting.

The last thing in GetDelay():


return m_timePerPacket * (float)m_packetsSent + 0.325 + 0.075;


To be honest, I don't know how to calculate the correct delay value here, this value here was the delay I found out on my machine, just try to play some movie, then try to match the audio to the video, then it's done. (I know, it's very hacky and not the right way, but since the constant value seems to solve my problem perfectly, don't feel pressure to dig into it anymore :) )

Put everything together and make it

Now every thing is ready, you can set it up and make it.

I suppose you have enough knowledge about how to compile XBMC on your system, this page http://xbmc.org/wiki/?title=Installing_XBMC_for_Linux has all the information you need.

Modify linuxport/XBMC/xbmc/cores/AudioRenderers/Makefile.in to include the new files (both jack_cpp and my codes)


--- Makefile.in (revision 19572)
+++ Makefile.in (working copy)
@@ -4,11 +4,17 @@

ifeq ($(findstring osx,$(ARCH)), osx)
SRCS = \
+ jackaudioio.cpp \
+ jackblockingaudioio.cpp \
+ JackDirectSound.cpp \
NullDirectSound.cpp \
AudioRendererFactory.cpp \
PortaudioDirectSound.cpp
else
SRCS = \
+ jackaudioio.cpp \
+ jackblockingaudioio.cpp \
+ JackDirectSound.cpp \
NullDirectSound.cpp \
AudioRendererFactory.cpp \
ALSADirectSound.cpp \


And also add jack lib into XBMC/Makefile, search for "-lasound" add "-ljack" the the same line. (Again, this is my hacky and improper way)

Now you are ready to compile it and enjoy the two fantastic software working together!

Download the Patch:


xbmc-jack.tgz