gstreamer/sys/wasapi2/gstwasapi2ringbuffer.cpp

1413 lines
40 KiB
C++
Raw Normal View History

wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
/* GStreamer
* Copyright (C) 2021 Seungha Yang <seungha@centricular.com>
*
* 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
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "gstwasapi2ringbuffer.h"
#include <string.h>
#include <mfapi.h>
#include <wrl.h>
GST_DEBUG_CATEGORY_STATIC (gst_wasapi2_ring_buffer_debug);
#define GST_CAT_DEFAULT gst_wasapi2_ring_buffer_debug
static HRESULT gst_wasapi2_ring_buffer_io_callback (GstWasapi2RingBuffer * buf);
static HRESULT
gst_wasapi2_ring_buffer_loopback_callback (GstWasapi2RingBuffer * buf);
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
/* *INDENT-OFF* */
using namespace Microsoft::WRL;
class GstWasapiAsyncCallback : public IMFAsyncCallback
{
public:
GstWasapiAsyncCallback(GstWasapi2RingBuffer *listener,
DWORD queue_id,
gboolean loopback)
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
: ref_count_(1)
, queue_id_(queue_id)
, loopback_(loopback)
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
{
g_weak_ref_init (&listener_, listener);
}
virtual ~GstWasapiAsyncCallback ()
{
g_weak_ref_set (&listener_, nullptr);
}
/* IUnknown */
STDMETHODIMP_ (ULONG)
AddRef (void)
{
GST_TRACE ("%p, %d", this, ref_count_);
return InterlockedIncrement (&ref_count_);
}
STDMETHODIMP_ (ULONG)
Release (void)
{
ULONG ref_count;
GST_TRACE ("%p, %d", this, ref_count_);
ref_count = InterlockedDecrement (&ref_count_);
if (ref_count == 0) {
GST_TRACE ("Delete instance %p", this);
delete this;
}
return ref_count;
}
STDMETHODIMP
QueryInterface (REFIID riid, void ** object)
{
if (!object)
return E_POINTER;
if (riid == IID_IUnknown) {
GST_TRACE ("query IUnknown interface %p", this);
*object = static_cast<IUnknown *> (static_cast<GstWasapiAsyncCallback *> (this));
} else if (riid == __uuidof (IMFAsyncCallback)) {
GST_TRACE ("query IUnknown interface %p", this);
*object = static_cast<IUnknown *> (static_cast<GstWasapiAsyncCallback *> (this));
} else {
*object = nullptr;
return E_NOINTERFACE;
}
AddRef ();
return S_OK;
}
/* IMFAsyncCallback */
STDMETHODIMP
GetParameters(DWORD * pdwFlags, DWORD * pdwQueue)
{
*pdwFlags = 0;
*pdwQueue = queue_id_;
return S_OK;
}
STDMETHODIMP
Invoke(IMFAsyncResult * pAsyncResult)
{
GstWasapi2RingBuffer *ringbuffer;
HRESULT hr;
ringbuffer = (GstWasapi2RingBuffer *) g_weak_ref_get (&listener_);
if (!ringbuffer) {
GST_WARNING ("Listener was removed");
return S_OK;
}
if (loopback_)
hr = gst_wasapi2_ring_buffer_loopback_callback (ringbuffer);
else
hr = gst_wasapi2_ring_buffer_io_callback (ringbuffer);
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
gst_object_unref (ringbuffer);
return hr;
}
private:
ULONG ref_count_;
DWORD queue_id_;
GWeakRef listener_;
gboolean loopback_;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
};
/* *INDENT-ON* */
struct _GstWasapi2RingBuffer
{
GstAudioRingBuffer parent;
GstWasapi2ClientDeviceClass device_class;
gchar *device_id;
gboolean low_latency;
gboolean mute;
gdouble volume;
gpointer dispatcher;
gboolean can_auto_routing;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
GstWasapi2Client *client;
GstWasapi2Client *loopback_client;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
IAudioCaptureClient *capture_client;
IAudioRenderClient *render_client;
ISimpleAudioVolume *volume_object;
GstWasapiAsyncCallback *callback_object;
IMFAsyncResult *callback_result;
MFWORKITEM_KEY callback_key;
HANDLE event_handle;
GstWasapiAsyncCallback *loopback_callback_object;
IMFAsyncResult *loopback_callback_result;
MFWORKITEM_KEY loopback_callback_key;
HANDLE loopback_event_handle;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
guint64 expected_position;
gboolean is_first;
gboolean running;
UINT32 buffer_size;
UINT32 loopback_buffer_size;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
gint segoffset;
guint64 write_frame_offset;
GMutex volume_lock;
gboolean mute_changed;
gboolean volume_changed;
};
static void gst_wasapi2_ring_buffer_constructed (GObject * object);
static void gst_wasapi2_ring_buffer_dispose (GObject * object);
static void gst_wasapi2_ring_buffer_finalize (GObject * object);
static gboolean gst_wasapi2_ring_buffer_open_device (GstAudioRingBuffer * buf);
static gboolean gst_wasapi2_ring_buffer_close_device (GstAudioRingBuffer * buf);
static gboolean gst_wasapi2_ring_buffer_acquire (GstAudioRingBuffer * buf,
GstAudioRingBufferSpec * spec);
static gboolean gst_wasapi2_ring_buffer_release (GstAudioRingBuffer * buf);
static gboolean gst_wasapi2_ring_buffer_start (GstAudioRingBuffer * buf);
static gboolean gst_wasapi2_ring_buffer_resume (GstAudioRingBuffer * buf);
static gboolean gst_wasapi2_ring_buffer_pause (GstAudioRingBuffer * buf);
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
static gboolean gst_wasapi2_ring_buffer_stop (GstAudioRingBuffer * buf);
static guint gst_wasapi2_ring_buffer_delay (GstAudioRingBuffer * buf);
#define gst_wasapi2_ring_buffer_parent_class parent_class
G_DEFINE_TYPE (GstWasapi2RingBuffer, gst_wasapi2_ring_buffer,
GST_TYPE_AUDIO_RING_BUFFER);
static void
gst_wasapi2_ring_buffer_class_init (GstWasapi2RingBufferClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstAudioRingBufferClass *ring_buffer_class =
GST_AUDIO_RING_BUFFER_CLASS (klass);
gobject_class->constructed = gst_wasapi2_ring_buffer_constructed;
gobject_class->dispose = gst_wasapi2_ring_buffer_dispose;
gobject_class->finalize = gst_wasapi2_ring_buffer_finalize;
ring_buffer_class->open_device =
GST_DEBUG_FUNCPTR (gst_wasapi2_ring_buffer_open_device);
ring_buffer_class->close_device =
GST_DEBUG_FUNCPTR (gst_wasapi2_ring_buffer_close_device);
ring_buffer_class->acquire =
GST_DEBUG_FUNCPTR (gst_wasapi2_ring_buffer_acquire);
ring_buffer_class->release =
GST_DEBUG_FUNCPTR (gst_wasapi2_ring_buffer_release);
ring_buffer_class->start = GST_DEBUG_FUNCPTR (gst_wasapi2_ring_buffer_start);
ring_buffer_class->resume =
GST_DEBUG_FUNCPTR (gst_wasapi2_ring_buffer_resume);
ring_buffer_class->pause = GST_DEBUG_FUNCPTR (gst_wasapi2_ring_buffer_pause);
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
ring_buffer_class->stop = GST_DEBUG_FUNCPTR (gst_wasapi2_ring_buffer_stop);
ring_buffer_class->delay = GST_DEBUG_FUNCPTR (gst_wasapi2_ring_buffer_delay);
GST_DEBUG_CATEGORY_INIT (gst_wasapi2_ring_buffer_debug,
"wasapi2ringbuffer", 0, "wasapi2ringbuffer");
}
static void
gst_wasapi2_ring_buffer_init (GstWasapi2RingBuffer * self)
{
self->volume = 1.0f;
self->mute = FALSE;
self->event_handle = CreateEvent (nullptr, FALSE, FALSE, nullptr);
self->loopback_event_handle = CreateEvent (nullptr, FALSE, FALSE, nullptr);
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
g_mutex_init (&self->volume_lock);
}
static void
gst_wasapi2_ring_buffer_constructed (GObject * object)
{
GstWasapi2RingBuffer *self = GST_WASAPI2_RING_BUFFER (object);
HRESULT hr;
DWORD task_id = 0;
DWORD queue_id = 0;
hr = MFLockSharedWorkQueue (L"Pro Audio", 0, &task_id, &queue_id);
if (!gst_wasapi2_result (hr)) {
GST_WARNING_OBJECT (self, "Failed to get work queue id");
goto out;
}
self->callback_object = new GstWasapiAsyncCallback (self, queue_id, FALSE);
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
hr = MFCreateAsyncResult (nullptr, self->callback_object, nullptr,
&self->callback_result);
if (!gst_wasapi2_result (hr)) {
GST_WARNING_OBJECT (self, "Failed to create IAsyncResult");
GST_WASAPI2_CLEAR_COM (self->callback_object);
}
/* Create another callback object for loopback silence feed */
self->loopback_callback_object =
new GstWasapiAsyncCallback (self, queue_id, TRUE);
hr = MFCreateAsyncResult (nullptr, self->loopback_callback_object, nullptr,
&self->loopback_callback_result);
if (!gst_wasapi2_result (hr)) {
GST_WARNING_OBJECT (self, "Failed to create IAsyncResult");
GST_WASAPI2_CLEAR_COM (self->callback_object);
GST_WASAPI2_CLEAR_COM (self->callback_result);
GST_WASAPI2_CLEAR_COM (self->loopback_callback_object);
}
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
out:
G_OBJECT_CLASS (parent_class)->constructed (object);
}
static void
gst_wasapi2_ring_buffer_dispose (GObject * object)
{
GstWasapi2RingBuffer *self = GST_WASAPI2_RING_BUFFER (object);
GST_WASAPI2_CLEAR_COM (self->render_client);
GST_WASAPI2_CLEAR_COM (self->capture_client);
GST_WASAPI2_CLEAR_COM (self->volume_object);
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
GST_WASAPI2_CLEAR_COM (self->callback_result);
GST_WASAPI2_CLEAR_COM (self->callback_object);
GST_WASAPI2_CLEAR_COM (self->loopback_callback_result);
GST_WASAPI2_CLEAR_COM (self->loopback_callback_object);
gst_clear_object (&self->client);
gst_clear_object (&self->loopback_client);
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
gst_wasapi2_ring_buffer_finalize (GObject * object)
{
GstWasapi2RingBuffer *self = GST_WASAPI2_RING_BUFFER (object);
g_free (self->device_id);
CloseHandle (self->event_handle);
CloseHandle (self->loopback_event_handle);
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
g_mutex_clear (&self->volume_lock);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gst_wasapi2_ring_buffer_post_open_error (GstWasapi2RingBuffer * self)
{
GstElement *parent = (GstElement *) GST_OBJECT_PARENT (self);
if (!parent) {
GST_WARNING_OBJECT (self, "Cannot find parent");
return;
}
if (self->device_class == GST_WASAPI2_CLIENT_DEVICE_CLASS_RENDER) {
GST_ELEMENT_ERROR (parent, RESOURCE, OPEN_WRITE,
(nullptr), ("Failed to open device"));
} else {
GST_ELEMENT_ERROR (parent, RESOURCE, OPEN_READ,
(nullptr), ("Failed to open device"));
}
}
static void
gst_wasapi2_ring_buffer_post_scheduling_error (GstWasapi2RingBuffer * self)
{
GstElement *parent = (GstElement *) GST_OBJECT_PARENT (self);
if (!parent) {
GST_WARNING_OBJECT (self, "Cannot find parent");
return;
}
GST_ELEMENT_ERROR (parent, RESOURCE, FAILED,
(nullptr), ("Failed to schedule next I/O"));
}
static void
gst_wasapi2_ring_buffer_post_io_error (GstWasapi2RingBuffer * self, HRESULT hr)
{
GstElement *parent = (GstElement *) GST_OBJECT_PARENT (self);
gchar *error_msg;
if (!parent) {
GST_WARNING_OBJECT (self, "Cannot find parent");
return;
}
error_msg = gst_wasapi2_util_get_error_message (hr);
GST_ERROR_OBJECT (self, "Posting I/O error %s (hr: 0x%x)", error_msg, hr);
if (self->device_class == GST_WASAPI2_CLIENT_DEVICE_CLASS_RENDER) {
GST_ELEMENT_ERROR (parent, RESOURCE, WRITE,
("Failed to write to device"), ("%s, hr: 0x%x", error_msg, hr));
} else {
GST_ELEMENT_ERROR (parent, RESOURCE, READ,
("Failed to read from device"), ("%s hr: 0x%x", error_msg, hr));
}
g_free (error_msg);
}
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
static gboolean
gst_wasapi2_ring_buffer_open_device (GstAudioRingBuffer * buf)
{
GstWasapi2RingBuffer *self = GST_WASAPI2_RING_BUFFER (buf);
GST_DEBUG_OBJECT (self, "Open");
self->client = gst_wasapi2_client_new (self->device_class,
-1, self->device_id, self->dispatcher);
if (!self->client) {
gst_wasapi2_ring_buffer_post_open_error (self);
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
return FALSE;
}
g_object_get (self->client, "auto-routing", &self->can_auto_routing, nullptr);
/* Open another render client to feed silence */
if (self->device_class == GST_WASAPI2_CLIENT_DEVICE_CLASS_LOOPBACK_CAPTURE) {
self->loopback_client =
gst_wasapi2_client_new (GST_WASAPI2_CLIENT_DEVICE_CLASS_RENDER,
-1, self->device_id, self->dispatcher);
if (!self->loopback_client) {
gst_wasapi2_ring_buffer_post_open_error (self);
gst_clear_object (&self->client);
return FALSE;
}
}
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
return TRUE;
}
static gboolean
gst_wasapi2_ring_buffer_close_device (GstAudioRingBuffer * buf)
{
GstWasapi2RingBuffer *self = GST_WASAPI2_RING_BUFFER (buf);
GST_DEBUG_OBJECT (self, "Close");
if (self->running)
gst_wasapi2_ring_buffer_stop (buf);
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
GST_WASAPI2_CLEAR_COM (self->capture_client);
GST_WASAPI2_CLEAR_COM (self->render_client);
g_mutex_lock (&self->volume_lock);
if (self->volume_object)
self->volume_object->SetMute (FALSE, nullptr);
GST_WASAPI2_CLEAR_COM (self->volume_object);
g_mutex_unlock (&self->volume_lock);
gst_clear_object (&self->client);
gst_clear_object (&self->loopback_client);
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
return TRUE;
}
static HRESULT
gst_wasapi2_ring_buffer_read (GstWasapi2RingBuffer * self)
{
GstAudioRingBuffer *ringbuffer = GST_AUDIO_RING_BUFFER_CAST (self);
BYTE *data = nullptr;
UINT32 to_read = 0;
guint32 to_read_bytes;
DWORD flags = 0;
HRESULT hr;
guint64 position;
GstAudioInfo *info = &ringbuffer->spec.info;
IAudioCaptureClient *capture_client = self->capture_client;
guint gap_size = 0;
guint offset = 0;
gint segment;
guint8 *readptr;
gint len;
if (!capture_client) {
GST_ERROR_OBJECT (self, "IAudioCaptureClient is not available");
return E_FAIL;
}
hr = capture_client->GetBuffer (&data, &to_read, &flags, &position, nullptr);
if (hr == AUDCLNT_S_BUFFER_EMPTY || to_read == 0) {
GST_LOG_OBJECT (self, "Empty buffer");
to_read = 0;
goto out;
}
to_read_bytes = to_read * GST_AUDIO_INFO_BPF (info);
GST_LOG_OBJECT (self, "Reading %d frames offset at %" G_GUINT64_FORMAT
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
", expected position %" G_GUINT64_FORMAT, to_read, position,
self->expected_position);
if (self->is_first) {
self->expected_position = position + to_read;
self->is_first = FALSE;
} else {
if (position > self->expected_position) {
guint gap_frames;
gap_frames = (guint) (position - self->expected_position);
GST_WARNING_OBJECT (self, "Found %u frames gap", gap_frames);
gap_size = gap_frames * GST_AUDIO_INFO_BPF (info);
}
self->expected_position = position + to_read;
}
/* Fill gap data if any */
while (gap_size > 0) {
if (!gst_audio_ring_buffer_prepare_read (ringbuffer,
&segment, &readptr, &len)) {
GST_INFO_OBJECT (self, "No segment available");
goto out;
}
g_assert (self->segoffset >= 0);
len -= self->segoffset;
if (len > gap_size)
len = gap_size;
gst_audio_format_info_fill_silence (ringbuffer->spec.info.finfo,
readptr + self->segoffset, len);
self->segoffset += len;
gap_size -= len;
if (self->segoffset == ringbuffer->spec.segsize) {
gst_audio_ring_buffer_advance (ringbuffer, 1);
self->segoffset = 0;
}
}
while (to_read_bytes) {
if (!gst_audio_ring_buffer_prepare_read (ringbuffer,
&segment, &readptr, &len)) {
GST_INFO_OBJECT (self, "No segment available");
goto out;
}
len -= self->segoffset;
if (len > to_read_bytes)
len = to_read_bytes;
if ((flags & AUDCLNT_BUFFERFLAGS_SILENT) == AUDCLNT_BUFFERFLAGS_SILENT) {
gst_audio_format_info_fill_silence (ringbuffer->spec.info.finfo,
readptr + self->segoffset, len);
} else {
memcpy (readptr + self->segoffset, data + offset, len);
}
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
self->segoffset += len;
offset += len;
to_read_bytes -= len;
if (self->segoffset == ringbuffer->spec.segsize) {
gst_audio_ring_buffer_advance (ringbuffer, 1);
self->segoffset = 0;
}
}
out:
hr = capture_client->ReleaseBuffer (to_read);
/* For debugging */
gst_wasapi2_result (hr);
return hr;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
}
static HRESULT
gst_wasapi2_ring_buffer_write (GstWasapi2RingBuffer * self, gboolean preroll)
{
GstAudioRingBuffer *ringbuffer = GST_AUDIO_RING_BUFFER_CAST (self);
HRESULT hr;
IAudioClient *client_handle;
IAudioRenderClient *render_client;
guint32 padding_frames = 0;
guint32 can_write;
guint32 can_write_bytes;
gint segment;
guint8 *readptr;
gint len;
BYTE *data = nullptr;
client_handle = gst_wasapi2_client_get_handle (self->client);
if (!client_handle) {
GST_ERROR_OBJECT (self, "IAudioClient is not available");
return E_FAIL;
}
render_client = self->render_client;
if (!render_client) {
GST_ERROR_OBJECT (self, "IAudioRenderClient is not available");
return E_FAIL;
}
hr = client_handle->GetCurrentPadding (&padding_frames);
if (!gst_wasapi2_result (hr))
return hr;
if (padding_frames >= self->buffer_size) {
GST_INFO_OBJECT (self,
"Padding size %d is larger than or equal to buffer size %d",
padding_frames, self->buffer_size);
return S_OK;
}
can_write = self->buffer_size - padding_frames;
can_write_bytes = can_write * GST_AUDIO_INFO_BPF (&ringbuffer->spec.info);
if (preroll) {
GST_INFO_OBJECT (self, "Pre-fill %d frames with silence", can_write);
hr = render_client->GetBuffer (can_write, &data);
if (!gst_wasapi2_result (hr))
return hr;
hr = render_client->ReleaseBuffer (can_write, AUDCLNT_BUFFERFLAGS_SILENT);
return gst_wasapi2_result (hr);
}
GST_LOG_OBJECT (self, "Writing %d frames offset at %" G_GUINT64_FORMAT,
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
can_write, self->write_frame_offset);
self->write_frame_offset += can_write;
while (can_write_bytes > 0) {
if (!gst_audio_ring_buffer_prepare_read (ringbuffer,
&segment, &readptr, &len)) {
GST_INFO_OBJECT (self, "No segment available, fill silence");
/* This would be case where in the middle of PAUSED state change.
* Just fill silent buffer to avoid immediate I/O callback after
* we return here */
hr = render_client->GetBuffer (can_write, &data);
if (!gst_wasapi2_result (hr))
return hr;
hr = render_client->ReleaseBuffer (can_write, AUDCLNT_BUFFERFLAGS_SILENT);
/* for debugging */
gst_wasapi2_result (hr);
return hr;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
}
len -= self->segoffset;
if (len > can_write_bytes)
len = can_write_bytes;
can_write = len / GST_AUDIO_INFO_BPF (&ringbuffer->spec.info);
if (can_write == 0)
break;
hr = render_client->GetBuffer (can_write, &data);
if (!gst_wasapi2_result (hr))
return hr;
memcpy (data, readptr + self->segoffset, len);
hr = render_client->ReleaseBuffer (can_write, 0);
self->segoffset += len;
can_write_bytes -= len;
if (self->segoffset == ringbuffer->spec.segsize) {
gst_audio_ring_buffer_clear (ringbuffer, segment);
gst_audio_ring_buffer_advance (ringbuffer, 1);
self->segoffset = 0;
}
if (!gst_wasapi2_result (hr)) {
GST_WARNING_OBJECT (self, "Failed to release buffer");
break;
}
}
return S_OK;
}
static HRESULT
gst_wasapi2_ring_buffer_io_callback (GstWasapi2RingBuffer * self)
{
HRESULT hr = E_FAIL;
g_return_val_if_fail (GST_IS_WASAPI2_RING_BUFFER (self), E_FAIL);
if (!self->running) {
GST_INFO_OBJECT (self, "We are not running now");
return S_OK;
}
switch (self->device_class) {
case GST_WASAPI2_CLIENT_DEVICE_CLASS_CAPTURE:
case GST_WASAPI2_CLIENT_DEVICE_CLASS_LOOPBACK_CAPTURE:
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
hr = gst_wasapi2_ring_buffer_read (self);
break;
case GST_WASAPI2_CLIENT_DEVICE_CLASS_RENDER:
hr = gst_wasapi2_ring_buffer_write (self, FALSE);
break;
default:
g_assert_not_reached ();
break;
}
/* We can ignore errors for device unplugged event if client can support
* automatic stream routing, but except for loopback capture.
* loopback capture client doesn't seem to be able to recover status from this
* situation */
if (self->can_auto_routing &&
self->device_class != GST_WASAPI2_CLIENT_DEVICE_CLASS_LOOPBACK_CAPTURE &&
(hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED
|| hr == AUDCLNT_E_DEVICE_INVALIDATED)) {
GST_WARNING_OBJECT (self,
"Device was unplugged but client can support automatic routing");
hr = S_OK;
}
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
if (self->running) {
if (gst_wasapi2_result (hr)) {
hr = MFPutWaitingWorkItem (self->event_handle, 0, self->callback_result,
&self->callback_key);
if (!gst_wasapi2_result (hr)) {
GST_ERROR_OBJECT (self, "Failed to put item");
gst_wasapi2_ring_buffer_post_scheduling_error (self);
return hr;
}
}
} else {
GST_INFO_OBJECT (self, "We are not running now");
return S_OK;
}
if (FAILED (hr))
gst_wasapi2_ring_buffer_post_io_error (self, hr);
return hr;
}
static HRESULT
gst_wasapi2_ring_buffer_fill_loopback_silence (GstWasapi2RingBuffer * self)
{
HRESULT hr;
IAudioClient *client_handle;
IAudioRenderClient *render_client;
guint32 padding_frames = 0;
guint32 can_write;
BYTE *data = nullptr;
client_handle = gst_wasapi2_client_get_handle (self->loopback_client);
if (!client_handle) {
GST_ERROR_OBJECT (self, "IAudioClient is not available");
return E_FAIL;
}
render_client = self->render_client;
if (!render_client) {
GST_ERROR_OBJECT (self, "IAudioRenderClient is not available");
return E_FAIL;
}
hr = client_handle->GetCurrentPadding (&padding_frames);
if (!gst_wasapi2_result (hr))
return hr;
if (padding_frames >= self->buffer_size) {
GST_INFO_OBJECT (self,
"Padding size %d is larger than or equal to buffer size %d",
padding_frames, self->buffer_size);
return S_OK;
}
can_write = self->buffer_size - padding_frames;
GST_TRACE_OBJECT (self,
"Writing %d silent frames offset at %" G_GUINT64_FORMAT, can_write);
hr = render_client->GetBuffer (can_write, &data);
if (!gst_wasapi2_result (hr))
return hr;
hr = render_client->ReleaseBuffer (can_write, AUDCLNT_BUFFERFLAGS_SILENT);
return gst_wasapi2_result (hr);
}
static HRESULT
gst_wasapi2_ring_buffer_loopback_callback (GstWasapi2RingBuffer * self)
{
HRESULT hr = E_FAIL;
g_return_val_if_fail (GST_IS_WASAPI2_RING_BUFFER (self), E_FAIL);
g_return_val_if_fail (self->device_class ==
GST_WASAPI2_CLIENT_DEVICE_CLASS_LOOPBACK_CAPTURE, E_FAIL);
if (!self->running) {
GST_INFO_OBJECT (self, "We are not running now");
return S_OK;
}
hr = gst_wasapi2_ring_buffer_fill_loopback_silence (self);
if (self->running) {
if (gst_wasapi2_result (hr)) {
hr = MFPutWaitingWorkItem (self->loopback_event_handle, 0,
self->loopback_callback_result, &self->loopback_callback_key);
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
if (!gst_wasapi2_result (hr)) {
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
GST_ERROR_OBJECT (self, "Failed to put item");
gst_wasapi2_ring_buffer_post_scheduling_error (self);
return hr;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
}
}
} else {
GST_INFO_OBJECT (self, "We are not running now");
return S_OK;
}
if (FAILED (hr))
gst_wasapi2_ring_buffer_post_io_error (self, hr);
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
return hr;
}
static HRESULT
gst_wasapi2_ring_buffer_initialize_audio_client3 (GstWasapi2RingBuffer * self,
IAudioClient * client_handle, WAVEFORMATEX * mix_format, guint * period)
{
HRESULT hr = S_OK;
UINT32 default_period, fundamental_period, min_period, max_period;
/* AUDCLNT_STREAMFLAGS_NOPERSIST is not allowed for
* InitializeSharedAudioStream */
DWORD stream_flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
ComPtr < IAudioClient3 > audio_client;
hr = client_handle->QueryInterface (IID_PPV_ARGS (&audio_client));
if (!gst_wasapi2_result (hr)) {
GST_INFO_OBJECT (self, "IAudioClient3 interface is unavailable");
return hr;
}
hr = audio_client->GetSharedModeEnginePeriod (mix_format,
&default_period, &fundamental_period, &min_period, &max_period);
if (!gst_wasapi2_result (hr)) {
GST_INFO_OBJECT (self, "Couldn't get period");
return hr;
}
GST_INFO_OBJECT (self, "Using IAudioClient3, default period %d frames, "
"fundamental period %d frames, minimum period %d frames, maximum period "
"%d frames", default_period, fundamental_period, min_period, max_period);
*period = min_period;
hr = audio_client->InitializeSharedAudioStream (stream_flags, min_period,
mix_format, nullptr);
if (!gst_wasapi2_result (hr))
GST_WARNING_OBJECT (self, "Failed to initialize IAudioClient3");
return hr;
}
static HRESULT
gst_wasapi2_ring_buffer_initialize_audio_client (GstWasapi2RingBuffer * self,
IAudioClient * client_handle, WAVEFORMATEX * mix_format, guint * period,
DWORD extra_flags)
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
{
GstAudioRingBuffer *ringbuffer = GST_AUDIO_RING_BUFFER_CAST (self);
REFERENCE_TIME default_period, min_period;
DWORD stream_flags =
AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST;
HRESULT hr;
stream_flags |= extra_flags;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
hr = client_handle->GetDevicePeriod (&default_period, &min_period);
if (!gst_wasapi2_result (hr)) {
GST_WARNING_OBJECT (self, "Couldn't get device period info");
return hr;
}
GST_INFO_OBJECT (self, "wasapi2 default period: %" G_GINT64_FORMAT
", min period: %" G_GINT64_FORMAT, default_period, min_period);
hr = client_handle->Initialize (AUDCLNT_SHAREMODE_SHARED, stream_flags,
/* hnsBufferDuration should be same as hnsPeriodicity
* when AUDCLNT_STREAMFLAGS_EVENTCALLBACK is used.
* And in case of shared mode, hnsPeriodicity should be zero, so
* this value should be zero as well */
0,
/* This must always be 0 in shared mode */
0, mix_format, nullptr);
if (!gst_wasapi2_result (hr)) {
GST_WARNING_OBJECT (self, "Couldn't initialize audioclient");
return hr;
}
*period = gst_util_uint64_scale_round (default_period * 100,
GST_AUDIO_INFO_RATE (&ringbuffer->spec.info), GST_SECOND);
return S_OK;
}
static gboolean
gst_wasapi2_ring_buffer_prepare_loopback_client (GstWasapi2RingBuffer * self)
{
IAudioClient *client_handle;
HRESULT hr;
WAVEFORMATEX *mix_format = nullptr;
guint period = 0;
ComPtr < IAudioRenderClient > render_client;
if (!self->loopback_client) {
GST_ERROR_OBJECT (self, "No configured client object");
return FALSE;
}
if (!gst_wasapi2_client_ensure_activation (self->loopback_client)) {
GST_ERROR_OBJECT (self, "Failed to activate audio client");
return FALSE;
}
client_handle = gst_wasapi2_client_get_handle (self->loopback_client);
if (!client_handle) {
GST_ERROR_OBJECT (self, "IAudioClient handle is not available");
return FALSE;
}
hr = client_handle->GetMixFormat (&mix_format);
if (!gst_wasapi2_result (hr)) {
GST_ERROR_OBJECT (self, "Failed to get mix format");
return FALSE;
}
hr = gst_wasapi2_ring_buffer_initialize_audio_client (self, client_handle,
mix_format, &period, 0);
if (!gst_wasapi2_result (hr)) {
GST_ERROR_OBJECT (self, "Failed to initialize audio client");
return FALSE;
}
hr = client_handle->SetEventHandle (self->loopback_event_handle);
if (!gst_wasapi2_result (hr)) {
GST_ERROR_OBJECT (self, "Failed to set event handle");
return FALSE;
}
hr = client_handle->GetBufferSize (&self->loopback_buffer_size);
if (!gst_wasapi2_result (hr)) {
GST_ERROR_OBJECT (self, "Failed to query buffer size");
return FALSE;
}
hr = client_handle->GetService (IID_PPV_ARGS (&render_client));
if (!gst_wasapi2_result (hr)) {
GST_ERROR_OBJECT (self, "IAudioRenderClient is unavailable");
return FALSE;
}
self->render_client = render_client.Detach ();
return TRUE;
}
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
static gboolean
gst_wasapi2_ring_buffer_acquire (GstAudioRingBuffer * buf,
GstAudioRingBufferSpec * spec)
{
GstWasapi2RingBuffer *self = GST_WASAPI2_RING_BUFFER (buf);
IAudioClient *client_handle;
HRESULT hr;
WAVEFORMATEX *mix_format = nullptr;
ComPtr < ISimpleAudioVolume > audio_volume;
GstAudioChannelPosition *position = nullptr;
guint period = 0;
GST_DEBUG_OBJECT (buf, "Acquire");
if (self->device_class == GST_WASAPI2_CLIENT_DEVICE_CLASS_LOOPBACK_CAPTURE) {
if (!gst_wasapi2_ring_buffer_prepare_loopback_client (self)) {
GST_ERROR_OBJECT (self, "Failed to prepare loopback client");
goto error;
}
}
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
if (!self->client) {
GST_ERROR_OBJECT (self, "No configured client object");
goto error;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
}
if (!gst_wasapi2_client_ensure_activation (self->client)) {
GST_ERROR_OBJECT (self, "Failed to activate audio client");
goto error;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
}
client_handle = gst_wasapi2_client_get_handle (self->client);
if (!client_handle) {
GST_ERROR_OBJECT (self, "IAudioClient handle is not available");
goto error;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
}
/* TODO: convert given caps to mix format */
hr = client_handle->GetMixFormat (&mix_format);
if (!gst_wasapi2_result (hr)) {
GST_ERROR_OBJECT (self, "Failed to get mix format");
goto error;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
}
/* Only use audioclient3 when low-latency is requested because otherwise
* very slow machines and VMs with 1 CPU allocated will get glitches:
* https://bugzilla.gnome.org/show_bug.cgi?id=794497 */
hr = E_FAIL;
if (self->low_latency &&
/* AUDCLNT_STREAMFLAGS_LOOPBACK is not allowed for
* InitializeSharedAudioStream */
self->device_class != GST_WASAPI2_CLIENT_DEVICE_CLASS_LOOPBACK_CAPTURE) {
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
hr = gst_wasapi2_ring_buffer_initialize_audio_client3 (self, client_handle,
mix_format, &period);
}
/* Try again if IAudioClinet3 API is unavailable.
* NOTE: IAudioClinet3:: methods might not be available for default device
* NOTE: The default device is a special device which is needed for supporting
* automatic stream routing
* https://docs.microsoft.com/en-us/windows/win32/coreaudio/automatic-stream-routing
*/
if (FAILED (hr)) {
DWORD extra_flags = 0;
if (self->device_class == GST_WASAPI2_CLIENT_DEVICE_CLASS_LOOPBACK_CAPTURE)
extra_flags = AUDCLNT_STREAMFLAGS_LOOPBACK;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
hr = gst_wasapi2_ring_buffer_initialize_audio_client (self, client_handle,
mix_format, &period, extra_flags);
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
}
if (!gst_wasapi2_result (hr)) {
GST_ERROR_OBJECT (self, "Failed to initialize audio client");
goto error;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
}
hr = client_handle->SetEventHandle (self->event_handle);
if (!gst_wasapi2_result (hr)) {
GST_ERROR_OBJECT (self, "Failed to set event handle");
goto error;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
}
gst_wasapi2_util_waveformatex_to_channel_mask (mix_format, &position);
if (position)
gst_audio_ring_buffer_set_channel_positions (buf, position);
g_free (position);
CoTaskMemFree (mix_format);
if (!gst_wasapi2_result (hr)) {
GST_ERROR_OBJECT (self, "Failed to init audio client");
goto error;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
}
hr = client_handle->GetBufferSize (&self->buffer_size);
if (!gst_wasapi2_result (hr)) {
GST_ERROR_OBJECT (self, "Failed to query buffer size");
goto error;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
}
g_assert (period > 0);
spec->segsize = period * GST_AUDIO_INFO_BPF (&buf->spec.info);
spec->segtotal = 2;
GST_INFO_OBJECT (self,
"Buffer size: %d frames, period: %d frames, segsize: %d bytes",
self->buffer_size, period, spec->segsize);
if (self->device_class == GST_WASAPI2_CLIENT_DEVICE_CLASS_RENDER) {
ComPtr < IAudioRenderClient > render_client;
hr = client_handle->GetService (IID_PPV_ARGS (&render_client));
if (!gst_wasapi2_result (hr)) {
GST_ERROR_OBJECT (self, "IAudioRenderClient is unavailable");
goto error;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
}
self->render_client = render_client.Detach ();
} else {
ComPtr < IAudioCaptureClient > capture_client;
hr = client_handle->GetService (IID_PPV_ARGS (&capture_client));
if (!gst_wasapi2_result (hr)) {
GST_ERROR_OBJECT (self, "IAudioCaptureClient is unavailable");
goto error;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
}
self->capture_client = capture_client.Detach ();
}
hr = client_handle->GetService (IID_PPV_ARGS (&audio_volume));
if (!gst_wasapi2_result (hr)) {
GST_ERROR_OBJECT (self, "ISimpleAudioVolume is unavailable");
goto error;
}
g_mutex_lock (&self->volume_lock);
self->volume_object = audio_volume.Detach ();
if (self->mute_changed) {
self->volume_object->SetMute (self->mute, nullptr);
self->mute_changed = FALSE;
} else {
self->volume_object->SetMute (FALSE, nullptr);
}
if (self->volume_changed) {
self->volume_object->SetMasterVolume (self->volume, nullptr);
self->volume_changed = FALSE;
}
g_mutex_unlock (&self->volume_lock);
buf->size = spec->segtotal * spec->segsize;
buf->memory = (guint8 *) g_malloc (buf->size);
gst_audio_format_info_fill_silence (buf->spec.info.finfo,
buf->memory, buf->size);
return TRUE;
error:
GST_WASAPI2_CLEAR_COM (self->render_client);
GST_WASAPI2_CLEAR_COM (self->capture_client);
GST_WASAPI2_CLEAR_COM (self->volume_object);
gst_wasapi2_ring_buffer_post_open_error (self);
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
return FALSE;
}
static gboolean
gst_wasapi2_ring_buffer_release (GstAudioRingBuffer * buf)
{
GST_DEBUG_OBJECT (buf, "Release");
g_clear_pointer (&buf->memory, g_free);
return TRUE;
}
static gboolean
gst_wasapi2_ring_buffer_start_internal (GstWasapi2RingBuffer * self)
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
{
IAudioClient *client_handle;
HRESULT hr;
if (self->running) {
GST_INFO_OBJECT (self, "We are running already");
return TRUE;
}
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
client_handle = gst_wasapi2_client_get_handle (self->client);
self->is_first = TRUE;
self->running = TRUE;
self->segoffset = 0;
self->write_frame_offset = 0;
switch (self->device_class) {
case GST_WASAPI2_CLIENT_DEVICE_CLASS_RENDER:
/* render client might read data from buffer immediately once it's prepared.
* Pre-fill with silence in order to start-up glitch */
hr = gst_wasapi2_ring_buffer_write (self, TRUE);
if (!gst_wasapi2_result (hr)) {
GST_ERROR_OBJECT (self, "Failed to pre-fill buffer with silence");
goto error;
}
break;
case GST_WASAPI2_CLIENT_DEVICE_CLASS_LOOPBACK_CAPTURE:
{
IAudioClient *loopback_client_handle;
/* Start silence feed client first */
loopback_client_handle =
gst_wasapi2_client_get_handle (self->loopback_client);
hr = loopback_client_handle->Start ();
if (!gst_wasapi2_result (hr)) {
GST_ERROR_OBJECT (self, "Failed to start loopback client");
self->running = FALSE;
goto error;
}
hr = MFPutWaitingWorkItem (self->loopback_event_handle,
0, self->loopback_callback_result, &self->loopback_callback_key);
if (!gst_wasapi2_result (hr)) {
GST_ERROR_OBJECT (self, "Failed to put waiting item");
loopback_client_handle->Stop ();
self->running = FALSE;
goto error;
}
break;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
}
default:
break;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
}
hr = client_handle->Start ();
if (!gst_wasapi2_result (hr)) {
GST_ERROR_OBJECT (self, "Failed to start client");
self->running = FALSE;
goto error;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
}
hr = MFPutWaitingWorkItem (self->event_handle, 0, self->callback_result,
&self->callback_key);
if (!gst_wasapi2_result (hr)) {
GST_ERROR_OBJECT (self, "Failed to put waiting item");
client_handle->Stop ();
self->running = FALSE;
goto error;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
}
return TRUE;
error:
gst_wasapi2_ring_buffer_post_open_error (self);
return FALSE;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
}
static gboolean
gst_wasapi2_ring_buffer_start (GstAudioRingBuffer * buf)
{
GstWasapi2RingBuffer *self = GST_WASAPI2_RING_BUFFER (buf);
GST_DEBUG_OBJECT (self, "Start");
return gst_wasapi2_ring_buffer_start_internal (self);
}
static gboolean
gst_wasapi2_ring_buffer_resume (GstAudioRingBuffer * buf)
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
{
GstWasapi2RingBuffer *self = GST_WASAPI2_RING_BUFFER (buf);
GST_DEBUG_OBJECT (self, "Resume");
return gst_wasapi2_ring_buffer_start_internal (self);
}
static gboolean
gst_wasapi2_ring_buffer_stop_internal (GstWasapi2RingBuffer * self)
{
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
IAudioClient *client_handle;
HRESULT hr;
if (!self->client) {
GST_DEBUG_OBJECT (self, "No configured client");
return TRUE;
}
if (!self->running) {
GST_DEBUG_OBJECT (self, "We are not running");
return TRUE;
}
client_handle = gst_wasapi2_client_get_handle (self->client);
self->running = FALSE;
MFCancelWorkItem (self->callback_key);
hr = client_handle->Stop ();
gst_wasapi2_result (hr);
/* Call reset for later reuse case */
hr = client_handle->Reset ();
self->expected_position = 0;
self->write_frame_offset = 0;
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
if (self->loopback_client) {
client_handle = gst_wasapi2_client_get_handle (self->loopback_client);
MFCancelWorkItem (self->loopback_callback_key);
hr = client_handle->Stop ();
gst_wasapi2_result (hr);
client_handle->Reset ();
}
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
return TRUE;
}
static gboolean
gst_wasapi2_ring_buffer_stop (GstAudioRingBuffer * buf)
{
GstWasapi2RingBuffer *self = GST_WASAPI2_RING_BUFFER (buf);
GST_DEBUG_OBJECT (buf, "Stop");
return gst_wasapi2_ring_buffer_stop_internal (self);
}
static gboolean
gst_wasapi2_ring_buffer_pause (GstAudioRingBuffer * buf)
{
GstWasapi2RingBuffer *self = GST_WASAPI2_RING_BUFFER (buf);
GST_DEBUG_OBJECT (buf, "Pause");
return gst_wasapi2_ring_buffer_stop_internal (self);
}
wasapi2: Rewrite plugin and implement audioringbuffer subclass ... based on MediaFoundation work queue API. By this commit, wasapi2 plugin will make use of pull mode scheduling with audioringbuffer subclass. There are several drawbacks of audiosrc/audiosink subclassing (not audiobasesrc/audiobasesink) for WASAPI API, which are: * audiosrc/audiosink classes try to set high priority to read/write thread via MMCSS (Multimedia Class Scheduler Service) but it's not allowed in case of UWP application. In order to use MMCSS in UWP, application should use MediaFoundation work queue indirectly. Since audiosrc/audiosink scheduling model is not compatible with MediaFoundation's work queue model, audioringbuffer subclassing is required. * WASAPI capture device might report larger packet size than expected (i.e., larger frames we can read than expected frame size per period). Meanwhile, in any case, application should drain all packets at that moment. In order to handle the case, wasapi/wasapi2 plugins were making use of GstAdapter which is obviously sub-optimal because it requires additional memory allocation and copy. By implementing audioringbuffer subclassing, we can avoid such inefficiency. In this commit, all the device read/write operations will be moved to newly implemented wasapi2ringbuffer class and existing wasapi2client class will take care of device enumeration and activation parts only. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2306>
2021-05-10 11:45:28 +00:00
static guint
gst_wasapi2_ring_buffer_delay (GstAudioRingBuffer * buf)
{
/* NOTE: WASAPI supports GetCurrentPadding() method for querying
* currently unread buffer size, but it doesn't seem to be quite useful
* here because:
*
* In case of capture client, GetCurrentPadding() will return the number of
* unread frames which will be identical to pNumFramesToRead value of
* IAudioCaptureClient::GetBuffer()'s return. Since we are running on
* event-driven mode and whenever available, WASAPI will notify signal
* so it's likely zero at this moment. And there is a chance to
* return incorrect value here because our IO callback happens from
* other thread.
*
* And render client's padding size will return the total size of buffer
* which is likely larger than twice of our period. Which doesn't represent
* the amount queued frame size in device correctly
*/
return 0;
}
GstAudioRingBuffer *
gst_wasapi2_ring_buffer_new (GstWasapi2ClientDeviceClass device_class,
gboolean low_latency, const gchar * device_id, gpointer dispatcher,
const gchar * name)
{
GstWasapi2RingBuffer *self;
self = (GstWasapi2RingBuffer *)
g_object_new (GST_TYPE_WASAPI2_RING_BUFFER, "name", name, nullptr);
if (!self->callback_object) {
gst_object_unref (self);
return nullptr;
}
self->device_class = device_class;
self->low_latency = low_latency;
self->device_id = g_strdup (device_id);
self->dispatcher = dispatcher;
return GST_AUDIO_RING_BUFFER_CAST (self);
}
GstCaps *
gst_wasapi2_ring_buffer_get_caps (GstWasapi2RingBuffer * buf)
{
g_return_val_if_fail (GST_IS_WASAPI2_RING_BUFFER (buf), nullptr);
if (!buf->client)
return nullptr;
if (!gst_wasapi2_client_ensure_activation (buf->client)) {
GST_ERROR_OBJECT (buf, "Failed to activate audio client");
return nullptr;
}
return gst_wasapi2_client_get_caps (buf->client);
}
HRESULT
gst_wasapi2_ring_buffer_set_mute (GstWasapi2RingBuffer * buf, gboolean mute)
{
HRESULT hr = S_OK;
g_return_val_if_fail (GST_IS_WASAPI2_RING_BUFFER (buf), E_INVALIDARG);
g_mutex_lock (&buf->volume_lock);
buf->mute = mute;
if (buf->volume_object)
hr = buf->volume_object->SetMute (mute, nullptr);
else
buf->volume_changed = TRUE;
g_mutex_unlock (&buf->volume_lock);
return S_OK;
}
HRESULT
gst_wasapi2_ring_buffer_get_mute (GstWasapi2RingBuffer * buf, gboolean * mute)
{
BOOL mute_val;
HRESULT hr = S_OK;
g_return_val_if_fail (GST_IS_WASAPI2_RING_BUFFER (buf), E_INVALIDARG);
g_return_val_if_fail (mute != nullptr, E_INVALIDARG);
mute_val = buf->mute;
g_mutex_lock (&buf->volume_lock);
if (buf->volume_object)
hr = buf->volume_object->GetMute (&mute_val);
g_mutex_unlock (&buf->volume_lock);
*mute = mute_val ? TRUE : FALSE;
return hr;
}
HRESULT
gst_wasapi2_ring_buffer_set_volume (GstWasapi2RingBuffer * buf, gfloat volume)
{
HRESULT hr = S_OK;
g_return_val_if_fail (GST_IS_WASAPI2_RING_BUFFER (buf), E_INVALIDARG);
g_return_val_if_fail (volume >= 0 && volume <= 1.0, E_INVALIDARG);
g_mutex_lock (&buf->volume_lock);
buf->volume = volume;
if (buf->volume_object)
hr = buf->volume_object->SetMasterVolume (volume, nullptr);
else
buf->mute_changed = TRUE;
g_mutex_unlock (&buf->volume_lock);
return hr;
}
HRESULT
gst_wasapi2_ring_buffer_get_volume (GstWasapi2RingBuffer * buf, gfloat * volume)
{
gfloat volume_val;
HRESULT hr = S_OK;
g_return_val_if_fail (GST_IS_WASAPI2_RING_BUFFER (buf), E_INVALIDARG);
g_return_val_if_fail (volume != nullptr, E_INVALIDARG);
g_mutex_lock (&buf->volume_lock);
volume_val = buf->volume;
if (buf->volume_object)
hr = buf->volume_object->GetMasterVolume (&volume_val);
g_mutex_unlock (&buf->volume_lock);
*volume = volume_val;
return hr;
}