--- /dev/null
+/*
+ * Structure and enum definitions are from audioclient.h in the Windows 10 SDK
+ *
+ * These should be defined by MinGW, but they aren't yet since they're very new
+ * so we keep a copy in our tree. All definitions are guarded, so it should be
+ * fine to always include this even when building with MSVC.
+ */
+#pragma once
+
+#ifndef __IAudioClient3_FWD_DEFINED__
+#define __IAudioClient3_FWD_DEFINED__
+typedef interface IAudioClient3 IAudioClient3;
+
+#endif /* __IAudioClient3_FWD_DEFINED__ */
+
+#ifndef __IAudioClient3_INTERFACE_DEFINED__
+#define __IAudioClient3_INTERFACE_DEFINED__
+
+#ifndef AUDIO_STREAM_CATEGORY
+typedef enum _AUDIO_STREAM_CATEGORY {
+ AudioCategory_Other = 0,
+ AudioCategory_ForegroundOnlyMedia,
+ AudioCategory_BackgroundCapableMedia,
+ AudioCategory_Communications,
+ AudioCategory_Alerts,
+ AudioCategory_SoundEffects,
+ AudioCategory_GameEffects,
+ AudioCategory_GameMedia,
+ AudioCategory_GameChat,
+ AudioCategory_Speech,
+ AudioCategory_Movie,
+ AudioCategory_Media
+} AUDIO_STREAM_CATEGORY;
+#endif
+
+#ifndef AUDCLNT_STREAMOPTIONS
+typedef enum AUDCLNT_STREAMOPTIONS
+{
+ AUDCLNT_STREAMOPTIONS_NONE = 0,
+ AUDCLNT_STREAMOPTIONS_RAW = 0x1,
+ AUDCLNT_STREAMOPTIONS_MATCH_FORMAT = 0x2
+} AUDCLNT_STREAMOPTIONS;
+#endif
+
+#ifndef AudioClientProperties
+typedef struct AudioClientProperties
+{
+ UINT32 cbSize;
+ BOOL bIsOffload;
+ AUDIO_STREAM_CATEGORY eCategory;
+ AUDCLNT_STREAMOPTIONS Options;
+} AudioClientProperties;
+#endif
+
+EXTERN_C const IID IID_IAudioClient3;
+
+typedef struct IAudioClient3Vtbl
+{
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IAudioClient3 * This,
+ REFIID riid,
+ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IAudioClient3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IAudioClient3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize )(
+ IAudioClient3 * This,
+ AUDCLNT_SHAREMODE ShareMode,
+ DWORD StreamFlags,
+ REFERENCE_TIME hnsBufferDuration,
+ REFERENCE_TIME hnsPeriodicity,
+ const WAVEFORMATEX *pFormat,
+ LPCGUID AudioSessionGuid);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBufferSize )(
+ IAudioClient3 * This,
+ UINT32 *pNumBufferFrames);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStreamLatency )(
+ IAudioClient3 * This,
+ REFERENCE_TIME *phnsLatency);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentPadding )(
+ IAudioClient3 * This,
+ UINT32 *pNumPaddingFrames);
+
+ HRESULT ( STDMETHODCALLTYPE *IsFormatSupported )(
+ IAudioClient3 * This,
+ AUDCLNT_SHAREMODE ShareMode,
+ const WAVEFORMATEX *pFormat,
+ WAVEFORMATEX **ppClosestMatch);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMixFormat )(
+ IAudioClient3 * This,
+ WAVEFORMATEX **ppDeviceFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDevicePeriod )(
+ IAudioClient3 * This,
+ REFERENCE_TIME *phnsDefaultDevicePeriod,
+ REFERENCE_TIME *phnsMinimumDevicePeriod);
+
+ HRESULT ( STDMETHODCALLTYPE *Start )(
+ IAudioClient3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Stop )(
+ IAudioClient3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ IAudioClient3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEventHandle )(
+ IAudioClient3 * This,
+ HANDLE eventHandle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetService )(
+ IAudioClient3 * This,
+ REFIID riid,
+ void **ppv);
+
+ HRESULT ( STDMETHODCALLTYPE *IsOffloadCapable )(
+ IAudioClient3 * This,
+ AUDIO_STREAM_CATEGORY Category,
+ BOOL *pbOffloadCapable);
+
+ HRESULT ( STDMETHODCALLTYPE *SetClientProperties )(
+ IAudioClient3 * This,
+ const AudioClientProperties *pProperties);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBufferSizeLimits )(
+ IAudioClient3 * This,
+ const WAVEFORMATEX *pFormat,
+ BOOL bEventDriven,
+ REFERENCE_TIME *phnsMinBufferDuration,
+ REFERENCE_TIME *phnsMaxBufferDuration);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSharedModeEnginePeriod )(
+ IAudioClient3 * This,
+ const WAVEFORMATEX *pFormat,
+ UINT32 *pDefaultPeriodInFrames,
+ UINT32 *pFundamentalPeriodInFrames,
+ UINT32 *pMinPeriodInFrames,
+ UINT32 *pMaxPeriodInFrames);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentSharedModeEnginePeriod )(
+ IAudioClient3 * This,
+ WAVEFORMATEX **ppFormat,
+ UINT32 *pCurrentPeriodInFrames);
+
+ HRESULT ( STDMETHODCALLTYPE *InitializeSharedAudioStream )(
+ IAudioClient3 * This,
+ DWORD StreamFlags,
+ UINT32 PeriodInFrames,
+ const WAVEFORMATEX *pFormat,
+ LPCGUID AudioSessionGuid);
+
+ END_INTERFACE
+} IAudioClient3Vtbl;
+
+interface IAudioClient3
+{
+ CONST_VTBL struct IAudioClient3Vtbl *lpVtbl;
+};
+
+#define IAudioClient3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IAudioClient3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IAudioClient3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IAudioClient3_Initialize(This,ShareMode,StreamFlags,hnsBufferDuration,hnsPeriodicity,pFormat,AudioSessionGuid) \
+ ( (This)->lpVtbl -> Initialize(This,ShareMode,StreamFlags,hnsBufferDuration,hnsPeriodicity,pFormat,AudioSessionGuid) )
+
+#define IAudioClient3_GetBufferSize(This,pNumBufferFrames) \
+ ( (This)->lpVtbl -> GetBufferSize(This,pNumBufferFrames) )
+
+#define IAudioClient3_GetStreamLatency(This,phnsLatency) \
+ ( (This)->lpVtbl -> GetStreamLatency(This,phnsLatency) )
+
+#define IAudioClient3_GetCurrentPadding(This,pNumPaddingFrames) \
+ ( (This)->lpVtbl -> GetCurrentPadding(This,pNumPaddingFrames) )
+
+#define IAudioClient3_IsFormatSupported(This,ShareMode,pFormat,ppClosestMatch) \
+ ( (This)->lpVtbl -> IsFormatSupported(This,ShareMode,pFormat,ppClosestMatch) )
+
+#define IAudioClient3_GetMixFormat(This,ppDeviceFormat) \
+ ( (This)->lpVtbl -> GetMixFormat(This,ppDeviceFormat) )
+
+#define IAudioClient3_GetDevicePeriod(This,phnsDefaultDevicePeriod,phnsMinimumDevicePeriod) \
+ ( (This)->lpVtbl -> GetDevicePeriod(This,phnsDefaultDevicePeriod,phnsMinimumDevicePeriod) )
+
+#define IAudioClient3_Start(This) \
+ ( (This)->lpVtbl -> Start(This) )
+
+#define IAudioClient3_Stop(This) \
+ ( (This)->lpVtbl -> Stop(This) )
+
+#define IAudioClient3_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define IAudioClient3_SetEventHandle(This,eventHandle) \
+ ( (This)->lpVtbl -> SetEventHandle(This,eventHandle) )
+
+#define IAudioClient3_GetService(This,riid,ppv) \
+ ( (This)->lpVtbl -> GetService(This,riid,ppv) )
+
+
+#define IAudioClient3_IsOffloadCapable(This,Category,pbOffloadCapable) \
+ ( (This)->lpVtbl -> IsOffloadCapable(This,Category,pbOffloadCapable) )
+
+#define IAudioClient3_SetClientProperties(This,pProperties) \
+ ( (This)->lpVtbl -> SetClientProperties(This,pProperties) )
+
+#define IAudioClient3_GetBufferSizeLimits(This,pFormat,bEventDriven,phnsMinBufferDuration,phnsMaxBufferDuration) \
+ ( (This)->lpVtbl -> GetBufferSizeLimits(This,pFormat,bEventDriven,phnsMinBufferDuration,phnsMaxBufferDuration) )
+
+
+#define IAudioClient3_GetSharedModeEnginePeriod(This,pFormat,pDefaultPeriodInFrames,pFundamentalPeriodInFrames,pMinPeriodInFrames,pMaxPeriodInFrames) \
+ ( (This)->lpVtbl -> GetSharedModeEnginePeriod(This,pFormat,pDefaultPeriodInFrames,pFundamentalPeriodInFrames,pMinPeriodInFrames,pMaxPeriodInFrames) )
+
+#define IAudioClient3_GetCurrentSharedModeEnginePeriod(This,ppFormat,pCurrentPeriodInFrames) \
+ ( (This)->lpVtbl -> GetCurrentSharedModeEnginePeriod(This,ppFormat,pCurrentPeriodInFrames) )
+
+#define IAudioClient3_InitializeSharedAudioStream(This,StreamFlags,PeriodInFrames,pFormat,AudioSessionGuid) \
+ ( (This)->lpVtbl -> InitializeSharedAudioStream(This,StreamFlags,PeriodInFrames,pFormat,AudioSessionGuid) )
+
+
+#endif /* __IAudioClient3_INTERFACE_DEFINED__ */
GstWasapiSink *self = GST_WASAPI_SINK (asink);
gboolean res = FALSE;
REFERENCE_TIME latency_rt;
- REFERENCE_TIME default_period, min_period;
- REFERENCE_TIME device_period, device_buffer_duration;
- guint bpf, rate;
+ guint bpf, rate, devicep_frames;
HRESULT hr;
- hr = IAudioClient_GetDevicePeriod (self->client, &default_period,
- &min_period);
- HR_FAILED_RET (hr, IAudioClient::GetDevicePeriod, FALSE);
-
- GST_INFO_OBJECT (self, "wasapi default period: %" G_GINT64_FORMAT
- ", min period: %" G_GINT64_FORMAT, default_period, min_period);
-
- bpf = GST_AUDIO_INFO_BPF (&spec->info);
- rate = GST_AUDIO_INFO_RATE (&spec->info);
-
- if (self->low_latency) {
- if (self->sharemode == AUDCLNT_SHAREMODE_SHARED) {
- device_period = default_period;
- device_buffer_duration = 0;
- } else {
- device_period = min_period;
- device_buffer_duration = min_period;
- }
+ if (self->sharemode == AUDCLNT_SHAREMODE_SHARED &&
+ gst_wasapi_util_have_audioclient3 ()) {
+ if (!gst_wasapi_util_initialize_audioclient3 (GST_ELEMENT (self), spec,
+ (IAudioClient3 *) self->client, self->mix_format, self->low_latency,
+ &devicep_frames))
+ goto beach;
} else {
- /* Clamp values to integral multiples of an appropriate period */
- gst_wasapi_util_get_best_buffer_sizes (spec,
- self->sharemode == AUDCLNT_SHAREMODE_EXCLUSIVE, default_period,
- min_period, &device_period, &device_buffer_duration);
+ if (!gst_wasapi_util_initialize_audioclient (GST_ELEMENT (self), spec,
+ self->client, self->mix_format, self->sharemode, self->low_latency,
+ &devicep_frames))
+ goto beach;
}
- /* For some reason, we need to call this a second time for exclusive mode */
- if (self->sharemode == AUDCLNT_SHAREMODE_EXCLUSIVE)
- CoInitialize (NULL);
-
- hr = IAudioClient_Initialize (self->client, self->sharemode,
- AUDCLNT_STREAMFLAGS_EVENTCALLBACK, device_buffer_duration,
- /* This must always be 0 in shared mode */
- self->sharemode == AUDCLNT_SHAREMODE_SHARED ? 0 : device_period,
- self->mix_format, NULL);
-
- if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED &&
- self->sharemode == AUDCLNT_SHAREMODE_EXCLUSIVE) {
- guint32 n_frames;
-
- GST_WARNING_OBJECT (self, "initialize failed due to unaligned period %i",
- (int) device_period);
-
- /* Calculate a new aligned period. First get the aligned buffer size. */
- hr = IAudioClient_GetBufferSize (self->client, &n_frames);
- HR_FAILED_RET (hr, IAudioClient::GetBufferSize, FALSE);
-
- device_period = (GST_SECOND / 100) * n_frames / rate;
-
- GST_WARNING_OBJECT (self, "trying to re-initialize with period %i "
- "(%i frames, %i rate)", (int) device_period, n_frames, rate);
-
- hr = IAudioClient_Initialize (self->client, self->sharemode,
- AUDCLNT_STREAMFLAGS_EVENTCALLBACK, device_period,
- device_period, self->mix_format, NULL);
- }
- HR_FAILED_GOTO (hr, IAudioClient::Initialize, beach);
+ bpf = GST_AUDIO_INFO_BPF (&spec->info);
+ rate = GST_AUDIO_INFO_RATE (&spec->info);
/* Total size of the allocated buffer that we will write to */
hr = IAudioClient_GetBufferSize (self->client, &self->buffer_frame_count);
HR_FAILED_GOTO (hr, IAudioClient::GetBufferSize, beach);
- GST_INFO_OBJECT (self, "buffer size is %i frames, bpf is %i bytes, "
- "rate is %i Hz", self->buffer_frame_count, bpf, rate);
+ GST_INFO_OBJECT (self, "buffer size is %i frames, device period is %i "
+ "frames, bpf is %i bytes, rate is %i Hz", self->buffer_frame_count,
+ devicep_frames, bpf, rate);
- /* Actual latency-time/buffer-time are different now */
- spec->segsize = gst_util_uint64_scale_int_round (rate * bpf,
- device_period * 100, GST_SECOND);
+ /* Actual latency-time/buffer-time will be different now */
+ spec->segsize = devicep_frames * bpf;
/* We need a minimum of 2 segments to ensure glitch-free playback */
spec->segtotal = MAX (self->buffer_frame_count * bpf / spec->segsize, 2);
{
GstWasapiSink *self = GST_WASAPI_SINK (asink);
- if (self->sharemode == AUDCLNT_SHAREMODE_EXCLUSIVE)
+ if (self->sharemode == AUDCLNT_SHAREMODE_EXCLUSIVE &&
+ !gst_wasapi_util_have_audioclient3 ())
CoUninitialize ();
#if defined(_MSC_VER) || defined(GST_FORCE_WIN_AVRT)
{
GstWasapiSrc *self = GST_WASAPI_SRC (asrc);
gboolean res = FALSE;
- REFERENCE_TIME latency_rt, default_period, min_period;
- REFERENCE_TIME device_period, device_buffer_duration;
- guint bpf, rate, buffer_frames;
+ REFERENCE_TIME latency_rt;
+ guint bpf, rate, devicep_frames, buffer_frames;
HRESULT hr;
- hr = IAudioClient_GetDevicePeriod (self->client, &default_period,
- &min_period);
- HR_FAILED_RET (hr, IAudioClient::GetDevicePeriod, FALSE);
-
- GST_INFO_OBJECT (self, "wasapi default period: %" G_GINT64_FORMAT
- ", min period: %" G_GINT64_FORMAT, default_period, min_period);
-
- bpf = GST_AUDIO_INFO_BPF (&spec->info);
- rate = GST_AUDIO_INFO_RATE (&spec->info);
-
- if (self->low_latency) {
- if (self->sharemode == AUDCLNT_SHAREMODE_SHARED) {
- device_period = default_period;
- device_buffer_duration = 0;
- } else {
- device_period = min_period;
- device_buffer_duration = min_period;
- }
+ if (self->sharemode == AUDCLNT_SHAREMODE_SHARED &&
+ gst_wasapi_util_have_audioclient3 ()) {
+ if (!gst_wasapi_util_initialize_audioclient3 (GST_ELEMENT (self), spec,
+ (IAudioClient3 *) self->client, self->mix_format, self->low_latency,
+ &devicep_frames))
+ goto beach;
} else {
- /* Clamp values to integral multiples of an appropriate period */
- gst_wasapi_util_get_best_buffer_sizes (spec,
- self->sharemode == AUDCLNT_SHAREMODE_EXCLUSIVE, default_period,
- min_period, &device_period, &device_buffer_duration);
+ if (!gst_wasapi_util_initialize_audioclient (GST_ELEMENT (self), spec,
+ self->client, self->mix_format, self->sharemode, self->low_latency,
+ &devicep_frames))
+ goto beach;
}
- /* For some reason, we need to call this a second time for exclusive mode */
- if (self->sharemode == AUDCLNT_SHAREMODE_EXCLUSIVE)
- CoInitialize (NULL);
-
- hr = IAudioClient_Initialize (self->client, self->sharemode,
- AUDCLNT_STREAMFLAGS_EVENTCALLBACK, device_buffer_duration,
- /* This must always be 0 in shared mode */
- self->sharemode == AUDCLNT_SHAREMODE_SHARED ? 0 : device_period,
- self->mix_format, NULL);
-
- if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED &&
- self->sharemode == AUDCLNT_SHAREMODE_EXCLUSIVE) {
- guint32 n_frames;
-
- GST_WARNING_OBJECT (self, "initialize failed due to unaligned period %i",
- (int) device_period);
-
- /* Calculate a new aligned period. First get the aligned buffer size. */
- hr = IAudioClient_GetBufferSize (self->client, &n_frames);
- HR_FAILED_GOTO (hr, IAudioClient::GetBufferSize, beach);
-
- device_period = (GST_SECOND / 100) * n_frames / rate;
-
- GST_WARNING_OBJECT (self, "trying to re-initialize with period %i "
- "(%i frames, %i rate)", (int) device_period, n_frames, rate);
-
- hr = IAudioClient_Initialize (self->client, self->sharemode,
- AUDCLNT_STREAMFLAGS_EVENTCALLBACK, device_period,
- device_period, self->mix_format, NULL);
- }
- HR_FAILED_GOTO (hr, IAudioClient::Initialize, beach);
+ bpf = GST_AUDIO_INFO_BPF (&spec->info);
+ rate = GST_AUDIO_INFO_RATE (&spec->info);
/* Total size in frames of the allocated buffer that we will read from */
hr = IAudioClient_GetBufferSize (self->client, &buffer_frames);
HR_FAILED_GOTO (hr, IAudioClient::GetBufferSize, beach);
- GST_INFO_OBJECT (self, "buffer size is %i frames, bpf is %i bytes, "
- "rate is %i Hz", buffer_frames, bpf, rate);
+ GST_INFO_OBJECT (self, "buffer size is %i frames, device period is %i "
+ "frames, bpf is %i bytes, rate is %i Hz", buffer_frames,
+ devicep_frames, bpf, rate);
- spec->segsize = gst_util_uint64_scale_int_round (rate * bpf,
- device_period * 100, GST_SECOND);
+ /* Actual latency-time/buffer-time will be different now */
+ spec->segsize = devicep_frames * bpf;
/* We need a minimum of 2 segments to ensure glitch-free playback */
spec->segtotal = MAX (self->buffer_frame_count * bpf / spec->segsize, 2);
{0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03, 0xb2}
};
+const IID IID_IAudioClient3 = { 0x7ed4ee07, 0x8e67, 0x4cd4,
+ {0x8c, 0x1a, 0x2b, 0x7a, 0x59, 0x87, 0xad, 0x42}
+};
+
const IID IID_IAudioClock = { 0xcd63314f, 0x3fba, 0x4a1b,
{0x81, 0x2c, 0xef, 0x96, 0x35, 0x87, 0x28, 0xe7}
};
{SPEAKER_TOP_BACK_RIGHT, GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT}
};
+static int windows_major_version = 0;
+
+gboolean
+gst_wasapi_util_have_audioclient3 (void)
+{
+ if (windows_major_version > 0)
+ return windows_major_version == 10;
+
+ if (g_getenv ("GST_WASAPI_DISABLE_AUDIOCLIENT3") != NULL) {
+ windows_major_version = 6;
+ return FALSE;
+ }
+
+ /* https://msdn.microsoft.com/en-us/library/windows/desktop/ms724834(v=vs.85).aspx */
+ windows_major_version = 6;
+ if (g_win32_check_windows_version (10, 0, 0, G_WIN32_OS_ANY))
+ windows_major_version = 10;
+
+ return windows_major_version == 10;
+}
+
GType
gst_wasapi_device_role_get_type (void)
{
}
}
- hr = IMMDevice_Activate (device, &IID_IAudioClient, CLSCTX_ALL, NULL,
- (void **) &client);
+ if (gst_wasapi_util_have_audioclient3 ())
+ hr = IMMDevice_Activate (device, &IID_IAudioClient3, CLSCTX_ALL, NULL,
+ (void **) &client);
+ else
+ hr = IMMDevice_Activate (device, &IID_IAudioClient, CLSCTX_ALL, NULL,
+ (void **) &client);
HR_FAILED_GOTO (hr, IMMDevice::Activate (IID_IAudioClient), beach);
IUnknown_AddRef (client);
*ret_period = use_period;
*ret_buffer_duration = use_buffer;
}
+
+gboolean
+gst_wasapi_util_initialize_audioclient (GstElement * self,
+ GstAudioRingBufferSpec * spec, IAudioClient * client,
+ WAVEFORMATEX * format, guint sharemode, gboolean low_latency,
+ guint * ret_devicep_frames)
+{
+ REFERENCE_TIME default_period, min_period;
+ REFERENCE_TIME device_period, device_buffer_duration;
+ guint rate;
+ HRESULT hr;
+
+ hr = IAudioClient_GetDevicePeriod (client, &default_period, &min_period);
+ HR_FAILED_RET (hr, IAudioClient::GetDevicePeriod, FALSE);
+
+ GST_INFO_OBJECT (self, "wasapi default period: %" G_GINT64_FORMAT
+ ", min period: %" G_GINT64_FORMAT, default_period, min_period);
+
+ rate = GST_AUDIO_INFO_RATE (&spec->info);
+
+ if (low_latency) {
+ if (sharemode == AUDCLNT_SHAREMODE_SHARED) {
+ device_period = default_period;
+ device_buffer_duration = 0;
+ } else {
+ device_period = min_period;
+ device_buffer_duration = min_period;
+ }
+ } else {
+ /* Clamp values to integral multiples of an appropriate period */
+ gst_wasapi_util_get_best_buffer_sizes (spec,
+ sharemode == AUDCLNT_SHAREMODE_EXCLUSIVE, default_period,
+ min_period, &device_period, &device_buffer_duration);
+ }
+
+ /* For some reason, we need to call this a second time for exclusive mode */
+ if (sharemode == AUDCLNT_SHAREMODE_EXCLUSIVE)
+ CoInitialize (NULL);
+
+ hr = IAudioClient_Initialize (client, sharemode,
+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK, device_buffer_duration,
+ /* This must always be 0 in shared mode */
+ sharemode == AUDCLNT_SHAREMODE_SHARED ? 0 : device_period, format, NULL);
+
+ if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED &&
+ sharemode == AUDCLNT_SHAREMODE_EXCLUSIVE) {
+ guint32 n_frames;
+
+ GST_WARNING_OBJECT (self, "initialize failed due to unaligned period %i",
+ (int) device_period);
+
+ /* Calculate a new aligned period. First get the aligned buffer size. */
+ hr = IAudioClient_GetBufferSize (client, &n_frames);
+ HR_FAILED_RET (hr, IAudioClient::GetBufferSize, FALSE);
+
+ device_period = (GST_SECOND / 100) * n_frames / rate;
+
+ GST_WARNING_OBJECT (self, "trying to re-initialize with period %i "
+ "(%i frames, %i rate)", (int) device_period, n_frames, rate);
+
+ hr = IAudioClient_Initialize (client, sharemode,
+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK, device_period,
+ device_period, format, NULL);
+ }
+ HR_FAILED_RET (hr, IAudioClient::Initialize, FALSE);
+
+ *ret_devicep_frames = (rate * device_period * 100) / GST_SECOND;
+
+ return TRUE;
+}
+
+gboolean
+gst_wasapi_util_initialize_audioclient3 (GstElement * self,
+ GstAudioRingBufferSpec * spec, IAudioClient3 * client,
+ WAVEFORMATEX * format, gboolean low_latency, guint * ret_devicep_frames)
+{
+ HRESULT hr;
+ guint rate, devicep_frames;
+ guint defaultp_frames, fundp_frames, minp_frames, maxp_frames;
+ WAVEFORMATEX *tmpf;
+
+ rate = GST_AUDIO_INFO_RATE (&spec->info);
+
+ hr = IAudioClient3_GetSharedModeEnginePeriod (client, format,
+ &defaultp_frames, &fundp_frames, &minp_frames, &maxp_frames);
+ HR_FAILED_RET (hr, IAudioClient3::GetSharedModeEnginePeriod, FALSE);
+
+ GST_INFO_OBJECT (self, "Using IAudioClient3, default period %i frames, "
+ "fundamental period %i frames, minimum period %i frames, maximum period "
+ "%i frames", defaultp_frames, fundp_frames, minp_frames, maxp_frames);
+
+ if (low_latency) {
+ devicep_frames = minp_frames;
+ } else {
+ /* rate is in Hz, latency_time is in usec */
+ int tmp = (rate * spec->latency_time * GST_USECOND) / GST_SECOND;
+ devicep_frames = CLAMP (tmp, minp_frames, maxp_frames);
+ /* Ensure it's a multiple of the fundamental period */
+ tmp = devicep_frames / fundp_frames;
+ devicep_frames = tmp * fundp_frames;
+ }
+
+ hr = IAudioClient3_InitializeSharedAudioStream (client,
+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK, devicep_frames, format, NULL);
+ HR_FAILED_RET (hr, IAudioClient3::InitializeSharedAudioStream, FALSE);
+
+ hr = IAudioClient3_GetCurrentSharedModeEnginePeriod (client, &tmpf,
+ &devicep_frames);
+ CoTaskMemFree (tmpf);
+ HR_FAILED_RET (hr, IAudioClient3::GetCurrentSharedModeEnginePeriod, FALSE);
+
+ *ret_devicep_frames = devicep_frames;
+ return TRUE;
+}
#include <mmdeviceapi.h>
#include <audioclient.h>
+#include "gstaudioclient3.h"
+
/* Static Caps shared between source, sink, and device provider */
#define GST_WASAPI_STATIC_CAPS "audio/x-raw, " \
"format = (string) " GST_AUDIO_FORMATS_ALL ", " \
/* Utilities */
+gboolean gst_wasapi_util_have_audioclient3 (void);
+
gint gst_wasapi_device_role_to_erole (gint role);
gint gst_wasapi_erole_to_device_role (gint erole);
REFERENCE_TIME min_period, REFERENCE_TIME * ret_period,
REFERENCE_TIME * ret_buffer_duration);
+gboolean gst_wasapi_util_initialize_audioclient (GstElement * element,
+ GstAudioRingBufferSpec * spec, IAudioClient * client,
+ WAVEFORMATEX * format, guint sharemode, gboolean low_latency,
+ guint * ret_devicep_frames);
+
+gboolean gst_wasapi_util_initialize_audioclient3 (GstElement * element,
+ GstAudioRingBufferSpec * spec, IAudioClient3 * client,
+ WAVEFORMATEX * format, gboolean low_latency, guint * ret_devicep_frames);
+
#endif /* __GST_WASAPI_UTIL_H__ */