I got my Raspberry Pi (photos) about a month ago and got time to set it up a couple of weeks back. At the moment, it is running Raspbmc RC4 which is a distribution of XBMC tailored just for this device.
The Pi has been playing most of my video & audio collection without issues over LAN. Video is smooth with hardly any stuttering or frame-drops. Audio over HDMI works just fine playing full DTS or surround sound via my Sony. Raspmbc also supports HDMI-CEC pretty well so I can control it using my TV's remote control.
Here's what doesn't work at the moment:
- Fast forward & rewind for videos doesn't work. I've to either jump or direct seek, which work without issues.
Haven't found a way to activate the XBMC Context Menu using the TV remote
- Music & TV show libraries show up empty on the Android phone remote.
There's a noticeable delay (about 2-3 seconds) switching between normal interface & full screen video playback.
If you notice, these are all XBMC issues. The Pi itself is great and for the price, it is a noiseless, heatless computing powerhouse!
More photos on G+
Update (02/09/2012) The delay switching from normal UI to full screen video playback went away by disabling the Adjust display refresh rate to match video option in XBMC's Video Playback settings screen. And using the following custom remote mapping file, I can now access the Context Menu by pressing the TV remote's yellow color key labelled "C":
<!-- /home/pi/.xbmc/userdata/keymaps/remote.xml -->
<!-- Configuration file for driving CEClib remote -->
<keymap>
<global>
<remote>
<green>Info</green>
<yellow>ContextMenu</yellow>
<blue>XBMC.ActivateWindow(Favourites)</blue>
</remote>
</global>
<FullscreenVideo>
<remote>
<select>OSD</select>
<green>Info</green>
<yellow>CodecInfo</yellow>
<blue>NextSubtitle</blue>
</remote>
</FullscreenVideo>
</keymap>
The Android SDK has evolved quite a bit since I last worked on Cabbie Pro. Most notably, the release of Ice Cream Sandwich, aka Android 4.0, brought with it a whole new set of design & interaction patterns with associated development building blocks.
I decided to write a simple app to get acquainted with these changes in the Android platform. The app I chose to experiment with is quite simple: it would display a bus schedule. A simple list of timings showing when a bus is scheduled to depart with just one twist, for departure times in the upcoming thirty minutes, the list would switch from showing something like 'at 10:45' to 'in 10 minutes'. The schedule itself is static and is stored locally, it is just the display which needs to be dynamic.
One new piece of infrastructure in the Android SDK is the LoaderManager and associated Loader classes. These are designed to help manage the loading & display of data while taking care of maintaining & cleaning up state along with the activity lifecycle. The SDK documentation explains these in more detail.
For the purpose of this app, using the SDK supplied AsyncTaskLoader made the most sense. It uses a background thread to load data and then supply that to the UI thread for rendering, typically in a ListView. The API docs for this class supply a complete example of how to use it. Pretty much the only thing I need to do on top of that example is to periodically refresh the displayed list.
Suppose each scheduled timing is modelled as a Timing object and we populate a ListView with instances of these - one per row - using an ArrayAdapter. Since the adapter would call the toString() method of Timing objects to populate the list view, one dumb way to refresh the list would be to compute the display string each time in the toString() method. It is dumb because (a) it blocks the UI thread making the UI janky, (b) doesn't actually update the display unless the row is scrolled off and back on the screen.
The approach I took is to spawn off a thread in the AsyncTaskLoader which would wake up periodically and call forceLoad() causing the loader to deliver new data to the LoaderManager and subsequently the ArrayAdapter.
Here are my onStartLoading() and onStopLoading() methods of TimingsLoader, a class that extends AsyncTaskLoader:
@Override
protected void onStartLoading() {
isAppRunning = true;
if (refreshThread != null) {
refreshThread.interrupt();
} else {
refreshThread = new Thread() {
public void run() {
while (true) {
try {
TimeUnit.SECONDS.sleep(30);
} catch (InterruptedException e) {
}
synchronized (refreshLock) {
while (!isAppRunning) {
try {
refreshLock.wait();
} catch (InterruptedException e) {
}
}
}
TimingsLoader.this.mHandler.post(new Runnable() {
@Override
public void run() {
TimingsLoader.this.forceLoad();
}
});
}
};
};
refreshThread.start();
forceLoad();
}
}
@Override
protected void onStopLoading() {
super.onStopLoading();
isAppRunning = false;
}
The forceLoad() calls the loadInBackground() method (not shown here) which would compute the list of new data and deliver it back to the UI.
While the thirty second sleep & subsequent forceload() call takes care of periodically refreshing the list view, there are a couple of scenarios it doesn't account for:
- When the user navigates away from the app by hitting the home button or via a notification to another app, the background thread continues to run causing unnecessary wake-ups and battery drain.
- When the user locks and unlocks the screen, while the app is still in the foreground, the list doesn't immediately refresh after unlocking. It waits for the next 30 second refresh cycle. This isn't ideal.
Both these problems can be solved by tracking when the app is visible and when it is backgrounded. I do this by calling the stopLoading() and startLoading() methods of the TimingsLoader instance from the onPause() and onResume() method of the main application activity. I use a volatile boolean isAppRunning variable to capture these state changes.
Finally, I use a refreshLock monitor object to sleep until interrupted when the app is backgrounded. An interrupt is delivered to the refresh thread from the onStartLoading() method so that it starts computing new results as soon as the app is resumed.
There is actually an isStarted() method in the base Loader class that can be used to track (start/stop)Loading states. But I can't use the same here because the underlying state variable used there is non-volatile. This works out okay for isStarted() because it is only meant to be called from the main thread but not for the present use-case where the state needs to be updated from one thread and read from another - hence the use of a volatile isAppRunning variable.
Another point to note is the 'mHandler' variable which is bound to an instance of Handler class in the TimingsLoader's constructor. Since the constructor is called from the main thread, the handler gets bound to the main thread too. Thus, calling post() on this handler causes the provided runnable to be executed on the main thread. Why go through all this trouble? Because, as documented, a Loader's forceLoad() must be called from the main thread!
In conclusion, the new LoaderManager framework provides a clean and convenient mechanism to keep expensive computation off the main thread. I am happy with how this app turned out and plan to use this new framework feature in Cabbie Pro too!
We moved to a new house sometime back and one of the features of the place was that the living room was already wired for surround sound speakers. If that's not an excuse to buy a home theatre setup, what is? :-)
Thus began an exploration of the world of AV receivers, speakers, blu-ray players, streaming players, etc., etc. After much analysis-paralysis, the conclusion was that a "serious" setup - one involving a Marantz/Denon/Onkyo AVR paired with a set of Boston Acoustics/JBL/Jamo speakers would cost at least S$ 2000, a number far north of the WAF.
The next best option? A Home Theatre in a Box.
HTIBs, as these are known, are mass-market consumer appliances that combine a DVD or Blu-Ray player and an AV Receiver in a single box and pair those with some entry level speakers. Virtually every consumer electronics manufacturer, from Panasonic to Samsung to Toshiba has a product in this segment. Prices range from a modest 300 S$ to about 1000 S$ at the top-end.
The biggest drawback of these HTIB systems is the under-powered amplifier that they come with; it is practically impossible to find a quality set of speakers that can be driven by these amps. The other drawback is the generally limited range of connectivity options.
In some sense, the situation is similar to getting a compact camera vs an SLR!
Now I am no audiophile and the main thing I was looking to get out of a surround sound setup was a decent home movie experience. Thus, I didn't really mind settling for a budget system.
(Incidentally, if you are thinking of buying an AVR, I think the Denon AVR-1612 is a fine choice.)
I thought it would take a while to decide which system to buy but as it turned out, the choice was surprisingly easy to make. Of all the brands in the market, only Sony had systems which supported HDMI input! Think about that - not one other manufacturer thought that their customers would want to connect, say, an XBox or a PS3 to their surround-sound system!
Having finalized my choice, on 31st March 2012, I bought home a Sony BDV-E380 Blu-ray Home Theatre System. Herewith, some thoughts on it after having used it for three months now.
The system (full specs) looks and feels quite heavy but has a clean and smart looking front that, once setup inside my TV console, looks great. Upon powering on, the interface is straight-forward to navigate and anyone who has used a PS3 will feel right at home. There's a first-run wizard which guides you through all the setup tasks, including calibrating the speakers using the provided auto-calibration microphone.
I've found the video and audio output from this system to be excellent and have no complaint in that department. Blu-rays especially look and sound fantastic to my eyes and ears. For reference, I have a 40" Samsung LCD connected to this E380.
The highlight of this device has been the excellent video file format support. It plays pretty much all the files I've thrown at it - AVI (Xvid), MP4, WMV, MKV. It even supports multiple audio tracks within an mkv file - giving me the option to choose the movie's language. It has no problem playing back 1080p streaming videos, even over my less-than-optimal powerline ethernet LAN connection.
This system, like many others these days, claims to be loaded with "apps" promising rich content from a variety of online sources. The skeptic in me didn't put much stock in these claims and I wasn't wrong. The apps are, by and large, useless and are best ignored. I thought at least the YouTube app would be useful but even that has a ridiculous limitation - it plays only SD or at best 480p videos!
Another irritant is that when turned on, the default menu selection always goes to something Sony calls a "3D Showcase". I don't have a 3D television, nor do I intend to get one. So this is one default choice which I'll never choose!
I've installed Serviio to stream media from my home computer to the E380. I've found Serviio to be fairly easy to use and quite reliable in operation. There's just one thing I wish to point out. The Serviio software comes with a set of profiles that describe the capabilities and formats supported by the various network streaming devices. Based on these profiles, Serviio can transcode videos from their original format to one that would be playable by the streaming media device.
For Sony, Serviio ships with a profile that aims to support all of Sony's Blu-ray players. However, this profile appears to be optimized for models sold in the US/UK which, based on the profile, seem to have very poor support for different video formats. This causes needless transcoding and the associated drop in quality for videos served to the E380. At the end of this post, I've appended an updated profile that minimizes transcoding and has worked out well for me.
All in all, I am quite happy with this product. If you are looking for a nice home theatre setup on a budget, you can't go wrong with the E380!
<Profile id="50" name="Sony E380 Player" extendsProfileId="1">
<Detection>
<UPnPSearch>
<FriendlyName>(Blu-ray Disc Player|.*Home Theat(re|er) System|Media Player)</FriendlyName>
<Manufacturer>Sony Corporation</Manufacturer>
</UPnPSearch>
<HttpHeaders>
<X-AV-Client-Info>.*cn="Sony Corporation"; mn="(Blu-ray Disc Player|.*Home Theat(re|er) System|Media Player)".*</X-AV-Client-Info>
</HttpHeaders>
</Detection>
<DeviceDescription>
<!-- act as WMP so that the TV doesn't show root categories -->
<ModelName>Windows Media Player Sharing</ModelName>
<ModelNumber>3.0</ModelNumber>
<Manufacturer>Microsoft Corporation</Manufacturer>
</DeviceDescription>
<ContentDirectoryMessageBuilder>org.serviio.upnp.service.contentdirectory.SonyDLNAMessageBuilder</ContentDirectoryMessageBuilder>
<ContentDirectoryDefinitionFilter>org.serviio.upnp.service.contentdirectory.definition.WMPContentDirectoryDefinitionFilter</ContentDirectoryDefinitionFilter>
<MediaFormatProfiles>
<!-- force DLNA profile names of supported formats -->
<!-- e.g. though renderer should support wma, it only does so when disguised as mp3 (many other audio types are transcoded later in the profile) -->
<MediaFormatProfile mime-type="audio/mpeg" name="MP3">WMA_BASE</MediaFormatProfile>
<MediaFormatProfile mime-type="audio/mpeg" name="MP3">WMA_FULL</MediaFormatProfile>
</MediaFormatProfiles>
<Transcoding>
<Video targetContainer="mpegts" targetACodec="ac3" aBitrate="320">
<!-- FFmpeg cannot currently remux dts audio properly so it must be transcoded, but all other audio is left alone -->
<Matches container="ogg" vCodec="mpeg4" />
</Video>
<!-- unsupported codecs will be transcoded to mpegts with mpeg2video and ac3 audio -->
<Video targetContainer="mpegts" targetVCodec="mpeg2video" targetACodec="ac3">
<Matches container="asf" />
<Matches container="flv" />
<Matches container="ogg" />
</Video>
<Audio targetContainer="lpcm">
<Matches container="mp4" />
<Matches container="flac" />
<Matches container="ogg" />
<Matches container="adts" />
</Audio>
</Transcoding>
</Profile>
Take any Java application of a reasonable size and there's an almost 100% chance that at least one class in the codebase uses the lazy initialization pattern. One typical usage is in the creation of Singleton classes.
For a basic pattern in such widespread use, it is surprising how often it is implemented incorrectly! Why does this happen? Let's take a look with a simple example:
class Demo {
private Collaborator collaborator = new Collaborator();
public Collaborator getCollaborator() {
return collaborator;
}
public static void main(String... args) {
Demo demo = new Demo();
Collaborator collaborator = demo.getCollaborator();
}
}
Perfectly pedestrian stuff so far. We define a Demo class in which a Collaborator object is created and is ready for use as soon as an instance of Demo is created. But what if we don't always need the collaborator? We would be paying the cost of creating it even in situations where it isn't used. This becomes a real concern if it is relatively expensive to create a new collaborator. Enter lazy initialization:
class Demo {
private Collaborator collaborator;
public Collaborator getCollaborator() {
if (collaborator == null) {
collaborator = new Collaborator();
}
return collaborator;
}
}
In the revamped Demo class, we've delayed the construction of Collaborator to when the getter method is called thus ensuring that we don't create an instance before we need it.
Although it solves our first problem, it introduces another one: the Demo class will likely exhibit unexpected behaviour in a multi-threaded environment. If two or more threads simultaneously invoke the getCollaborator() method on an instance of Demo, then it is very much possible that more than one instance of Collaborator gets created. Depending on what Collaborator actually is, the effects of this can range from simply wasteful to downright dangerous!
Making the Demo class' behaviour predictable in a multi-threaded environment is easy - just make the getCollaborator() method synchronized.
class Demo {
private Collaborator collaborator;
public synchronized Collaborator getCollaborator() {
if (collaborator == null) {
collaborator = new Collaborator();
}
return collaborator;
}
}
By making the getCollaborator() method synchronized, we ensure that only one thread can invoke the method at a time and are thus guaranteed that only one instance of collaborator will be created.
However, there's yet another problem with our change. (In case you haven't guessed, this is the pattern for this entire post!)
The problem is that even though we needed to ensure exclusive access to the getter method only during the initial instantiation of Collaborator, we pay the cost of synchronization on all subsequent calls to the method!
Alright, let's try another change:
class Demo {
private Collaborator collaborator;
public Collaborator getCollaborator() {
if (collaborator == null) {
synchronized(this) {
if (collaborator == null) {
collaborator = new Collaborator();
}
}
}
return collaborator;
}
}
This is known as the double-checked lock pattern. What we are doing is first checking if the collaborator reference is null. If it is, we try to gain a lock on the Demo object instance (this). Once we hold the object lock, we need to check again if collaborator is still null. This double check is required because it is quite possible that between the time of the first check and the time we get the object lock, a different thread could come in, gain the lock and go ahead and construct a collaborator. So our second check is a defence against that. If we find that the collaborator is still null, we go ahead and construct one.
This seems right, doesn't it? Unfortunately, it is not.
This is where our intuitive sense of reasoning starts breaking down in the face of modern technology.
The problem (once again) is that modern compilers do this thing called instruction re-ordering or out-of-order execution. In fact, the Java Language Specification (JLS) even explicitly permits implementations to do instruction re-ordering code optimizations because it can improve execution speed. And Java isn't the only language doing this either; pretty much all modern programming language compilers do these optimizations.
We won't get into the details of how these optimizations work - that is the job of the JVM engineers! As application developers, our job is to know that these things happen and to ensure that our programs don't fail in the presence of these optimizations.
To better demonstrate the effect of instruction reordering, let me define a simple Collaborator class:
class Collaborator {
public Associate associate;
public Collaborator() {
associate = new Associate();
}
}
With the above class definition in mind, imagine an optimization where the constructor call is inlined in our double-checked Demo class:
class Demo {
private Collaborator collaborator;
public Collaborator getCollaborator() {
if (collaborator == null) {
synchronized(this) {
if (collaborator == null) {
// psuedo code now
associate = new Associate();
collaborator = new Collaborator();
}
}
}
return collaborator;
}
}
NOTE: I am not saying that this is how the code will look if the constructor is inlined. I am just asking you to visualize the fact that there are two reference assignment operations going on here: (1) the associate reference and (2) the collaborator reference.
Now since the JVM is free to re-order these instructions, it may choose to move the collaborator reference assignment before the associate reference assignment. If this happens, think of what happens if another thread comes in and calls getCollaborator() in between the collaborator reference store and the associate reference store? The second thread will reach the if (collaborator == null) check, find that collaborator is not null (since the store was already done!) and so it would skip the if block and return the collaborator reference.
Now with the collaborator that it got, if the second thread tries to do anything with collaborator.associate, it'll get an unexpected NullPointerException since the associate reference is still null!
This is how our intuition fails us and this is one of the reasons why folks keep saying that multi-threaded programming is hard!
Some of you may legitimately ask the question: shouldn't the synchronized block take care of this? Well, a synchronized block is essentially a 'monitor entry' operation at the start of the block and then a 'monitor exit' operation at the end of the block. The JLS guarantees that once we 'monitor exit', all other threads will see all the memory assignments that happened before the exit. However, and crucially, it makes no guarantee that other threads will not see these assignments before 'monitor exit'. See the problem?
So how do we fix this?
Solution 1
We got into this whole mess because we tried to do lazy initialization. So the first question is to ask ourselves if we really need to initialize our class lazily? If not, the safest is to just construct the object at Step 0:
class Demo {
private final Collaborator collaborator = new Collaborator();
public Collaborator getCollaborator() {
return collaborator;
}
}
The critical point to note here is the use of the final modifier. Without that, this class will not be thread-safe. Why? Suppose Thread 1 constructs a Demo instance and then hands it off to thread 2. In the absence of any synchronization, there is no guarantee that the second thread will see the collaborator reference assignment. To put it in a different way, the memory operations done by thread 1 are not guaranteed to be visible to thread 2 in the absence of synchronization. Declaring the reference as final is a great way of ensuring visibility without paying the cost of synchronization. This is made possible due to the special guarantees that the JLS provides for final fields. Go read up on it :-)
Solution 2
If eager initialization is not an option, this is how we can fix our double checked locking code:
class Demo {
private volatile Collaborator collaborator;
public Collaborator getCollaborator() {
if (collaborator == null) {
synchronized(this) {
if (collaborator == null) {
collaborator = new Collaborator();
}
}
}
return collaborator;
}
}
All we did was to add the volatile modifier to collaborator. By doing this, we invoke the JLS guarantee that reads and writes of volatile references shall not be re-ordered. This solves our earlier problem caused by non-apparent instruction reordering. Note that we still need the synchronized block!
There are performance implications to using volatile references but in most scenarios, they aren't too bad. At least on x86, a volatile read instruction is almost as cheap as a regular read. Volatile writes on the other hand are very expensive! If you wish to further optimize the above by reducing the number of volatile read operations, you can use a local variable:
class Demo {
private volatile Collaborator collaborator;
public Collaborator getCollaborator() {
Collaborator tmp = collaborator;
if (tmp == null) {
synchronized(this) {
tmp = collaborator;
if (tmp == null) {
tmp = new Collaborator();
collaborator = tmp;
}
}
}
return tmp;
}
}
Solution 3
In this final solution, we make use of another guarantee of the JLS: an inner class will not be initialized until it is referenced elsewhere.
class Demo {
private static class CollaboratorHolder {
public static final Collaborator collaborator = new Collaborator();
}
public Collaborator getCollaborator() {
return CollaboratorHolder.collaborator;
}
}
When the JVM loads our Demo class, it skips the initialization of the inner CollaboratorHolder class. It is only when a caller invokes the getCollaborator() method that the CollaboratorHolder class is initialized causing the construction of a new Collaborator object. Moreover, this code is 100% thread-safe since the JLS guarantees that class initialization is a serial operation. This pattern is known as the initialization on demand holder pattern.
Summary
As this simple pattern demonstrates, writing multi-threaded code that is both correct and fast is not an easy task. It is very important that we know our development platform and the facilities it provides. And as a meta-observation: we should try not to "optimize" code unless required!
Further Reading
I use Eclipse almost every day at work for Java development. It isn't the best piece of software out there but it mostly works, has a plethora of features and you can't beat the price!
I do have to make several changes to the default settings to make Eclipse work according to my tastes. However, these changes are linked to a workspace and thus, every time that I create a new workspace, I have to remember the tweaks and re-do them.
So here's my attempt at listing them all out so I have a quick reference the next time I need to setup Eclipse.
Installation
Head to eclipse.org/downloads/ and get the relevant Eclipse bundle. The Eclipse IDE for Java Developers is what would generally suit me as a core Java developer. However, I find this bundle to contain unnecessary features (integrated CVS client, really?!) and prefer building up from a base installation starting with just the Eclipse Platform Runtime Binary. Unfortunately, the Eclipse folks keep re-organizing their site and each time, I've to hunt for the download location for the platform binary package. A bit of web searching should help here.
Once you've installed just the base Eclipse platform runtime, you can add the relevant plugins from within Eclipse. Go to Help > Install New Software or Help > Eclipse Marketplace and search for the required features.
My current list of plugins:
- Eclipse Java Development Tools
- Eclipse Color Theme
- ExploreFS
- Perforce SCM Support
- Vrapper (Vim Emulator)
Startup
Eclipse is a memory hog. It is unlikely that the default memory settings will give you a decent experience so it is best to change them. Edit the eclipse.ini file (lives next to eclipse.exe) as follows:
-startup
plugins/org.eclipse.equinox.launcher_1.1.1.R36x_v20101122_1400.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_1.1.2.R36x_v20101222
-showsplash
org.eclipse.platform
--launcher.XXMaxPermSize
256m
--launcher.defaultAction
openFile
-vmargs
-Xms40m
-Xmx512m
The first few lines should already be present in the file. Add the memory related args with values suited to your development machine.
Configuration
Finally, time to tweak some preferences. These need to be set for each new workspace that you create.
Open the Window > Preferences dialog and change the following:
- General > Appearance:
Uncheck Enable animations
- General > Editors > Text Editors:
Set Display tab width to 4; Check Insert spaces for tabs
- General > Editors > Text Editors > Spelling:
Uncheck Enable spell checking
- General > Startup and Shutdown:
Uncheck Mylyn Tasks UI
- General > Workspace:
Set Text file encoding to UTF-8; Set New text file line delimiter to Unix
- General > Compare/Patch > General:
Uncheck Open structure compare automatically; Check Ignore white space
- General > Compare/Patch > Text Compare:
Uncheck Connect ranges with single line
- Java > Code Style > Formatter:
Download Android's code style profile and Import it here
- Java > Editor > Content Assist > Advanced:
Check only the following proposals in both sections: Java Non-Type Proposals, Java Proposals, Java Type Proposals and Template Proposals
- Java > Editor > Content Assist > Favorites:
Add New Type org.junit.Assert
- Java > Installed JREs:
Add a new JDK by pointing to the install directory; Add -server to the Default VM Arguments; Use Add External JARs to add tools.jar to the default libraries.
- Team > Perforce:
Check Use "move" command during refactoring operations
Ideally, you should be able to File > Export > General > Preferences from one workspace and then File > Import > General > Preferences into a new workspace. But it takes only a couple of minutes to make the above config changes and I don't have to worry that Eclipse screwed up something else under the covers. :-)