Introduction

This article shows how we can set Audio Endpoints on the same soundcard. While the example here has been specifically written for the onboard Realtek HD Audio chip ALC883, it gives an easy to adapt framework for CPL Applet manipulation. As such, it can be quickly changed to service any CPL Applet.

Update

The Executable has been updated. It now can be minimized to tray. The trayicon has a rightclick popupmenu to set endpoints. LeftClick on the trayicon restores the window. The endpointlist is updated every 60 seconds. The source is purely written for Codegear.

Background

A large part (and the basic idea) is based on AudioConfigManager. Since the writer goes into detail on the basics of it, I'll just present my adaptation for running it on Vista or Windows 7. Windows 7 has the ability to change Endpoints on the fly, which is a major improvement over Vista, and where this application will be the most useful. Still, with the addition of commandline switches, it can also do service with Vista by adding it to a batch file which starts up your audio application.

Using the Code

Whilst the writer showed how to use the Sound Applet to switch between different soundcards under XP, I made a small adaptation to change Audio Endpoints on the same card using Vista/Windows 7.

The basic principle is really simple; we call up the Applet and feed it the desired keystrokes by sending it messages using SendMessage. However, to be able to find out which Endpoint is currently active, and retrieve a list of Endpoints, it needs some inter-process communication.

I changed the function ChangeAudioDevice as found in the original to reflect this.

int ChangeAudioDevice(void)

becomes:

bool ChangeAudioDevice((int cmdSwitch,int Index)

The first parameter passes an int to use in a switch/case to decide which action to take; Index serves as an index of the chosen Audio Endpoint to set. So now we can direct our function to find the correct Endpoint by name, or by index as presented in the Sound Applet.

So look for the proper string or index, check if the Set Default Button is enabled. If it is, this means the device is not presently active, so feed it a message to press it.

So far it is easy going, but to get here, we need to do a whole lot of work to prepare the SoundApplet for interaction running on Vista. We first need to allocate inter-process memory space with the SoundApplet.

To do this, we need to be sure we have proper access rights to the SoundApplet's memory space.

After this, we do our cleanup, release the memory, and close our handles. This is about the most important change to the original code; the rest of the project contains small changes which are self evident from the source.

Points of Interest

The single most important point of interest I discovered was that the official MSDN docs are written by people with PhDs in writing completely illegible material, surpassing advanced quantum physics in its use of incomprehensible language. Managed/Unmanaged code mixing using C++ is not my forte, so I had to look up a lot. My first thought was to inject a thread into the SoundApplet to manipulate the Applet, but after running afoul on the documentation, I switched to this method. It's quick and dirty, but it does the job.

Call SetTrayIcon with an TIcon object you loaded into memory. Hide your main window. The NoTrayIcon flag is to signal delete icon.

Setting speakers and HDMI (or any multiple endpoint) is only possible on a per program basis. Basically the W7 endpoints are setup so that each app can control a separate endpoint itself programmatically. This little app is actually meant to circumvent that, so it can set the endpoints for all apps at once.

If your application has not this capacity built in the output will always go to the default endpoint. Of the top of my head i'd say it should be possible to build a shellprog which redirects the output to another endpoint but that's quite involved.