Menu

andipanda.dev

CaRadio: Audio, Navigation Prompts, and the Final Improvements to Version One

In the previous articles, I described how I managed to get CarPlay running on Raspberry Pi, achieve a stable phone connection, and implement touchscreen controls.

But one important part of any car multimedia system still remained: audio.

At first glance, the task seems simple: receive audio data from Carlinkit and send it to an audio output. In practice, however, audio handling turned out to be one of the most time-consuming parts of developing CaRadio.

Especially when it came to navigation prompts.

Volume Control with Nowhere to Put It

I'll start with a fairly simple but unexpected problem.

In the original head unit design, I physically had no room to install a volume control knob.

At first, I actually adjusted the volume using a small wireless keyboard. That was perfectly acceptable for experiments, but inconvenient for everyday use in a car.

Eventually, I added a second screen with volume control buttons.

I also included an option to reboot the system if something went wrong.

It wasn't quite the solution I had imagined at the beginning of development, but it allowed me to work around the physical limitations without significantly rebuilding the head unit's enclosure.

One PCM5102 for All Audio

For audio output in CaRadio, I used a PCM5102 digital-to-analog converter (DAC).

As far as I understood while studying FastCarPlay, the original implementation split audio between two devices.

In my case, however, I had only one PCM5102, which needed to handle everything: music, navigation prompts, and all other CarPlay sounds.

The thing is, CarPlay transmits different types of audio as separate streams.

This is convenient from the system's perspective, but it creates an additional challenge when everything has to be played through a single physical audio output.

So I had to implement software audio mixing.

As a result, multiple audio streams were combined and sent to a single DAC.

But as it turned out, the mixing itself was far from the hardest part of the job.

When the Navigator Starts Talking

Imagine an ordinary situation.

Music is playing in the car, the driver approaches an intersection, and the navigation system announces where to turn.

In a properly functioning multimedia system, the music becomes quieter during the announcement, the navigation voice remains clearly audible, and the original volume is restored afterward.

That was exactly the behavior I wanted to achieve in CaRadio.

The problem was that I didn't have all the information needed for proper volume control.

Either Carlinkit did not transmit the relevant data in the accessible part of the protocol, or the developers reverse-engineering it had not yet figured out how to retrieve that information.

I can't say which explanation was correct.

In particular, it was unclear what volume levels should be used for music and voice prompts, or exactly when the music should be reduced and restored to its previous level.

I had to find my own way to handle it.

A Timer Instead of Precise Information from CarPlay

The solution was based on monitoring the incoming navigation prompt audio stream.

When a voice prompt started arriving, CaRadio could lower the music volume so that the navigation voice wouldn't get lost in the background.

But another problem appeared: how could I tell when the prompt had actually finished?

If the music volume was restored immediately after the next batch of audio data stopped arriving, the transition could be abrupt or even cut off the end of a sentence.

Navigation prompts don't always arrive as one continuous segment of audio. There can be short pauses between individual parts.

So I added a delay before restoring the music volume.

After the navigation prompt stream stopped arriving, a timer of approximately 300–500 milliseconds was started.

If new audio data arrived during that time, restoring the volume was postponed.

This helped reduce abrupt transitions, clicks, and the risk of cutting off the last words of a navigation prompt.

The solution wasn't perfect, but it proved effective enough in practice.

The Most Inconvenient Debugging Process

This is probably the stage of development I remember most vividly.

The problem was that navigation prompts didn't play all the time or under every condition.

Simply running the head unit on a workbench and checking the audio wasn't enough.

For a proper test, I had to install CaRadio in the car and go for a drive with navigation running.

If a problem appeared while driving, I tried to remember the circumstances in which it occurred.

After the drive, I had to remove the head unit again, take it home, modify the code, and repeat the test.

And I did this many times.

What made it particularly frustrating was that some issues only appeared in specific situations. I could drive part of a route without any problems, only to suddenly hear the music ducking incorrectly or a navigation prompt being cut off.

After each change, I had to test the system again under real driving conditions.

It's hard to call this a convenient debugging process, but at the time I didn't have another sufficiently reliable way to reproduce all those situations.

Not Perfect, but It Works

Gradually, I managed to achieve behavior where music and navigation prompts no longer interfered with each other.

Of course, I can't call this implementation perfect.

Some shortcomings remain, and the volume control algorithm could certainly be refined further.

But the most important thing is that the system started working reliably.

Music plays, navigation prompts are audible, and the volume returns to its previous level afterward.

For me, that was the result I had been working toward.

After all, CaRadio wasn't meant to be a demonstration project that only needed to run once on a workbench.

I wanted to use my own head unit every day.

The First Version of CaRadio

And with that, I think it's time to conclude the story of developing the first version of CaRadio.

Along the way, I had to solve quite a few problems: from getting CarPlay running through Carlinkit to handling touchscreen input, managing power, and playing audio.

Some solutions turned out to be fairly simple, while others required countless experiments.

There were compromises, too, dictated by the head unit's design, the hardware I had available, and the time I could devote to the project.

But in the end, a collection of components and software experiments became a working car multimedia system.

Not without flaws, and not with every feature I would have liked to implement, but stable enough for everyday use.

And that is probably the greatest achievement of the first version of CaRadio.

This isn't the end of the project's story. It simply marks the beginning of a different stage in its development.