7" Touch Display (old technology), ARM v7 CPU (800 BogoMIPS), 512 MB RAM, SD card slot, USB, Audio-Out (TRS), Wifi. Perhaps even GPS, Accelerometer and more gimmicks?
The device is a small tablet, primarly used as media player. It has support for radio and TV streaming, getting its list of available channels directly from the distributor, Orange France.
Unfortunately, Orange seems to discontinue those devices and might take down the servers at the end of 2012, effectively rendering the device useless for TV/Radio streaming.
Quest: understanding how Tabbee works internally
The list of available radio stations is fixed and while there is a way to add them to local favorites, there is no direct mechanism for entering them as URLs. So we took a closer look at the internals. Luckily the Tabbee is based on a small Linux kernel and the Internet provided us with the knowledge of the root password: "$agem30
"
Accessing the file system (assuming the Tabbee got the local IP 10.20.23.193):
sshfs 10.20.23.193:/ /mnt/tabbee/ -o allow_other
allow_other
was required in our case, as we wanted to export the rootfs via Samba, so that it can be directly accessed from our Windows desktops. Alternatively a SSH connection from Windows would also work, but directly pointing an editor to the file, without a need to reupload them all the time is just more convenient. Samba was instructed to disrespect file access control by using force user = root
. Remember to redo this command every time you reboot the Tabbee.
The whole interface of Tabbee seems to be a fullscreen webpage (displayed with Opera) where individual Javascript-widgets are loaded. Changing the files on disk thus only takes effect when this browser page is reloaded. Apart from rebooting the whole tablet this can be done easily by going to the home screen and then opening the web browser. Closing it again leads to a refresh of the "homepage" webpage and re-initialization of all widgets.
The radio application can be found in /opt/www/widgets/system/RadioApplication
. It consists of a main index.html
file, included Javascript, images, etc, and two PHP files. The latter are executed in the local thhptd for file access permission, the rest is executed in the browser. Some files are actually symbolic links pointing to /tmp/lang/widgets/...
, which in turn is a symbolic link to /opt/www/widgets.fr for the french language files. There is also a folder widgets.en
and a configuration option to select English language, however, this didn't seem to work.
The radio application has three categories - International radio stations, French stations, and Favorites. Those are defined in the index.html
file at the beginning:
WidgetApplication.categoryList = [
/* most popular group */
{ name: "Radios internationales", id: "WorldRadios" , playlist: "/tmp/Radio_list1.m3u", list: null, wma: 1 },
/* french radios */
{ name: "Radios françaises", id: "folder" , playlist: "/tmp/Radio_list2.m3u", list: null, wma: 1 },
/* favorite */
{ name: "Radios favorites", id: null , playlist: "/tmp/Radio_list3.m3u", list: null, wma: 1 }
];
WidgetApplication.CATEGORY_FAVORITE_ID = 2;
Once you select a category the JS calls the PHP file GetRadioList.php
which calls the binary program /usr/bin/irs
, unless it's the favorite folder (id: null
) or it has already been loaded in this browser session. IRS is a proprietary application which retrieves the list of radio stations from the orange servers and returns it in JSON format. Additionally it also writes a m3u playlist to e.g. /tmp/Radio_list1.m3u
(passed as parameter).
For the favorite folder, a JS object PlgPreferencies
is instantiated. I couldn't find the source for it nor find any information on the net about it. It appears to be a simple, grouped, persistant key-value-store provided as an Opera plugin. Example usage, in RadioApplication/js/WidgetApplicationClass.js
:
var pref = new PlgPreferencies("RadioApplication");
pref.set_preferency("radio_index", index);
var radioURL = pref.get_preferency("favoriteRadioURL" + offset);
The JS triggers music play, playlist change, etc using the object PlayerClass
. The music itself continues to run in the background even when the webpage is replaced, assumingly using an Opera plugin. This needs to access an m3u playlist file, which is written in the /tmp
folder by IRS for the server-loaded playlists. For the favorite category, the playlist categoryList[CATEGORY_FAVORITE_ID]
is passed in WidgetApplicationClass.saveFavoritePlaylist()
as GET-Parameter to the saveRadioList.php
script, which in turn stores this as m3u file in the /tmp
folder, returning the actual filename. The filename is of the form Radio_favorites.XXX.m3u
with XXX being a random string. It is overwritten every time the favorite list is initially loaded or changed.
Quest: get our own music streams into the device
We decided to stick with the probably better tested French files and just replace some texts as we went along. Our main goal was to add our own favorite radio stations, with the secondary goal to be able to continue using the device once the orange servers were shut down. For the latter a more exhaustive search would be required for the full tablet functionality, so the initial scope was just the radio widget.
First we changed the list of available categories, adding our own category, removing the French radios, and changing the ordering. The CATEGORY_FAVORITE_ID
needed to be adjusted accordingly.
WidgetApplication.categoryList = [
/* favorite */
{ name: "Favorites", id: null , playlist: "/tmp/Radio_list3.m3u", list: null, wma: 1 }
/* our own station list */
{ name: "Dragon Radios", id: "dragon" , playlist: "/tmp/Radio_list_dragon.m3u", list: null, wma: 1 }
/* most popular group */
{ name: "International Radios", id: "WorldRadios" , playlist: "/tmp/Radio_list1.m3u", list: null, wma: 1 },
];
WidgetApplication.CATEGORY_FAVORITE_ID = 0;
Next the GetRadioList.php
was extended: based on the group it would now either call IRS as usual or fetch our own list. Though we could easily just return a simple text file stored on the device it was more fun to have it point to our own webpage instead and retrieve the list from there. This gives us the change to add a web frontend to manage our playlist. To be able to actually play the category it also needs to be written as m3u file to the temp folder, too.
Download the new GetRadioList.php
file or our example category playlist JSON file
Editing GetRadioList.php
When changing the PHP file it's useful to add the responseText
to the Javascript-Alert in WidgetApplicationClass.getRadioList()
. For this, change:
catch (e)
{
alert("Impossible d\'obtenir la liste des radios");
}
to catch (e) {
alert("Failed to parse list of radios." + responseText);
}
Resetting the device
It's possible to reset the device to factory settings by going to the service menu. This can be accessed by going to "Réglages / à propos" and touching the lower left corner while holding down the 'Volume down' button (right side, lower button). It will ask for a pincode - the default '0000' worked for us.
What to do when the servers are shut down?
We haven't looked into the rest of the software, but at least for the radio widget the functionality will be cut off once the server list is not available anymore - leaving just the locally stored favorites. However it is simple to use the above script to also return our own list for the default categories. So we could just store what's currently returned from the server, or create our own lists. We assume that's similar for the other apps, e.g. the TV widget. However when the streams itself are provided by Orange and are also shut down then we can't do anything about this, of course.
Additional stuff we found out
The device can blank the screen after some time. Unfortunately this only displays a black screen, but does not actually turn it off. We need to see how much energy this consumes and how hot it will get when used primarly as a music player connected to the home stereo.
The power adapter is rated 12V DC 1,25A, and it can be run w/o the battery.
Even though a USB port is available and a connected keyboard was listed with lsusb
(SSH to the device), it wasn't detected as input device. We didn't investigate further.
I tried to make a backup of the device, but lacked the knowledge how to do so correctly. I tried this command:
tar cvzf - / | ssh user@our.own.machine "cat > /backup/tabbee.tgz"
but it returned a "short read" and produced a defective archive. Neither the parameters -p nor -l were available. This was before I though of using sshfs, though.
The browser or music player plugin crashed quite some time, leading to a white screen and an automatic restart of the browser. Only a minor inconvenience.