After hours of searching the net I have finally figured out a way to programmatically get and set the microphone gain (boost) value.
The code mentioned below can be built on VS and does the job of setting gain value.
#include "stdafx.h"
#include <mmdeviceapi.h>
#include <endpointvolume.h>
#include <Functiondiscoverykeys_devpkey.h>
#include "Audioclient.h"
#include "comutil.h"
#define EXIT_ON_ERROR(hres) if (FAILED(hres)) { goto Exit; }
#define SAFE_RELEASE(punk) if ((punk) != NULL) { (punk)->Release(); (punk) = NULL; }
HRESULT getMicrophoneBoostVolumeLevel(IMMDevice *pEndptDev, IAudioVolumeLevel** ppVolumeLevel)
{
HRESULT hr = S_OK;
DataFlow flow;
IDeviceTopology *pDeviceTopology = NULL;
IConnector *pConnFrom = NULL;
IConnector *pConnTo = NULL;
IPart *pPartPrev = NULL;
IPart *pPartNext = NULL;
*ppVolumeLevel = NULL;
wchar_t microphoneBoostName[] = L"Microphone Boost";//if your system language is English,the name is "microphone boost"
if (pEndptDev == NULL)
{
EXIT_ON_ERROR(hr = E_POINTER)
}
// Get the endpoint device's IDeviceTopology interface.
hr = pEndptDev->Activate(
__uuidof(IDeviceTopology), CLSCTX_ALL, NULL,
(void**)&pDeviceTopology);
EXIT_ON_ERROR(hr)
// The device topology for an endpoint device always
// contains just one connector (connector number 0).
hr = pDeviceTopology->GetConnector(0, &pConnFrom);
SAFE_RELEASE(pDeviceTopology)
EXIT_ON_ERROR(hr)
// Make sure that this is a capture device.
hr = pConnFrom->GetDataFlow(&flow);
EXIT_ON_ERROR(hr)
if (flow != Out)
{
// Error -- this is a rendering device.
//EXIT_ON_ERROR(hr = AUDCLNT_E_WRONG_ENDPOINT_TYPE)
}
// Outer loop: Each iteration traverses the data path
// through a device topology starting at the input
// connector and ending at the output connector.
while (TRUE)
{
BOOL bConnected;
hr = pConnFrom->IsConnected(&bConnected);
EXIT_ON_ERROR(hr)
// Does this connector connect to another device?
if (bConnected == FALSE)
{
// This is the end of the data path that
// stretches from the endpoint device to the
// system bus or external bus. Verify that
// the connection type is Software_IO.
ConnectorType connType;
hr = pConnFrom->GetType(&connType);
EXIT_ON_ERROR(hr)
if (connType == Software_IO)
{
break; // finished
}
EXIT_ON_ERROR(hr = E_FAIL)
}
// Get the connector in the next device topology,
// which lies on the other side of the connection.
hr = pConnFrom->GetConnectedTo(&pConnTo);
EXIT_ON_ERROR(hr)
SAFE_RELEASE(pConnFrom)
// Get the connector's IPart interface.
hr = pConnTo->QueryInterface(
__uuidof(IPart), (void**)&pPartPrev);
EXIT_ON_ERROR(hr)
SAFE_RELEASE(pConnTo)
// Inner loop: Each iteration traverses one link in a
// device topology and looks for input multiplexers.
while (TRUE)
{
PartType parttype;
IPartsList *pParts;
// Follow downstream link to next part.
hr = pPartPrev->EnumPartsOutgoing(&pParts);
EXIT_ON_ERROR(hr)
hr = pParts->GetPart(0, &pPartNext);
pParts->Release();
EXIT_ON_ERROR(hr)
hr = pPartNext->GetPartType(&parttype);
EXIT_ON_ERROR(hr)
LPWSTR pName;
if (SUCCEEDED(pPartNext->GetName(&pName)))
{
// Failure of the following call means only that
// the part is not a boost (micrphone boost).
if (wcscmp(microphoneBoostName, pName) == 0)
{
//get IAudioVolumeLevel to control volume
hr = pPartNext->Activate(CLSCTX_ALL, __uuidof(IAudioVolumeLevel), (void**)ppVolumeLevel);
goto Exit;
}
CoTaskMemFree(pName);
}
GUID subType;
pPartNext->GetSubType(&subType);
if (parttype == Connector)
{
// We've reached the output connector that
// lies at the end of this device topology.
hr = pPartNext->QueryInterface(
__uuidof(IConnector),
(void**)&pConnFrom);
EXIT_ON_ERROR(hr)
SAFE_RELEASE(pPartPrev)
SAFE_RELEASE(pPartNext)
break;
}
SAFE_RELEASE(pPartPrev)
pPartPrev = pPartNext;
pPartNext = NULL;
}
}
Exit:
SAFE_RELEASE(pConnFrom)
SAFE_RELEASE(pConnTo)
SAFE_RELEASE(pPartPrev)
SAFE_RELEASE(pPartNext)
return hr;
}
int setMicrophoneBoost(bool bIsBoost, bool bIsIncrease) {
HRESULT hr = NULL;
CoInitialize(NULL);
IMMDeviceEnumerator *deviceEnumerator = NULL;
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER,
__uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
IMMDevice *defaultDevice = NULL;
if (hr != S_OK)
{
return 0;
}
hr = deviceEnumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, &defaultDevice);
deviceEnumerator->Release();
deviceEnumerator = NULL;
IAudioVolumeLevel* pIaudioVolumeLevel;
getMicrophoneBoostVolumeLevel(defaultDevice, &pIaudioVolumeLevel);
defaultDevice->Release();
defaultDevice = NULL;
if (pIaudioVolumeLevel == NULL)
{
return 0;
}
if (bIsBoost)
{
float fMinDb;
float fMaxDb;
float fStepDb;
float pfCurrentDb = 0.0f;
pIaudioVolumeLevel->GetLevelRange(0, &fMinDb, &fMaxDb, &fStepDb);
pIaudioVolumeLevel->GetLevel(0, &pfCurrentDb);
if (bIsIncrease) {
if (pfCurrentDb < fMaxDb) {
pfCurrentDb += fStepDb; // Incrementing DB level By stepincrement
pIaudioVolumeLevel->SetLevel(0, pfCurrentDb, NULL);
}
}
else {
if (pfCurrentDb > fMinDb) {
pfCurrentDb -= fStepDb; // Decrementing DB level By stepincrement
pIaudioVolumeLevel->SetLevel(0, pfCurrentDb, NULL);
}
}
}
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
int choice;
printf("\r\n Choose 1: to increment gain \r\n Choose 2: to decrement gain \r\n else press any key to return \r\n");
scanf_s("%d", &choice);
switch (choice) {
case 1:
setMicrophoneBoost(true, true); // incrementing db level
break;
case 2:
setMicrophoneBoost(true, false); // decrementing db level
break;
default:
printf("Keeping the microphone gain as is!!!");
break;
}
return 0;
}
User choices are simple, Run the exe from command prompt, enter 1 to increase the microphone boost DB value or 2 to decrease the same.
The code mentioned below can be built on VS and does the job of setting gain value.
#include "stdafx.h"
#include <mmdeviceapi.h>
#include <endpointvolume.h>
#include <Functiondiscoverykeys_devpkey.h>
#include "Audioclient.h"
#include "comutil.h"
#define EXIT_ON_ERROR(hres) if (FAILED(hres)) { goto Exit; }
#define SAFE_RELEASE(punk) if ((punk) != NULL) { (punk)->Release(); (punk) = NULL; }
HRESULT getMicrophoneBoostVolumeLevel(IMMDevice *pEndptDev, IAudioVolumeLevel** ppVolumeLevel)
{
HRESULT hr = S_OK;
DataFlow flow;
IDeviceTopology *pDeviceTopology = NULL;
IConnector *pConnFrom = NULL;
IConnector *pConnTo = NULL;
IPart *pPartPrev = NULL;
IPart *pPartNext = NULL;
*ppVolumeLevel = NULL;
wchar_t microphoneBoostName[] = L"Microphone Boost";//if your system language is English,the name is "microphone boost"
if (pEndptDev == NULL)
{
EXIT_ON_ERROR(hr = E_POINTER)
}
// Get the endpoint device's IDeviceTopology interface.
hr = pEndptDev->Activate(
__uuidof(IDeviceTopology), CLSCTX_ALL, NULL,
(void**)&pDeviceTopology);
EXIT_ON_ERROR(hr)
// The device topology for an endpoint device always
// contains just one connector (connector number 0).
hr = pDeviceTopology->GetConnector(0, &pConnFrom);
SAFE_RELEASE(pDeviceTopology)
EXIT_ON_ERROR(hr)
// Make sure that this is a capture device.
hr = pConnFrom->GetDataFlow(&flow);
EXIT_ON_ERROR(hr)
if (flow != Out)
{
// Error -- this is a rendering device.
//EXIT_ON_ERROR(hr = AUDCLNT_E_WRONG_ENDPOINT_TYPE)
}
// Outer loop: Each iteration traverses the data path
// through a device topology starting at the input
// connector and ending at the output connector.
while (TRUE)
{
BOOL bConnected;
hr = pConnFrom->IsConnected(&bConnected);
EXIT_ON_ERROR(hr)
// Does this connector connect to another device?
if (bConnected == FALSE)
{
// This is the end of the data path that
// stretches from the endpoint device to the
// system bus or external bus. Verify that
// the connection type is Software_IO.
ConnectorType connType;
hr = pConnFrom->GetType(&connType);
EXIT_ON_ERROR(hr)
if (connType == Software_IO)
{
break; // finished
}
EXIT_ON_ERROR(hr = E_FAIL)
}
// Get the connector in the next device topology,
// which lies on the other side of the connection.
hr = pConnFrom->GetConnectedTo(&pConnTo);
EXIT_ON_ERROR(hr)
SAFE_RELEASE(pConnFrom)
// Get the connector's IPart interface.
hr = pConnTo->QueryInterface(
__uuidof(IPart), (void**)&pPartPrev);
EXIT_ON_ERROR(hr)
SAFE_RELEASE(pConnTo)
// Inner loop: Each iteration traverses one link in a
// device topology and looks for input multiplexers.
while (TRUE)
{
PartType parttype;
IPartsList *pParts;
// Follow downstream link to next part.
hr = pPartPrev->EnumPartsOutgoing(&pParts);
EXIT_ON_ERROR(hr)
hr = pParts->GetPart(0, &pPartNext);
pParts->Release();
EXIT_ON_ERROR(hr)
hr = pPartNext->GetPartType(&parttype);
EXIT_ON_ERROR(hr)
LPWSTR pName;
if (SUCCEEDED(pPartNext->GetName(&pName)))
{
// Failure of the following call means only that
// the part is not a boost (micrphone boost).
if (wcscmp(microphoneBoostName, pName) == 0)
{
//get IAudioVolumeLevel to control volume
hr = pPartNext->Activate(CLSCTX_ALL, __uuidof(IAudioVolumeLevel), (void**)ppVolumeLevel);
goto Exit;
}
CoTaskMemFree(pName);
}
GUID subType;
pPartNext->GetSubType(&subType);
if (parttype == Connector)
{
// We've reached the output connector that
// lies at the end of this device topology.
hr = pPartNext->QueryInterface(
__uuidof(IConnector),
(void**)&pConnFrom);
EXIT_ON_ERROR(hr)
SAFE_RELEASE(pPartPrev)
SAFE_RELEASE(pPartNext)
break;
}
SAFE_RELEASE(pPartPrev)
pPartPrev = pPartNext;
pPartNext = NULL;
}
}
Exit:
SAFE_RELEASE(pConnFrom)
SAFE_RELEASE(pConnTo)
SAFE_RELEASE(pPartPrev)
SAFE_RELEASE(pPartNext)
return hr;
}
int setMicrophoneBoost(bool bIsBoost, bool bIsIncrease) {
HRESULT hr = NULL;
CoInitialize(NULL);
IMMDeviceEnumerator *deviceEnumerator = NULL;
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER,
__uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
IMMDevice *defaultDevice = NULL;
if (hr != S_OK)
{
return 0;
}
hr = deviceEnumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, &defaultDevice);
deviceEnumerator->Release();
deviceEnumerator = NULL;
IAudioVolumeLevel* pIaudioVolumeLevel;
getMicrophoneBoostVolumeLevel(defaultDevice, &pIaudioVolumeLevel);
defaultDevice->Release();
defaultDevice = NULL;
if (pIaudioVolumeLevel == NULL)
{
return 0;
}
if (bIsBoost)
{
float fMinDb;
float fMaxDb;
float fStepDb;
float pfCurrentDb = 0.0f;
pIaudioVolumeLevel->GetLevelRange(0, &fMinDb, &fMaxDb, &fStepDb);
pIaudioVolumeLevel->GetLevel(0, &pfCurrentDb);
if (bIsIncrease) {
if (pfCurrentDb < fMaxDb) {
pfCurrentDb += fStepDb; // Incrementing DB level By stepincrement
pIaudioVolumeLevel->SetLevel(0, pfCurrentDb, NULL);
}
}
else {
if (pfCurrentDb > fMinDb) {
pfCurrentDb -= fStepDb; // Decrementing DB level By stepincrement
pIaudioVolumeLevel->SetLevel(0, pfCurrentDb, NULL);
}
}
}
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
int choice;
printf("\r\n Choose 1: to increment gain \r\n Choose 2: to decrement gain \r\n else press any key to return \r\n");
scanf_s("%d", &choice);
switch (choice) {
case 1:
setMicrophoneBoost(true, true); // incrementing db level
break;
case 2:
setMicrophoneBoost(true, false); // decrementing db level
break;
default:
printf("Keeping the microphone gain as is!!!");
break;
}
return 0;
}
User choices are simple, Run the exe from command prompt, enter 1 to increase the microphone boost DB value or 2 to decrease the same.
Hi DHAV.
ReplyDeleteI just copied your code : Getting and Setting Microphone Gain or Microphone Boost on Windows 7 / 8 Programmatically
It run good on VC++2012 Console.
Can you help me ? how to run on Vb.net with winform.
Thankyou very much.
Daianhtai,
ReplyDeleteI am sorry, I am not aware of how to get/set mic gain using Vb.net with winform.
In case if you do not find a method to get/set mic db using winform, I would suggest you to run the above mentioned exe in the background and use post message from your vb.net program to above mentioned exe to increase or decrease mic gain.
This comment has been removed by the author.
DeleteHi DHAV.
ReplyDeleteDo you have email ?
I have some issues ,can you help me
Thankyou very much.
post ur mail id here
Deletemy email : daianhtai2007@gmail.com
DeleteCan you tell me your email ?
I will send my issue for you by email ,because it's so long.
Thankyou very much.
Do you sure that there's no unused marks in your code? or such error typing?
ReplyDeleteSo I can use the microphone as a mic on xbox live and ps4 for this party members and they pick up me through that likewise? hyperx quadcast
ReplyDelete