Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT] OSS sound support on NetBSD #1527

Closed
nbvins opened this issue Jan 26, 2025 · 6 comments
Closed

[FEAT] OSS sound support on NetBSD #1527

nbvins opened this issue Jan 26, 2025 · 6 comments
Labels
enhancement New feature or request

Comments

@nbvins
Copy link

nbvins commented Jan 26, 2025

Description

The native NetBSD sound subsystem - audio(4) - is based on the SunAudio API derived from OpenSolaris.
However, a compat library providing OSS emulation - ossaudio(3) - is available for commodity on any NetBSD system.

While a native implementation may be preferred in the future[1], the following patch allows building sound_bsd.c on NetBSD. For this to work, fastfetch needs to be linked with -lossaudio. The default sound unit is detected through the command line using audiocfg(1).

--- src/detection/sound/sound_bsd.c.orig	2025-01-13 07:57:52.000000000 +0000
+++ src/detection/sound/sound_bsd.c
@@ -5,13 +5,39 @@
 #include <fcntl.h>
 #include <sys/soundcard.h>
 
+/* Obsolete macros */
+#ifndef SOUND_MIXER_MUTE	// unavailable on some platforms
+#define SOUND_MIXER_MUTE	SOUND_MIXER_NONE
+#define SOUND_MIXER_READ_MUTE	MIXER_READ(SOUND_MIXER_MUTE)
+#endif
+
 const char* ffDetectSound(FFlist* devices)
 {
     char path[] = "/dev/mixer0";
+
+#if defined(__FreeBSD) || defined(__DragonFly__)
     int defaultDev = ffSysctlGetInt("hw.snd.default_unit", -1);
 
     if (defaultDev == -1)
         return "sysctl(hw.snd.default_unit) failed";
+#elif defined(__NetBSD__)
+    const char* const cmd = "audiocfg list | grep [*] | cut -d: -f1";
+    char buf[32];
+    long defaultDev = -1;
+
+    FILE* f = popen(cmd, "r");
+    if (f == NULL)
+        return "popen() failed";
+
+    while (fgets(buf, sizeof buf, f) != NULL) {
+	defaultDev = strtol(buf, NULL, 10);
+        if (defaultDev == -1)
+	    return "audiocfg: failed to get default sound unit";
+
+    if (pclose(f) != 0)
+        return "pclose() failed";
+#endif
+    }
 
     for (int idev = 0; idev <= 9; ++idev)
     { i
@@ -26,7 +52,7 @@ const char* ffDetectSound(FFlist* device
             continue;
 
         uint32_t mutemask = 0;
-        ioctl(fd, SOUND_MIXER_READ_MUTE, &mutemask); // doesn't seem to be available on DragonFly
+        ioctl(fd, SOUND_MIXER_READ_MUTE, &mutemask);
 
         struct oss_card_info ci = { .card = idev };
         if (ioctl(fd, SNDCTL_CARDINFO, &ci) < 0)

[1] TODO; aiomixer(1) sources may represent a good starting point.

Motivation

To avoid an additional dependency on pulseaudio on NetBSD.

Additional context

Using the patch above, on a NetBSD 10.1_STABLE system running on a Thinkpad T460s, I get:

~ $ fastfetch -s sound --format json
[
  {
    "type": "Sound",
    "result": [
      {
        "active": true,
        "main": true,
        "volume": 68,
        "name": "Realtek ALC293 01h",
        "identifier": "/dev/mixer0",
        "platformApi": "OSS"
      },
      {
        "active": true,
        "main": false,
        "volume": 0,
        "name": "Intel HDMI/DP 01h",
        "identifier": "/dev/mixer1",
        "platformApi": "OSS"
      }
    ]
  }
]

If the default sound unit is changed to the onboard intel device:

~ $ audiocfg default 1
setting default audio device to audio1
~ $ audiocfg list
0: [ ] audio0 @ hdafg0: Realtek ALC293
       playback: 2ch, 48000Hz
       record:   2ch, 48000Hz
       (PR) slinear_le 16/16, 2ch, { 32000, 44100, 48000, 88200, 96000, 192000 }
       (PR) slinear_le 20/32, 2ch, { 32000, 44100, 48000, 88200, 96000, 192000 }
       (PR) slinear_le 24/32, 2ch, { 32000, 44100, 48000, 88200, 96000, 192000 }
       (  ) ac3 16/16, 2ch, { 32000, 44100, 48000, 88200, 96000, 192000 }
1: [*] audio1 @ hdafg1: Intel HDMI/DP
       playback: 2ch, 48000Hz
       record:   2ch, 48000Hz
       (P-) slinear_le 16/16, 2ch, { 48000 }
       (P-) slinear_le 16/16, 4ch, { 48000 }
       (P-) slinear_le 16/16, 6ch, { 48000 }
       (P-) slinear_le 16/16, 8ch, { 48000 }
       (PR) slinear_le 16/16, 2ch, 48000-48000Hz

~ $ fastfetch -s sound --format json
[
  {
    "type": "Sound",
    "result": [
      {
        "active": true,
        "main": false,
        "volume": 68,
        "name": "Realtek ALC293 01h",
        "identifier": "/dev/mixer0",
        "platformApi": "OSS"
      },
      {
        "active": true,
        "main": true,
        "volume": 0,
        "name": "Intel HDMI/DP 01h",
        "identifier": "/dev/mixer1",
        "platformApi": "OSS"
      }
    ]
  }
]
@nbvins nbvins added the enhancement New feature or request label Jan 26, 2025
@CarterLi
Copy link
Member

Please test the dev build

@nbvins
Copy link
Author

nbvins commented Jan 26, 2025

Thank you for the extremely quick reply and commit. Using readlink() is indeed better than spawning a subprocess. One thing, the array size for mixerp, as well as the character count returned by readlink should be larger (to store /dev/mixerN), otherwise the call will fail.

--- src/detection/sound/sound_bsd.c.orig	2025-01-26 13:09:45.000000000 +0000
+++ src/detection/sound/sound_bsd.c
@@ -15,10 +15,10 @@ const char* ffDetectSound(FFlist* device
     #else
     int defaultDev;
     {
-        char mixerp[8];
-        if (readlink("/dev/mixer", mixerp, ARRAY_SIZE(mixerp)) != 6)
+        char mixerp[12];
+        if (readlink("/dev/mixer", mixerp, ARRAY_SIZE(mixerp)) != 11)
             return "readlink(/dev/mixer) failed";
-        defaultDev = mixerp[5] - '0';
+        defaultDev = mixerp[10] - '0';
         if (defaultDev < 0 || defaultDev > 9)
             return "Invalid mixer device";
     }

@CarterLi
Copy link
Member

One thing, the array size for mixerp, as well as the character count returned by readlink should be larger (to store /dev/mixerN), otherwise the call will fail.

Strange. As I tested in VM, readlink reported mixer0 instead of /dev/mixer0

@CarterLi
Copy link
Member

Anyway 4e9fecc should work for both cases. Please test it again

@CarterLi
Copy link
Member

BTW, are you vins?

@nbvins
Copy link
Author

nbvins commented Jan 26, 2025

Strange. As I tested in VM, readlink reported mixer0 instead of /dev/mixer0

I think readlink(2) should just store the contents of the symlink's path in the buffer (so it's the full path), while readlinkat() stores the path relative to a directory.

If you do:
printf("'%s' points to '%.*s'\n", "/dev/mixer", (int) plen, mixerp);

it returns: '/dev/mixer' points to '/dev/mixer0'

Anyway 4e9fecc should work for both cases. Please test it again

It works, thank you.

BTW, are you vins?

Yes, I will update the patch to include your changes while updating the package to 2.35.0.
EDIT: done [2]

[2] https://mail-index.netbsd.org/pkgsrc-changes/2025/01/26/msg315346.html

netbsd-srcmastr pushed a commit to NetBSD/pkgsrc that referenced this issue Jan 26, 2025
# pkgsrc changes

* Incorporate upstream patch to enable OSS support on NetBSD.
  Likely to be included in the next formal release. See:
  fastfetch-cli/fastfetch#1527

# upstream changes (since 2.34.0)
Bugfixes:

    * Suppress output of EGL again (#1513, GPU, Linux)
        Regression of 2.34.0

Features:

    * Show SOC name reported in cpuinfo if available (#1510, CPU, Linux)
    * Change package manager name of NetBSD from pkg to pkgsrc (#1515, Packages, NetBSD)
    * Detect SOC name on RISCV (#1519, CPU, Linux)
    * Report marketing name of new QS8Es (CPU, Android)
    * Acquire acquire more os info from lsb-release if missing from os-release (#1521)
    * CMake: add option -DCUSTOM_LSB_RELEASE_PATH to specify the path of lsb-release file
        -DCUSTOM_OS_RELEASE_PATH has been supported since v2.11.4
    * Report more SOC names on Android (CPU, Android)
    * Support duration printing in custom format (Disk / Users)

Logo:

    * Add Arch_old
    * Update key color of NetBSD_small
    * Fix OpenBSD and many other ascii logos (#1522)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants