summaryrefslogtreecommitdiff
path: root/sys/directsound
diff options
context:
space:
mode:
authorVictor Toso <victortoso@redhat.com>2015-03-31 10:53:55 +0100
committerJulien Isorce <j.isorce@samsung.com>2015-03-31 10:53:55 +0100
commit1b564bfb8b0db43a24cf311dca24038558b80a68 (patch)
treef76fc449d14f3879f979f7070ed9d86d932fe728 /sys/directsound
parent4504356ddab34a680d0d19f5d4c130114f621ea3 (diff)
downloadgstreamer-plugins-bad-1b564bfb8b0db43a24cf311dca24038558b80a68.tar.gz
directsoundsrc: Implement volume and mute
Using the MixerAPI as IDirectSoundCaptureBuffer doesn't implement volume control. https://bugzilla.gnome.org/show_bug.cgi?id=744383
Diffstat (limited to 'sys/directsound')
-rw-r--r--sys/directsound/Makefile.am2
-rw-r--r--sys/directsound/gstdirectsoundsrc.c267
-rw-r--r--sys/directsound/gstdirectsoundsrc.h10
3 files changed, 276 insertions, 3 deletions
diff --git a/sys/directsound/Makefile.am b/sys/directsound/Makefile.am
index 18b0980b9..cfc769f6c 100644
--- a/sys/directsound/Makefile.am
+++ b/sys/directsound/Makefile.am
@@ -5,7 +5,7 @@ libgstdirectsoundsrc_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) \
$(GST_PLUGINS_BASE_CFLAGS) $(DIRECTX_CFLAGS)
libgstdirectsoundsrc_la_LIBADD = \
$(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) \
- $(DIRECTX_LDFLAGS) -ldsound
+ $(DIRECTX_LDFLAGS) $(DIRECTSOUND_LIBS)
libgstdirectsoundsrc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstdirectsoundsrc_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
diff --git a/sys/directsound/gstdirectsoundsrc.c b/sys/directsound/gstdirectsoundsrc.c
index 420a70d57..0bd77e829 100644
--- a/sys/directsound/gstdirectsoundsrc.c
+++ b/sys/directsound/gstdirectsoundsrc.c
@@ -73,18 +73,22 @@
#include <windows.h>
#include <dsound.h>
+#include <mmsystem.h>
GST_DEBUG_CATEGORY_STATIC (directsoundsrc_debug);
#define GST_CAT_DEFAULT directsoundsrc_debug
/* defaults here */
#define DEFAULT_DEVICE 0
+#define DEFAULT_MUTE FALSE
/* properties */
enum
{
PROP_0,
- PROP_DEVICE_NAME
+ PROP_DEVICE_NAME,
+ PROP_VOLUME,
+ PROP_MUTE
};
static HRESULT (WINAPI * pDSoundCaptureCreate) (LPGUID,
@@ -114,6 +118,18 @@ static void gst_directsound_src_dispose (GObject * object);
static guint gst_directsound_src_delay (GstAudioSrc * asrc);
+static gboolean gst_directsound_src_mixer_find (GstDirectSoundSrc * dsoundsrc,
+ MIXERCAPS * mixer_caps);
+static void gst_directsound_src_mixer_init (GstDirectSoundSrc * dsoundsrc);
+
+static gdouble gst_directsound_src_get_volume (GstDirectSoundSrc * dsoundsrc);
+static void gst_directsound_src_set_volume (GstDirectSoundSrc * dsoundsrc,
+ gdouble volume);
+
+static gboolean gst_directsound_src_get_mute (GstDirectSoundSrc * dsoundsrc);
+static void gst_directsound_src_set_mute (GstDirectSoundSrc * dsoundsrc,
+ gboolean mute);
+
static GstStaticPadTemplate directsound_src_src_factory =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
@@ -124,7 +140,9 @@ GST_STATIC_PAD_TEMPLATE ("src",
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]"));
#define gst_directsound_src_parent_class parent_class
-G_DEFINE_TYPE (GstDirectSoundSrc, gst_directsound_src, GST_TYPE_AUDIO_SRC);
+G_DEFINE_TYPE_WITH_CODE (GstDirectSoundSrc, gst_directsound_src,
+ GST_TYPE_AUDIO_SRC, G_IMPLEMENT_INTERFACE (GST_TYPE_STREAM_VOLUME, NULL)
+ );
static void
gst_directsound_src_dispose (GObject * object)
@@ -193,6 +211,18 @@ gst_directsound_src_class_init (GstDirectSoundSrcClass * klass)
(gobject_class, PROP_DEVICE_NAME,
g_param_spec_string ("device-name", "Device name",
"Human-readable name of the sound device", NULL, G_PARAM_READWRITE));
+
+ g_object_class_install_property
+ (gobject_class, PROP_VOLUME,
+ g_param_spec_double ("volume", "Volume",
+ "Volume of this stream", 0.0, 1.0, 1.0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property
+ (gobject_class, PROP_MUTE,
+ g_param_spec_boolean ("mute", "Mute",
+ "Mute state of this stream", DEFAULT_MUTE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
static GstCaps *
@@ -223,6 +253,12 @@ gst_directsound_src_set_property (GObject * object, guint prop_id,
}
break;
+ case PROP_VOLUME:
+ gst_directsound_src_set_volume (src, g_value_get_double (value));
+ break;
+ case PROP_MUTE:
+ gst_directsound_src_set_mute (src, g_value_get_boolean (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -241,6 +277,12 @@ gst_directsound_src_get_property (GObject * object, guint prop_id,
case PROP_DEVICE_NAME:
g_value_set_string (value, src->device_name);
break;
+ case PROP_VOLUME:
+ g_value_set_double (value, gst_directsound_src_get_volume (src));
+ break;
+ case PROP_MUTE:
+ g_value_set_boolean (value, gst_directsound_src_get_mute (src));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -260,6 +302,11 @@ gst_directsound_src_init (GstDirectSoundSrc * src)
g_mutex_init (&src->dsound_lock);
src->device_guid = NULL;
src->device_name = NULL;
+ src->mixer = NULL;
+ src->control_id_mute = -1;
+ src->control_id_volume = -1;
+ src->volume = 100;
+ src->mute = FALSE;
}
@@ -326,6 +373,7 @@ gst_directsound_src_open (GstAudioSrc * asrc)
goto capture_object;
}
+ gst_directsound_src_mixer_init (dsoundsrc);
return TRUE;
capture_function:
@@ -374,6 +422,9 @@ gst_directsound_src_close (GstAudioSrc * asrc)
/* Close library */
FreeLibrary (dsoundsrc->DSoundDLL);
+ if (dsoundsrc->mixer)
+ mixerClose (dsoundsrc->mixer);
+
return TRUE;
}
@@ -661,3 +712,215 @@ gst_directsound_src_reset (GstAudioSrc * asrc)
GST_DSOUND_UNLOCK (dsoundsrc);
}
+
+/* If the PROP_DEVICE_NAME is set, find the mixer related to device;
+ * otherwise we get the default input mixer. */
+static gboolean
+gst_directsound_src_mixer_find (GstDirectSoundSrc * dsoundsrc,
+ MIXERCAPS * mixer_caps)
+{
+ MMRESULT mmres;
+ guint i, num_mixers;
+
+ num_mixers = mixerGetNumDevs ();
+ for (i = 0; i < num_mixers; i++) {
+ mmres = mixerOpen (&dsoundsrc->mixer, i, 0L, 0L,
+ MIXER_OBJECTF_MIXER | MIXER_OBJECTF_WAVEIN);
+
+ if (mmres != MMSYSERR_NOERROR)
+ continue;
+
+ mmres = mixerGetDevCaps ((UINT) dsoundsrc->mixer,
+ mixer_caps, sizeof (MIXERCAPS));
+
+ if (mmres != MMSYSERR_NOERROR) {
+ mixerClose (dsoundsrc->mixer);
+ continue;
+ }
+
+ /* Get default mixer */
+ if (dsoundsrc->device_name == NULL) {
+ GST_DEBUG ("Got default input mixer: %s", mixer_caps->szPname);
+ return TRUE;
+ }
+
+ if (g_strstr_len (dsoundsrc->device_name, -1, mixer_caps->szPname) != NULL) {
+ GST_DEBUG ("Got requested input mixer: %s", mixer_caps->szPname);
+ return TRUE;
+ }
+
+ /* Wrong mixer */
+ mixerClose (dsoundsrc->mixer);
+ }
+
+ GST_DEBUG ("Can't find input mixer");
+ return FALSE;
+}
+
+static void
+gst_directsound_src_mixer_init (GstDirectSoundSrc * dsoundsrc)
+{
+ gint i, k;
+ gboolean found_mic;
+ MMRESULT mmres;
+ MIXERCAPS mixer_caps;
+ MIXERLINE mixer_line;
+ MIXERLINECONTROLS ml_ctrl;
+ PMIXERCONTROL pamixer_ctrls;
+
+ if (!gst_directsound_src_mixer_find (dsoundsrc, &mixer_caps))
+ goto mixer_init_fail;
+
+ /* Find the MIXERLINE related to MICROPHONE */
+ found_mic = FALSE;
+ for (i = 0; i < mixer_caps.cDestinations && !found_mic; i++) {
+ gint j, num_connections;
+
+ mixer_line.cbStruct = sizeof (mixer_line);
+ mixer_line.dwDestination = i;
+ mmres = mixerGetLineInfo ((HMIXEROBJ) dsoundsrc->mixer,
+ &mixer_line, MIXER_GETLINEINFOF_DESTINATION);
+
+ if (mmres != MMSYSERR_NOERROR)
+ goto mixer_init_fail;
+
+ num_connections = mixer_line.cConnections;
+ for (j = 0; j < num_connections && !found_mic; j++) {
+ mixer_line.cbStruct = sizeof (mixer_line);
+ mixer_line.dwDestination = i;
+ mixer_line.dwSource = j;
+ mmres = mixerGetLineInfo ((HMIXEROBJ) dsoundsrc->mixer,
+ &mixer_line, MIXER_GETLINEINFOF_SOURCE);
+
+ if (mmres != MMSYSERR_NOERROR)
+ goto mixer_init_fail;
+
+ if (mixer_line.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE
+ || mixer_line.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_LINE)
+ found_mic = TRUE;
+ }
+ }
+
+ if (found_mic == FALSE) {
+ GST_DEBUG ("Can't find mixer line related to input");
+ goto mixer_init_fail;
+ }
+
+ /* Get control associated with microphone audio line */
+ pamixer_ctrls = g_malloc (sizeof (MIXERCONTROL) * mixer_line.cControls);
+ ml_ctrl.cbStruct = sizeof (ml_ctrl);
+ ml_ctrl.dwLineID = mixer_line.dwLineID;
+ ml_ctrl.cControls = mixer_line.cControls;
+ ml_ctrl.cbmxctrl = sizeof (MIXERCONTROL);
+ ml_ctrl.pamxctrl = pamixer_ctrls;
+ mmres = mixerGetLineControls ((HMIXEROBJ) dsoundsrc->mixer,
+ &ml_ctrl, MIXER_GETLINECONTROLSF_ALL);
+
+ /* Find control associated with volume and mute */
+ for (k = 0; k < mixer_line.cControls; k++) {
+ if (strstr (pamixer_ctrls[k].szName, "Volume") != NULL) {
+ dsoundsrc->control_id_volume = pamixer_ctrls[k].dwControlID;
+ dsoundsrc->dw_vol_max = pamixer_ctrls[k].Bounds.dwMaximum;
+ dsoundsrc->dw_vol_min = pamixer_ctrls[k].Bounds.dwMinimum;
+ } else if (strstr (pamixer_ctrls[k].szName, "Mute") != NULL) {
+ dsoundsrc->control_id_mute = pamixer_ctrls[k].dwControlID;
+ } else {
+ GST_DEBUG ("Control not handled: %s", pamixer_ctrls[k].szName);
+ }
+ }
+ g_free (pamixer_ctrls);
+
+ if (dsoundsrc->control_id_volume < 0 && dsoundsrc->control_id_mute < 0)
+ goto mixer_init_fail;
+
+ /* Save cChannels information to properly changes in volume */
+ dsoundsrc->mixerline_cchannels = mixer_line.cChannels;
+ return;
+
+mixer_init_fail:
+ GST_WARNING ("Failed to get Volume and Mute controls");
+ if (dsoundsrc->mixer != NULL) {
+ mixerClose (dsoundsrc->mixer);
+ dsoundsrc->mixer = NULL;
+ }
+}
+
+static gdouble
+gst_directsound_src_get_volume (GstDirectSoundSrc * dsoundsrc)
+{
+ return (gdouble) dsoundsrc->volume / 100;
+}
+
+static gboolean
+gst_directsound_src_get_mute (GstDirectSoundSrc * dsoundsrc)
+{
+ return dsoundsrc->mute;
+}
+
+static void
+gst_directsound_src_set_volume (GstDirectSoundSrc * dsoundsrc, gdouble volume)
+{
+ MMRESULT mmres;
+ MIXERCONTROLDETAILS details;
+ MIXERCONTROLDETAILS_UNSIGNED details_unsigned;
+ glong dwvolume;
+
+ if (dsoundsrc->mixer == NULL || dsoundsrc->control_id_volume < 0) {
+ GST_WARNING ("mixer not initialized");
+ return;
+ }
+
+ dwvolume = volume * dsoundsrc->dw_vol_max;
+ dwvolume = CLAMP (dwvolume, dsoundsrc->dw_vol_min, dsoundsrc->dw_vol_max);
+
+ GST_DEBUG ("max volume %ld | min volume %ld",
+ dsoundsrc->dw_vol_max, dsoundsrc->dw_vol_min);
+ GST_DEBUG ("set volume to %f (%ld)", volume, dwvolume);
+
+ details.cbStruct = sizeof (details);
+ details.dwControlID = dsoundsrc->control_id_volume;
+ details.cChannels = dsoundsrc->mixerline_cchannels;
+ details.cMultipleItems = 0;
+
+ details_unsigned.dwValue = dwvolume;
+ details.cbDetails = sizeof (MIXERCONTROLDETAILS_UNSIGNED);
+ details.paDetails = &details_unsigned;
+
+ mmres = mixerSetControlDetails ((HMIXEROBJ) dsoundsrc->mixer,
+ &details, MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE);
+
+ if (mmres != MMSYSERR_NOERROR)
+ GST_WARNING ("Failed to set volume");
+ else
+ dsoundsrc->volume = volume * 100;
+}
+
+static void
+gst_directsound_src_set_mute (GstDirectSoundSrc * dsoundsrc, gboolean mute)
+{
+ MMRESULT mmres;
+ MIXERCONTROLDETAILS details;
+ MIXERCONTROLDETAILS_BOOLEAN details_boolean;
+
+ if (dsoundsrc->mixer == NULL || dsoundsrc->control_id_mute < 0) {
+ GST_WARNING ("mixer not initialized");
+ return;
+ }
+
+ details.cbStruct = sizeof (details);
+ details.dwControlID = dsoundsrc->control_id_mute;
+ details.cChannels = dsoundsrc->mixerline_cchannels;
+ details.cMultipleItems = 0;
+
+ details_boolean.fValue = mute;
+ details.cbDetails = sizeof (MIXERCONTROLDETAILS_BOOLEAN);
+ details.paDetails = &details_boolean;
+
+ mmres = mixerSetControlDetails ((HMIXEROBJ) dsoundsrc->mixer,
+ &details, MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE);
+
+ if (mmres != MMSYSERR_NOERROR)
+ GST_WARNING ("Failed to set mute");
+ else
+ dsoundsrc->mute = mute;
+}
diff --git a/sys/directsound/gstdirectsoundsrc.h b/sys/directsound/gstdirectsoundsrc.h
index 4c65372c9..a2ac6ffd3 100644
--- a/sys/directsound/gstdirectsoundsrc.h
+++ b/sys/directsound/gstdirectsoundsrc.h
@@ -52,6 +52,7 @@
#include <gst/audio/gstaudiosrc.h>
#include <windows.h>
#include <dsound.h>
+#include <mmsystem.h>
/* add here some headers if needed */
@@ -91,6 +92,15 @@ struct _GstDirectSoundSrc
guint buffer_time;
guint latency_time;
+ HMIXER mixer;
+ DWORD mixerline_cchannels;
+ gint control_id_volume;
+ gint control_id_mute;
+ glong dw_vol_max;
+ glong dw_vol_min;
+
+ glong volume;
+ gboolean mute;
GUID *device_guid;
char *device_name;