From ea775fa501e283e0f7777e71970c09e04af11093 Mon Sep 17 00:00:00 2001 From: Michael McAllister Date: Tue, 21 Jul 2026 00:38:53 +0100 Subject: [PATCH] hibyr1: add USB DAC scaffolding Introduce the generic, target-agnostic pieces for a gadget-driven USB Audio Class DAC, gated by the HAVE_HOST_USB_AUDIO target flag so they stay inert unless a target opts in. Rather than adding a new USB mode, reuse the existing usb_audio setting (never / always / while charge-only / while mass-storage) with its LANG_USB_DAC string, usb_set_audio() callback and the PCM_MIXER_CHAN_USBAUDIO mixer channel. HAVE_HOST_USB_AUDIO becomes the umbrella capability flag for this common code; USB_ENABLE_AUDIO stays the native usbstack class-driver contract (which needs HAVE_USBSTACK and so cannot be used by hosted ports whose kernel owns the USB controller). usb_set_audio() is declared here and implemented by the target (natively by the usbstack driver, or in the hosted port for gadget targets, as with usb_audio_get_active()), and applied at settings load. The playback interlock in wps.c/playback.c keeps local playback from mixing with host audio while the DAC is active. Simulator stubs for usb_set_audio() and usb_audio_get_active() keep sim builds linking. Co-Authored-By: Claude Opus 4.8 Change-Id: I5b7738508c24721d91d4c32379102a1ac7c6228b --- apps/features.txt | 2 +- apps/gui/wps.c | 2 +- apps/menus/settings_menu.c | 6 +++--- apps/playback.c | 5 ++++- apps/settings.c | 3 +++ apps/settings.h | 2 +- apps/settings_list.c | 2 +- firmware/export/pcm_mixer.h | 2 +- firmware/export/usb.h | 9 ++++++++- uisimulator/common/stubs.c | 12 ++++++++++++ 10 files changed, 35 insertions(+), 10 deletions(-) diff --git a/apps/features.txt b/apps/features.txt index 2d3ad26a73..5453ec86bc 100644 --- a/apps/features.txt +++ b/apps/features.txt @@ -313,7 +313,7 @@ codec_aac_he lto #endif -#if defined(USB_ENABLE_AUDIO) +#if defined(USB_ENABLE_AUDIO) || defined(HAVE_HOST_USB_AUDIO) usbdac #endif diff --git a/apps/gui/wps.c b/apps/gui/wps.c index add47d08db..dec58008b8 100644 --- a/apps/gui/wps.c +++ b/apps/gui/wps.c @@ -696,7 +696,7 @@ static inline int action_wpsab_single(long button) long gui_wps_show(void) { /* NOTE: if USBAudio ever gets its own DSP channel, this block can go away! */ -#ifdef USB_ENABLE_AUDIO +#if defined(USB_ENABLE_AUDIO) || defined(HAVE_HOST_USB_AUDIO) if (usb_audio_get_active()) { splash(HZ*2, ID2P(LANG_USB_DAC_ACTIVE)); diff --git a/apps/menus/settings_menu.c b/apps/menus/settings_menu.c index 9b017dc2f9..1879ada8fe 100644 --- a/apps/menus/settings_menu.c +++ b/apps/menus/settings_menu.c @@ -368,7 +368,7 @@ MENUITEM_SETTING(lineout_onoff, &global_settings.lineout_active, NULL); MENUITEM_SETTING(usb_hid, &global_settings.usb_hid, NULL); MENUITEM_SETTING(usb_keypad_mode, &global_settings.usb_keypad_mode, NULL); #endif -#ifdef USB_ENABLE_AUDIO +#if defined(USB_ENABLE_AUDIO) || defined(HAVE_HOST_USB_AUDIO) MENUITEM_SETTING(usb_audio, &global_settings.usb_audio, NULL); #endif #if defined(USB_ENABLE_STORAGE) && defined(HAVE_MULTIDRIVE) @@ -421,7 +421,7 @@ MAKE_MENU(usb_menu, ID2P(LANG_USB_MENU), 0, Icon_NOICON, &usb_hid, &usb_keypad_mode, #endif -#ifdef USB_ENABLE_AUDIO +#if defined(USB_ENABLE_AUDIO) || defined(HAVE_HOST_USB_AUDIO) &usb_audio, #endif #if defined(USB_ENABLE_STORAGE) && defined(HAVE_MULTIDRIVE) @@ -480,7 +480,7 @@ MAKE_MENU(system_menu, ID2P(LANG_SYSTEM), &sel_softlock, #endif #if defined(USB_ENABLE_HID) || \ - defined(USB_ENABLE_AUDIO) || \ + defined(USB_ENABLE_AUDIO) || defined(HAVE_HOST_USB_AUDIO) || \ (defined(USB_ENABLE_STORAGE) && defined(HAVE_MULTIDRIVE)) || \ defined(HAVE_USB_MODE) &usb_menu, diff --git a/apps/playback.c b/apps/playback.c index 6e4e7b2dc3..ccb9aa1c8c 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -66,8 +66,11 @@ #include /* For strncasecmp() */ #endif +#if defined(USB_ENABLE_AUDIO) || defined(HAVE_HOST_USB_AUDIO) #ifdef USB_ENABLE_AUDIO #include "usbstack/usb_audio.h" +#endif +#include "usb.h" #include "splash.h" #include "lang.h" #endif @@ -2993,7 +2996,7 @@ static void audio_start_playback(const struct audio_resume_info *resume_info, * a splash message to the user. * NOTE: if USBAudio ever gets its own DSP channel, this block can go away! */ -#ifdef USB_ENABLE_AUDIO +#if defined(USB_ENABLE_AUDIO) || defined(HAVE_HOST_USB_AUDIO) if (usb_audio_get_active()) { queue_reply(&audio_queue, 0); diff --git a/apps/settings.c b/apps/settings.c index afe62299e3..0423eebd29 100644 --- a/apps/settings.c +++ b/apps/settings.c @@ -1128,6 +1128,9 @@ void settings_apply(bool read_disk) #if !defined(SIMULATOR) && !defined(USB_NONE) && (defined(HAVE_USB_ADB) || defined(HAVE_USB_POWER)) usb_set_mode(global_settings.usb_mode); #endif +#if defined(USB_ENABLE_AUDIO) || defined(HAVE_HOST_USB_AUDIO) + usb_set_audio(global_settings.usb_audio); +#endif #if defined(HAVE_GENERAL_PURPOSE_LED) led_hw_on(); #endif diff --git a/apps/settings.h b/apps/settings.h index 178817f280..a2ce824a5e 100644 --- a/apps/settings.h +++ b/apps/settings.h @@ -814,7 +814,7 @@ struct user_settings int usb_keypad_mode; #endif -#ifdef USB_ENABLE_AUDIO +#if defined(USB_ENABLE_AUDIO) || defined(HAVE_HOST_USB_AUDIO) int usb_audio; #endif diff --git a/apps/settings_list.c b/apps/settings_list.c index 1f24a8e0af..0887e0527a 100644 --- a/apps/settings_list.c +++ b/apps/settings_list.c @@ -2310,7 +2310,7 @@ const struct settings_list settings[] = { ), /* CHOICE_SETTING( usb_keypad_mode ) */ #endif -#ifdef USB_ENABLE_AUDIO +#if defined(USB_ENABLE_AUDIO) || defined(HAVE_HOST_USB_AUDIO) CHOICE_SETTING(0, usb_audio, LANG_USB_DAC, 0, "usb-dac", "never,always,while_charge_only,while_mass_storage", usb_set_audio, 4, ID2P(LANG_NEVER), ID2P(LANG_ALWAYS), ID2P(LANG_WHILE_USB_CHARGE_ONLY), ID2P(LANG_WHILE_MASS_STORAGE_USB_ONLY)), #endif diff --git a/firmware/export/pcm_mixer.h b/firmware/export/pcm_mixer.h index a003100285..bbc2c2c9cd 100644 --- a/firmware/export/pcm_mixer.h +++ b/firmware/export/pcm_mixer.h @@ -71,7 +71,7 @@ enum pcm_mixer_channel { PCM_MIXER_CHAN_PLAYBACK = 0, -#ifdef USB_ENABLE_AUDIO +#if defined(USB_ENABLE_AUDIO) || defined(HAVE_HOST_USB_AUDIO) PCM_MIXER_CHAN_USBAUDIO, #endif PCM_MIXER_CHAN_VOICE, diff --git a/firmware/export/usb.h b/firmware/export/usb.h index a324b1174c..aa1e25c93b 100644 --- a/firmware/export/usb.h +++ b/firmware/export/usb.h @@ -272,8 +272,15 @@ void usb_firewire_connect_event(void); void usb_set_hid(bool enable); #endif -#ifdef USB_ENABLE_AUDIO +#if defined(USB_ENABLE_AUDIO) || defined(HAVE_HOST_USB_AUDIO) +/* Select when the USB Audio (DAC) function is active. Values follow the + * usb_audio setting: 0 never, 1 always, 2 while charge-only, 3 while + * mass-storage. Native targets use the usbstack driver; hosted targets + * (HiBy) drive their configfs gadget. */ void usb_set_audio(int value); + +/* true while host-PCM (USB-DAC) playback is active */ +bool usb_audio_get_active(void); #endif #if defined(USB_ENABLE_STORAGE) && defined(HAVE_MULTIDRIVE) diff --git a/uisimulator/common/stubs.c b/uisimulator/common/stubs.c index 9f9dc0d4e0..1823461709 100644 --- a/uisimulator/common/stubs.c +++ b/uisimulator/common/stubs.c @@ -202,6 +202,18 @@ bool usb_charging_enable(bool on) } #endif +#if defined(HAVE_HOST_USB_AUDIO) +void usb_set_audio(int value) +{ + (void)value; +} + +bool usb_audio_get_active(void) +{ + return false; +} +#endif + #ifdef HAVE_REMOTE_LCD_TICKING void lcd_remote_emireduce(bool state) {