From 182ac7e012b5bcda1416e5edac4e2dff83cf6cbd Mon Sep 17 00:00:00 2001
From: aymeric <aymeric@3f6dc0c8-ddfe-455d-9043-3cd528dc4637>
Date: Tue, 28 Apr 2009 14:35:25 +0000
Subject: [PATCH] Add mute/unmute support in mediastreamer2 and winsnd2 filter

git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@445 3f6dc0c8-ddfe-455d-9043-3cd528dc4637
---
 .../build/win32-novideo/mediastreamer2.def    |   2 +
 .../build/win32native/mediastreamer2.def      |   2 +
 .../include/mediastreamer2/mssndcard.h        |  52 ++-
 linphone/mediastreamer2/src/mssndcard.c       |  21 +-
 linphone/mediastreamer2/src/winsnd2.c         | 323 +++++++++++++-----
 5 files changed, 314 insertions(+), 86 deletions(-)

diff --git a/linphone/mediastreamer2/build/win32-novideo/mediastreamer2.def b/linphone/mediastreamer2/build/win32-novideo/mediastreamer2.def
index 89f7c3797f..f8c592e131 100755
--- a/linphone/mediastreamer2/build/win32-novideo/mediastreamer2.def
+++ b/linphone/mediastreamer2/build/win32-novideo/mediastreamer2.def
@@ -40,6 +40,8 @@ EXPORTS
 	ms_snd_card_set_level
 	ms_snd_card_get_level
 	ms_snd_card_set_capture
+	ms_snd_card_set_control
+	ms_snd_card_get_control
 	
 	ms_ticker_new
 	ms_ticker_set_name
diff --git a/linphone/mediastreamer2/build/win32native/mediastreamer2.def b/linphone/mediastreamer2/build/win32native/mediastreamer2.def
index 21693b2174..f880c1bf77 100755
--- a/linphone/mediastreamer2/build/win32native/mediastreamer2.def
+++ b/linphone/mediastreamer2/build/win32native/mediastreamer2.def
@@ -40,6 +40,8 @@ EXPORTS
 	ms_snd_card_set_level
 	ms_snd_card_get_level
 	ms_snd_card_set_capture
+	ms_snd_card_set_control
+	ms_snd_card_get_control
 	
 	ms_ticker_new
 	ms_ticker_set_name
diff --git a/linphone/mediastreamer2/include/mediastreamer2/mssndcard.h b/linphone/mediastreamer2/include/mediastreamer2/mssndcard.h
index 0561cd12c8..b4aa9f2f76 100644
--- a/linphone/mediastreamer2/include/mediastreamer2/mssndcard.h
+++ b/linphone/mediastreamer2/include/mediastreamer2/mssndcard.h
@@ -65,6 +65,18 @@ enum _MSSndCardCapture {
 	MS_SND_CARD_LINE
 };
 
+/**
+ * Structure for sound card mixer values.
+ * @var MSSndCardMixerElem
+ */
+typedef enum _MSSndCardControlElem MSSndCardControlElem;
+
+enum _MSSndCardControlElem {
+	MS_SND_CARD_MASTER_MUTE,
+	MS_SND_CARD_PLAYBACK_MUTE,
+	MS_SND_CARD_CAPTURE_MUTE
+};
+
 /**
  * Structure for sound card capture source values.
  * @var MSSndCardCapture
@@ -79,6 +91,8 @@ typedef void (*MSSndCardUninitFunc)(struct _MSSndCard *obj);
 typedef void (*MSSndCardSetLevelFunc)(struct _MSSndCard *obj, MSSndCardMixerElem e, int percent);
 typedef void (*MSSndCardSetCaptureFunc)(struct _MSSndCard *obj, MSSndCardCapture e);
 typedef int (*MSSndCardGetLevelFunc)(struct _MSSndCard *obj, MSSndCardMixerElem e);
+typedef void (*MSSndCardSetControlFunc)(struct _MSSndCard *obj, MSSndCardControlElem e, int val);
+typedef int (*MSSndCardGetControlFunc)(struct _MSSndCard *obj, MSSndCardControlElem e);
 typedef struct _MSFilter * (*MSSndCardCreateReaderFunc)(struct _MSSndCard *obj);
 typedef struct _MSFilter * (*MSSndCardCreateWriterFunc)(struct _MSSndCard *obj);
 typedef struct _MSSndCard * (*MSSndCardDuplicateFunc)(struct _MSSndCard *obj);
@@ -90,6 +104,8 @@ struct _MSSndCardDesc{
 	MSSndCardSetLevelFunc set_level;
 	MSSndCardGetLevelFunc get_level;
 	MSSndCardSetCaptureFunc set_capture;
+	MSSndCardSetControlFunc set_control;
+	MSSndCardGetControlFunc get_control;
 	MSSndCardCreateReaderFunc create_reader;
 	MSSndCardCreateWriterFunc create_writer;
 	MSSndCardUninitFunc uninit;
@@ -342,7 +358,7 @@ void ms_snd_card_set_level(MSSndCard *obj, MSSndCardMixerElem e, int percent);
  * @param obj      A sound card object.
  * @param e        A sound card mixer object.
  *
- * Returns: A int if successfull, 0 otherwise.
+ * Returns: A int if successfull, <0 otherwise.
  */
 int ms_snd_card_get_level(MSSndCard *obj, MSSndCardMixerElem e);
 
@@ -362,6 +378,40 @@ int ms_snd_card_get_level(MSSndCard *obj, MSSndCardMixerElem e);
  */
 void ms_snd_card_set_capture(MSSndCard *obj, MSSndCardCapture c);
 
+/**
+ * Set some mixer control.
+ *
+ * <PRE>
+ *   MS_SND_CARD_MASTER_MUTE, -> 0: unmute, 1: mute
+ *   MS_SND_CARD_PLAYBACK_MUTE, -> 0: unmute, 1: mute
+ *   MS_SND_CARD_CAPTURE_MUTE -> 0: unmute, 1: mute
+ * </PRE>
+ * Note: not implemented on all sound card filters.
+ *
+ * @param obj      A sound card object.
+ * @param e        A sound card control object.
+ * @param percent  A value for control.
+ *
+ */
+void ms_snd_card_set_control(MSSndCard *obj, MSSndCardControlElem e, int val);
+
+/**
+ * Get some mixer control.
+ *
+ * <PRE>
+ *   MS_SND_CARD_MASTER_MUTE, -> return 0: unmute, 1: mute
+ *   MS_SND_CARD_PLAYBACK_MUTE, -> return 0: unmute, 1: mute
+ *   MS_SND_CARD_CAPTURE_MUTE -> return 0: unmute, 1: mute
+ * </PRE>
+ * Note: not implemented on all sound card filters.
+ *
+ * @param obj      A sound card object.
+ * @param e        A sound card mixer object.
+ *
+ * Returns: A int if successfull, <0 otherwise.
+ */
+int ms_snd_card_get_control(MSSndCard *obj, MSSndCardControlElem e);
+
 /**
  * Create a alsa card with user supplied pcm name and mixer name.
  * @param pcmdev The pcm device name following alsa conventions (ex: plughw:0)
diff --git a/linphone/mediastreamer2/src/mssndcard.c b/linphone/mediastreamer2/src/mssndcard.c
index 2313b85dc4..e8de161430 100644
--- a/linphone/mediastreamer2/src/mssndcard.c
+++ b/linphone/mediastreamer2/src/mssndcard.c
@@ -156,14 +156,14 @@ const char *ms_snd_card_get_string_id(MSSndCard *obj){
 void ms_snd_card_set_level(MSSndCard *obj, MSSndCardMixerElem e, int percent){
 	if (obj->desc->set_level!=NULL)
 		obj->desc->set_level(obj,e,percent);
-	else ms_warning("ms_snd_card_set_capture: unimplemented by %s wrapper",obj->desc->driver_type);
+	else ms_warning("ms_snd_card_set_level: unimplemented by %s wrapper",obj->desc->driver_type);
 }
 
 int ms_snd_card_get_level(MSSndCard *obj, MSSndCardMixerElem e){
 	if (obj->desc->get_level!=NULL)
 		return obj->desc->get_level(obj,e);
 	else {
-		ms_warning("ms_snd_card_set_capture: unimplemented by %s wrapper",obj->desc->driver_type);
+		ms_warning("ms_snd_card_get_level: unimplemented by %s wrapper",obj->desc->driver_type);
 		return -1;
 	}
 }
@@ -174,6 +174,23 @@ void ms_snd_card_set_capture(MSSndCard *obj, MSSndCardCapture c){
 	else ms_warning("ms_snd_card_set_capture: unimplemented by %s wrapper",obj->desc->driver_type);
 }
 
+void ms_snd_card_set_control(MSSndCard *obj, MSSndCardControlElem e, int val)
+{
+	if (obj->desc->set_control!=NULL)
+		obj->desc->set_control(obj,e,val);
+	else ms_warning("ms_snd_card_set_control: unimplemented by %s wrapper",obj->desc->driver_type);
+}
+
+int ms_snd_card_get_control(MSSndCard *obj, MSSndCardControlElem e)
+{
+	if (obj->desc->get_control!=NULL)
+		return obj->desc->get_control(obj,e);
+	else {
+		ms_warning("ms_snd_card_get_control: unimplemented by %s wrapper",obj->desc->driver_type);
+		return -1;
+	}
+}
+
 struct _MSFilter * ms_snd_card_create_reader(MSSndCard *obj){
 	if (obj->desc->create_reader!=NULL)
 		return obj->desc->create_reader(obj);
diff --git a/linphone/mediastreamer2/src/winsnd2.c b/linphone/mediastreamer2/src/winsnd2.c
index 933ebf5fbd..f45973f44d 100755
--- a/linphone/mediastreamer2/src/winsnd2.c
+++ b/linphone/mediastreamer2/src/winsnd2.c
@@ -76,7 +76,7 @@ static void winsndcard_set_level(MSSndCard *card, MSSndCardMixerElem e, int perc
 			mr = waveOutSetVolume((HWAVEOUT)d->out_devid, dwNewVol);
 			if (mr != MMSYSERR_NOERROR)
 			{
-				ms_warning("Failed to set master volume. (waveOutSetVolume:0x%i)", mr);
+				ms_error("winsndcard_set_level: waveOutSetVolume failed. (0x%x)", mr);
 				return;
 			}
 			break;
@@ -84,14 +84,14 @@ static void winsndcard_set_level(MSSndCard *card, MSSndCardMixerElem e, int perc
 			mr = mixerGetID( (HMIXEROBJ)d->in_devid, &uMixerID, MIXER_OBJECTF_WAVEIN );
 			if ( mr != MMSYSERR_NOERROR )
 			{
-				ms_error("winsndcard_set_level: mixerGetID failed. mr=%d\n", mr );
+				ms_error("winsndcard_set_level: mixerGetID failed. (0x%x)", mr);
 				return;
 			}
 			mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L );
 			if ( mr != MMSYSERR_NOERROR )
 			{
 				mixerClose( (HMIXER)dwMixerHandle );
-				ms_error("winsndcard_set_level: Could not open Mixer. mr=%d\n", mr );
+				ms_error("winsndcard_set_level: mixerGetLineInfo failed. (0x%x)", mr);
 				return;
 			}
 			memset( &MixerLine, 0, sizeof(MIXERLINE) );
@@ -101,12 +101,12 @@ static void winsndcard_set_level(MSSndCard *card, MSSndCardMixerElem e, int perc
 			if ( mr != MMSYSERR_NOERROR )
 			{
 				mixerClose( (HMIXER)dwMixerHandle );
-				ms_error("winsndcard_set_level: Could not get WaveIn Destination Line for the requested source while enumerating. mr=%d\n", mr );
+				ms_error("winsndcard_set_level: mixerGetLineInfo failed. (0x%x)", mr);
 				return;
 			}
-			ms_message("Name: %s\n", MixerLine.szName);
-			ms_message("Source Line: %d\n", MixerLine.dwSource);
-			ms_message("ComponentType: %d\n", MixerLine.dwComponentType);
+			/* ms_message("Name: %s\n", MixerLine.szName); */
+			/* ms_message("Source Line: %d\n", MixerLine.dwSource); */
+			/* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
 
 			for (uLineIndex = 0; uLineIndex < MixerLine.cConnections; uLineIndex++)
 			{
@@ -118,16 +118,15 @@ static void winsndcard_set_level(MSSndCard *card, MSSndCardMixerElem e, int perc
 				if ( mr != MMSYSERR_NOERROR )
 				{
 					mixerClose( (HMIXER)dwMixerHandle );
-					ms_error("winsndcard_set_level: Could not get the interated Source Line while enumerating. mr=%d\n", mr );
+					ms_error("winsndcard_set_level: mixerGetLineInfo failed. (0x%x)", mr);
 					return;
 				}
-				else
-				{
-					ms_message("Name: %s\n", MixerLine.szName);
-					ms_message("Source Line: %d\n", MixerLine.dwSource);
-					ms_message("LineID: %d\n", MixerLine.dwLineID);
-					ms_message("ComponentType: %d\n", MixerLine.dwComponentType);
-				}
+
+				/* ms_message("Name: %s\n", MixerLine.szName); */
+				/* ms_message("Source Line: %d\n", MixerLine.dwSource); */
+				/* ms_message("LineID: %d\n", MixerLine.dwLineID); */
+				/* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
+
 				memset( &Line, 0, sizeof(MIXERLINE) );
 				Line.cbStruct = sizeof(MIXERLINE);
 				Line.dwDestination = MixerLine.dwDestination;
@@ -136,52 +135,14 @@ static void winsndcard_set_level(MSSndCard *card, MSSndCardMixerElem e, int perc
 				if ( mr != MMSYSERR_NOERROR )
 				{
 					mixerClose( (HMIXER)dwMixerHandle );
-					ms_error("winsndcard_set_level: Could not get the interated Source Line while enumerating. mr=%d\n", mr );
+					ms_error("winsndcard_set_level: mixerGetLineInfo failed. (0x%x)", mr);
 					return;
 				}
-				else
-				{
-					ms_message("Name: %s\n", MixerLine.szName);
-					ms_message("Source Line: %d\n", MixerLine.dwSource);
-					ms_message("LineID: %d\n", MixerLine.dwLineID);
-					ms_message("ComponentType: %d\n", MixerLine.dwComponentType);
-				}
-				if (MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE == Line.dwComponentType)  
-				{
-					/* unmute */
-					/* Find a mute control, if any, of the microphone line  */
 
-					LPMIXERCONTROL pmxctrl = (LPMIXERCONTROL)malloc(sizeof(MIXERCONTROL));  
-					MIXERLINECONTROLS mxlctrl = {sizeof mxlctrl, Line.dwLineID, MIXERCONTROL_CONTROLTYPE_MUTE, 1, sizeof(MIXERCONTROL), pmxctrl};  
-					if(!mixerGetLineControls((HMIXEROBJ)dwMixerHandle, &mxlctrl, MIXER_GETLINECONTROLSF_ONEBYTYPE)){  
-						DWORD cChannels = Line.cChannels;
-						LPMIXERCONTROLDETAILS_BOOLEAN pbool;
-						MIXERCONTROLDETAILS mxcd;
-
-						if (MIXERCONTROL_CONTROLF_UNIFORM & pmxctrl->fdwControl)  
-							cChannels = 1;  
-						pbool = (LPMIXERCONTROLDETAILS_BOOLEAN) malloc(cChannels * sizeof(
-							MIXERCONTROLDETAILS_BOOLEAN));
-
-						mxcd.cbStruct = sizeof(mxcd);
-						mxcd.dwControlID = pmxctrl->dwControlID;
-						mxcd.cChannels = cChannels;
-						mxcd.hwndOwner = (HWND)0;
-						mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
-						mxcd.paDetails = (LPVOID) pbool;
-
-						mixerGetControlDetails((HMIXEROBJ)dwMixerHandle, &mxcd,  
-							MIXER_SETCONTROLDETAILSF_VALUE);  
-						/* Unmute the microphone line (for both channels) */
-						pbool[0].fValue = pbool[cChannels - 1].fValue = 0; /* 0 -> unmute; */
-						mixerSetControlDetails((HMIXEROBJ)dwMixerHandle, &mxcd,  
-							MIXER_SETCONTROLDETAILSF_VALUE);  
-						free(pmxctrl);  
-						free(pbool);  
-					}  
-					else  
-						free(pmxctrl);  
-				}
+				/* ms_message("Name: %s\n", MixerLine.szName); */
+				/* ms_message("Source Line: %d\n", MixerLine.dwSource); */
+				/* ms_message("LineID: %d\n", MixerLine.dwLineID); */
+				/* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
 
 				if (MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE == Line.dwComponentType)  
 				{
@@ -221,7 +182,7 @@ static void winsndcard_set_level(MSSndCard *card, MSSndCardMixerElem e, int perc
 			mixerClose( (HMIXER)dwMixerHandle );
 			if (mr != MMSYSERR_NOERROR)
 			{
-				ms_warning("Failed to set capture volume. (mixerClose:0x%i)", mr);
+				ms_error("winsndcard_set_level: mixerClose failed. (0x%x)", mr);
 				return;
 			}
 			break;
@@ -235,14 +196,14 @@ static void winsndcard_set_level(MSSndCard *card, MSSndCardMixerElem e, int perc
 				mr = mixerGetID( (HMIXEROBJ)d->out_devid, &uMixerID, MIXER_OBJECTF_WAVEOUT );
 				if ( mr != MMSYSERR_NOERROR )
 				{
-					ms_error("winsndcard_set_level: mixerGetID failed. mr=%d\n", mr );
+					ms_error("winsndcard_set_level: mixerGetID failed. (0x%x)", mr);
 					return;
 				}
 				mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L );
 				if ( mr != MMSYSERR_NOERROR )
 				{
 					mixerClose( (HMIXER)dwMixerHandle );
-					ms_error("winsndcard_set_level: Could not open Mixer. mr=%d\n", mr );
+					ms_error("winsndcard_set_level: mixerOpen failed. (0x%x)", mr);
 					return;
 				}
 				memset( &MixerLine, 0, sizeof(MIXERLINE) );
@@ -252,12 +213,13 @@ static void winsndcard_set_level(MSSndCard *card, MSSndCardMixerElem e, int perc
 				if ( mr != MMSYSERR_NOERROR )
 				{
 					mixerClose( (HMIXER)dwMixerHandle );
-					ms_error("winsndcard_set_level: Could not get WaveIn Destination Line for the requested source while enumerating. mr=%d\n", mr );
+					ms_error("winsndcard_set_level: mixerGetLineInfo failed. (0x%x)", mr);
 					return;
 				}
-				ms_message("Name: %s\n", MixerLine.szName);
-				ms_message("Source Line: %d\n", MixerLine.dwSource);
-				ms_message("ComponentType: %d\n", MixerLine.dwComponentType);
+
+				/* ms_message("Name: %s\n", MixerLine.szName); */
+				/* ms_message("Source Line: %d\n", MixerLine.dwSource); */
+				/* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
 
 				mlc.cbStruct = sizeof(MIXERLINECONTROLS);
 				mlc.dwLineID = MixerLine.dwLineID;
@@ -282,7 +244,7 @@ static void winsndcard_set_level(MSSndCard *card, MSSndCardMixerElem e, int perc
 
 				if (mr != MMSYSERR_NOERROR)
 				{
-					ms_warning("Failed to set playback volume. (waveOutSetVolume:0x%i)", mr);
+					ms_error("winsndcard_set_level: mixerSetControlDetails failed. (0x%x)", mr);
 					return;
 				}
 			}
@@ -340,9 +302,10 @@ static int winsndcard_get_level(MSSndCard *card, MSSndCardMixerElem e){
 				ms_error("winsndcard_set_level: Could not get WaveIn Destination Line for the requested source while enumerating. mr=%d\n", mr );
 				return -1;
 			}
-			ms_message("Name: %s\n", MixerLine.szName);
-			ms_message("Source Line: %d\n", MixerLine.dwSource);
-			ms_message("ComponentType: %d\n", MixerLine.dwComponentType);
+
+			/* ms_message("Name: %s\n", MixerLine.szName); */
+			/* ms_message("Source Line: %d\n", MixerLine.dwSource); */
+			/* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
 
 			for (uLineIndex = 0; uLineIndex < MixerLine.cConnections; uLineIndex++)
 			{
@@ -357,13 +320,12 @@ static int winsndcard_get_level(MSSndCard *card, MSSndCardMixerElem e){
 					ms_error("winsndcard_set_level: Could not get the interated Source Line while enumerating. mr=%d\n", mr );
 					return -1;
 				}
-				else
-				{
-					ms_message("Name: %s\n", MixerLine.szName);
-					ms_message("Source Line: %d\n", MixerLine.dwSource);
-					ms_message("LineID: %d\n", MixerLine.dwLineID);
-					ms_message("ComponentType: %d\n", MixerLine.dwComponentType);
-				}
+
+				/* ms_message("Name: %s\n", MixerLine.szName); */
+				/* ms_message("Source Line: %d\n", MixerLine.dwSource); */
+				/* ms_message("LineID: %d\n", MixerLine.dwLineID); */
+				/* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
+
 				memset( &Line, 0, sizeof(MIXERLINE) );
 				Line.cbStruct = sizeof(MIXERLINE);
 				Line.dwDestination = MixerLine.dwDestination;
@@ -375,13 +337,11 @@ static int winsndcard_get_level(MSSndCard *card, MSSndCardMixerElem e){
 					ms_error("winsndcard_set_level: Could not get the interated Source Line while enumerating. mr=%d\n", mr );
 					return -1;
 				}
-				else
-				{
-					ms_message("Name: %s\n", MixerLine.szName);
-					ms_message("Source Line: %d\n", MixerLine.dwSource);
-					ms_message("LineID: %d\n", MixerLine.dwLineID);
-					ms_message("ComponentType: %d\n", MixerLine.dwComponentType);
-				}
+
+				/* ms_message("Name: %s\n", MixerLine.szName); */
+				/* ms_message("Source Line: %d\n", MixerLine.dwSource); */
+				/* ms_message("LineID: %d\n", MixerLine.dwLineID); */
+				/* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
 
 				if (MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE == Line.dwComponentType)  
 				{
@@ -440,6 +400,201 @@ static void winsndcard_set_source(MSSndCard *card, MSSndCardCapture source){
 	}	
 }
 
+static void winsndcard_set_control(MSSndCard *card, MSSndCardControlElem e, int val){
+	WinSndCard *d=(WinSndCard*)card->data;
+
+	UINT uMixerID;
+	DWORD dwMixerHandle;
+	MIXERLINE MixerLine;
+	MIXERLINE Line;
+	UINT uLineIndex;
+
+	MMRESULT mr = MMSYSERR_NOERROR;
+
+	switch(e){
+		case MS_SND_CARD_CAPTURE_MUTE:
+
+			mr = mixerGetID( (HMIXEROBJ)d->in_devid, &uMixerID, MIXER_OBJECTF_WAVEIN );
+			if ( mr != MMSYSERR_NOERROR )
+			{
+				ms_error("winsndcard_set_control: mixerGetID failed. (0x%x)", mr);
+				return;
+			}
+			mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L );
+			if ( mr != MMSYSERR_NOERROR )
+			{
+				mixerClose( (HMIXER)dwMixerHandle );
+				ms_error("winsndcard_set_control: mixerOpen failed. (0x%x)", mr);
+				return;
+			}
+			memset( &MixerLine, 0, sizeof(MIXERLINE) );
+			MixerLine.cbStruct = sizeof(MIXERLINE);
+			MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
+			mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &MixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE );
+			if ( mr != MMSYSERR_NOERROR )
+			{
+				mixerClose( (HMIXER)dwMixerHandle );
+				ms_error("winsndcard_set_control: mixerGetLineInfo failed. (0x%x)", mr);
+				return;
+			}
+			/* ms_message("Name: %s\n", MixerLine.szName); */
+			/* ms_message("Source Line: %d\n", MixerLine.dwSource); */
+			/* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
+
+			for (uLineIndex = 0; uLineIndex < MixerLine.cConnections; uLineIndex++)
+			{
+				memset( &Line, 0, sizeof(MIXERLINE) );
+				Line.cbStruct = sizeof(MIXERLINE);
+				Line.dwDestination = MixerLine.dwDestination;
+				Line.dwSource = uLineIndex;
+				mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &Line, MIXER_GETLINEINFOF_LINEID);
+				if ( mr != MMSYSERR_NOERROR )
+				{
+					mixerClose( (HMIXER)dwMixerHandle );
+					ms_error("winsndcard_set_control: mixerGetLineInfo failed. (0x%x)", mr);
+					return;
+				}
+				
+				/* ms_message("Name: %s\n", MixerLine.szName); */
+				/* ms_message("Source Line: %d\n", MixerLine.dwSource); */
+				/* ms_message("LineID: %d\n", MixerLine.dwLineID); */
+				/* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
+
+				memset( &Line, 0, sizeof(MIXERLINE) );
+				Line.cbStruct = sizeof(MIXERLINE);
+				Line.dwDestination = MixerLine.dwDestination;
+				Line.dwSource = uLineIndex;
+				mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &Line, MIXER_GETLINEINFOF_SOURCE);
+				if ( mr != MMSYSERR_NOERROR )
+				{
+					mixerClose( (HMIXER)dwMixerHandle );
+					ms_error("winsndcard_set_control: mixerGetLineInfo failed. (0x%x)", mr);
+					return;
+				}
+
+				/* ms_message("Name: %s\n", MixerLine.szName); */
+				/* ms_message("Source Line: %d\n", MixerLine.dwSource); */
+				/* ms_message("LineID: %d\n", MixerLine.dwLineID); */
+				/* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
+
+				if (MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE == Line.dwComponentType)  
+				{
+					/* unmute */
+					/* Find a mute control, if any, of the microphone line  */
+
+					LPMIXERCONTROL pmxctrl = (LPMIXERCONTROL)malloc(sizeof(MIXERCONTROL));
+					MIXERLINECONTROLS mxlctrl = {sizeof(mxlctrl), Line.dwLineID, MIXERCONTROL_CONTROLTYPE_MUTE, 1, sizeof(MIXERCONTROL), pmxctrl};  
+					if(!mixerGetLineControls((HMIXEROBJ)dwMixerHandle, &mxlctrl, MIXER_GETLINECONTROLSF_ONEBYTYPE)){  
+						DWORD cChannels = Line.cChannels;
+						LPMIXERCONTROLDETAILS_BOOLEAN pbool;
+						MIXERCONTROLDETAILS mxcd;
+
+						if (MIXERCONTROL_CONTROLF_UNIFORM & pmxctrl->fdwControl)  
+							cChannels = 1;  
+						pbool = (LPMIXERCONTROLDETAILS_BOOLEAN) malloc(cChannels * sizeof(
+							MIXERCONTROLDETAILS_BOOLEAN));
+
+						mxcd.cbStruct = sizeof(mxcd);
+						mxcd.dwControlID = pmxctrl->dwControlID;
+						mxcd.cChannels = cChannels;
+						mxcd.hwndOwner = (HWND)0;
+						mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
+						mxcd.paDetails = (LPVOID) pbool;
+
+						mixerGetControlDetails((HMIXEROBJ)dwMixerHandle, &mxcd,  
+							MIXER_SETCONTROLDETAILSF_VALUE);  
+						/* Unmute the microphone line (for both channels) */
+						pbool[0].fValue = pbool[cChannels - 1].fValue = val; /* 0 -> unmute; */
+						mixerSetControlDetails((HMIXEROBJ)dwMixerHandle, &mxcd,  
+							MIXER_SETCONTROLDETAILSF_VALUE);  
+						free(pmxctrl);  
+						free(pbool);  
+					}  
+					else  
+						free(pmxctrl);  
+				}
+			}
+			mixerClose( (HMIXER)dwMixerHandle );
+			if (mr != MMSYSERR_NOERROR)
+			{
+				ms_error("winsndcard_set_control: mixerClose failed. (0x%x)", mr);
+				return;
+			}
+			break;
+
+		case MS_SND_CARD_MASTER_MUTE:
+		case MS_SND_CARD_PLAYBACK_MUTE:
+			{
+				MIXERLINECONTROLS mlc = {0};
+				MIXERCONTROL mc = {0};
+				MIXERCONTROLDETAILS mcd = {0};
+				MIXERCONTROLDETAILS_BOOLEAN bMute;
+
+				bMute.fValue = (val>0);
+
+				mr = mixerGetID( (HMIXEROBJ)d->out_devid, &uMixerID, MIXER_OBJECTF_WAVEOUT );
+				if ( mr != MMSYSERR_NOERROR )
+				{
+					ms_error("winsndcard_set_control: mixerGetID failed. (0x%x)", mr);
+					return;
+				}
+				mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L );
+				if ( mr != MMSYSERR_NOERROR )
+				{
+					mixerClose( (HMIXER)dwMixerHandle );
+					ms_error("winsndcard_set_control: mixerOpen failed. (0x%x)", mr);
+					return;
+				}
+				memset( &MixerLine, 0, sizeof(MIXERLINE) );
+				MixerLine.cbStruct = sizeof(MIXERLINE);
+				MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
+				mr = mixerGetLineInfo( (HMIXEROBJ)dwMixerHandle, &MixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE );
+				if ( mr != MMSYSERR_NOERROR )
+				{
+					mixerClose( (HMIXER)dwMixerHandle );
+					ms_error("winsndcard_set_control: mixerSetControlDetails failed. (0x%x)", mr);
+					return;
+				}
+
+				/* ms_message("Name: %s\n", MixerLine.szName); */
+				/* ms_message("Source Line: %d\n", MixerLine.dwSource); */
+				/* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */
+
+				mlc.cbStruct = sizeof(MIXERLINECONTROLS);
+				mlc.dwLineID = MixerLine.dwLineID;
+				mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE; //MIXERCONTROL_CONTROLTYPE_VOLUME;
+				mlc.cControls = 1;
+				mlc.pamxctrl = &mc;
+				mlc.cbmxctrl = sizeof(MIXERCONTROL);
+				mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle, 
+					&mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
+
+				mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
+				mcd.hwndOwner = 0;
+				mcd.dwControlID = mc.dwControlID;
+				mcd.paDetails = &bMute;
+				mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
+				mcd.cChannels = 1;
+				mr = mixerSetControlDetails((HMIXEROBJ)dwMixerHandle, 
+					&mcd, MIXER_SETCONTROLDETAILSF_VALUE);
+
+				if (mr != MMSYSERR_NOERROR)
+				{
+					ms_error("winsndcard_set_control: mixerSetControlDetails failed. (0x%x)", mr);
+					return;
+				}
+			}
+			break;
+		default:
+			ms_warning("winsndcard_set_control: unsupported command.");
+	}
+}
+
+static int winsndcard_get_control(MSSndCard *card, MSSndCardControlElem e){
+	WinSndCard *d=(WinSndCard*)card->data;
+	return -1;
+}
+
 static void winsndcard_init(MSSndCard *card){
 	WinSndCard *c=(WinSndCard *)ms_new(WinSndCard,1);
 	card->data=c;
@@ -459,6 +614,8 @@ MSSndCardDesc winsnd_card_desc={
 	winsndcard_set_level,
 	winsndcard_get_level,
 	winsndcard_set_source,
+	winsndcard_set_control,
+	winsndcard_get_control,
 	ms_winsnd_read_new,
 	ms_winsnd_write_new,
 	winsndcard_uninit,
-- 
GitLab