g3n/engine

OpenAL device enumeration will only return the first device

notnot opened this issue · 1 comments

I'm getting ready to do some OpenAL based work and found this Go binding for it. My first experiment was to implement device enumeration. It turns out that with the current code, only the first device name is found, if there is more than a single device available.
It turns out that al.CtxGetString(dev, al.AllDevicesSpecifier)
goes wrong because the string that the C library returns in this case can't be parsed well by C.GoString(), because the string can actually return multiple null terminated strings, and ends with an extra null to indicate the end of the list of names. I have come up with this function that avoids this problem:

// CtxDeviceNames returns the names of all available audio devices.
func CtxGetDeviceNames() ([]string, error) {
	ddev := &Device{}
	if !CtxIsExtensionPresent(ddev, "ALC_ENUMERATE_ALL_EXT") {
		return nil, fmt.Errorf("no ALC_ENUMERATE_ALL_EXT extension present\n")
	}
	names := []string{}
	cstr := C.alcGetString(nil, C.ALCenum(AllDevicesSpecifier))
	cc := uintptr(unsafe.Pointer(cstr))
        // The returned C string is a list of null terminated device names, plus a 
        // null to indicate the end of the list. C.GoString() will parse only up to 
        // the first null, so use it in a loop to extract all names. 
	for {
		str := C.GoString((*C.char)(unsafe.Pointer(cc)))
		if len(str) == 0 { // found the null value that ends the set of names
			break
		}
		names = append(names, str)
		cc += uintptr(len(str) + 1) // advance pointer to next name
	}
	return names, nil
}

Maybe good to include it to your package?

Hi @notnot! Thanks for idea+snippet and also for your other issue #245
Listing all devices requires the OpenAl extension ALC_ENUMERATE_ALL_EXT which is potentially not supported on some systems, so we will hold off adding this requirement.
This issue will be a good reference in case we decide to implement this in the future.
Thanks again!