output/wasapi: fix coding style
This commit is contained in:
@@ -61,7 +61,9 @@
|
|||||||
namespace {
|
namespace {
|
||||||
static constexpr Domain wasapi_output_domain("wasapi_output");
|
static constexpr Domain wasapi_output_domain("wasapi_output");
|
||||||
|
|
||||||
gcc_const constexpr uint32_t GetChannelMask(const uint8_t channels) noexcept {
|
constexpr uint32_t
|
||||||
|
GetChannelMask(const uint8_t channels) noexcept
|
||||||
|
{
|
||||||
switch (channels) {
|
switch (channels) {
|
||||||
case 1:
|
case 1:
|
||||||
return KSAUDIO_SPEAKER_MONO;
|
return KSAUDIO_SPEAKER_MONO;
|
||||||
@@ -86,7 +88,9 @@ gcc_const constexpr uint32_t GetChannelMask(const uint8_t channels) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Functor>
|
template <typename Functor>
|
||||||
inline bool SafeSilenceTry(Functor &&functor) {
|
inline bool
|
||||||
|
SafeSilenceTry(Functor &&functor) noexcept
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
functor();
|
functor();
|
||||||
return true;
|
return true;
|
||||||
@@ -95,7 +99,9 @@ inline bool SafeSilenceTry(Functor &&functor) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<WAVEFORMATEXTENSIBLE> GetFormats(const AudioFormat &audio_format) noexcept {
|
std::vector<WAVEFORMATEXTENSIBLE>
|
||||||
|
GetFormats(const AudioFormat &audio_format) noexcept
|
||||||
|
{
|
||||||
#ifdef ENABLE_DSD
|
#ifdef ENABLE_DSD
|
||||||
if (audio_format.format == SampleFormat::DSD) {
|
if (audio_format.format == SampleFormat::DSD) {
|
||||||
AudioFormat dop_format = audio_format;
|
AudioFormat dop_format = audio_format;
|
||||||
@@ -141,7 +147,9 @@ std::vector<WAVEFORMATEXTENSIBLE> GetFormats(const AudioFormat &audio_format) no
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_DSD
|
#ifdef ENABLE_DSD
|
||||||
void SetDSDFallback(AudioFormat &audio_format) noexcept {
|
void
|
||||||
|
SetDSDFallback(AudioFormat &audio_format) noexcept
|
||||||
|
{
|
||||||
audio_format.format = SampleFormat::FLOAT;
|
audio_format.format = SampleFormat::FLOAT;
|
||||||
audio_format.sample_rate = 384000;
|
audio_format.sample_rate = 384000;
|
||||||
}
|
}
|
||||||
@@ -150,8 +158,26 @@ void SetDSDFallback(AudioFormat &audio_format) noexcept {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
class WasapiOutputThread : public Thread {
|
class WasapiOutputThread : public Thread {
|
||||||
public:
|
friend class WasapiOutput;
|
||||||
|
WinEvent event;
|
||||||
|
WinEvent data_poped;
|
||||||
|
IAudioClient *client;
|
||||||
|
ComPtr<IAudioRenderClient> render_client;
|
||||||
|
const UINT32 frame_size;
|
||||||
|
const UINT32 buffer_size_in_frames;
|
||||||
|
bool is_exclusive;
|
||||||
|
|
||||||
enum class Status : uint32_t { FINISH, PLAY, PAUSE };
|
enum class Status : uint32_t { FINISH, PLAY, PAUSE };
|
||||||
|
alignas(BOOST_LOCKFREE_CACHELINE_BYTES) std::atomic<Status> status =
|
||||||
|
Status::PAUSE;
|
||||||
|
alignas(BOOST_LOCKFREE_CACHELINE_BYTES) struct {
|
||||||
|
std::atomic_bool occur = false;
|
||||||
|
std::exception_ptr ptr = nullptr;
|
||||||
|
WinEvent thrown;
|
||||||
|
} error;
|
||||||
|
boost::lockfree::spsc_queue<BYTE> spsc_buffer;
|
||||||
|
|
||||||
|
public:
|
||||||
WasapiOutputThread(IAudioClient *_client,
|
WasapiOutputThread(IAudioClient *_client,
|
||||||
ComPtr<IAudioRenderClient> &&_render_client,
|
ComPtr<IAudioRenderClient> &&_render_client,
|
||||||
const UINT32 _frame_size, const UINT32 _buffer_size_in_frames,
|
const UINT32 _frame_size, const UINT32 _buffer_size_in_frames,
|
||||||
@@ -159,7 +185,10 @@ public:
|
|||||||
:Thread(BIND_THIS_METHOD(Work)), client(_client),
|
:Thread(BIND_THIS_METHOD(Work)), client(_client),
|
||||||
render_client(std::move(_render_client)), frame_size(_frame_size),
|
render_client(std::move(_render_client)), frame_size(_frame_size),
|
||||||
buffer_size_in_frames(_buffer_size_in_frames), is_exclusive(_is_exclusive),
|
buffer_size_in_frames(_buffer_size_in_frames), is_exclusive(_is_exclusive),
|
||||||
spsc_buffer(_buffer_size_in_frames * 4 * _frame_size) {}
|
spsc_buffer(_buffer_size_in_frames * 4 * _frame_size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void Finish() noexcept { return SetStatus(Status::FINISH); }
|
void Finish() noexcept { return SetStatus(Status::FINISH); }
|
||||||
void Play() noexcept { return SetStatus(Status::PLAY); }
|
void Play() noexcept { return SetStatus(Status::PLAY); }
|
||||||
void Pause() noexcept { return SetStatus(Status::PAUSE); }
|
void Pause() noexcept { return SetStatus(Status::PAUSE); }
|
||||||
@@ -173,23 +202,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class WasapiOutput;
|
|
||||||
WinEvent event;
|
|
||||||
WinEvent data_poped;
|
|
||||||
IAudioClient *client;
|
|
||||||
ComPtr<IAudioRenderClient> render_client;
|
|
||||||
const UINT32 frame_size;
|
|
||||||
const UINT32 buffer_size_in_frames;
|
|
||||||
bool is_exclusive;
|
|
||||||
alignas(BOOST_LOCKFREE_CACHELINE_BYTES) std::atomic<Status> status =
|
|
||||||
Status::PAUSE;
|
|
||||||
alignas(BOOST_LOCKFREE_CACHELINE_BYTES) struct {
|
|
||||||
std::atomic_bool occur = false;
|
|
||||||
std::exception_ptr ptr = nullptr;
|
|
||||||
WinEvent thrown;
|
|
||||||
} error;
|
|
||||||
boost::lockfree::spsc_queue<BYTE> spsc_buffer;
|
|
||||||
|
|
||||||
void SetStatus(Status s) noexcept {
|
void SetStatus(Status s) noexcept {
|
||||||
status.store(s);
|
status.store(s);
|
||||||
event.Set();
|
event.Set();
|
||||||
@@ -198,6 +210,23 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class WasapiOutput final : public AudioOutput {
|
class WasapiOutput final : public AudioOutput {
|
||||||
|
std::atomic_flag not_interrupted = true;
|
||||||
|
bool is_started = false;
|
||||||
|
bool is_exclusive;
|
||||||
|
bool enumerate_devices;
|
||||||
|
#ifdef ENABLE_DSD
|
||||||
|
bool dop_setting;
|
||||||
|
#endif
|
||||||
|
std::string device_config;
|
||||||
|
std::shared_ptr<COMWorker> com_worker;
|
||||||
|
ComPtr<IMMDeviceEnumerator> enumerator;
|
||||||
|
ComPtr<IMMDevice> device;
|
||||||
|
ComPtr<IAudioClient> client;
|
||||||
|
WAVEFORMATEXTENSIBLE device_format;
|
||||||
|
std::optional<WasapiOutputThread> thread;
|
||||||
|
std::size_t watermark;
|
||||||
|
std::optional<PcmExport> pcm_export;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static AudioOutput *Create(EventLoop &, const ConfigBlock &block);
|
static AudioOutput *Create(EventLoop &, const ConfigBlock &block);
|
||||||
WasapiOutput(const ConfigBlock &block);
|
WasapiOutput(const ConfigBlock &block);
|
||||||
@@ -238,23 +267,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::atomic_flag not_interrupted = true;
|
|
||||||
bool is_started = false;
|
|
||||||
bool is_exclusive;
|
|
||||||
bool enumerate_devices;
|
|
||||||
#ifdef ENABLE_DSD
|
|
||||||
bool dop_setting;
|
|
||||||
#endif
|
|
||||||
std::string device_config;
|
|
||||||
std::shared_ptr<COMWorker> com_worker;
|
|
||||||
ComPtr<IMMDeviceEnumerator> enumerator;
|
|
||||||
ComPtr<IMMDevice> device;
|
|
||||||
ComPtr<IAudioClient> client;
|
|
||||||
WAVEFORMATEXTENSIBLE device_format;
|
|
||||||
std::optional<WasapiOutputThread> thread;
|
|
||||||
std::size_t watermark;
|
|
||||||
std::optional<PcmExport> pcm_export;
|
|
||||||
|
|
||||||
friend bool wasapi_is_exclusive(WasapiOutput &output) noexcept;
|
friend bool wasapi_is_exclusive(WasapiOutput &output) noexcept;
|
||||||
friend IMMDevice *wasapi_output_get_device(WasapiOutput &output) noexcept;
|
friend IMMDevice *wasapi_output_get_device(WasapiOutput &output) noexcept;
|
||||||
friend IAudioClient *wasapi_output_get_client(WasapiOutput &output) noexcept;
|
friend IAudioClient *wasapi_output_get_client(WasapiOutput &output) noexcept;
|
||||||
@@ -271,11 +283,17 @@ private:
|
|||||||
ComPtr<IMMDevice> SearchDevice(std::string_view name);
|
ComPtr<IMMDevice> SearchDevice(std::string_view name);
|
||||||
};
|
};
|
||||||
|
|
||||||
WasapiOutput &wasapi_output_downcast(AudioOutput &output) noexcept {
|
WasapiOutput &
|
||||||
|
wasapi_output_downcast(AudioOutput &output) noexcept
|
||||||
|
{
|
||||||
return static_cast<WasapiOutput &>(output);
|
return static_cast<WasapiOutput &>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wasapi_is_exclusive(WasapiOutput &output) noexcept { return output.is_exclusive; }
|
bool
|
||||||
|
wasapi_is_exclusive(WasapiOutput &output) noexcept
|
||||||
|
{
|
||||||
|
return output.is_exclusive;
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<COMWorker>
|
std::shared_ptr<COMWorker>
|
||||||
wasapi_output_get_com_worker(WasapiOutput &output) noexcept
|
wasapi_output_get_com_worker(WasapiOutput &output) noexcept
|
||||||
@@ -283,15 +301,21 @@ wasapi_output_get_com_worker(WasapiOutput &output) noexcept
|
|||||||
return output.GetComWorker();
|
return output.GetComWorker();
|
||||||
}
|
}
|
||||||
|
|
||||||
IMMDevice *wasapi_output_get_device(WasapiOutput &output) noexcept {
|
IMMDevice *
|
||||||
|
wasapi_output_get_device(WasapiOutput &output) noexcept
|
||||||
|
{
|
||||||
return output.device.get();
|
return output.device.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
IAudioClient *wasapi_output_get_client(WasapiOutput &output) noexcept {
|
IAudioClient *
|
||||||
|
wasapi_output_get_client(WasapiOutput &output) noexcept
|
||||||
|
{
|
||||||
return output.client.get();
|
return output.client.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WasapiOutputThread::Work() noexcept {
|
void
|
||||||
|
WasapiOutputThread::Work() noexcept
|
||||||
|
{
|
||||||
SetThreadName("Wasapi Output Worker");
|
SetThreadName("Wasapi Output Worker");
|
||||||
FormatDebug(wasapi_output_domain, "Working thread started");
|
FormatDebug(wasapi_output_domain, "Working thread started");
|
||||||
COM com;
|
COM com;
|
||||||
@@ -350,7 +374,9 @@ void WasapiOutputThread::Work() noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioOutput *WasapiOutput::Create(EventLoop &, const ConfigBlock &block) {
|
AudioOutput *
|
||||||
|
WasapiOutput::Create(EventLoop &, const ConfigBlock &block)
|
||||||
|
{
|
||||||
return new WasapiOutput(block);
|
return new WasapiOutput(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,11 +387,14 @@ WasapiOutput::WasapiOutput(const ConfigBlock &block)
|
|||||||
#ifdef ENABLE_DSD
|
#ifdef ENABLE_DSD
|
||||||
dop_setting(block.GetBlockValue("dop", false)),
|
dop_setting(block.GetBlockValue("dop", false)),
|
||||||
#endif
|
#endif
|
||||||
device_config(block.GetBlockValue("device", "")) {
|
device_config(block.GetBlockValue("device", ""))
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// run inside COMWorkerThread
|
/// run inside COMWorkerThread
|
||||||
void WasapiOutput::DoDisable() noexcept {
|
void
|
||||||
|
WasapiOutput::DoDisable() noexcept
|
||||||
|
{
|
||||||
if (thread) {
|
if (thread) {
|
||||||
try {
|
try {
|
||||||
thread->Finish();
|
thread->Finish();
|
||||||
@@ -382,7 +411,9 @@ void WasapiOutput::DoDisable() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// run inside COMWorkerThread
|
/// run inside COMWorkerThread
|
||||||
void WasapiOutput::DoOpen(AudioFormat &audio_format) {
|
void
|
||||||
|
WasapiOutput::DoOpen(AudioFormat &audio_format)
|
||||||
|
{
|
||||||
client.reset();
|
client.reset();
|
||||||
|
|
||||||
if (GetState(*device) != DEVICE_STATE_ACTIVE) {
|
if (GetState(*device) != DEVICE_STATE_ACTIVE) {
|
||||||
@@ -519,7 +550,9 @@ void WasapiOutput::DoOpen(AudioFormat &audio_format) {
|
|||||||
thread->Start();
|
thread->Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WasapiOutput::Close() noexcept {
|
void
|
||||||
|
WasapiOutput::Close() noexcept
|
||||||
|
{
|
||||||
assert(thread);
|
assert(thread);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -541,7 +574,9 @@ void WasapiOutput::Close() noexcept {
|
|||||||
pcm_export.reset();
|
pcm_export.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::chrono::steady_clock::duration WasapiOutput::Delay() const noexcept {
|
std::chrono::steady_clock::duration
|
||||||
|
WasapiOutput::Delay() const noexcept
|
||||||
|
{
|
||||||
if (!is_started) {
|
if (!is_started) {
|
||||||
// idle while paused
|
// idle while paused
|
||||||
return std::chrono::seconds(1);
|
return std::chrono::seconds(1);
|
||||||
@@ -558,7 +593,9 @@ std::chrono::steady_clock::duration WasapiOutput::Delay() const noexcept {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t WasapiOutput::Play(const void *chunk, size_t size) {
|
size_t
|
||||||
|
WasapiOutput::Play(const void *chunk, size_t size)
|
||||||
|
{
|
||||||
assert(thread);
|
assert(thread);
|
||||||
|
|
||||||
not_interrupted.test_and_set();
|
not_interrupted.test_and_set();
|
||||||
@@ -599,7 +636,9 @@ size_t WasapiOutput::Play(const void *chunk, size_t size) {
|
|||||||
} while (true);
|
} while (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WasapiOutput::Pause() {
|
bool
|
||||||
|
WasapiOutput::Pause()
|
||||||
|
{
|
||||||
if (is_started) {
|
if (is_started) {
|
||||||
thread->Pause();
|
thread->Pause();
|
||||||
is_started = false;
|
is_started = false;
|
||||||
@@ -608,14 +647,18 @@ bool WasapiOutput::Pause() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WasapiOutput::Interrupt() noexcept {
|
void
|
||||||
|
WasapiOutput::Interrupt() noexcept
|
||||||
|
{
|
||||||
if (thread) {
|
if (thread) {
|
||||||
not_interrupted.clear();
|
not_interrupted.clear();
|
||||||
thread->data_poped.Set();
|
thread->data_poped.Set();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WasapiOutput::Drain() {
|
void
|
||||||
|
WasapiOutput::Drain()
|
||||||
|
{
|
||||||
assert(thread);
|
assert(thread);
|
||||||
|
|
||||||
thread->spsc_buffer.consume_all([](auto &&) {});
|
thread->spsc_buffer.consume_all([](auto &&) {});
|
||||||
@@ -623,7 +666,9 @@ void WasapiOutput::Drain() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// run inside COMWorkerThread
|
/// run inside COMWorkerThread
|
||||||
void WasapiOutput::OpenDevice() {
|
void
|
||||||
|
WasapiOutput::OpenDevice()
|
||||||
|
{
|
||||||
enumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr,
|
enumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr,
|
||||||
CLSCTX_INPROC_SERVER);
|
CLSCTX_INPROC_SERVER);
|
||||||
|
|
||||||
@@ -650,7 +695,9 @@ void WasapiOutput::OpenDevice() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// run inside COMWorkerThread
|
/// run inside COMWorkerThread
|
||||||
bool WasapiOutput::TryFormatExclusive(const AudioFormat &audio_format) {
|
bool
|
||||||
|
WasapiOutput::TryFormatExclusive(const AudioFormat &audio_format)
|
||||||
|
{
|
||||||
for (auto test_format : GetFormats(audio_format)) {
|
for (auto test_format : GetFormats(audio_format)) {
|
||||||
HRESULT result = client->IsFormatSupported(
|
HRESULT result = client->IsFormatSupported(
|
||||||
AUDCLNT_SHAREMODE_EXCLUSIVE,
|
AUDCLNT_SHAREMODE_EXCLUSIVE,
|
||||||
@@ -674,7 +721,9 @@ bool WasapiOutput::TryFormatExclusive(const AudioFormat &audio_format) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// run inside COMWorkerThread
|
/// run inside COMWorkerThread
|
||||||
void WasapiOutput::FindExclusiveFormatSupported(AudioFormat &audio_format) {
|
void
|
||||||
|
WasapiOutput::FindExclusiveFormatSupported(AudioFormat &audio_format)
|
||||||
|
{
|
||||||
for (uint8_t channels : {0, 2, 6, 8, 7, 1, 4, 5, 3}) {
|
for (uint8_t channels : {0, 2, 6, 8, 7, 1, 4, 5, 3}) {
|
||||||
if (audio_format.channels == channels) {
|
if (audio_format.channels == channels) {
|
||||||
continue;
|
continue;
|
||||||
@@ -734,7 +783,9 @@ void WasapiOutput::FindExclusiveFormatSupported(AudioFormat &audio_format) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// run inside COMWorkerThread
|
/// run inside COMWorkerThread
|
||||||
void WasapiOutput::FindSharedFormatSupported(AudioFormat &audio_format) {
|
void
|
||||||
|
WasapiOutput::FindSharedFormatSupported(AudioFormat &audio_format)
|
||||||
|
{
|
||||||
HRESULT result;
|
HRESULT result;
|
||||||
|
|
||||||
// In shared mode, different sample rate is always unsupported.
|
// In shared mode, different sample rate is always unsupported.
|
||||||
@@ -837,7 +888,9 @@ void WasapiOutput::FindSharedFormatSupported(AudioFormat &audio_format) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// run inside COMWorkerThread
|
/// run inside COMWorkerThread
|
||||||
void WasapiOutput::EnumerateDevices() {
|
void
|
||||||
|
WasapiOutput::EnumerateDevices()
|
||||||
|
{
|
||||||
const auto device_collection = EnumAudioEndpoints(*enumerator);
|
const auto device_collection = EnumAudioEndpoints(*enumerator);
|
||||||
|
|
||||||
const UINT count = GetCount(*device_collection);
|
const UINT count = GetCount(*device_collection);
|
||||||
@@ -884,7 +937,11 @@ WasapiOutput::SearchDevice(std::string_view name)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool wasapi_output_test_default_device() { return true; }
|
static bool
|
||||||
|
wasapi_output_test_default_device()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const struct AudioOutputPlugin wasapi_output_plugin = {
|
const struct AudioOutputPlugin wasapi_output_plugin = {
|
||||||
"wasapi",
|
"wasapi",
|
||||||
|
|||||||
Reference in New Issue
Block a user