mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2024-12-23 02:55:30 +00:00
WASAPI: sine wave example works with shared device
This commit is contained in:
parent
ba0d45b8fa
commit
c2bc2c7c21
|
@ -287,8 +287,6 @@ void soundio_os_thread_destroy(struct SoundIoOsThread *thread) {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SoundIoOsMutex *soundio_os_mutex_create(void) {
|
struct SoundIoOsMutex *soundio_os_mutex_create(void) {
|
||||||
int err;
|
|
||||||
|
|
||||||
struct SoundIoOsMutex *mutex = allocate<SoundIoOsMutex>(1);
|
struct SoundIoOsMutex *mutex = allocate<SoundIoOsMutex>(1);
|
||||||
if (!mutex) {
|
if (!mutex) {
|
||||||
soundio_os_mutex_destroy(mutex);
|
soundio_os_mutex_destroy(mutex);
|
||||||
|
@ -298,6 +296,7 @@ struct SoundIoOsMutex *soundio_os_mutex_create(void) {
|
||||||
#if defined(SOUNDIO_OS_WINDOWS)
|
#if defined(SOUNDIO_OS_WINDOWS)
|
||||||
InitializeCriticalSection(&mutex->id);
|
InitializeCriticalSection(&mutex->id);
|
||||||
#else
|
#else
|
||||||
|
int err;
|
||||||
if ((err = pthread_mutex_init(&mutex->id, NULL))) {
|
if ((err = pthread_mutex_init(&mutex->id, NULL))) {
|
||||||
soundio_os_mutex_destroy(mutex);
|
soundio_os_mutex_destroy(mutex);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
124
src/wasapi.cpp
124
src/wasapi.cpp
|
@ -349,7 +349,6 @@ static int detect_valid_layouts(RefreshDevices *rd, WAVEFORMATEXTENSIBLE *wave_f
|
||||||
SoundIoDevicePrivate *dev, AUDCLNT_SHAREMODE share_mode)
|
SoundIoDevicePrivate *dev, AUDCLNT_SHAREMODE share_mode)
|
||||||
{
|
{
|
||||||
SoundIoDevice *device = &dev->pub;
|
SoundIoDevice *device = &dev->pub;
|
||||||
SoundIoDeviceWasapi *dw = &dev->backend_data.wasapi;
|
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
device->layout_count = 0;
|
device->layout_count = 0;
|
||||||
|
@ -366,7 +365,7 @@ static int detect_valid_layouts(RefreshDevices *rd, WAVEFORMATEXTENSIBLE *wave_f
|
||||||
to_wave_format_layout(test_layout, wave_format);
|
to_wave_format_layout(test_layout, wave_format);
|
||||||
complete_wave_format_data(wave_format);
|
complete_wave_format_data(wave_format);
|
||||||
|
|
||||||
HRESULT hr = IAudioClient_IsFormatSupported(rd->audio_client, share_mode,
|
hr = IAudioClient_IsFormatSupported(rd->audio_client, share_mode,
|
||||||
(WAVEFORMATEX*)wave_format, &closest_match);
|
(WAVEFORMATEX*)wave_format, &closest_match);
|
||||||
if (closest_match) {
|
if (closest_match) {
|
||||||
CoTaskMemFree(closest_match);
|
CoTaskMemFree(closest_match);
|
||||||
|
@ -390,7 +389,6 @@ static int detect_valid_formats(RefreshDevices *rd, WAVEFORMATEXTENSIBLE *wave_f
|
||||||
SoundIoDevicePrivate *dev, AUDCLNT_SHAREMODE share_mode)
|
SoundIoDevicePrivate *dev, AUDCLNT_SHAREMODE share_mode)
|
||||||
{
|
{
|
||||||
SoundIoDevice *device = &dev->pub;
|
SoundIoDevice *device = &dev->pub;
|
||||||
SoundIoDeviceWasapi *dw = &dev->backend_data.wasapi;
|
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
device->format_count = 0;
|
device->format_count = 0;
|
||||||
|
@ -406,7 +404,7 @@ static int detect_valid_formats(RefreshDevices *rd, WAVEFORMATEXTENSIBLE *wave_f
|
||||||
to_wave_format_format(test_format, wave_format);
|
to_wave_format_format(test_format, wave_format);
|
||||||
complete_wave_format_data(wave_format);
|
complete_wave_format_data(wave_format);
|
||||||
|
|
||||||
HRESULT hr = IAudioClient_IsFormatSupported(rd->audio_client, share_mode,
|
hr = IAudioClient_IsFormatSupported(rd->audio_client, share_mode,
|
||||||
(WAVEFORMATEX*)wave_format, &closest_match);
|
(WAVEFORMATEX*)wave_format, &closest_match);
|
||||||
if (closest_match) {
|
if (closest_match) {
|
||||||
CoTaskMemFree(closest_match);
|
CoTaskMemFree(closest_match);
|
||||||
|
@ -956,10 +954,25 @@ static void wakeup_wasapi(struct SoundIoPrivate *si) {
|
||||||
static void outstream_destroy_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
static void outstream_destroy_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamWasapi *osw = &os->backend_data.wasapi;
|
SoundIoOutStreamWasapi *osw = &os->backend_data.wasapi;
|
||||||
|
|
||||||
|
if (osw->thread) {
|
||||||
|
osw->thread_exit_flag.clear();
|
||||||
|
soundio_os_mutex_lock(osw->mutex);
|
||||||
|
soundio_os_cond_signal(osw->cond, osw->mutex);
|
||||||
|
soundio_os_mutex_unlock(osw->mutex);
|
||||||
|
soundio_os_thread_destroy(osw->thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (osw->audio_render_client)
|
||||||
|
IUnknown_Release(osw->audio_render_client);
|
||||||
if (osw->audio_clock_adjustment)
|
if (osw->audio_clock_adjustment)
|
||||||
IUnknown_Release(osw->audio_clock_adjustment);
|
IUnknown_Release(osw->audio_clock_adjustment);
|
||||||
if (osw->audio_client)
|
if (osw->audio_client)
|
||||||
IUnknown_Release(osw->audio_client);
|
IUnknown_Release(osw->audio_client);
|
||||||
|
|
||||||
|
soundio_os_cond_destroy(osw->cond);
|
||||||
|
soundio_os_mutex_destroy(osw->mutex);
|
||||||
|
|
||||||
|
CoUninitialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_open_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
static int outstream_open_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
|
@ -969,10 +982,24 @@ static int outstream_open_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStr
|
||||||
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
|
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
|
||||||
SoundIoDeviceWasapi *dw = &dev->backend_data.wasapi;
|
SoundIoDeviceWasapi *dw = &dev->backend_data.wasapi;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
int err;
|
|
||||||
|
if (FAILED(hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED))) {
|
||||||
|
outstream_destroy_wasapi(si, os);
|
||||||
|
return SoundIoErrorNoMem;
|
||||||
|
}
|
||||||
|
|
||||||
osw->is_raw = device->is_raw;
|
osw->is_raw = device->is_raw;
|
||||||
|
|
||||||
|
if (!(osw->cond = soundio_os_cond_create())) {
|
||||||
|
outstream_destroy_wasapi(si, os);
|
||||||
|
return SoundIoErrorNoMem;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(osw->mutex = soundio_os_mutex_create())) {
|
||||||
|
outstream_destroy_wasapi(si, os);
|
||||||
|
return SoundIoErrorNoMem;
|
||||||
|
}
|
||||||
|
|
||||||
if (FAILED(hr = IMMDevice_Activate(dw->mm_device, IID_IAudioClient,
|
if (FAILED(hr = IMMDevice_Activate(dw->mm_device, IID_IAudioClient,
|
||||||
CLSCTX_ALL, nullptr, (void**)&osw->audio_client)))
|
CLSCTX_ALL, nullptr, (void**)&osw->audio_client)))
|
||||||
{
|
{
|
||||||
|
@ -1084,6 +1111,13 @@ static int outstream_open_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (FAILED(hr = IAudioClient_GetService(osw->audio_client, IID_IAudioRenderClient,
|
||||||
|
(void **)&osw->audio_render_client)))
|
||||||
|
{
|
||||||
|
outstream_destroy_wasapi(si, os);
|
||||||
|
return SoundIoErrorOpeningDevice;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1099,13 +1133,51 @@ static int outstream_pause_wasapi(struct SoundIoPrivate *si, struct SoundIoOutSt
|
||||||
void outstream_shared_run(void *arg) {
|
void outstream_shared_run(void *arg) {
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *) arg;
|
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *) arg;
|
||||||
SoundIoOutStreamWasapi *osw = &os->backend_data.wasapi;
|
SoundIoOutStreamWasapi *osw = &os->backend_data.wasapi;
|
||||||
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
|
|
||||||
// TODO set up timer to wake up at the appropriate time
|
HRESULT hr;
|
||||||
soundio_panic("TODO thread");
|
|
||||||
//HRESULT hr;
|
UINT32 frames_used;
|
||||||
//if (FAILED(hr = IAudioClient_Start(osw->audio_client)))
|
if (FAILED(hr = IAudioClient_GetCurrentPadding(osw->audio_client, &frames_used))) {
|
||||||
// return SoundIoErrorStreaming;
|
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
||||||
//return 0;
|
return;
|
||||||
|
}
|
||||||
|
osw->writable_frame_count = osw->buffer_frame_count - frames_used;
|
||||||
|
if (osw->writable_frame_count <= 0) {
|
||||||
|
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
outstream->write_callback(outstream, 0, osw->writable_frame_count);
|
||||||
|
|
||||||
|
if (FAILED(hr = IAudioClient_Start(osw->audio_client))) {
|
||||||
|
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (FAILED(hr = IAudioClient_GetCurrentPadding(osw->audio_client, &frames_used))) {
|
||||||
|
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
osw->writable_frame_count = osw->buffer_frame_count - frames_used;
|
||||||
|
double time_until_underrun = frames_used / (double)outstream->sample_rate;
|
||||||
|
double wait_time = time_until_underrun / 2.0;
|
||||||
|
soundio_os_mutex_lock(osw->mutex);
|
||||||
|
soundio_os_cond_timed_wait(osw->cond, osw->mutex, wait_time);
|
||||||
|
if (!osw->thread_exit_flag.test_and_set()) {
|
||||||
|
soundio_os_mutex_unlock(osw->mutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
soundio_os_mutex_unlock(osw->mutex);
|
||||||
|
|
||||||
|
if (FAILED(hr = IAudioClient_GetCurrentPadding(osw->audio_client, &frames_used))) {
|
||||||
|
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
osw->writable_frame_count = osw->buffer_frame_count - frames_used;
|
||||||
|
if (osw->writable_frame_count > 0)
|
||||||
|
outstream->write_callback(outstream, 0, osw->writable_frame_count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_start_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
static int outstream_start_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
|
@ -1128,11 +1200,36 @@ static int outstream_start_wasapi(struct SoundIoPrivate *si, struct SoundIoOutSt
|
||||||
static int outstream_begin_write_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
|
static int outstream_begin_write_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
|
||||||
SoundIoChannelArea **out_areas, int *frame_count)
|
SoundIoChannelArea **out_areas, int *frame_count)
|
||||||
{
|
{
|
||||||
soundio_panic("TODO");
|
SoundIoOutStreamWasapi *osw = &os->backend_data.wasapi;
|
||||||
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
osw->write_frame_count = *frame_count;
|
||||||
|
|
||||||
|
char *data;
|
||||||
|
if (FAILED(hr = IAudioRenderClient_GetBuffer(osw->audio_render_client,
|
||||||
|
osw->write_frame_count, (BYTE**)&data)))
|
||||||
|
{
|
||||||
|
return SoundIoErrorStreaming;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||||
|
osw->areas[ch].ptr = data + ch * outstream->bytes_per_sample;
|
||||||
|
osw->areas[ch].step = outstream->bytes_per_frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_areas = osw->areas;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_end_write_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
static int outstream_end_write_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
soundio_panic("TODO");
|
SoundIoOutStreamWasapi *osw = &os->backend_data.wasapi;
|
||||||
|
HRESULT hr;
|
||||||
|
if (FAILED(hr = IAudioRenderClient_ReleaseBuffer(osw->audio_render_client, osw->write_frame_count, 0))) {
|
||||||
|
return SoundIoErrorStreaming;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_clear_buffer_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
static int outstream_clear_buffer_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
|
@ -1140,6 +1237,7 @@ static int outstream_clear_buffer_wasapi(struct SoundIoPrivate *si, struct Sound
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
if (FAILED(hr = IAudioClient_Reset(osw->audio_client)))
|
if (FAILED(hr = IAudioClient_Reset(osw->audio_client)))
|
||||||
return SoundIoErrorStreaming;
|
return SoundIoErrorStreaming;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,11 +53,17 @@ struct SoundIoWasapi {
|
||||||
struct SoundIoOutStreamWasapi {
|
struct SoundIoOutStreamWasapi {
|
||||||
IAudioClient *audio_client;
|
IAudioClient *audio_client;
|
||||||
IAudioClockAdjustment *audio_clock_adjustment;
|
IAudioClockAdjustment *audio_clock_adjustment;
|
||||||
|
IAudioRenderClient *audio_render_client;
|
||||||
bool need_resample;
|
bool need_resample;
|
||||||
SoundIoOsThread *thread;
|
SoundIoOsThread *thread;
|
||||||
|
SoundIoOsMutex *mutex;
|
||||||
|
SoundIoOsCond *cond;
|
||||||
atomic_flag thread_exit_flag;
|
atomic_flag thread_exit_flag;
|
||||||
bool is_raw;
|
bool is_raw;
|
||||||
|
int writable_frame_count;
|
||||||
UINT32 buffer_frame_count;
|
UINT32 buffer_frame_count;
|
||||||
|
int write_frame_count;
|
||||||
|
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundIoInStreamWasapi {
|
struct SoundIoInStreamWasapi {
|
||||||
|
|
Loading…
Reference in a new issue