#include <stdlib.h>
#include <assert.h>
#include <audioclient.h>
-#include <mmdeviceapi.h>
#include <vlc_common.h>
#include <vlc_aout.h>
-#include "mmdevice.h"
+#include "audio_output/mmdevice.h"
static LARGE_INTEGER freq; /* performance counters frequency */
return (d.quot * 10000000) + ((d.rem * 10000000) / freq.QuadPart);
}
-static void Enter(void)
-{
- HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
- if (unlikely(FAILED(hr)))
- abort();
-}
-
-static void Leave(void)
-{
- CoUninitialize();
-}
-
-typedef struct aout_api_sys
+typedef struct aout_stream_sys
{
IAudioClient *client;
uint8_t chans_table[AOUT_CHAN_MAX];
uint8_t chans_to_reorder;
- uint8_t bits; /**< Bits per sample */
+ vlc_fourcc_t format; /**< Sample format */
unsigned rate; /**< Sample rate */
unsigned bytes_per_frame;
UINT32 written; /**< Frames written to the buffer */
UINT32 frames; /**< Total buffer size (frames) */
-} aout_api_sys_t;
+} aout_stream_sys_t;
/*** VLC audio output callbacks ***/
-static HRESULT TimeGet(aout_api_t *api, mtime_t *restrict delay)
+static HRESULT TimeGet(aout_stream_t *s, mtime_t *restrict delay)
{
- aout_api_sys_t *sys = api->sys;
+ aout_stream_sys_t *sys = s->sys;
void *pv;
UINT64 pos, qpcpos;
HRESULT hr;
- Enter();
hr = IAudioClient_GetService(sys->client, &IID_IAudioClock, &pv);
if (SUCCEEDED(hr))
{
hr = IAudioClock_GetPosition(clock, &pos, &qpcpos);
if (FAILED(hr))
- msg_Err(api, "cannot get position (error 0x%lx)", hr);
+ msg_Err(s, "cannot get position (error 0x%lx)", hr);
IAudioClock_Release(clock);
}
else
- msg_Err(api, "cannot get clock (error 0x%lx)", hr);
- Leave();
+ msg_Err(s, "cannot get clock (error 0x%lx)", hr);
if (SUCCEEDED(hr))
{
else
{
*delay = sys->written * CLOCK_FREQ / sys->rate;
- msg_Dbg(api, "extrapolating position: still propagating buffers");
+ msg_Dbg(s, "extrapolating position: still propagating buffers");
}
}
return hr;
}
-static HRESULT Play(aout_api_t *api, block_t *block)
+static HRESULT Play(aout_stream_t *s, block_t *block)
{
- aout_api_sys_t *sys = api->sys;
+ aout_stream_sys_t *sys = s->sys;
void *pv;
HRESULT hr;
if (sys->chans_to_reorder)
aout_ChannelReorder(block->p_buffer, block->i_buffer,
- sys->chans_to_reorder, sys->chans_table, sys->bits);
+ sys->chans_to_reorder, sys->chans_table, sys->format);
- Enter();
hr = IAudioClient_GetService(sys->client, &IID_IAudioRenderClient, &pv);
if (FAILED(hr))
{
- msg_Err(api, "cannot get render client (error 0x%lx)", hr);
+ msg_Err(s, "cannot get render client (error 0x%lx)", hr);
goto out;
}
hr = IAudioClient_GetCurrentPadding(sys->client, &frames);
if (FAILED(hr))
{
- msg_Err(api, "cannot get current padding (error 0x%lx)", hr);
+ msg_Err(s, "cannot get current padding (error 0x%lx)", hr);
break;
}
hr = IAudioRenderClient_GetBuffer(render, frames, &dst);
if (FAILED(hr))
{
- msg_Err(api, "cannot get buffer (error 0x%lx)", hr);
+ msg_Err(s, "cannot get buffer (error 0x%lx)", hr);
break;
}
hr = IAudioRenderClient_ReleaseBuffer(render, frames, 0);
if (FAILED(hr))
{
- msg_Err(api, "cannot release buffer (error 0x%lx)", hr);
+ msg_Err(s, "cannot release buffer (error 0x%lx)", hr);
break;
}
IAudioClient_Start(sys->client);
}
IAudioRenderClient_Release(render);
out:
- Leave();
block_Release(block);
return hr;
}
-static HRESULT Pause(aout_api_t *api, bool paused)
+static HRESULT Pause(aout_stream_t *s, bool paused)
{
- aout_api_sys_t *sys = api->sys;
+ aout_stream_sys_t *sys = s->sys;
HRESULT hr;
- Enter();
if (paused)
hr = IAudioClient_Stop(sys->client);
else
hr = IAudioClient_Start(sys->client);
if (FAILED(hr))
- msg_Warn(api, "cannot %s stream (error 0x%lx)",
+ msg_Warn(s, "cannot %s stream (error 0x%lx)",
paused ? "stop" : "start", hr);
- Leave();
return hr;
}
-static HRESULT Flush(aout_api_t *api)
+static HRESULT Flush(aout_stream_t *s)
{
- aout_api_sys_t *sys = api->sys;
+ aout_stream_sys_t *sys = s->sys;
HRESULT hr;
- Enter();
IAudioClient_Stop(sys->client);
- hr = IAudioClient_Reset(sys->client);
- Leave();
+ hr = IAudioClient_Reset(sys->client);
if (FAILED(hr))
- msg_Warn(api, "cannot reset stream (error 0x%lx)", hr);
+ msg_Warn(s, "cannot reset stream (error 0x%lx)", hr);
else
sys->written = 0;
return hr;
wf->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
break;
- case VLC_CODEC_S8:
case VLC_CODEC_U8:
audio->i_format = VLC_CODEC_S16N;
case VLC_CODEC_S16N:
return aout_CheckChannelReorder(chans_in, chans_out, mask, table);
}
-static HRESULT Start(aout_api_t *api, audio_sample_format_t *restrict fmt,
- IMMDevice *dev, const GUID *sid)
+static HRESULT Start(aout_stream_t *s, audio_sample_format_t *restrict fmt,
+ const GUID *sid)
{
- aout_api_sys_t *sys = malloc(sizeof (*sys));
+ aout_stream_sys_t *sys = malloc(sizeof (*sys));
if (unlikely(sys == NULL))
return E_OUTOFMEMORY;
sys->client = NULL;
- HRESULT hr;
-
- Enter();
void *pv;
- hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_ALL, NULL, &pv);
+ HRESULT hr = aout_stream_Activate(s, &IID_IAudioClient, NULL, &pv);
if (FAILED(hr))
{
- msg_Err(api, "cannot activate client (error 0x%lx)", hr);
+ msg_Err(s, "cannot activate client (error 0x%lx)", hr);
goto error;
}
sys->client = pv;
&wf.Format, &pwf);
if (FAILED(hr))
{
- msg_Err(api, "cannot negotiate audio format (error 0x%lx)", hr);
+ msg_Err(s, "cannot negotiate audio format (error 0x%lx)", hr);
goto error;
}
if (vlc_FromWave(pwf, fmt))
{
CoTaskMemFree(pwf);
- msg_Err(api, "unsupported audio format");
+ msg_Err(s, "unsupported audio format");
hr = E_INVALIDARG;
goto error;
}
- msg_Dbg(api, "modified format");
+ msg_Dbg(s, "modified format");
}
else
assert(pwf == NULL);
sys->chans_to_reorder = vlc_CheckWaveOrder((hr == S_OK) ? &wf.Format : pwf,
sys->chans_table);
- sys->bits = fmt->i_bitspersample;
+ sys->format = fmt->i_format;
hr = IAudioClient_Initialize(sys->client, AUDCLNT_SHAREMODE_SHARED, 0,
AOUT_MAX_PREPARE_TIME * 10, 0,
CoTaskMemFree(pwf);
if (FAILED(hr))
{
- msg_Err(api, "cannot initialize audio client (error 0x%lx)", hr);
+ msg_Err(s, "cannot initialize audio client (error 0x%lx)", hr);
goto error;
}
hr = IAudioClient_GetBufferSize(sys->client, &sys->frames);
if (FAILED(hr))
{
- msg_Err(api, "cannot get buffer size (error 0x%lx)", hr);
+ msg_Err(s, "cannot get buffer size (error 0x%lx)", hr);
goto error;
}
- Leave();
-
sys->rate = fmt->i_rate;
sys->bytes_per_frame = fmt->i_bytes_per_frame;
sys->written = 0;
- api->sys = sys;
- api->time_get = TimeGet;
- api->play = Play;
- api->pause = Pause;
- api->flush = Flush;
- return VLC_SUCCESS;
+ s->sys = sys;
+ s->time_get = TimeGet;
+ s->play = Play;
+ s->pause = Pause;
+ s->flush = Flush;
+ return S_OK;
error:
if (sys->client != NULL)
IAudioClient_Release(sys->client);
- Leave();
+ free(sys);
return hr;
}
-static void Stop(aout_api_t *api)
+static void Stop(aout_stream_t *s)
{
- aout_api_sys_t *sys = api->sys;
+ aout_stream_sys_t *sys = s->sys;
- Enter();
IAudioClient_Stop(sys->client); /* should not be needed */
IAudioClient_Release(sys->client);
- Leave();
}
-#undef aout_api_Start
-aout_api_t *aout_api_Start(vlc_object_t *parent, audio_sample_format_t *fmt,
- IMMDevice *dev, const GUID *sid)
+HRESULT aout_stream_Start(aout_stream_t *s,
+ audio_sample_format_t *restrict fmt, const GUID *sid)
{
- aout_api_t *api = vlc_object_create(parent, sizeof (*api));
- if (unlikely(api == NULL))
- return NULL;
-
- HRESULT hr = Start(api, fmt, dev, sid);
- if (FAILED(hr))
- {
- vlc_object_release(api);
- api = NULL;
- }
- return NULL;
+ return Start(s, fmt, sid);
}
-void aout_api_Stop(aout_api_t *api)
+void aout_stream_Stop(aout_stream_t *s)
{
- Stop(api);
- vlc_object_release(api);
+ Stop(s);
}