Programmatically switch audio devices on Windows 7 - winapi

On my Windows 7 PC, I've got a set of speakers, some wireless headphones and a USB web cam. This means that I have two possible audio output devices and 2 possible audio input devices.
I find myself having to switch between them fairly frequently. At the moment this is a manual process: right-click on the speaker icon, choose one of "Playback devices" or "Recording devices", choose the correct device in the list (and there's some "dead" ones in there, too) and then hit "Set Default".
I've looked around, and all I can find are people scripting SendKeys to automate this.
That sucks.
Is there anyway to programmatically switch audio input/output devices, so that I can write a simple tray app/hotkey app to make this easier?

Allegedly undocumented COM-interface IPolicyConfig (kudos to #author EreTIk) allows to do that.
This is a sample implementation.
HRESULT SetDefaultAudioPlaybackDevice(LPCWSTR devID)
{
IPolicyConfigVista *pPolicyConfig;
ERole reserved = eConsole;
HRESULT hr = CoCreateInstance(
__uuidof(CPolicyConfigVistaClient),
NULL,
CLSCTX_ALL,
__uuidof(IPolicyConfigVista),
(LPVOID *)&pPolicyConfig);
if (SUCCEEDED(hr))
{
hr = pPolicyConfig->SetDefaultEndpoint(devID, reserved);
pPolicyConfig->Release();
}
return hr;
}
A string of Device ID needs to be passed to this function. An example of a device id
{0.0.1.00000000}.{d915c7bb-d5d7-4c92-80d9-1a0ee5d954f1}
This device id can be obtained through audio device enumeration.

If you are looking into changing default devices programmatically, then this is impossible by design.
Programatically setting the default playback device (and recording device)
How to change default sound playback device programatically?

Related

How to ignore changing audio-output from System Preference? (macOS)

I made my app can select audio-output. (like 'system default' or 'user's DAC')
but when user choose a output from system preferences panel - sound, my app's output follows the output user seleced.
I searched a lot and add some listener so I can change immediatly my app's output to previously user selected if system output has been changed.
BUT it makes very anonying few milliseconds swiching delay.
I guess it is because I switch my app's output after it's already changed to system default.
So I wonder If I can know BEFORE system default output's changing.
(Like viewWillAppear api from cocoa)
Thank you.
listener that I used for knowing chaninging of system default audio out is from the article below.
How to get notification if System Preferences Default Sound changed
thanks
more details
I used AudioUnitSetProperty(audioOut, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Output, 0, &deviceID, (UInt32)sizeof(deviceID)) for selecting output device. apple document
and add this listener
func addListenerBlock(listenerBlock: #escaping AudioObjectPropertyListenerBlock, onAudioObjectID: AudioObjectID, forPropertyAddress: inout AudioObjectPropertyAddress) {
if (kAudioHardwareNoError != AudioObjectAddPropertyListenerBlock(onAudioObjectID, &forPropertyAddress, nil, listenerBlock)) {
LOG("Error calling: AudioObjectAddPropertyListenerBlock") }
}
func add() {
var propertyAddress = AudioObjectPropertyAddress(mSelector: kAudioHardwarePropertyDefaultOutputDevice,
mScope: kAudioObjectPropertyScopeGlobal,
mElement: kAudioObjectPropertyElementMaster)
self.addListenerBlock(listenerBlock: audioObjectPropertyListenerBlock,
onAudioObjectID: AudioObjectID(bitPattern: kAudioObjectSystemObject),
forPropertyAddress: &propertyAddress)
}
kAudioUnitSubType_DefaultOutput tracks the current output device selected by the user in the Sound Preferences. To play to a specific device use kAudioUnitSubType_HALOutput. The comments in AUComponent.h are helpful:
#enum Apple input/output audio unit sub types (OS X)
#constant kAudioUnitSubType_HALOutput
- desktop only
The audio unit that interfaces to any audio device. The user specifies which
audio device to track. The audio unit can do input from the device as well as
output to the device. Bus 0 is used for the output side, bus 1 is used
to get audio input from the device.
#constant kAudioUnitSubType_DefaultOutput
- desktop only
A specialisation of AUHAL that is used to track the user's selection of the
default device as set in the Sound Prefs
#constant kAudioUnitSubType_SystemOutput
- desktop only
A specialisation of AUHAL that is used to track the user's selection of the
device to use for sound effects, alerts
and other UI sounds.
You didn't specify how you're setting up your output (AUGraph?) so the way to use kAudioUnitSubType_HALOutput varies.

How to stop Explorer starting my application maximized?

Explorer seems to always start my application with SW_MAXIMIZE (STARTF_USESHOWWINDOW is set in STARTUPINFO.dwFlags). I know that ShowWindow will use this value the first time you/Windows needs to display a window but it has the unfortunate consequence of maximizing a window that should never be maximized.
My window is created with CreateDialogIndirectParam and has the following styles: WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_CLIPCHILDREN|DS_MODALFRAME|DS_CENTER|WS_VISIBLE. Why does ShowWindow not check if WS_MAXIMIZEBOX is set before allowing STARTF_USESHOWWINDOW to force SW_MAXIMIZE? Is this a bug in Windows?
This happens on a HP Stream 7 with Windows 8.1. I'm not sure if Explorer does this because it is touch enabled or because of the small screen.
Is this Explorer behavior documented anywhere and is there a way to turn it off? What is the best way to stop Explorer (or any other parent process) from affecting my initial window mode? (I don't want to block people starting me with SW_*MINIMIZE*)
WinVer.exe in system32 has the same problem:
My first thought was to turn off STARTF_USESHOWWINDOW in the PEB if the parent wanted me to start maximized but that is too nasty and undocumented so I have not tried that yet.
Preventing any kind of size change (which is OK for my application since it is just a "modal" dialog) sort of works:
case WM_WINDOWPOSCHANGING:
((WINDOWPOS*)lp)->flags |= SWP_NOSIZE;
return true;
The problem is that the window position is still set to 0 x 0 like a maximized window.
A better solution seems to be to detect and correct the problem after WM_INITDIALOG:
case WM_INITDIALOG:
PostMessage(hDlg, WM_APP, 0, 0);
break;
case WM_APP:
if (IsZoomed(hDlg)) ShowWindow(hDlg, SW_SHOWNOACTIVATE);
break;
I am the proud owner of several HP Stream 7 tablets and I would like to add my 2 cents here. Microsoft has made an arbitrary decision that devices with screen sizes smaller than 8 inches will behave differently than the norm. A lot of users are somewhat aware of this, but unaware that this is where your problem originates.
Windows determines a screen's size by reading the EDID information from the screen, which contains sizing information in it, in centimeters.
If no sizing information is present in the EDID, or the sizing information is below Microsoft's arbitrarily chosen 8 inch threshold, you get this apparent misbehavior which is at the very least, aggrivating to those who notice it and don't want it.
The solution is to override the default driver for the monitor in Device Manager with one that informs Windows that the screen is in fact, 8 inches or larger.
To do so, you need to first read the EDID information from the registry with a tool such as Deltacast's E-EDID Editor (free, last time I checked), and modify the size values and save the modified file someplace you can find it.
After you have modified your EDID file and saved it, download Monitor Asset Manager from EnTech (also free) and use it to create an INF file.
Once the INF file has been created, you need to restart Windows with the Advanced settings menu and choose to Disable Driver Signing Enforcement, since the INF file you created won't be digitally signed. Once disabled, open Device Manager in Windows and update the driver for the monitor using the INF file you created. You will need to confirm that you do in fact want to install the unsigned driver file.
Reboot and Windows will now behave normally with the one catch that, the onscreen keyboard will now appear a different size and will have more options available.
Sadly, Microsoft can change this behavior in the future, so there is no guarantee that through the same flawed decision making process they used to implement this in the first place, they won't force it down our throats again, using a much more difficult to counteract method.

Change the output device for AVAudioPlayer on OSX

I need to play audio from AVAudioPlayer to a particular audio device such as a USB headset. By default the audio will get played out to the system default device setting. With QTKit, I was able to use SetMovieAudioContext() to do such a task but do not see equivalent in AVFoundation. How is it possible to change this on OSX?
Use NSSound instead:
Get list of audio devices with CoreAudio functions. Then get the devices' unique identifiers:
//...
address.mSelector = kAudioDevicePropertyDeviceUID;
CFStringRef uid = NULL;
UInt32 size = sizeof(uid);
AudioObjectGetPropertyData(deviceId, &address, 0, NULL, &size, &uid);
//...
Initialize sound item, set playbackDeviceIdentifier property value.
Opened a DTS case with Apple and they said it was not possible (as i need to support 10.8). If you only need to support 10.9 and above AVPlayerAudioDeviceSupport should work.

How to turn Windows system network icon on/off programmatically

I want to turn the system network icon on/off in my application likes what we can do via control panel. I know the "HideSCANetwork" registry item, but to use this solution I need to restart the explorer after changing the setting. Is there any other solution which can do this seamlessly like the system?
There is no official API for doing thois. The reason for this is that Microsoft wanted to give the user the ability to keep their notification area from becoming too full. The problem being too many applications starting notification icons that the user doesn't care for.
Since many users don't know how to get rid of these icons, Microsoft decided to help by hiding them by default. If applications had access to these hide/show settings then applications would simply show the notifications by default and we'd be back where we started. So there is no mechanism provided for modifying these settings programmatically.
You want to do something different that sounds equally malicious, namely to hide an important system icon. If you are determined to do this then you can reverse engineer how the setting is stored (likely in the registry) and change the setting that way. However, you'll be going against the system design should you do so.
Now I find a imperfect solution. The basic idea comes from here:
http://www.codeproject.com/Articles/10807/Shell-Tray-Info-Arrange-your-system-tray-icons
Some tips:
This solution supports Win 7, you can remove XP checking code.
On wow64, you need to change the struct TRAYDATA and use TBUTTON64:
struct TRAYDATA
{
DWORD64 hwnd;
UINT uID;
UINT uCallbackMessage;
DWORD Reserved[2];
DWORD64 hIcon;
};
typedef struct _TBBUTTON64
{
int iBitmap;
int idCommand;
BYTE fsState;
BYTE fsStyle;
BYTE bReserved[6];
DWORD64 dwData;
DWORD64 iString;
} TBBUTTON64, NEAR* PTBBUTTON64, *LPTBBUTTON64;
typedef const TBBUTTON64 *LPCTBBUTTON64;
When you find the icon you want to hide(By using the tip text plus the owner process), send a TB_HIDEBUTTON message to the notification area window.
The imperfect part is that the tray icon will be hidden, but the notification area will not resize. So there is a blank area on the notification area.

How to detect when an Audio Device is disconnected in CoreAudio?

Is there a way to set up a listener for any Audio Device to detect if it's been removed or unplugged? I found this post which helps if you only care about built-in audio related devices:
How to get notifications when the headphones are plugged in/out? Mac
But I'm looking for a more universal solution (i.e. all devices, USB, HDMI, etc.). And it's OSX specific.
Any ideas on how to do this?
I figured it out! One just needs to add a listener to the appropriate AudioDeviceID (the device you wish to monitor):
// add listener for detecting when a device is removed
const AudioObjectPropertyAddress alive_address =
{
kAudioDevicePropertyDeviceIsAlive,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
AudioObjectAddPropertyListener(current_device_id_, &alive_address, deviceIsAliveCallback, &player_);
And then write the corresponding callback:
OSStatus deviceIsAliveCallback(AudioObjectID inObjectID,
UInt32 inNumberAddresses,
const AudioObjectPropertyAddress inAddresses[],
void* inClientData)
{
// your code here
}
Hope this helps someone!

Resources