2009-08-10 09:36:41 +00:00
|
|
|
|
/*
|
|
|
|
|
* GStreamer
|
|
|
|
|
* Copyright 2005 Thomas Vander Stichele <thomas@apestaart.org>
|
|
|
|
|
* Copyright 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
|
2012-09-14 15:08:49 +00:00
|
|
|
|
* Copyright 2005 S<EFBFBD>bastien Moutte <sebastien@moutte.net>
|
2009-08-10 09:36:41 +00:00
|
|
|
|
* Copyright 2006 Joni Valtanen <joni.valtanen@movial.fi>
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
|
|
|
*
|
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
|
* DEALINGS IN THE SOFTWARE.
|
|
|
|
|
*
|
|
|
|
|
* Alternatively, the contents of this file may be used under the
|
|
|
|
|
* GNU Lesser General Public License Version 2.1 (the "LGPL"), in
|
|
|
|
|
* which case the following provisions apply instead of the ones
|
|
|
|
|
* mentioned above:
|
|
|
|
|
*
|
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
* Library General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
|
* License along with this library; if not, write to the
|
2012-11-03 20:38:00 +00:00
|
|
|
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
|
|
|
* Boston, MA 02110-1301, USA.
|
2009-08-10 09:36:41 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
TODO: add device selection and check rate etc.
|
|
|
|
|
*/
|
|
|
|
|
|
2012-04-03 09:09:19 +00:00
|
|
|
|
/**
|
|
|
|
|
* SECTION:element-directsoundsrc
|
|
|
|
|
*
|
|
|
|
|
* Reads audio data using the DirectSound API.
|
|
|
|
|
*
|
|
|
|
|
* <refsect2>
|
|
|
|
|
* <title>Example pipelines</title>
|
|
|
|
|
* |[
|
|
|
|
|
* gst-launch -v directsoundsrc ! audioconvert ! vorbisenc ! oggmux ! filesink location=dsound.ogg
|
|
|
|
|
* ]| Record from DirectSound and encode to Ogg/Vorbis.
|
|
|
|
|
* </refsect2>
|
|
|
|
|
*/
|
|
|
|
|
|
2009-08-10 09:36:41 +00:00
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
# include "config.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include <gst/gst.h>
|
2012-12-12 21:57:21 +00:00
|
|
|
|
#include <gst/audio/audio.h>
|
2012-04-03 09:09:19 +00:00
|
|
|
|
#include <gst/audio/gstaudiobasesrc.h>
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
#include "gstdirectsoundsrc.h"
|
|
|
|
|
|
|
|
|
|
#include <windows.h>
|
|
|
|
|
#include <dsound.h>
|
2015-03-31 09:53:55 +00:00
|
|
|
|
#include <mmsystem.h>
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
GST_DEBUG_CATEGORY_STATIC (directsoundsrc_debug);
|
|
|
|
|
#define GST_CAT_DEFAULT directsoundsrc_debug
|
|
|
|
|
|
|
|
|
|
/* defaults here */
|
|
|
|
|
#define DEFAULT_DEVICE 0
|
2015-03-31 09:53:55 +00:00
|
|
|
|
#define DEFAULT_MUTE FALSE
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
/* properties */
|
|
|
|
|
enum
|
|
|
|
|
{
|
|
|
|
|
PROP_0,
|
2015-03-31 09:53:55 +00:00
|
|
|
|
PROP_DEVICE_NAME,
|
|
|
|
|
PROP_VOLUME,
|
|
|
|
|
PROP_MUTE
|
2009-07-29 13:35:03 +00:00
|
|
|
|
};
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
static HRESULT (WINAPI * pDSoundCaptureCreate) (LPGUID,
|
|
|
|
|
LPDIRECTSOUNDCAPTURE *, LPUNKNOWN);
|
|
|
|
|
|
2012-07-03 10:57:58 +00:00
|
|
|
|
static void gst_directsound_src_finalize (GObject * object);
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
static void gst_directsound_src_set_property (GObject * object,
|
|
|
|
|
guint prop_id, const GValue * value, GParamSpec * pspec);
|
|
|
|
|
|
|
|
|
|
static void gst_directsound_src_get_property (GObject * object,
|
|
|
|
|
guint prop_id, GValue * value, GParamSpec * pspec);
|
|
|
|
|
|
|
|
|
|
static gboolean gst_directsound_src_open (GstAudioSrc * asrc);
|
|
|
|
|
static gboolean gst_directsound_src_close (GstAudioSrc * asrc);
|
|
|
|
|
static gboolean gst_directsound_src_prepare (GstAudioSrc * asrc,
|
2012-04-03 09:09:19 +00:00
|
|
|
|
GstAudioRingBufferSpec * spec);
|
2009-08-10 09:36:41 +00:00
|
|
|
|
static gboolean gst_directsound_src_unprepare (GstAudioSrc * asrc);
|
|
|
|
|
static void gst_directsound_src_reset (GstAudioSrc * asrc);
|
2012-04-03 09:09:19 +00:00
|
|
|
|
static GstCaps *gst_directsound_src_getcaps (GstBaseSrc * bsrc,
|
|
|
|
|
GstCaps * filter);
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
static guint gst_directsound_src_read (GstAudioSrc * asrc,
|
2012-10-17 19:54:28 +00:00
|
|
|
|
gpointer data, guint length, GstClockTime * timestamp);
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
static void gst_directsound_src_dispose (GObject * object);
|
|
|
|
|
|
|
|
|
|
static guint gst_directsound_src_delay (GstAudioSrc * asrc);
|
|
|
|
|
|
2015-03-31 09:53:55 +00:00
|
|
|
|
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);
|
|
|
|
|
|
2009-08-10 09:36:41 +00:00
|
|
|
|
static GstStaticPadTemplate directsound_src_src_factory =
|
2012-04-03 09:09:19 +00:00
|
|
|
|
GST_STATIC_PAD_TEMPLATE ("src",
|
2009-08-10 09:36:41 +00:00
|
|
|
|
GST_PAD_SRC,
|
|
|
|
|
GST_PAD_ALWAYS,
|
2012-04-03 09:09:19 +00:00
|
|
|
|
GST_STATIC_CAPS ("audio/x-raw, "
|
|
|
|
|
"format = (string) { S16LE, S8 }, "
|
|
|
|
|
"layout = (string) interleaved, "
|
2009-08-10 09:36:41 +00:00
|
|
|
|
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]"));
|
|
|
|
|
|
2012-04-03 09:09:19 +00:00
|
|
|
|
#define gst_directsound_src_parent_class parent_class
|
2015-03-31 09:53:55 +00:00
|
|
|
|
G_DEFINE_TYPE_WITH_CODE (GstDirectSoundSrc, gst_directsound_src,
|
|
|
|
|
GST_TYPE_AUDIO_SRC, G_IMPLEMENT_INTERFACE (GST_TYPE_STREAM_VOLUME, NULL)
|
|
|
|
|
);
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gst_directsound_src_dispose (GObject * object)
|
2009-07-29 13:35:03 +00:00
|
|
|
|
{
|
2009-08-10 09:36:41 +00:00
|
|
|
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
|
|
|
|
}
|
2009-07-29 13:35:03 +00:00
|
|
|
|
|
2009-08-10 09:36:41 +00:00
|
|
|
|
static void
|
2012-07-03 10:57:58 +00:00
|
|
|
|
gst_directsound_src_finalize (GObject * object)
|
2009-07-29 13:35:03 +00:00
|
|
|
|
{
|
2009-08-10 09:36:41 +00:00
|
|
|
|
GstDirectSoundSrc *dsoundsrc = GST_DIRECTSOUND_SRC (object);
|
|
|
|
|
|
2012-10-25 15:10:40 +00:00
|
|
|
|
g_mutex_clear (&dsoundsrc->dsound_lock);
|
2012-07-03 10:57:58 +00:00
|
|
|
|
|
2013-08-22 15:32:17 +00:00
|
|
|
|
g_free (dsoundsrc->device_name);
|
|
|
|
|
g_free (dsoundsrc->device_guid);
|
2013-08-22 11:45:59 +00:00
|
|
|
|
|
2012-07-03 10:57:58 +00:00
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
2009-08-10 09:36:41 +00:00
|
|
|
|
}
|
2009-07-29 13:35:03 +00:00
|
|
|
|
|
2009-08-10 09:36:41 +00:00
|
|
|
|
static void
|
|
|
|
|
gst_directsound_src_class_init (GstDirectSoundSrcClass * klass)
|
2009-07-29 13:35:03 +00:00
|
|
|
|
{
|
2009-08-10 09:36:41 +00:00
|
|
|
|
GObjectClass *gobject_class;
|
|
|
|
|
GstElementClass *gstelement_class;
|
|
|
|
|
GstBaseSrcClass *gstbasesrc_class;
|
|
|
|
|
GstAudioSrcClass *gstaudiosrc_class;
|
|
|
|
|
|
|
|
|
|
gobject_class = (GObjectClass *) klass;
|
|
|
|
|
gstelement_class = (GstElementClass *) klass;
|
|
|
|
|
gstbasesrc_class = (GstBaseSrcClass *) klass;
|
|
|
|
|
gstaudiosrc_class = (GstAudioSrcClass *) klass;
|
|
|
|
|
|
2014-04-08 11:20:54 +00:00
|
|
|
|
GST_DEBUG_CATEGORY_INIT (directsoundsrc_debug, "directsoundsrc", 0,
|
|
|
|
|
"DirectSound Src");
|
|
|
|
|
|
2012-04-03 09:09:19 +00:00
|
|
|
|
GST_DEBUG ("initializing directsoundsrc class");
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
2012-07-03 10:57:58 +00:00
|
|
|
|
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_directsound_src_finalize);
|
2009-08-10 09:36:41 +00:00
|
|
|
|
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_directsound_src_dispose);
|
|
|
|
|
gobject_class->get_property =
|
2009-07-29 13:35:03 +00:00
|
|
|
|
GST_DEBUG_FUNCPTR (gst_directsound_src_get_property);
|
2009-08-10 09:36:41 +00:00
|
|
|
|
gobject_class->set_property =
|
2009-07-29 13:35:03 +00:00
|
|
|
|
GST_DEBUG_FUNCPTR (gst_directsound_src_set_property);
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_directsound_src_getcaps);
|
|
|
|
|
|
|
|
|
|
gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_directsound_src_open);
|
|
|
|
|
gstaudiosrc_class->close = GST_DEBUG_FUNCPTR (gst_directsound_src_close);
|
|
|
|
|
gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_directsound_src_read);
|
|
|
|
|
gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_directsound_src_prepare);
|
|
|
|
|
gstaudiosrc_class->unprepare =
|
2009-07-29 13:35:03 +00:00
|
|
|
|
GST_DEBUG_FUNCPTR (gst_directsound_src_unprepare);
|
2009-08-10 09:36:41 +00:00
|
|
|
|
gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_directsound_src_delay);
|
|
|
|
|
gstaudiosrc_class->reset = GST_DEBUG_FUNCPTR (gst_directsound_src_reset);
|
|
|
|
|
|
2012-04-03 09:09:19 +00:00
|
|
|
|
gst_element_class_set_static_metadata (gstelement_class,
|
|
|
|
|
"DirectSound audio source", "Source/Audio",
|
|
|
|
|
"Capture from a soundcard via DirectSound",
|
|
|
|
|
"Joni Valtanen <joni.valtanen@movial.fi>");
|
|
|
|
|
|
|
|
|
|
gst_element_class_add_pad_template (gstelement_class,
|
|
|
|
|
gst_static_pad_template_get (&directsound_src_src_factory));
|
2013-08-22 11:45:59 +00:00
|
|
|
|
|
|
|
|
|
g_object_class_install_property
|
|
|
|
|
(gobject_class, PROP_DEVICE_NAME,
|
|
|
|
|
g_param_spec_string ("device-name", "Device name",
|
2013-08-22 15:32:17 +00:00
|
|
|
|
"Human-readable name of the sound device", NULL, G_PARAM_READWRITE));
|
2015-03-31 09:53:55 +00:00
|
|
|
|
|
|
|
|
|
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));
|
2009-08-10 09:36:41 +00:00
|
|
|
|
}
|
2009-07-29 13:35:03 +00:00
|
|
|
|
|
2009-08-10 09:36:41 +00:00
|
|
|
|
static GstCaps *
|
2012-04-03 09:09:19 +00:00
|
|
|
|
gst_directsound_src_getcaps (GstBaseSrc * bsrc, GstCaps * filter)
|
2009-07-29 13:35:03 +00:00
|
|
|
|
{
|
2009-08-10 09:36:41 +00:00
|
|
|
|
GstCaps *caps = NULL;
|
2012-04-03 09:09:19 +00:00
|
|
|
|
GST_DEBUG_OBJECT (bsrc, "get caps");
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
2014-08-09 11:22:42 +00:00
|
|
|
|
caps = gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (bsrc));
|
2009-08-10 09:36:41 +00:00
|
|
|
|
return caps;
|
|
|
|
|
}
|
2009-07-29 13:35:03 +00:00
|
|
|
|
|
2009-08-10 09:36:41 +00:00
|
|
|
|
static void
|
2009-07-29 13:35:03 +00:00
|
|
|
|
gst_directsound_src_set_property (GObject * object, guint prop_id,
|
2009-08-10 09:36:41 +00:00
|
|
|
|
const GValue * value, GParamSpec * pspec)
|
2009-07-29 13:35:03 +00:00
|
|
|
|
{
|
2013-08-22 11:45:59 +00:00
|
|
|
|
GstDirectSoundSrc *src = GST_DIRECTSOUND_SRC (object);
|
2012-04-03 09:09:19 +00:00
|
|
|
|
GST_DEBUG ("set property");
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
switch (prop_id) {
|
2013-08-22 11:45:59 +00:00
|
|
|
|
case PROP_DEVICE_NAME:
|
|
|
|
|
if (src->device_name) {
|
|
|
|
|
g_free (src->device_name);
|
|
|
|
|
src->device_name = NULL;
|
|
|
|
|
}
|
|
|
|
|
if (g_value_get_string (value)) {
|
|
|
|
|
src->device_name = g_strdup (g_value_get_string (value));
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-31 09:53:55 +00:00
|
|
|
|
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));
|
2009-08-10 09:36:41 +00:00
|
|
|
|
break;
|
2009-07-29 13:35:03 +00:00
|
|
|
|
default:
|
2009-08-10 09:36:41 +00:00
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-29 13:35:03 +00:00
|
|
|
|
|
2009-08-10 09:36:41 +00:00
|
|
|
|
static void
|
2009-07-29 13:35:03 +00:00
|
|
|
|
gst_directsound_src_get_property (GObject * object, guint prop_id,
|
2009-08-10 09:36:41 +00:00
|
|
|
|
GValue * value, GParamSpec * pspec)
|
2009-07-29 13:35:03 +00:00
|
|
|
|
{
|
2009-08-10 09:36:41 +00:00
|
|
|
|
GstDirectSoundSrc *src = GST_DIRECTSOUND_SRC (object);
|
|
|
|
|
|
2012-04-03 09:09:19 +00:00
|
|
|
|
GST_DEBUG ("get property");
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
switch (prop_id) {
|
2013-08-22 11:45:59 +00:00
|
|
|
|
case PROP_DEVICE_NAME:
|
|
|
|
|
g_value_set_string (value, src->device_name);
|
2009-08-10 09:36:41 +00:00
|
|
|
|
break;
|
2015-03-31 09:53:55 +00:00
|
|
|
|
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;
|
2009-07-29 13:35:03 +00:00
|
|
|
|
default:
|
2009-08-10 09:36:41 +00:00
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* initialize the new element
|
|
|
|
|
* instantiate pads and add them to element
|
|
|
|
|
* set functions
|
|
|
|
|
* initialize structure
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2012-04-03 09:09:19 +00:00
|
|
|
|
gst_directsound_src_init (GstDirectSoundSrc * src)
|
2009-07-29 13:35:03 +00:00
|
|
|
|
{
|
2012-04-03 09:09:19 +00:00
|
|
|
|
GST_DEBUG_OBJECT (src, "initializing directsoundsrc");
|
2012-10-25 15:10:40 +00:00
|
|
|
|
g_mutex_init (&src->dsound_lock);
|
2013-08-22 11:45:59 +00:00
|
|
|
|
src->device_guid = NULL;
|
|
|
|
|
src->device_name = NULL;
|
2015-03-31 09:53:55 +00:00
|
|
|
|
src->mixer = NULL;
|
|
|
|
|
src->control_id_mute = -1;
|
|
|
|
|
src->control_id_volume = -1;
|
|
|
|
|
src->volume = 100;
|
|
|
|
|
src->mute = FALSE;
|
2013-08-22 11:45:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Enumeration callback called by DirectSoundCaptureEnumerate.
|
|
|
|
|
* Gets the GUID of request audio device
|
|
|
|
|
*/
|
|
|
|
|
static BOOL CALLBACK
|
2013-08-22 15:32:17 +00:00
|
|
|
|
gst_directsound_enum_callback (GUID * pGUID, TCHAR * strDesc,
|
|
|
|
|
TCHAR * strDrvName, VOID * pContext)
|
2013-08-22 11:45:59 +00:00
|
|
|
|
{
|
|
|
|
|
GstDirectSoundSrc *dsoundsrc = GST_DIRECTSOUND_SRC (pContext);
|
|
|
|
|
|
2013-08-22 15:32:17 +00:00
|
|
|
|
if (pGUID && dsoundsrc && dsoundsrc->device_name &&
|
|
|
|
|
!g_strcmp0 (dsoundsrc->device_name, strDesc)) {
|
|
|
|
|
g_free (dsoundsrc->device_guid);
|
|
|
|
|
dsoundsrc->device_guid = (GUID *) g_malloc0 (sizeof (GUID));
|
|
|
|
|
memcpy (dsoundsrc->device_guid, pGUID, sizeof (GUID));
|
|
|
|
|
GST_INFO_OBJECT (dsoundsrc, "found the requested audio device :%s",
|
|
|
|
|
dsoundsrc->device_name);
|
2013-08-22 11:45:59 +00:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-22 15:32:17 +00:00
|
|
|
|
GST_INFO_OBJECT (dsoundsrc, "sound device names: %s, %s, requested device:%s",
|
|
|
|
|
strDesc, strDrvName, dsoundsrc->device_name);
|
2013-08-22 11:45:59 +00:00
|
|
|
|
|
|
|
|
|
return TRUE;
|
2009-08-10 09:36:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
gst_directsound_src_open (GstAudioSrc * asrc)
|
2009-07-29 13:35:03 +00:00
|
|
|
|
{
|
2009-08-10 09:36:41 +00:00
|
|
|
|
GstDirectSoundSrc *dsoundsrc;
|
|
|
|
|
HRESULT hRes; /* Result for windows functions */
|
|
|
|
|
|
2012-04-03 09:09:19 +00:00
|
|
|
|
GST_DEBUG_OBJECT (asrc, "opening directsoundsrc");
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
dsoundsrc = GST_DIRECTSOUND_SRC (asrc);
|
|
|
|
|
|
|
|
|
|
/* Open dsound.dll */
|
|
|
|
|
dsoundsrc->DSoundDLL = LoadLibrary ("dsound.dll");
|
|
|
|
|
if (!dsoundsrc->DSoundDLL) {
|
|
|
|
|
goto dsound_open;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Building the DLL Calls */
|
|
|
|
|
pDSoundCaptureCreate =
|
2009-07-29 13:35:03 +00:00
|
|
|
|
(void *) GetProcAddress (dsoundsrc->DSoundDLL,
|
2009-08-10 09:36:41 +00:00
|
|
|
|
TEXT ("DirectSoundCaptureCreate"));
|
|
|
|
|
|
|
|
|
|
/* If everything is not ok */
|
|
|
|
|
if (!pDSoundCaptureCreate) {
|
|
|
|
|
goto capture_function;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-22 15:32:17 +00:00
|
|
|
|
hRes = DirectSoundCaptureEnumerate ((LPDSENUMCALLBACK)
|
|
|
|
|
gst_directsound_enum_callback, (VOID *) dsoundsrc);
|
2013-08-22 11:45:59 +00:00
|
|
|
|
if (FAILED (hRes)) {
|
|
|
|
|
goto capture_enumerate;
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-10 09:36:41 +00:00
|
|
|
|
/* Create capture object */
|
2013-08-22 11:45:59 +00:00
|
|
|
|
hRes = pDSoundCaptureCreate (dsoundsrc->device_guid, &dsoundsrc->pDSC, NULL);
|
2009-08-10 09:36:41 +00:00
|
|
|
|
if (FAILED (hRes)) {
|
|
|
|
|
goto capture_object;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-31 09:53:55 +00:00
|
|
|
|
gst_directsound_src_mixer_init (dsoundsrc);
|
2009-08-10 09:36:41 +00:00
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
capture_function:
|
|
|
|
|
{
|
|
|
|
|
FreeLibrary (dsoundsrc->DSoundDLL);
|
|
|
|
|
GST_ELEMENT_ERROR (dsoundsrc, RESOURCE, OPEN_READ,
|
2009-07-29 13:35:03 +00:00
|
|
|
|
("Unable to get capturecreate function"), (NULL));
|
2009-08-10 09:36:41 +00:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2013-08-22 11:45:59 +00:00
|
|
|
|
capture_enumerate:
|
|
|
|
|
{
|
|
|
|
|
FreeLibrary (dsoundsrc->DSoundDLL);
|
|
|
|
|
GST_ELEMENT_ERROR (dsoundsrc, RESOURCE, OPEN_READ,
|
|
|
|
|
("Unable to enumerate audio capture devices"), (NULL));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2009-08-10 09:36:41 +00:00
|
|
|
|
capture_object:
|
|
|
|
|
{
|
|
|
|
|
FreeLibrary (dsoundsrc->DSoundDLL);
|
|
|
|
|
GST_ELEMENT_ERROR (dsoundsrc, RESOURCE, OPEN_READ,
|
2009-07-29 13:35:03 +00:00
|
|
|
|
("Unable to create capture object"), (NULL));
|
2009-08-10 09:36:41 +00:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
dsound_open:
|
|
|
|
|
{
|
|
|
|
|
DWORD err = GetLastError ();
|
|
|
|
|
GST_ELEMENT_ERROR (dsoundsrc, RESOURCE, OPEN_READ,
|
2009-07-29 13:35:03 +00:00
|
|
|
|
("Unable to open dsound.dll"), (NULL));
|
2010-04-30 21:16:50 +00:00
|
|
|
|
g_print ("0x%lx\n", HRESULT_FROM_WIN32 (err));
|
2009-08-10 09:36:41 +00:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-29 13:35:03 +00:00
|
|
|
|
|
2009-08-10 09:36:41 +00:00
|
|
|
|
static gboolean
|
|
|
|
|
gst_directsound_src_close (GstAudioSrc * asrc)
|
2009-07-29 13:35:03 +00:00
|
|
|
|
{
|
2009-08-10 09:36:41 +00:00
|
|
|
|
GstDirectSoundSrc *dsoundsrc;
|
|
|
|
|
|
2012-04-03 09:09:19 +00:00
|
|
|
|
GST_DEBUG_OBJECT (asrc, "closing directsoundsrc");
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
dsoundsrc = GST_DIRECTSOUND_SRC (asrc);
|
|
|
|
|
|
|
|
|
|
/* Release capture handler */
|
2012-10-25 15:10:40 +00:00
|
|
|
|
IDirectSoundCapture_Release (dsoundsrc->pDSC);
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
/* Close library */
|
|
|
|
|
FreeLibrary (dsoundsrc->DSoundDLL);
|
|
|
|
|
|
2015-03-31 09:53:55 +00:00
|
|
|
|
if (dsoundsrc->mixer)
|
|
|
|
|
mixerClose (dsoundsrc->mixer);
|
|
|
|
|
|
2009-08-10 09:36:41 +00:00
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
2012-04-03 09:09:19 +00:00
|
|
|
|
gst_directsound_src_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec)
|
2009-07-29 13:35:03 +00:00
|
|
|
|
{
|
2009-08-10 09:36:41 +00:00
|
|
|
|
GstDirectSoundSrc *dsoundsrc;
|
|
|
|
|
WAVEFORMATEX wfx; /* Wave format structure */
|
|
|
|
|
HRESULT hRes; /* Result for windows functions */
|
2012-04-03 09:09:19 +00:00
|
|
|
|
DSCBUFFERDESC descSecondary; /* Capturebuffer description */
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
dsoundsrc = GST_DIRECTSOUND_SRC (asrc);
|
|
|
|
|
|
2012-04-03 09:09:19 +00:00
|
|
|
|
GST_DEBUG_OBJECT (asrc, "preparing directsoundsrc");
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
/* Define buffer */
|
|
|
|
|
memset (&wfx, 0, sizeof (WAVEFORMATEX));
|
2012-04-03 09:09:19 +00:00
|
|
|
|
wfx.wFormatTag = WAVE_FORMAT_PCM;
|
|
|
|
|
wfx.nChannels = GST_AUDIO_INFO_CHANNELS (&spec->info);
|
|
|
|
|
wfx.nSamplesPerSec = GST_AUDIO_INFO_RATE (&spec->info);
|
|
|
|
|
wfx.wBitsPerSample = GST_AUDIO_INFO_BPF (&spec->info) * 8 / wfx.nChannels;
|
|
|
|
|
wfx.nBlockAlign = GST_AUDIO_INFO_BPF (&spec->info);
|
2009-08-10 09:36:41 +00:00
|
|
|
|
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
|
2012-04-03 09:09:19 +00:00
|
|
|
|
/* Ignored for WAVE_FORMAT_PCM. */
|
|
|
|
|
wfx.cbSize = 0;
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
2012-04-03 09:09:19 +00:00
|
|
|
|
if (wfx.wBitsPerSample != 16 && wfx.wBitsPerSample != 8)
|
|
|
|
|
goto dodgy_width;
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
/* Set the buffer size to two seconds.
|
|
|
|
|
This should never reached.
|
|
|
|
|
*/
|
|
|
|
|
dsoundsrc->buffer_size = wfx.nAvgBytesPerSec * 2;
|
|
|
|
|
|
2012-04-03 09:09:19 +00:00
|
|
|
|
GST_DEBUG_OBJECT (asrc, "Buffer size: %d", dsoundsrc->buffer_size);
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
/* Init secondary buffer desciption */
|
|
|
|
|
memset (&descSecondary, 0, sizeof (DSCBUFFERDESC));
|
|
|
|
|
descSecondary.dwSize = sizeof (DSCBUFFERDESC);
|
|
|
|
|
descSecondary.dwFlags = 0;
|
|
|
|
|
descSecondary.dwReserved = 0;
|
|
|
|
|
|
|
|
|
|
/* This is not primary buffer so have to set size */
|
|
|
|
|
descSecondary.dwBufferBytes = dsoundsrc->buffer_size;
|
|
|
|
|
descSecondary.lpwfxFormat = &wfx;
|
|
|
|
|
|
|
|
|
|
/* Create buffer */
|
|
|
|
|
hRes = IDirectSoundCapture_CreateCaptureBuffer (dsoundsrc->pDSC,
|
|
|
|
|
&descSecondary, &dsoundsrc->pDSBSecondary, NULL);
|
2012-04-03 09:09:19 +00:00
|
|
|
|
if (hRes != DS_OK)
|
2009-08-10 09:36:41 +00:00
|
|
|
|
goto capture_buffer;
|
|
|
|
|
|
2012-04-03 09:09:19 +00:00
|
|
|
|
dsoundsrc->bytes_per_sample = GST_AUDIO_INFO_BPF (&spec->info);
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
2012-07-03 10:57:58 +00:00
|
|
|
|
GST_DEBUG ("latency time: %" G_GUINT64_FORMAT " - buffer time: %"
|
|
|
|
|
G_GUINT64_FORMAT, spec->latency_time, spec->buffer_time);
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
2012-04-03 09:09:19 +00:00
|
|
|
|
/* Buffer-time should be always more than 2*latency */
|
2009-08-10 09:36:41 +00:00
|
|
|
|
if (spec->buffer_time < spec->latency_time * 2) {
|
|
|
|
|
spec->buffer_time = spec->latency_time * 2;
|
|
|
|
|
GST_WARNING ("buffer-time was less than latency");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Save the times */
|
|
|
|
|
dsoundsrc->buffer_time = spec->buffer_time;
|
|
|
|
|
dsoundsrc->latency_time = spec->latency_time;
|
|
|
|
|
|
|
|
|
|
dsoundsrc->latency_size = (gint) wfx.nAvgBytesPerSec *
|
|
|
|
|
dsoundsrc->latency_time / 1000000.0;
|
|
|
|
|
|
|
|
|
|
spec->segsize = (guint) (((double) spec->buffer_time / 1000000.0) *
|
|
|
|
|
wfx.nAvgBytesPerSec);
|
|
|
|
|
|
|
|
|
|
/* just in case */
|
|
|
|
|
if (spec->segsize < 1)
|
|
|
|
|
spec->segsize = 1;
|
|
|
|
|
|
2012-04-03 09:09:19 +00:00
|
|
|
|
spec->segtotal = GST_AUDIO_INFO_BPF (&spec->info) * 8 *
|
|
|
|
|
(wfx.nAvgBytesPerSec / spec->segsize);
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
2012-04-03 09:09:19 +00:00
|
|
|
|
GST_DEBUG_OBJECT (asrc,
|
|
|
|
|
"bytes/sec: %lu, buffer size: %d, segsize: %d, segtotal: %d",
|
|
|
|
|
wfx.nAvgBytesPerSec, dsoundsrc->buffer_size, spec->segsize,
|
|
|
|
|
spec->segtotal);
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
2012-04-03 09:09:19 +00:00
|
|
|
|
/* Not read anything yet */
|
2009-08-10 09:36:41 +00:00
|
|
|
|
dsoundsrc->current_circular_offset = 0;
|
|
|
|
|
|
2012-04-03 09:09:19 +00:00
|
|
|
|
GST_DEBUG_OBJECT (asrc, "channels: %d, rate: %d, bytes_per_sample: %d"
|
|
|
|
|
" WAVEFORMATEX.nSamplesPerSec: %ld, WAVEFORMATEX.wBitsPerSample: %d,"
|
|
|
|
|
" WAVEFORMATEX.nBlockAlign: %d, WAVEFORMATEX.nAvgBytesPerSec: %ld",
|
|
|
|
|
GST_AUDIO_INFO_CHANNELS (&spec->info), GST_AUDIO_INFO_RATE (&spec->info),
|
|
|
|
|
GST_AUDIO_INFO_BPF (&spec->info), wfx.nSamplesPerSec, wfx.wBitsPerSample,
|
|
|
|
|
wfx.nBlockAlign, wfx.nAvgBytesPerSec);
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
capture_buffer:
|
|
|
|
|
{
|
|
|
|
|
GST_ELEMENT_ERROR (dsoundsrc, RESOURCE, OPEN_READ,
|
2009-07-29 13:35:03 +00:00
|
|
|
|
("Unable to create capturebuffer"), (NULL));
|
2009-08-10 09:36:41 +00:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
dodgy_width:
|
|
|
|
|
{
|
|
|
|
|
GST_ELEMENT_ERROR (dsoundsrc, RESOURCE, OPEN_READ,
|
2012-04-03 09:09:19 +00:00
|
|
|
|
("Unexpected width %d", wfx.wBitsPerSample), (NULL));
|
2009-08-10 09:36:41 +00:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
gst_directsound_src_unprepare (GstAudioSrc * asrc)
|
2009-07-29 13:35:03 +00:00
|
|
|
|
{
|
2009-08-10 09:36:41 +00:00
|
|
|
|
GstDirectSoundSrc *dsoundsrc;
|
|
|
|
|
|
2012-04-03 09:09:19 +00:00
|
|
|
|
GST_DEBUG_OBJECT (asrc, "unpreparing directsoundsrc");
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
dsoundsrc = GST_DIRECTSOUND_SRC (asrc);
|
|
|
|
|
|
|
|
|
|
/* Stop capturing */
|
2012-10-25 15:10:40 +00:00
|
|
|
|
IDirectSoundCaptureBuffer_Stop (dsoundsrc->pDSBSecondary);
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
/* Release buffer */
|
2012-10-25 15:10:40 +00:00
|
|
|
|
IDirectSoundCaptureBuffer_Release (dsoundsrc->pDSBSecondary);
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
return number of readed bytes */
|
|
|
|
|
static guint
|
2012-10-17 19:54:28 +00:00
|
|
|
|
gst_directsound_src_read (GstAudioSrc * asrc, gpointer data, guint length,
|
|
|
|
|
GstClockTime * timestamp)
|
2009-07-29 13:35:03 +00:00
|
|
|
|
{
|
2009-08-10 09:36:41 +00:00
|
|
|
|
GstDirectSoundSrc *dsoundsrc;
|
|
|
|
|
|
|
|
|
|
HRESULT hRes; /* Result for windows functions */
|
|
|
|
|
DWORD dwCurrentCaptureCursor = 0;
|
|
|
|
|
DWORD dwBufferSize = 0;
|
|
|
|
|
|
|
|
|
|
LPVOID pLockedBuffer1 = NULL;
|
|
|
|
|
LPVOID pLockedBuffer2 = NULL;
|
|
|
|
|
DWORD dwSizeBuffer1 = 0;
|
|
|
|
|
DWORD dwSizeBuffer2 = 0;
|
|
|
|
|
|
|
|
|
|
DWORD dwStatus = 0;
|
|
|
|
|
|
2012-04-03 09:09:19 +00:00
|
|
|
|
GST_DEBUG_OBJECT (asrc, "reading directsoundsrc");
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
dsoundsrc = GST_DIRECTSOUND_SRC (asrc);
|
|
|
|
|
|
|
|
|
|
GST_DSOUND_LOCK (dsoundsrc);
|
|
|
|
|
|
|
|
|
|
/* Get current buffer status */
|
|
|
|
|
hRes = IDirectSoundCaptureBuffer_GetStatus (dsoundsrc->pDSBSecondary,
|
|
|
|
|
&dwStatus);
|
|
|
|
|
|
2012-04-03 09:09:19 +00:00
|
|
|
|
/* Starting capturing if not already */
|
2009-08-10 09:36:41 +00:00
|
|
|
|
if (!(dwStatus & DSCBSTATUS_CAPTURING)) {
|
|
|
|
|
hRes = IDirectSoundCaptureBuffer_Start (dsoundsrc->pDSBSecondary,
|
|
|
|
|
DSCBSTART_LOOPING);
|
|
|
|
|
// Sleep (dsoundsrc->latency_time/1000);
|
2012-04-03 09:09:19 +00:00
|
|
|
|
GST_DEBUG_OBJECT (asrc, "capture started");
|
2009-08-10 09:36:41 +00:00
|
|
|
|
}
|
|
|
|
|
// calculate_buffersize:
|
|
|
|
|
while (length > dwBufferSize) {
|
|
|
|
|
Sleep (dsoundsrc->latency_time / 1000);
|
|
|
|
|
|
|
|
|
|
hRes =
|
|
|
|
|
IDirectSoundCaptureBuffer_GetCurrentPosition (dsoundsrc->pDSBSecondary,
|
|
|
|
|
&dwCurrentCaptureCursor, NULL);
|
|
|
|
|
|
|
|
|
|
/* calculate the buffer */
|
|
|
|
|
if (dwCurrentCaptureCursor < dsoundsrc->current_circular_offset) {
|
|
|
|
|
dwBufferSize = dsoundsrc->buffer_size -
|
|
|
|
|
(dsoundsrc->current_circular_offset - dwCurrentCaptureCursor);
|
|
|
|
|
} else {
|
|
|
|
|
dwBufferSize =
|
|
|
|
|
dwCurrentCaptureCursor - dsoundsrc->current_circular_offset;
|
|
|
|
|
}
|
|
|
|
|
} // while (...
|
|
|
|
|
|
|
|
|
|
/* Lock the buffer */
|
|
|
|
|
hRes = IDirectSoundCaptureBuffer_Lock (dsoundsrc->pDSBSecondary,
|
|
|
|
|
dsoundsrc->current_circular_offset,
|
|
|
|
|
length,
|
|
|
|
|
&pLockedBuffer1, &dwSizeBuffer1, &pLockedBuffer2, &dwSizeBuffer2, 0L);
|
|
|
|
|
|
|
|
|
|
/* Copy buffer data to another buffer */
|
|
|
|
|
if (hRes == DS_OK) {
|
|
|
|
|
memcpy (data, pLockedBuffer1, dwSizeBuffer1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ...and if something is in another buffer */
|
|
|
|
|
if (pLockedBuffer2 != NULL) {
|
|
|
|
|
memcpy (((guchar *) data + dwSizeBuffer1), pLockedBuffer2, dwSizeBuffer2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dsoundsrc->current_circular_offset += dwSizeBuffer1 + dwSizeBuffer2;
|
|
|
|
|
dsoundsrc->current_circular_offset %= dsoundsrc->buffer_size;
|
|
|
|
|
|
|
|
|
|
IDirectSoundCaptureBuffer_Unlock (dsoundsrc->pDSBSecondary,
|
|
|
|
|
pLockedBuffer1, dwSizeBuffer1, pLockedBuffer2, dwSizeBuffer2);
|
|
|
|
|
|
|
|
|
|
GST_DSOUND_UNLOCK (dsoundsrc);
|
|
|
|
|
|
|
|
|
|
/* return length (readed data size in bytes) */
|
|
|
|
|
return length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static guint
|
|
|
|
|
gst_directsound_src_delay (GstAudioSrc * asrc)
|
2009-07-29 13:35:03 +00:00
|
|
|
|
{
|
2009-08-10 09:36:41 +00:00
|
|
|
|
GstDirectSoundSrc *dsoundsrc;
|
|
|
|
|
HRESULT hRes;
|
|
|
|
|
DWORD dwCurrentCaptureCursor;
|
|
|
|
|
DWORD dwBytesInQueue = 0;
|
|
|
|
|
gint nNbSamplesInQueue = 0;
|
|
|
|
|
|
2012-04-03 09:09:19 +00:00
|
|
|
|
GST_DEBUG_OBJECT (asrc, "Delay");
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
dsoundsrc = GST_DIRECTSOUND_SRC (asrc);
|
|
|
|
|
|
|
|
|
|
/* evaluate the number of samples in queue in the circular buffer */
|
|
|
|
|
hRes =
|
|
|
|
|
IDirectSoundCaptureBuffer_GetCurrentPosition (dsoundsrc->pDSBSecondary,
|
|
|
|
|
&dwCurrentCaptureCursor, NULL);
|
|
|
|
|
/* FIXME: Check is this calculated right */
|
|
|
|
|
if (hRes == S_OK) {
|
|
|
|
|
if (dwCurrentCaptureCursor < dsoundsrc->current_circular_offset) {
|
|
|
|
|
dwBytesInQueue =
|
|
|
|
|
dsoundsrc->buffer_size - (dsoundsrc->current_circular_offset -
|
|
|
|
|
dwCurrentCaptureCursor);
|
|
|
|
|
} else {
|
|
|
|
|
dwBytesInQueue =
|
|
|
|
|
dwCurrentCaptureCursor - dsoundsrc->current_circular_offset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nNbSamplesInQueue = dwBytesInQueue / dsoundsrc->bytes_per_sample;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nNbSamplesInQueue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gst_directsound_src_reset (GstAudioSrc * asrc)
|
2009-07-29 13:35:03 +00:00
|
|
|
|
{
|
2009-08-10 09:36:41 +00:00
|
|
|
|
GstDirectSoundSrc *dsoundsrc;
|
|
|
|
|
LPVOID pLockedBuffer = NULL;
|
|
|
|
|
DWORD dwSizeBuffer = 0;
|
|
|
|
|
|
2012-04-03 09:09:19 +00:00
|
|
|
|
GST_DEBUG_OBJECT (asrc, "reset directsoundsrc");
|
2009-08-10 09:36:41 +00:00
|
|
|
|
|
|
|
|
|
dsoundsrc = GST_DIRECTSOUND_SRC (asrc);
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
IDirectSoundCaptureBuffer_Stop (dsoundsrc->pDSBSecondary);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
GST_DSOUND_LOCK (dsoundsrc);
|
|
|
|
|
|
|
|
|
|
if (dsoundsrc->pDSBSecondary) {
|
|
|
|
|
/*stop capturing */
|
|
|
|
|
HRESULT hRes = IDirectSoundCaptureBuffer_Stop (dsoundsrc->pDSBSecondary);
|
|
|
|
|
|
|
|
|
|
/*reset position */
|
|
|
|
|
/* hRes = IDirectSoundCaptureBuffer_SetCurrentPosition (dsoundsrc->pDSBSecondary, 0); */
|
|
|
|
|
|
|
|
|
|
/*reset the buffer */
|
|
|
|
|
hRes = IDirectSoundCaptureBuffer_Lock (dsoundsrc->pDSBSecondary,
|
|
|
|
|
dsoundsrc->current_circular_offset, dsoundsrc->buffer_size,
|
|
|
|
|
pLockedBuffer, &dwSizeBuffer, NULL, NULL, 0L);
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED (hRes)) {
|
|
|
|
|
memset (pLockedBuffer, 0, dwSizeBuffer);
|
|
|
|
|
|
|
|
|
|
hRes =
|
|
|
|
|
IDirectSoundCaptureBuffer_Unlock (dsoundsrc->pDSBSecondary,
|
|
|
|
|
pLockedBuffer, dwSizeBuffer, NULL, 0);
|
|
|
|
|
}
|
|
|
|
|
dsoundsrc->current_circular_offset = 0;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GST_DSOUND_UNLOCK (dsoundsrc);
|
|
|
|
|
}
|
2015-03-31 09:53:55 +00:00
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
2015-09-09 04:58:05 +00:00
|
|
|
|
mmres = mixerGetDevCaps (GPOINTER_TO_UINT (dsoundsrc->mixer),
|
2015-03-31 09:53:55 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|