spotify-car-thing-reverse-engineering's People
spotify-car-thing-reverse-engineering's Issues
Custom HTML using the stock, out-of-the-box firmware
It seemed like extra hassle to have to update the firmware just to run a custom webapp, so here's the minimum amount of JavaScript to initialize the stock, OOTB Superbird so you can see your own HTML on it.
Unlike the Chromium in later firmware, the stock Superbird is running QtWebEngine 5.12.7, equivalent to Chromium 69.0.3497.113 (although its User-Agent reports 69.0.3497.128). The webapp is built into the qt-superbird-app
, embedded as Qt resources. It can be extracted from the binary using Ghidra and the scripts described in @gipi's article, Reversing C++, Qt based applications using Ghidra, available in their repo at https://github.com/gipi/ghidra_scripts.
There's no "Control WebSocket" in the stock app when it first launches, it instead initially uses a QWebChannel, and there appear to be a few initialization commands sent back from the webapp to qt-superbird-app
before it will start rendering HTML and provide messages over the QWebChannel. Not all the initialization commands are necessary to start rendering HTML, and the status messages that come in regularly over the QWebChannel can be ignored.
QtWebEngine heavily caches all the files it accesses, and manually emptying the cache(s) between runs will spare a lot of headaches when testing.
Assuming you've followed in the instructions in @frederic's https://github.com/frederic/superbird-bulkcmd repo to enable ADB (or equivalent), you can do something like this to stop the existing processes, upload an example.html
, clear the caches, and launch qt-superbird-app
manually using the same configuration as specified for supervisord
plus a Chrome remote debugging port:
$ adb shell supervisorctl stop swupdate
swupdate: stopped
$ adb shell supervisorctl stop superbird
superbird: stopped
$ adb shell mkdir /tmp/webapp
$ adb push example.html /tmp/webapp/
example.html: 1 file pushed, 0 skipped. 0.8 MB/s (1188 bytes in 0.001s)
$ adb forward tcp:9222 tcp:9222
9222
$ adb shell rm -rf /var/cache/QtWebEngineCache/*
$ adb shell rm -rf /var/cache/qt-superbird-app/*
$ adb shell 'QT_LOGGING_RULES="" QTWEBENGINE_CHROMIUM_FLAGS="--no-sandbox --ignore-gpu-blacklist --touch-events=enabled" QT_QPA_EGLFS_INTEGRATION="eglfs_mali" QMLSCENE_DEVICE="" QT_QUICK_BACKEND="" QT_QPA_EGLFS_PHYSICAL_WIDTH="51" QT_QPA_EGLFS_PHYSICAL_HEIGHT="86" QT_QPA_EGLFS_ROTATION="-90" QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS="/dev/input/event3:rotate=270" QT_QPA_EGLFS_NO_LIBINPUT="1" HOME="/home/superbird" XDG_CACHE_HOME="/var/cache" XDG_RUNTIME_DIR="/var/cache/qt-superbird-app" QTWEBENGINE_REMOTE_DEBUGGING=9222 qt-superbird-app --config=/etc/qt-superbird-app/superbird_target.ini --url file:///tmp/webapp/example.html'
2015-01-01T03:44:04.870Z [D] main.cpp:66 BOOTMARK: main(): 0ms
2015-01-01T03:44:04.872Z [D] main.cpp:73 BOOTMARK: Config Parsed: 3ms
...
You can also run your webapp on your local machine and reverse the port to the Superbird using ADB, replacing --url file:///tmp/webapp/example.html
above with --url http://localhost:8000/example.html
:
$ adb reverse tcp:8000 tcp:8000
$ python3 -m http.server
Serving HTTP on port 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
...
Here's the contents of example.html
, the meta
elements are from the stock webapp, qwebchannel.js
is built-in, the handleResponse
function overloads the stock one to not delete the callbacks once they're executed to avoid some JS warnings, and the signalEmitted
function is where you'd go to see the status messages coming in over the channel:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=800,height=480,initial-scale=1,maximum-scale=1,user-scalable=no">
<meta name="HandheldFriendly" content="true"/>
<title>Superbird</title>
<script src="qrc:///qtwebchannel/qwebchannel.js"></script>
<script>
var _superbirdchannel = new QWebChannel(qt.webChannelTransport, function(channel){});
_superbirdchannel.handleResponse = function(message) {
if (!message.hasOwnProperty("id")) {
console.error("Invalid response message received: ", JSON.stringify(message));
return;
};
this.execCallbacks[message.id](message.data);
};
_superbirdchannel.execCallbacks[0] = function(data){};
_superbirdchannel.execCallbacks[1] = function(data){};
_superbirdchannel.objects = {};
_superbirdchannel.objects.superbird = {};
_superbirdchannel.objects.superbird.signalEmitted = function(signal, args){};
_superbirdchannel.send({type: 3, id: 0});
_superbirdchannel.send({type: 7, object: 'superbird', signal: 5});
_superbirdchannel.send({type: 6, object: 'superbird', method: 9, args: [], id: 1});
</script>
</head>
<body style="background-color:#0f0;">
<h1>superbird OOTB</h1>
</body>
</html>
When run, it looks like this:
Discussion of Car Thing annoyances and possible future project goals
In another issue @chewitt posed the question, what are the goals of this work?
I figured that the best place to start is with the things that annoy us so I'd love to hear from folks what they wish the Car Thing did differently. Here's my initial list:
- Interaction with the Car Thing often returns audio playback to the phone. I'm currently using the car thing on my desk and with the current behavior I can't really do much more than use the previous/next buttons. Pressing "play" will cause audio to revert to being played out from my phone rather than my desktop Spotify player.
- Reliance on a phone at all. Right now I have an old iPhone 6 acting as the base station for the car thing, but it feels silly. It would be great to be able to pair this with my computer and not have to rely on a dummy phone at all.
- Volume control over Spotify connect works...sometimes. Sometimes it will change the desktop player's volume, sometimes it just doesn't.
- Turning the display off after N minutes of no playback. Right now the car thing stays on forever as long as it has power. Fortunately I can plug it into a power strip I use that has a master/slave setup with my main desktop. When the desktop goes to sleep or is off, the rest of my audio gear shuts off too. However it would be nice if the car thing could "go to sleep" if there's no activity for a while.
Reconstructed webapp source code (with working builds!)
Thanks to the sourcemaps Spotify left on the device, I've put together a complete reconstruction of the TypeScript/React source code of the superbird webapp with working builds (using Vite, so you also get hot reload) and a script to easily push changes to the device. Hopefully this should let us do things like add more menus and features or remove software restrictions!
I've put all the code in this repo along with some documentation, feel free to file issues and give feedback: https://github.com/Merlin04/superbird-webapp
Feature request feasibility
Hello!
As we go forward experimenting with the newly unlocked hardware, Woot Woot! (I'm very excited to see what comes of it), I was wondering if the following features were even possible:
-Google Maps navigation displayed on car thing
-Ability to accept calls with an android device
I've created a Discord Community Server
Hey guys I've created a simple community server for us to chat and share projects.
It's pretty simple and new but I'll be improving as we go on, and if there anyone who wishes to help let me know.
Here's the invite link: https://discord.gg/Nksa7SQc
Any questions just hit me up.
#Update 1 - Invite Link is fixed
Able to open dev menu (but it's useless)
Firmware images for the Car Thing
Firmware dumps, OTA updates and premodded images can be found here:
https://mega.nz/folder/NxNXQCaT#-n1zkoXsJuw-5rQ-ZYzRJw
If you have any carthing related files you want to upload, upload them here then make a comment on this issue. You shouldn't need a mega account but if it's giving you issues let me know. It'll also be completely anonymous if that's something you care about.
Getting more OEM/ODM info
I dont know if anyone else has research this yet but I found something interesting by searching for FCC applications by Spotify. Below is the link.
https://fccid.io/2AP3D
It seems as though there was an earlier style of Car Thing without a screen which I did not know about. Might be useful for anyone out there looking into this device though.
10%
Oops, accidentally pressed enter - ignore this
Button combinations
I just wanted to share that I came across the fact that if you hold the top 4 left buttons (excluding the recessed button) and then boot it, it seems to go into a different mode that shows up under lsusb. I am not well versed in the hardware side of things, so the info you have on here already might mean that you know this already, but just wanted to let you know.
Thanks,
-MH
CarPlay & Android Auto functionality
According to this twitter post by Zhuowei Zhang from July linking this Car Thing support article, it seems as if you can cast the display of your Car Thing to any CarPlay/Android Auto compatible on-board computer*.
This probably means that, if ever made possible, a CFW'd Car Thing could display whatever it wants to an on-board computer.
If anyone has any more info about this, please reply. And I ask of anyone with a supported device & a Car Thing to test this out for me.
Linked in the post's replies is proof that the CarPlay has MFi compatibility. Link (see lines 1033 thru 1043)
*Information from https://support.spotify.com/us/article/setting-up-car-thing/:
"Apple CarPlay and Android Auto
If Apple CarPlay or Android Auto is available in your car, you can use it with Car Thing. Just connect Car Thing to the sound system with the USB cable.
Car Thing’s screen will then also show on the head unit’s screen, but you can still use Car Thing to control what is playing.
For more information go to Android Auto Help Center or Apple CarPlay support site."
MITM Processing of Car Thing Requests
I've found that there is a lot of interesting information that gets streamed through the host device from the Car Thing using MITM.
A popular endpoint seems to be "https://spclient.wg.spotify.com/gabo-receiver-service/v3/events"
There is also a request to this domain "https://spclient.wg.spotify.com/carthing-proxy/network/v2/logevents/8550R786Q81O" that transmits vitals from the device.
[
{
"swap_cached": 0,
"cached": 129628,
"mem_total": 501172,
"swap_total": 0,
"type": "memory_v2",
"buffers": 1244,
"mem_free": 126880,
"swap_free": 0,
"timestamp": 1665943898032,
"mem_available": 254092,
"processes": {
"QtWebEngineProcess --type:zygote": {
"vm_hwm": 30132,
"vm_rss": 17512
},
"supervisord": {
"vm_rss": 11868,
"vm_hwm": 11948
},
"swupdate": {
"vm_rss": 1528,
"vm_hwm": 3260
},
"QtWebEngineProcess --type=renderer": {
"vm_rss": 125904,
"vm_hwm": 131756
},
"sp-als-backlight": {
"vm_hwm": 208,
"vm_rss": 172
},
"bluetoothd": {
"vm_rss": 2168,
"vm_hwm": 3004
},
"qt-superbird-app": {
"vm_rss": 139220,
"vm_hwm": 177360
}
}
},
{
"uptime": "12 12",
"mounts": {
"/var": {
"available_MB": 1882,
"used_MB": 35
},
"/var/lib": {
"available_MB": 221,
"used_MB": 2
},
"/": {
"used_MB": 392,
"available_MB": 76
},
"/home": {
"available_MB": 1882,
"used_MB": 35
}
},
"timestamp": 1665943898199,
"type": "storage"
},
{
"type": "temperature",
"timestamp": 1665943898200,
"temperatures": {
"dram_thermal": "34.72",
"soc_thermal": "42.10",
"ddr_thermal": "42.30",
"bluetooth_thermal": "34.56",
"pcb_thermal": "34.35"
}
}
]
Fixing a rattly knob?
My car thing has a particularly rattly knob (compared it to a friend's) - has anyone taken apart the device to the point where the internals of the knob are exposed? I think that could help with diagnosing the problem (in addition to satisfying my curiosity about how the mechanism works)
Similar to Radxa Zero ?
The Radxa Zero uses an Amlogic S905Y2, and I wonder if some of the development information is applicable?
For example, check out this page about maskrom, which mentions the same 1b8e:c003 Amlogic, Inc. GX-CHIP
device just like the Car Thing does when you hold the 4 buttons.
I wonder if this is a way we could sideload our own binaries, kind of like using fastboot to boot a recovery image on an android device.
10% off coupon code
To anyone who hasn't purchased the car thing yet - there's a 10% off coupon code you can use, EXTRA10
Random car thing findings
I'll just be logging random stuff I figure out here lol
Older firmware versions seem to use a very stripped down chromium thing for it's UI but newer versions (not sure when they made the switch) use a much more fully featured copy of chromium that has a new tab page and everything. Easiest way to access it is to edit /etc/supervisord.conf and remove the kiosk and webapp flags from the chrome command.
If you dump the fw from a brand new car thing you can essentially treat that dump like a factory image. A bit more info and a script to flash it are here: frederic/superbird-bulkcmd#12
Key Codes from buttons
You can use the command showkey to dump the key codes.
Back Button = ESC ( 0x1 KEY_ESC )
Rotary Button -RETRUN (0x1c KEY_ENTER)
Starting from Top left, the preset buttons
1 - Number key 1 - (0x2 KEY_1)
2 - Number key 2 - (0x3 KEY_2)
3 - Number key 3 - (0x4 KEY_3)
4 - Number key 4 - (0x5 KEY_4)
5 - Power Button - Letter Key M - (0x32 KEY_M)
Board picture with uart locations?
Could you include a photo of the uart locations and could you describe the other uart you mentioned what what it doing?
UBOOT Shell
Seem like Nole Johnson was able to connect via usb and access the UBOOT shell. Just wanted to post here so everyone was informed and updated.
Post:
https://npjohnson.github.io/Spotify-Car-Thing-Root/?s=09
Cross-platform alternative to amlogic usb tool binary
I found this repo which appears to be source for an earlier version of the amlogic usb tool. Specifically, it appears to be:
Amlogic update USB tool(Ver 1.5) 2017/05
as opposed to the one provided by Frederic, which is:
Amlogic update USB tool(Ver 1.7.2) 2018/04
I had no trouble building it on Ubuntu x86_64, but it doesn't work with superbird, which isn't terribly surprising.
There is another repo, forked from the first one, with some changes made to support p230. Probably not much use for us.
I also found that the khadas repo has the same update tool for Windows, x86_64 Linux, and armhf Linux. The versions here match the one provided by frederic. I got excited at the armhf one, but I'm getting an exec format error when i try to use it, so I think I'm missing some detail. I haven't tried the Windows one. There are some additional tools in that repo that may be useful as well.
So, my point is: If someone understands what's going on better than I, they could tweak that old source so that it works with superbird, and then we would have a tool that could potentially be ported to other platforms.
I am particularly interested in this, because my main dev machine is aarch64, and I had to haul out an old Intel machine to work on superbird; It
Source code request
Hi! Has anyone tried asking for the source code for whatever form of Linux they're running from Spotify themselves?
Might be some good pointers in there for how the hardware is wired up internally.
Method to switch between boot slots
The car thing seems to have a way to fallback to the previous version of the OS if something fails on the latest one, similar to newer android phones and their A/B partition layout.
Switching method:
- Plug in car thing
- Wait for Spotify logo to appear then wait an additional second
- Unplug it, never actually letting it load the OS
- Repeat the above steps 8 times
- Leave car thing plugged in on the 8th time
This should force it to go back to the previous OS version then if you do the same thing again it'll go to the latest one.
Car thing as a macropad!
Thanks to u/Jaba_Haba on reddit for bringing Macro Deck (the software making this possible) to my attention!
https://www.reddit.com/r/carthinghax/comments/yq5p77/macro_deck_for_car_thing/
- Flash the ADB image from here: #22
There's instructions on how to do it in the folder with the firmware images. - Make sure adb is installed and working on your PC. XDA has a decent walkthrough
- Install and set up Macro Deck https://macrodeck.org/
- Download these files:
https://github.com/Macro-Deck-org/Macro-Deck-Web-Client (Click Code then Download zip)
https://gist.github.com/lmore377/4c944a97407e34e10d998ee6a3e33f6a (For both files right click Raw then Save link as...)Currently not up to date, will fix soon ™️ - Extract the zip file to any folder then run these commands:
adb shell mount -o remount,rw /
adb push supervisord.conf /etc
adb shell cp -r /usr/share/qt-superbird-app/webapp/ /usr/share/qt-superbird-app/webapp.bak/
adb shell rm -rf /usr/share/qt-superbird-app/webapp/*
adb push Macro-Deck-Web-Client-main/* /usr/share/qt-superbird-app/webapp/
adb push index-edited.html /usr/share/qt-superbird-app/webapp/index.html
adb reboot
- After the car thing reboots you should see the macro deck web ui load up. At this point just run
adb reverse tcp:8191 tcp:8191
(change 8191 if you use a different port) then press connect on the car thing. You'll need to do this every time you reboot your pc or unplug/plug in car thing
The only caveat is that none of the physical buttons work. I think this is just a limitation of macro deck but if you manage to figure out how to get keyboard keys working here's the mapping:
Preset 1-4: Numbers 1-4 on a keyboard
Menu: M
Back: ESC
Wheel Button: Either space or enter. I can't remember which
Wheel: Mouse scroll wheel
The only edit on the index-edited.html file is at line 104 to autofill the IP address since there's no form of keyboard input on the car thing. supervisord.conf was just edited to disable swupdate and the process that handles phone communication to free up some resources.
Edit: one more thing, if you ever want to update the web client for whatever reason you just need to edit line 104 in index.html to match what I edited and push the updated files over ADB to /usr/share/qt-superbird-app/webapp/
Opening the Car Thing
Announce: Wall Thing - Debian Chromium Kiosk on Spotify Car Thing (superbird)
Since a lot of people are still lurking here, thought you might be interested in the progress I have made toward using the Car Thing as a kiosk for Home Assistant.
What I have now is Debian 13 in the data
partition, using the stock kernel (on boot_a
), with Chromium browser fullscreen showing a Home Assistant Lovelace page, and buttons controlling lighting and presets via Home Assistant API.
Here is the repo, :
superbird-debian-kiosk
You can download a pre-made image here: Releases
Please see the Readme for flashing instructions
Requirements:
- Spotify Car Thing
- another device to act as host, such as Radxa Zero, Rockpi S, Raspberry Pi 4, etc
- a USB cable to connect the two
- power supply for the host device
- a desktop/laptop for flashing the image to the Car Thing
Features
Working:
- Debian 13 (Trixie) aarch64
- Framebuffer display working with X11, in portrait or landscape, with touch input
- Networking via USB RNDIS (requires a host device)
- Automatic blacklight on/off with display wake/sleep
- VNC and SSH (forwarded through host device)
- Chromium browser, fullscreen kiosk mode
- Buttons and dial used to control a light and recall scenes/automations/scripts on Home Assistant
- 256MB
settings
partition used for Chromium user profile
Available, but not used in this image:
- Bluetooth
- Backlight brightness control (currently fixed at 100)
- Audio (mic array, DSP)
Not working:
- Wifi
- GPU acceleration
WiFi is technically possible on this hardware, but the stock bootloaders and kernel disable it.
It might be possible to cherry-pick the wifi information from the Radxa Zero device tree (practically the same SoC), but I think you would need to rebuild one or more of the bootloader stages to make it work.
GPU: the hardware has a Mali GPU, but the stock OS uses it via DirectFB QT library, and does not include necessary libraries to make it work with X11. It may be possible to grab the needed files from Radxa Zero.
Amlogic S905 SoC: bypassing the Secure Boot
Not sure if this will be helpful or not but I find this info:
https://fredericb.info/2016/10/amlogic-s905-soc-bypassing-not-so.html
It's from 2016 so BL2 might have been patched. But it might work
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.