Considering BASSWASAPI

Started by SoundMike,

SoundMike

I currently use BASS and BASSASIO as well as some of the BASS extras such as BASSMix, BASS FX, etc. I have not included BASSWASAPI but the program successfully handles WASAPI anyway. However, one feature of BASSWASAPI that interests me is the BASS_WASAPI_NOTIFY_DISABLED notification as equivalent notifications do not appear to be supported in BASS or BASSASIO. But to use the 'set notify' to gain access to this would I have to handle all the WASAPI processing via BASSWASAPI? For example, if WASAPI is to be used then should I use BASS_WASAPI_Init() instead of BASS_Init()?

Ian @ un4seen

It is possible to use BASSWASAPI for the device notifications and BASS for playback/recording, ie. you can use BASS_WASAPI_SetNotify without BASS_WASAPI_Init. Note that the BASS and BASSWASAPI device lists are different, so you would need to translate the BASSWASAPI device numbers to BASS device numbers. Here's some code for doing that:

   www.un4seen.com/forum/?topic=19759.msg138285#msg138285


SoundMike

Is there some reason WASAPI devices appear to be duplicated? I think I've got my code right, but when I disconnect my Roland Octa-Capture the WASAPI notify procedure reports info like this:
wasapiNotifyProc: WASAPI device: 22 (Line-Level: 1-2 (OCTA-CAPTURE)), BASS device: 4 (1-2 (OCTA-CAPTURE)), notify: The device has been disabled/disconnected.
wasapiNotifyProc: WASAPI device: 23 (Line-Level: 1-2 (OCTA-CAPTURE)), BASS device: 4 (1-2 (OCTA-CAPTURE)), notify: The device has been disabled/disconnected.

What's the reason for WASAPI devices 22 and 23 appearing to be the same? This also applies to all the other channels. Is 22 for channel 1 and 23 for channel 2?

Ian @ un4seen

What are the flags of each of those devices? You will see output devices duplicated in the list (at n and n+1), with the 2nd device having the BASS_DEVICE_LOOPBACK flag set to indicate that it's for "loopback" recording of the 1st device's output.

SoundMike

This is what I get when I include the flags:
wasapiNotifyProc: WASAPI device: 22 (Line-Level:1-2 (OCTA-CAPTURE), flags=BASS_DEVICE_DEFAULT), BASS device: 4 (1-2 (OCTA-CAPTURE)), notify: The device has been disabled/disconnected.
wasapiNotifyProc: WASAPI device: 23 (Line-Level:1-2 (OCTA-CAPTURE), flags=BASS_DEVICE_INPUT|BASS_DEVICE_LOOPBACK), BASS device: 4 (1-2 (OCTA-CAPTURE)), notify: The device has been disabled/disconnected.

I guess this is because the Octa-Capture does have both inputs and outputs, so presumably device 22 is the output device for the Octa-Capture's channels 1-2, and device 23 is for the corresponding input pair.

Ian @ un4seen

Yes, despite having "CAPTURE" in its name, that device appears to be an output/playback device (plus a loopback device).

SoundMike

Since this feature is not available with BASSASIO, if a user is using ASIO then is there some way I can identify a WASAPI device that is for the same physical device as a BASSASIO device? Sometimes the names contain the same words but from the equipment I've tested (primarily the Octa-Capture and an A&H Qu-16) there's no reliable way I can see to identify an ASIO device's corresponding WASAPI device.

Ian @ un4seen

No, unfortunately it isn't possible to reliably map WASAPI devices to ASIO devices, as ASIO is an entirely separate driver system. ASIO also doesn't have its own notification system. Trying to initialize an ASIO device/driver is really the only way to check if it's available.

elan

On the topic of duplicated entries, here's what I see with a USB AudioQuest device plugged in:

WASAPI Device 1: Speakers (AudioQuest DragonFly Red v1.0) - enabled input loopback speakers headphones digital ({0.0.0.00000000}.{373f5a70-22fc-4f67-9525-0d62b87035fb})
WASAPI Device 2: Speakers (High Definition Audio Device) - enabled default speakers headphones digital ({0.0.0.00000000}.{79e76ee7-1cd9-4eb0-863a-1a628347476b})
WASAPI Device 3: Speakers (High Definition Audio Device) - enabled input loopback speakers headphones digital ({0.0.0.00000000}.{79e76ee7-1cd9-4eb0-863a-1a628347476b})
WASAPI Device 4: Microphone (High Definition Audio Device) - enabled default input digital ({0.0.1.00000000}.{1d8c3817-96e0-4032-bd12-66613197914a})


The default device is duplicated (one with loopback + input), and the DragonFly only has a single entry with input, loopback, and speakers.

I'm not entirely sure how to process this into a sane list; I can skip the duplicate, but how do I know Device 1 is actually a real output device?

elan

In addition, I can't seem to play to the DragonFly device:

  // Initialize device.
  if (!BASS_WASAPI_Init(device, 0, 0, BASS_WASAPI_AUTOFORMAT | BASS_WASAPI_ASYNC | BASS_WASAPI_EXCLUSIVE | BASS_WASAPI_RAW | BASS_WASAPI_CATEGORY_MEDIA, 0.1f, 0.05f, WasapiProc, this))
  {
    eprintf("BASS: Error initializing WASAPI device %d with sample rate %d in exclusive mode: %d", device, bestSampleRate, BASS_ErrorGetCode());
    if (!BASS_WASAPI_Init(device, 0, 0, BASS_WASAPI_AUTOFORMAT | BASS_WASAPI_RAW | BASS_WASAPI_CATEGORY_MEDIA, 0.1f, 0.05f, WasapiProc, this))
    {
      eprintf("BASS: Error initializing WASAPI device %d with sample rate %d in shared mode: %d", device, bestSampleRate, BASS_ErrorGetCode());
      return false;
    }
  }

BASS: Error initializing WASAPI device 1 with sample rate 44100 in exclusive mode: 37
BASS: Error initializing WASAPI device 1 with sample rate 44100 in shared mode: -1

The other device (ID: 2) works great.

Curiously, in the Volume Mixer app in Windows 11. the AudioQuest DragonFly doesn't show up as an input device at all.

In BASS-land, things look more sane:

BASS: Device 1: Default - enabled default handset hdmi headset line speakers
BASS: Device 2: Speakers (AudioQuest DragonFly Red v1.0) - enabled default handset hdmi headset line speakers
BASS: Device 3: Speakers (High Definition Audio Device) - enabled handset hdmi headset line speakers


However, if I attempt to play to that device, I get a very similar errors:

BASS: Error initializing device 2 with sample rate 44100 and flags 00000000 (-1).

I've tested Foobar 2000 and the device works as expected (assuming it uses WASAPI as well but not sure)

(And forgive me for hjacking this thread, happy to open a new one if you'd like.)

Ian @ un4seen

Quote from: elanOn the topic of duplicated entries, here's what I see with a USB AudioQuest device plugged in:

WASAPI Device 1: Speakers (AudioQuest DragonFly Red v1.0) - enabled input loopback speakers headphones digital ({0.0.0.00000000}.{373f5a70-22fc-4f67-9525-0d62b87035fb})
WASAPI Device 2: Speakers (High Definition Audio Device) - enabled default speakers headphones digital ({0.0.0.00000000}.{79e76ee7-1cd9-4eb0-863a-1a628347476b})
WASAPI Device 3: Speakers (High Definition Audio Device) - enabled input loopback speakers headphones digital ({0.0.0.00000000}.{79e76ee7-1cd9-4eb0-863a-1a628347476b})
WASAPI Device 4: Microphone (High Definition Audio Device) - enabled default input digital ({0.0.1.00000000}.{1d8c3817-96e0-4032-bd12-66613197914a})


The default device is duplicated (one with loopback + input), and the DragonFly only has a single entry with input, loopback, and speakers.

I'm not entirely sure how to process this into a sane list; I can skip the duplicate, but how do I know Device 1 is actually a real output device?

BASSWASAPI doesn't have a "No Sound" device (like BASS does), so the real devices start at #0. You should find a non-loopback entry for the "Speakers (AudioQuest DragonFly Red v1.0)" device in that slot.

Quote from: elanIn addition, I can't seem to play to the DragonFly device:

  // Initialize device.
  if (!BASS_WASAPI_Init(device, 0, 0, BASS_WASAPI_AUTOFORMAT | BASS_WASAPI_ASYNC | BASS_WASAPI_EXCLUSIVE | BASS_WASAPI_RAW | BASS_WASAPI_CATEGORY_MEDIA, 0.1f, 0.05f, WasapiProc, this))
  {
    eprintf("BASS: Error initializing WASAPI device %d with sample rate %d in exclusive mode: %d", device, bestSampleRate, BASS_ErrorGetCode());
    if (!BASS_WASAPI_Init(device, 0, 0, BASS_WASAPI_AUTOFORMAT | BASS_WASAPI_RAW | BASS_WASAPI_CATEGORY_MEDIA, 0.1f, 0.05f, WasapiProc, this))
    {
      eprintf("BASS: Error initializing WASAPI device %d with sample rate %d in shared mode: %d", device, bestSampleRate, BASS_ErrorGetCode());
      return false;
    }
  }

BASS: Error initializing WASAPI device 1 with sample rate 44100 in exclusive mode: 37
BASS: Error initializing WASAPI device 1 with sample rate 44100 in shared mode: -1


The BASS_ERROR_NOTAVAIL (37) error will be because the BASS_WASAPI_EXCLUSIVE option isn't available on loopback devices.

The BASS_ERROR_UNKNOWN (-1) error is less obvious. Does it still happen with flags=0? One possible cause of BASS_ERROR_UNKNOWN is that BASS_WASAPI_Init is unable to get the device's sample format. Can you see/set the device's format in Window's Sound control panel?

Quote from: elanIn BASS-land, things look more sane:

BASS: Device 1: Default - enabled default handset hdmi headset line speakers
BASS: Device 2: Speakers (AudioQuest DragonFly Red v1.0) - enabled default handset hdmi headset line speakers
BASS: Device 3: Speakers (High Definition Audio Device) - enabled handset hdmi headset line speakers


However, if I attempt to play to that device, I get a very similar errors:

BASS: Error initializing device 2 with sample rate 44100 and flags 00000000 (-1).

Please try using the BASS_DEVICE_DSOUND flag in the BASS_Init call to see if that makes any difference.

elan

(Forgot to give system details: Windows ARM64 under VMware Fusion on macOS)

OK, got the devices sorted out properly starting at index 0, that let me select the correct device; I can play in exclusive (and shared) mode to both devices now.

For one of the devices (external USB), for some reason at some point after seconds to minutes, the WASAPI callback stops being called. I don't see WasapiNotifyProc being called with any notification, there's no obvious indication of why it would stop being called (flags are: BASS_WASAPI_ASYNC | BASS_WASAPI_RAW | BASS_WASAPI_CATEGORY_MEDIA | BASS_WASAPI_EXCLUSIVE).

In addition, in shared mode, I'm having a bit of trouble figuring out the resampling when sample rates don't match. The documentation says "WASAPI can resample when required in shared mode (if the BASS_WASAPI_AUTOFORMAT flag is not specified)" but what I think I'm seeing is that when the mixer sample rate differs from the device sample rate, there's no resampling happening.

Lastly, I still see the -1 error sporadically when calling BASS_WASAPI_Init. It's a bit weird, I get the -1, retry and get error 3 (one or more times) and then finally the device opens successfully.

Thanks as always for the help!

Ian @ un4seen

Quote from: elanFor one of the devices (external USB), for some reason at some point after seconds to minutes, the WASAPI callback stops being called. I don't see WasapiNotifyProc being called with any notification, there's no obvious indication of why it would stop being called (flags are: BASS_WASAPI_ASYNC | BASS_WASAPI_RAW | BASS_WASAPI_CATEGORY_MEDIA | BASS_WASAPI_EXCLUSIVE).

Sounds like that may need a debug version to get more info. To perhaps narrow it down a bit first, does changing the flags make any difference, eg. does it still happen with flags=0? And does BASS_WASAPI_IsStarted still return TRUE when the callbacks stop?

Quote from: elanIn addition, in shared mode, I'm having a bit of trouble figuring out the resampling when sample rates don't match. The documentation says "WASAPI can resample when required in shared mode (if the BASS_WASAPI_AUTOFORMAT flag is not specified)" but what I think I'm seeing is that when the mixer sample rate differs from the device sample rate, there's no resampling happening.

You can tell when WASAPI is resampling by comparing the values from BASS_WASAPI_GetInfo and BASS_WASAPI_GetDeviceInfo, eg. does BASS_WASAPI_INFO:freq (your rate) = BASS_WASAPI_DEVICEINFO:mixfreq (device's rate).

Quote from: elanLastly, I still see the -1 error sporadically when calling BASS_WASAPI_Init. It's a bit weird, I get the -1, retry and get error 3 (one or more times) and then finally the device opens successfully.

Is this only happening with the same external USB device as above, or other devices too? Do BASS_WASAPI_CheckFormat or BASS_WASAPI_GetDeviceLevel calls on the device also result in the same errors?

elan

#14
Quote from: Ian @ un4seenSounds like that may need a debug version to get more info. To perhaps narrow it down a bit first, does changing the flags make any difference, eg. does it still happen with flags=0? And does BASS_WASAPI_IsStarted still return TRUE when the callbacks stop?

So in terms of the Mysterious Disappearing Callback:

  • BASS_WASAPI_IsStarted keeps returning TRUE when the callbacks stop.
  • Using flags=0 (only exclusive) doesn't prevent the issue from happening.
  • Also happens in shared mode.

Quote from: Ian @ un4seenYou can tell when WASAPI is resampling by comparing the values from BASS_WASAPI_GetInfo and BASS_WASAPI_GetDeviceInfo, eg. does BASS_WASAPI_INFO:freq (your rate) = BASS_WASAPI_DEVICEINFO:mixfreq (device's rate).

OK, thanks, that clarifies nicely!

Quote from: Ian @ un4seenIs this only happening with the same external USB device as above, or other devices too? Do
BASS_WASAPI_CheckFormat or BASS_WASAPI_GetDeviceLevel calls on the device also result in the same errors?

It seems to be more prevalent on the external device, although I think I've seen it on the other one as well (I tried today to reproduce and could only reproduce on the external one).

Right before calling BASS_WASAPI_Init and getting back -1, BASS_WASAPI_GetDeviceLevel returns 0.0, and BASS_WASAPI_CheckFormat with the sample rate/channels I'm about to use returns 3 (24-bits).

[Edit: I've also see the exact same error sequence on the regular BASS audio driver, external device]

Happy to run a debug build to extract more information.

elan

I have found a tester on real hardware Windows/ARM64 and so far it doesn't sound like he's hit these issues in some quick testing.

I'm happy to do more debugging if you feel like it (e.g. maybe some sort of timing issue/race on VM) but otherwise I'll keep you posted if I see it on real hardware.

Ian @ un4seen

Quote from: elanSo in terms of the Mysterious Disappearing Callback:

  • BASS_WASAPI_IsStarted keeps returning TRUE when the callbacks stop.
  • Using flags=0 (only exclusive) doesn't prevent the issue from happening.
  • Also happens in shared mode.

I'll send you a debug BASSWASAPI version to get more info.