Виправлення CarPlay для Audi A3 8V

Коли я став власником свого рестайлового A3 e-tron, я вперше познайомився з CarPlay на цій моделі авто. Загалом CarPlay працював нормально й не викликав запитань, але з часом я почав помічати функції, які не працюють.

Мова далі піде про конкретну голову: Audi A3 8V Sportback e-tron 2017 року, магнітола MIB2 High, прошивка MU1326-MHI2_ER_AU37x_P5089, панель приладів — Virtual Cockpit (FPK). Усередині це QNX 6.5 на Tegra 3, ARMv7.

Найголовніша та найпомітніша непрацююча функція — це відсутність обкладинок пісень на панелі приладів, коли музика відтворюється з CarPlay (Apple Music, YouTube Music тощо).

Приклад відсутньої обкладинки на Audi A4

Водночас обкладинки нормально відображаються, якщо музика відтворюється через Bluetooth або з інших носіїв. Із якоїсь причини інженери Audi не доробили цей функціонал у CarPlay (і, ймовірно, в Android Auto). І наступні оновлення MIB2 цього функціоналу не додавали.

Друга функція, яка могла б працювати, але не реалізована з заводу, — це керування тачем у CarPlay, який розташований на крутилці панелі керування мультимедіа.

Центральна крутилка має тач-покриття

Її теж не реалізували. Можливо, на момент виходу авто ще не була популярна мультимедіа з тачскріном і вирішили не робити.

Також нещодавно побачив, що людина на ім’я Luka з чату про Virtual Cockpit і MIB у Telegram опублікувала свої доопрацювання щодо CarPlay для MHI2Q. Він також реалізував виведення на панель приладів маневрів із навігації CarPlay, тобто, проклавши маршрут наприклад у Google Maps на CarPlay, ви можете бачити маневри на приладовій панелі та HUD-дисплеї.

Одразу його рішення напряму до MHI2 (наша мультимедіа) перенести не можна. У нього стек Cinemo, Qualcomm, а в нас QNX 6.5, Tegra 3, ARMv7. У нього драйвер CarPlay на стеку Cinemo, а в нас Harman. А маневри в нього рендеряться прямо на MIB, а в нас такого немає в принципі.

Різниця глибша, ніж здається. У Luka протокол iPhone обробляє бібліотека Cinemo всередині процесу dio_manager, і її функції прийому-передачі можна просто «обгорнути» своїми — викликати оригінал і подивитися на байти. У нас же протоколом займається драйвер Harman (mm-ipod плюс ipod-drvr-iap2.so), обгортати там нічого: голова заходить у драйвер не за іменем функції, а через таблицю вказівників усередині нього. Тобто точку входу довелося шукати в самому бінарнику й підміняти вказівник на функцію прийому пакетів своїм.

У технічній частині MIB я практично нічого не знаю, але зараз у нашому житті активно використовується AI, і я вирішив спробувати доробити та додати ці фічі в нашу мультимедіа, вдавшись до допомоги AI. Для реалізації я використовував Claude Opus 5 High.

Для роботи я підготував теку з повним бекапом прошивки MIB, проєкт Luka, а також Luka зміг декомпілювати java-файли моєї прошивки, по суті отримавши вихідники java-стеку. Також для Claude написав простенькі скіли для підключення до MIB прямо на машині (через network), доступ до shell тощо.

Із реалізацією перших двох фіч — dpad і обкладинок пісень — Claude впорався доволі швидко. Dpad практично з одного заходу зробив, а обкладинки — першу робочу версію мабуть десь із третього заходу, і то зробив би швидше, якби зрозуміли, що на панелі приладів треба в адаптаціях увімкнути Picture_Upload_Download. Потім було доопрацювання обкладинок: вони то з великою затримкою з’являлися, то з’являлися артефакти при швидкому перегортанні, то, якщо пісня вже грала на телефоні й після підключення CarPlay, обкладинка не виводилася, та інші помилки. У машині сидів по пару годин після роботи й дивився, як Claude шукає рішення.

Робочі обкладинки пісень на панелі приладів

Після реалізації двох попередніх фіч я захотів реалізувати маневри з навігації CarPlay на віртуальному кокпіті. Дав завдання Claude усе проаналізувати й спробувати перенести функціонал із проєкту Luka. Але тут на мене чекав невеликий облом. Claude одразу сказав, що рендер у Luka відбувається прямо на MIB і там є окремий компонент, а в нас такого компонента немає, і в нас у штатній мультимедіа немає взагалі анімації для маневрів — у штатній навігації маневри виводяться статичною картинкою, а в Luka це просто 3D-графіка в реальному часі. У нас у теорії теж можна було б рендерити на GPU, але в драйвері NVIDIA на цій голові взагалі немає компілятора шейдерів: він уміє приймати їх лише заздалегідь зібраними бінарниками під свою версію драйвера, а зібрати такі ніде.

Окрема історія — як ці маневри взагалі змусити прийти в голову. Драйвер Harman про навігаційні повідомлення CarPlay не знає нічого: у його таблицях протоколу потрібної групи повідомлень немає, у конфізі теж. Телефон надсилає маневри лише тим, хто під час підключення оголосив себе «дисплеєм навігації», а оголоситися штатними засобами не можна — такого налаштування у прошивці не існує. Довелося дописувати це оголошення прямо у вже зібраний пакет представлення, побайтово, на льоту. Після цього iPhone почав слати потік маневрів, якого ця голова не бачила жодного разу за своє життя.

І тут вилізла головна неприємність: приблизно через пів хвилини після підключення CarPlay намертво зависав. Розбиралися кілька вечорів, і причина виявилася красивою. У драйвера є пул усього із шести пакетів на прийом. Кожне повідомлення про маневр потрапляє в обробник, який про такі повідомлення не знає, і повертає код помилки. А код, що його викликає, трактує будь-яку позитивну відповідь як «пакет забрали, він більше не мій», і в пул його не повертає. Шість маневрів — і пул порожній, прийом став назавжди. У Luka такого бути не може в принципі: його бібліотека віддає готові байти й жодного пулу не показує. Полагодження — повертати пакет у пул самим. Після нього шість хвилин під навантаженням без жодної просадки.

Claude запропонував не рендерити маневри на MIB, а зробити пререндер на ПК: розбити на кадри анімацію кожного маневру, а на MIB залишиться тільки програвати їх із певною частотою. Добре, що в репозиторії Luka були самі маневри та інструмент для їх рендера.

Claude відрендерив усі маневри, розбив кожен маневр на кадри, зробив демку, і я прямо на панелі приладів машини спостерігав анімації маневрів, а Claude питав, яка частота кадрів краща, і паралельно моніторив продуктивність. Спільними зусиллями дійшли висновку, що достатньо 18 кадрів на секунду: на 12 анімація виглядає повільною, а 30 підвішували MIB і клали всю систему. Де саме проходить межа між ними, ми не міряли — залишили 18 із запасом.

Спочатку ми пререндерили лише один вид, а в кокпіта є два види — для великої та малої сцени. Довелося відрендерити ще й для малої сцени. Сцени відрізняються розмірами (328×181 і 210×153 пікселя) і фоном; фон, до речі, довелося малювати свій — штатний виявився надто темним і надто «шумним», щоб нормально стискатися. Є ще третя сцена — спортивне розкладання кокпіта, але в мене e-tron-версія панелі приладів, і там вона повноцінно не працює, тому я цього не реалізовував. Наразі кадрів (картинок) відрендерено близько 3600 штук — по 1787 на кожну сцену, 47 різних маневрів.

Потім дуже довго Claude намагався розібратися з виведенням плиток маневрів, постійно вилізали накладки, також часто зависав CarPlay. На це пішло кілька днів і по чотири години сидіння в машині. Пізніше треба було ще протестувати в реальній поїздці — теж довелося кілька разів проїхатися районом.

Кумедно, що плитка маневру на панелі приладів у підсумку збирається з двох половинок. Стрілку малюємо ми — це наша картинка на штатній підкладці кокпіта. А число «600 м» над нею панель приладів малює сама: ми віддаємо їй відстань окремим каналом, текстом. Назву вулиці ми теж надсилаємо, але панель приладів її чомусь не показує — це ще належить розібрати.

Реальні поїздки дали ще пачку дрібниць, яких за столом не побачиш. Наприклад, iPhone віддає не весь маршрут, а ковзне вікно з двох маневрів і міняє їх місцями приблизно двічі на секунду — через це стрілка стрибала між справжнім поворотом і заглушкою «рухайтеся прямо». Або відстань зникала ближче ніж за 200 метрів до повороту: виявилося, панель приладів на цьому етапі малює смугу заповнення замість цифри. Або втрата GPS посеред маршруту, яку від завершення маршруту не відрізнити. Усе це ловиться лише на дорозі.

Google Maps в Україні з 2022 року нормально не оновлює карти й будує маршрути дуже погано та проти ПДР, але дані про маневри надсилає, на відміну від Waze. Waze із якоїсь причини перестав віднедавна надсилати дані про маневри на CarPlay, сподіваюся, невдовзі це повернуть, і тоді запрацює й на панелі приладів.

Свій проєкт я виклав на GitHub: https://github.com/chefranov/mhi2-au37x-carplay

Там напевно ще є багато помилок тощо. На дані та підтримку навігаторів я ніяк вплинути не можу: у CarPlay є свій формат даних, я його читаю й передаю на панель приладів, а надсилати ці дані чи ні — вирішує застосунок навігації.

Одразу зауважу: усе це робилося на своїй машині та на свій страх і ризик. Голова при таких правках монтується на запис, штатні файли підміняються, і будь-який експеримент тут — потенційно поїздка до дилера. Усе, що я ставив, відкочується назад у сток, але якщо ви не готові до того, що мультимедіа перестане вмикатися, — краще не повторювати.

Окреме спасибі Luka: без його розбору приладової частини й без набору маневрів це все зайняло б у рази більше часу. Java-половина його проєкту на нашу голову лягла практично один в один — уся морока була навколо драйвера та графіки.

Маневри на панелі приладів із навігатора CarPlay
Демо маневрів

На цьому все, гарних доріг!