directsoundsink: allow specifying audio playback device

https://bugzilla.gnome.org/show_bug.cgi?id=753670
This commit is contained in:
Dustin Spicuzza 2015-08-16 15:21:51 -04:00 committed by Sebastian Dröge
parent 0899529222
commit 5c680333ba
3 changed files with 72 additions and 4 deletions

View file

@ -388,7 +388,7 @@ AG_GST_CHECK_FEATURE(DIRECTSOUND, [DirectSound plug-in], directsoundsink, [
save_LIBS="$LIBS" save_LIBS="$LIBS"
CFLAGS="$CFLAGS $DIRECTSOUND_CFLAGS" CFLAGS="$CFLAGS $DIRECTSOUND_CFLAGS"
LDFLAGS="$LDFLAGS $DIRECTSOUND_LDFLAGS" LDFLAGS="$LDFLAGS $DIRECTSOUND_LDFLAGS"
LIBS="$LIBS -ldsound -ldxerr9 -luser32" LIBS="$LIBS -ldsound -ldxerr9 -luser32 -lole32"
AC_MSG_CHECKING(for DirectSound LDFLAGS) AC_MSG_CHECKING(for DirectSound LDFLAGS)
AC_LINK_IFELSE([AC_LANG_PROGRAM([[ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#include <windows.h> #include <windows.h>
@ -397,6 +397,7 @@ AG_GST_CHECK_FEATURE(DIRECTSOUND, [DirectSound plug-in], directsoundsink, [
]], [[ ]], [[
DXGetErrorString9 (0); DXGetErrorString9 (0);
DirectSoundCreate(NULL, NULL, NULL); DirectSoundCreate(NULL, NULL, NULL);
CLSIDFromString(NULL, NULL);
]]) ]])
], ],
[HAVE_DIRECTSOUND="yes"], [HAVE_DIRECTSOUND="yes"],
@ -408,7 +409,7 @@ AG_GST_CHECK_FEATURE(DIRECTSOUND, [DirectSound plug-in], directsoundsink, [
if test "x$HAVE_DIRECTSOUND" = "xyes"; then if test "x$HAVE_DIRECTSOUND" = "xyes"; then
dnl this is much more than we want dnl this is much more than we want
DIRECTSOUND_LIBS="-ldsound -ldxerr9 -luser32" DIRECTSOUND_LIBS="-ldsound -ldxerr9 -luser32 -lole32"
AC_SUBST(DIRECTSOUND_CFLAGS) AC_SUBST(DIRECTSOUND_CFLAGS)
AC_SUBST(DIRECTSOUND_LDFLAGS) AC_SUBST(DIRECTSOUND_LDFLAGS)
AC_SUBST(DIRECTSOUND_LIBS) AC_SUBST(DIRECTSOUND_LIBS)

View file

@ -101,6 +101,10 @@ static gdouble gst_directsound_sink_get_volume (GstDirectSoundSink * sink);
static void gst_directsound_sink_set_mute (GstDirectSoundSink * sink, static void gst_directsound_sink_set_mute (GstDirectSoundSink * sink,
gboolean mute); gboolean mute);
static gboolean gst_directsound_sink_get_mute (GstDirectSoundSink * sink); static gboolean gst_directsound_sink_get_mute (GstDirectSoundSink * sink);
static const gchar *gst_directsound_sink_get_device (GstDirectSoundSink *
dsoundsink);
static void gst_directsound_sink_set_device (GstDirectSoundSink * dsoundsink,
const gchar * device_id);
static gboolean gst_directsound_sink_is_spdif_format (GstAudioRingBufferSpec * static gboolean gst_directsound_sink_is_spdif_format (GstAudioRingBufferSpec *
spec); spec);
@ -124,7 +128,8 @@ enum
{ {
PROP_0, PROP_0,
PROP_VOLUME, PROP_VOLUME,
PROP_MUTE PROP_MUTE,
PROP_DEVICE
}; };
#define gst_directsound_sink_parent_class parent_class #define gst_directsound_sink_parent_class parent_class
@ -137,6 +142,9 @@ gst_directsound_sink_finalize (GObject * object)
{ {
GstDirectSoundSink *dsoundsink = GST_DIRECTSOUND_SINK (object); GstDirectSoundSink *dsoundsink = GST_DIRECTSOUND_SINK (object);
g_free (dsoundsink->device_id);
dsoundsink->device_id = NULL;
g_mutex_clear (&dsoundsink->dsound_lock); g_mutex_clear (&dsoundsink->dsound_lock);
G_OBJECT_CLASS (parent_class)->finalize (object); G_OBJECT_CLASS (parent_class)->finalize (object);
@ -189,6 +197,12 @@ gst_directsound_sink_class_init (GstDirectSoundSinkClass * klass)
"Mute state of this stream", DEFAULT_MUTE, "Mute state of this stream", DEFAULT_MUTE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_DEVICE,
g_param_spec_string ("device", "Device",
"DirectSound playback device as a GUID string",
NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_set_static_metadata (element_class, gst_element_class_set_static_metadata (element_class,
"Direct Sound Audio Sink", "Sink/Audio", "Direct Sound Audio Sink", "Sink/Audio",
"Output to a sound card via Direct Sound", "Output to a sound card via Direct Sound",
@ -203,6 +217,7 @@ gst_directsound_sink_init (GstDirectSoundSink * dsoundsink)
{ {
dsoundsink->volume = 100; dsoundsink->volume = 100;
dsoundsink->mute = FALSE; dsoundsink->mute = FALSE;
dsoundsink->device_id = NULL;
dsoundsink->pDS = NULL; dsoundsink->pDS = NULL;
dsoundsink->cached_caps = NULL; dsoundsink->cached_caps = NULL;
dsoundsink->pDSBSecondary = NULL; dsoundsink->pDSBSecondary = NULL;
@ -226,6 +241,9 @@ gst_directsound_sink_set_property (GObject * object,
case PROP_MUTE: case PROP_MUTE:
gst_directsound_sink_set_mute (sink, g_value_get_boolean (value)); gst_directsound_sink_set_mute (sink, g_value_get_boolean (value));
break; break;
case PROP_DEVICE:
gst_directsound_sink_set_device (sink, g_value_get_string (value));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -245,6 +263,9 @@ gst_directsound_sink_get_property (GObject * object,
case PROP_MUTE: case PROP_MUTE:
g_value_set_boolean (value, gst_directsound_sink_get_mute (sink)); g_value_set_boolean (value, gst_directsound_sink_get_mute (sink));
break; break;
case PROP_DEVICE:
g_value_set_string (value, gst_directsound_sink_get_device (sink));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -378,22 +399,51 @@ gst_directsound_sink_query (GstBaseSink * sink, GstQuery * query)
return res; return res;
} }
static LPGUID
string_to_guid (const gchar * str)
{
HRESULT ret;
gunichar2 *wstr;
LPGUID out;
wstr = g_utf8_to_utf16 (str, -1, NULL, NULL, NULL);
if (!wstr)
return NULL;
out = g_new (GUID, 1);
ret = CLSIDFromString ((LPOLESTR) wstr, out);
g_free (wstr);
if (ret != NOERROR) {
g_free (out);
return NULL;
}
return out;
}
static gboolean static gboolean
gst_directsound_sink_open (GstAudioSink * asink) gst_directsound_sink_open (GstAudioSink * asink)
{ {
GstDirectSoundSink *dsoundsink; GstDirectSoundSink *dsoundsink;
HRESULT hRes; HRESULT hRes;
LPGUID lpGuid = NULL;
dsoundsink = GST_DIRECTSOUND_SINK (asink); dsoundsink = GST_DIRECTSOUND_SINK (asink);
if (dsoundsink->device_id)
lpGuid = string_to_guid (dsoundsink->device_id);
/* create and initialize a DirecSound object */ /* create and initialize a DirecSound object */
if (FAILED (hRes = DirectSoundCreate (NULL, &dsoundsink->pDS, NULL))) { if (FAILED (hRes = DirectSoundCreate (lpGuid, &dsoundsink->pDS, NULL))) {
GST_ELEMENT_ERROR (dsoundsink, RESOURCE, OPEN_READ, GST_ELEMENT_ERROR (dsoundsink, RESOURCE, OPEN_READ,
("gst_directsound_sink_open: DirectSoundCreate: %s", ("gst_directsound_sink_open: DirectSoundCreate: %s",
DXGetErrorString9 (hRes)), (NULL)); DXGetErrorString9 (hRes)), (NULL));
g_free (lpGuid);
return FALSE; return FALSE;
} }
g_free (lpGuid);
if (FAILED (hRes = IDirectSound_SetCooperativeLevel (dsoundsink->pDS, if (FAILED (hRes = IDirectSound_SetCooperativeLevel (dsoundsink->pDS,
GetDesktopWindow (), DSSCL_PRIORITY))) { GetDesktopWindow (), DSSCL_PRIORITY))) {
GST_ELEMENT_ERROR (dsoundsink, RESOURCE, OPEN_READ, GST_ELEMENT_ERROR (dsoundsink, RESOURCE, OPEN_READ,
@ -874,3 +924,17 @@ gst_directsound_sink_get_mute (GstDirectSoundSink * dsoundsink)
{ {
return FALSE; return FALSE;
} }
static const gchar *
gst_directsound_sink_get_device (GstDirectSoundSink * dsoundsink)
{
return dsoundsink->device_id;
}
static void
gst_directsound_sink_set_device (GstDirectSoundSink * dsoundsink,
const gchar * device_id)
{
g_free (dsoundsink->device_id);
dsoundsink->device_id = g_strdup (device_id);
}

View file

@ -75,6 +75,9 @@ struct _GstDirectSoundSink
glong volume; glong volume;
gboolean mute; gboolean mute;
/* current directsound device ID */
gchar * device_id;
GstCaps *cached_caps; GstCaps *cached_caps;
/* lock used to protect writes and resets */ /* lock used to protect writes and resets */
GMutex dsound_lock; GMutex dsound_lock;