You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
262 lines
7.1 KiB
262 lines
7.1 KiB
/*****************************************************************************
|
|
* mmdevice.h : Windows Multimedia Device API audio output plugin for VLC
|
|
*****************************************************************************
|
|
* Copyright (C) 2012 Rémi Denis-Courmont
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation; either version 2.1 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program 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 Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
|
*****************************************************************************/
|
|
|
|
#ifndef VLC_AOUT_MMDEVICE_H
|
|
# define VLC_AOUT_MMDEVICE_H 1
|
|
|
|
#define MM_PASSTHROUGH_DISABLED 0
|
|
#define MM_PASSTHROUGH_ENABLED 1
|
|
#define MM_PASSTHROUGH_ENABLED_HD 2
|
|
#define MM_PASSTHROUGH_DEFAULT MM_PASSTHROUGH_DISABLED
|
|
|
|
typedef struct aout_stream aout_stream_t;
|
|
|
|
/**
|
|
* Audio output simplified API for Windows
|
|
*/
|
|
struct aout_stream
|
|
{
|
|
struct vlc_object_t obj;
|
|
void *sys;
|
|
|
|
void (*stop)(aout_stream_t *);
|
|
HRESULT (*play)(aout_stream_t *, block_t *, vlc_tick_t);
|
|
HRESULT (*pause)(aout_stream_t *, bool);
|
|
HRESULT (*flush)(aout_stream_t *);
|
|
};
|
|
|
|
struct aout_stream_owner
|
|
{
|
|
aout_stream_t s;
|
|
void *device;
|
|
HRESULT (*activate)(void *device, REFIID, PROPVARIANT *, void **);
|
|
HANDLE buffer_ready_event;
|
|
struct {
|
|
vlc_tick_t deadline;
|
|
void (*callback)(aout_stream_t *);
|
|
} timer;
|
|
|
|
block_t *chain;
|
|
block_t **last;
|
|
|
|
audio_output_t *aout;
|
|
};
|
|
|
|
/*
|
|
* "aout output" helpers
|
|
*/
|
|
|
|
static inline
|
|
struct aout_stream_owner *aout_stream_owner(aout_stream_t *s)
|
|
{
|
|
return container_of(s, struct aout_stream_owner, s);
|
|
}
|
|
|
|
/**
|
|
* Creates an audio output stream on a given Windows multimedia device.
|
|
* \param s audio output stream object to be initialized
|
|
* \param fmt audio output sample format [IN/OUT]
|
|
* \param sid audio output session GUID [IN]
|
|
*/
|
|
typedef HRESULT (*aout_stream_start_t)(aout_stream_t *s,
|
|
audio_sample_format_t *fmt, const GUID *sid);
|
|
|
|
/**
|
|
* Destroys an audio output stream.
|
|
*/
|
|
static inline
|
|
void aout_stream_owner_Stop(struct aout_stream_owner *owner)
|
|
{
|
|
owner->s.stop(&owner->s);
|
|
}
|
|
|
|
static inline
|
|
HRESULT aout_stream_owner_Play(struct aout_stream_owner *owner,
|
|
block_t *block, vlc_tick_t date)
|
|
{
|
|
return owner->s.play(&owner->s, block, date);
|
|
}
|
|
|
|
static inline
|
|
HRESULT aout_stream_owner_Pause(struct aout_stream_owner *owner, bool paused)
|
|
{
|
|
return owner->s.pause(&owner->s, paused);
|
|
}
|
|
|
|
static inline
|
|
HRESULT aout_stream_owner_Flush(struct aout_stream_owner *owner)
|
|
{
|
|
block_ChainRelease(owner->chain);
|
|
owner->chain = NULL;
|
|
owner->last = &owner->chain;
|
|
|
|
return owner->s.flush(&owner->s);
|
|
}
|
|
|
|
static inline
|
|
void aout_stream_owner_AppendBlock(struct aout_stream_owner *owner,
|
|
block_t *block, vlc_tick_t date)
|
|
{
|
|
block->i_dts = date;
|
|
block_ChainLastAppend(&owner->last, block);
|
|
}
|
|
|
|
static inline
|
|
HRESULT aout_stream_owner_PlayAll(struct aout_stream_owner *owner)
|
|
{
|
|
HRESULT hr;
|
|
|
|
block_t *block = owner->chain, *next;
|
|
while (block != NULL)
|
|
{
|
|
next = block->p_next;
|
|
|
|
vlc_tick_t date = block->i_dts;
|
|
block->i_dts = VLC_TICK_INVALID;
|
|
|
|
hr = aout_stream_owner_Play(owner, block, date);
|
|
|
|
if (hr == S_FALSE)
|
|
return hr;
|
|
else
|
|
{
|
|
block = owner->chain = next;
|
|
if (FAILED(hr))
|
|
{
|
|
if (block == NULL)
|
|
owner->last = &owner->chain;
|
|
return hr;
|
|
}
|
|
}
|
|
}
|
|
owner->last = &owner->chain;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static inline
|
|
DWORD aout_stream_owner_ProcessTimer(struct aout_stream_owner *owner)
|
|
{
|
|
if (owner->timer.deadline != VLC_TICK_INVALID)
|
|
{
|
|
vlc_tick_t now = vlc_tick_now();
|
|
/* Subtract 1 ms since WaitForMultipleObjects will likely sleep
|
|
* a little less than requested */
|
|
if (now >= owner->timer.deadline - VLC_TICK_FROM_MS(1))
|
|
{
|
|
assert(owner->timer.callback != NULL);
|
|
owner->timer.deadline = VLC_TICK_INVALID;
|
|
owner->timer.callback(&owner->s);
|
|
|
|
/* timer.deadline might be updated from timer.callback */
|
|
if (owner->timer.deadline != VLC_TICK_INVALID)
|
|
{
|
|
now = vlc_tick_now();
|
|
return MS_FROM_VLC_TICK(owner->timer.deadline - now);
|
|
}
|
|
}
|
|
else
|
|
return MS_FROM_VLC_TICK(owner->timer.deadline - now);
|
|
}
|
|
|
|
return INFINITE;
|
|
}
|
|
|
|
static inline
|
|
void *aout_stream_owner_New(audio_output_t *aout, size_t size,
|
|
HRESULT (*activate)(void *device, REFIID, PROPVARIANT *, void **))
|
|
{
|
|
assert(size >= sizeof(struct aout_stream_owner));
|
|
|
|
void *obj = vlc_object_create(aout, size);
|
|
if (unlikely(obj == NULL))
|
|
return NULL;
|
|
struct aout_stream_owner *owner = obj;
|
|
|
|
owner->aout = aout;
|
|
owner->chain = NULL;
|
|
owner->last = &owner->chain;
|
|
owner->activate = activate;
|
|
owner->timer.deadline = VLC_TICK_INVALID;
|
|
owner->timer.callback = NULL;
|
|
|
|
owner->buffer_ready_event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (unlikely(owner->buffer_ready_event == NULL))
|
|
{
|
|
vlc_object_delete(&owner->s);
|
|
return NULL;
|
|
}
|
|
|
|
return obj;
|
|
}
|
|
|
|
static inline
|
|
void aout_stream_owner_Delete(struct aout_stream_owner *owner)
|
|
{
|
|
CloseHandle(owner->buffer_ready_event);
|
|
vlc_object_delete(&owner->s);
|
|
}
|
|
|
|
/*
|
|
* "aout stream" helpers
|
|
*/
|
|
|
|
static inline
|
|
void aout_stream_TimingReport(aout_stream_t *s, vlc_tick_t system_ts,
|
|
vlc_tick_t audio_ts)
|
|
{
|
|
struct aout_stream_owner *owner = aout_stream_owner(s);
|
|
aout_TimingReport(owner->aout, system_ts, audio_ts);
|
|
}
|
|
|
|
static inline
|
|
HRESULT aout_stream_Activate(aout_stream_t *s, REFIID iid,
|
|
PROPVARIANT *actparms, void **pv)
|
|
{
|
|
struct aout_stream_owner *owner = aout_stream_owner(s);
|
|
return owner->activate(owner->device, iid, actparms, pv);
|
|
}
|
|
|
|
static inline
|
|
HANDLE aout_stream_GetBufferReadyEvent(aout_stream_t *s)
|
|
{
|
|
struct aout_stream_owner *owner = aout_stream_owner(s);
|
|
return owner->buffer_ready_event;
|
|
}
|
|
|
|
static inline
|
|
void aout_stream_TriggerTimer(aout_stream_t *s,
|
|
void (*callback)(aout_stream_t *),
|
|
vlc_tick_t deadline)
|
|
{
|
|
struct aout_stream_owner *owner = aout_stream_owner(s);
|
|
owner->timer.deadline = deadline;
|
|
owner->timer.callback = callback;
|
|
}
|
|
|
|
static inline
|
|
void aout_stream_DisarmTimer(aout_stream_t *s)
|
|
{
|
|
struct aout_stream_owner *owner = aout_stream_owner(s);
|
|
owner->timer.deadline = VLC_TICK_INVALID;
|
|
owner->timer.callback = NULL;
|
|
}
|
|
|
|
#endif
|
|
|