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

Add API to set default audio output device #7

Open
ThiefMaster opened this issue Jan 31, 2021 · 4 comments
Open

Add API to set default audio output device #7

ThiefMaster opened this issue Jan 31, 2021 · 4 comments

Comments

@ThiefMaster
Copy link
Contributor

ThiefMaster commented Jan 31, 2021

There is an undocumented COM API called IPolicyConfig which allows to do nice things like changing the default audio device used by Windows. An example tool (which works fine) can be found e.g. here: https://github.com/DanStevens/AudioEndPointController/tree/master/EndPointController

Is there any chance you could add those APIs to this library as well?

@ThiefMaster
Copy link
Contributor Author

This works fine for me - just leaving it here in case someone else wants to use it :)

package main

import (
	"syscall"
	"unsafe"

	"github.com/go-ole/go-ole"
	"github.com/moutend/go-wca/pkg/wca"
)

type IPolicyConfigVista struct {
	ole.IUnknown
}

type IPolicyConfigVistaVtbl struct {
	ole.IUnknownVtbl
	GetMixFormat          uintptr
	GetDeviceFormat       uintptr
	SetDeviceFormat       uintptr
	GetProcessingPeriod   uintptr
	SetProcessingPeriod   uintptr
	GetShareMode          uintptr
	SetShareMode          uintptr
	GetPropertyValue      uintptr
	SetPropertyValue      uintptr
	SetDefaultEndpoint    uintptr
	SetEndpointVisibility uintptr
}

func (v *IPolicyConfigVista) VTable() *IPolicyConfigVistaVtbl {
	return (*IPolicyConfigVistaVtbl)(unsafe.Pointer(v.RawVTable))
}

func (v *IPolicyConfigVista) SetDefaultEndpoint(deviceID string, eRole wca.ERole) (err error) {
	err = pcvSetDefaultEndpoint(v, deviceID, eRole)
	return
}

func pcvSetDefaultEndpoint(pcv *IPolicyConfigVista, deviceID string, eRole wca.ERole) (err error) {
	var ptr *uint16
	if ptr, err = syscall.UTF16PtrFromString(deviceID); err != nil {
		return
	}
	hr, _, _ := syscall.Syscall(
		pcv.VTable().SetDefaultEndpoint,
		3,
		uintptr(unsafe.Pointer(pcv)),
		uintptr(unsafe.Pointer(ptr)),
		uintptr(uint32(eRole)))
	if hr != 0 {
		err = ole.NewError(hr)
	}
	return
}

@Silenc3IsGold3n
Copy link

Thanks, just implemented this and its working on my end as well

@syllith
Copy link

syllith commented Mar 7, 2023

Can you please use this in a complete example? I'm having a hard time understanding how to use this. Thank you

@gluek
Copy link

gluek commented Nov 16, 2023

@syllith if it still helps here is an example which works for me in combination with the code provided by ThiefMaster.

func SetAudioDeviceByID(deviceID string) {
	GUID_IPolicyConfigVista := ole.NewGUID("{568b9108-44bf-40b4-9006-86afe5b5a620}")
	GUID_CPolicyConfigVistaClient := ole.NewGUID("{294935CE-F637-4E7C-A41B-AB255460B862}")
	var policyConfig *IPolicyConfigVista

	if err = ole.CoInitializeEx(0, ole.COINIT_APARTMENTTHREADED); err != nil {
		panic(err)
	}
	defer ole.CoUninitialize()

	if err = wca.CoCreateInstance(GUID_CPolicyConfigVistaClient, 0, wca.CLSCTX_ALL, GUID_IPolicyConfigVista, &policyConfig); err != nil {
		panic(err)
	}
	defer policyConfig.Release()

	if err = policyConfig.SetDefaultEndpoint(deviceID, wca.EConsole); err != nil {
		panic(err)
	}
}

diegosz added a commit to diegosz/go-wca that referenced this issue Sep 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants