mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2025-01-20 18:31:11 +00:00
parent
c88e79cb7b
commit
c14d61fa32
|
@ -186,6 +186,11 @@ int main(int argc, char **argv) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fprintf(stderr,
|
||||||
|
"'p\\n' - pause\n"
|
||||||
|
"'u\\n' - unpause\n"
|
||||||
|
"'c\\n' - clear buffer\n"
|
||||||
|
"'q\\n' - quit\n");
|
||||||
fprintf(stderr, "Output device: %s\n", device->name);
|
fprintf(stderr, "Output device: %s\n", device->name);
|
||||||
|
|
||||||
if (device->probe_error) {
|
if (device->probe_error) {
|
||||||
|
|
|
@ -973,12 +973,17 @@ SOUNDIO_EXPORT int soundio_outstream_end_write(struct SoundIoOutStream *outstrea
|
||||||
|
|
||||||
/// Clears the output stream buffer.
|
/// Clears the output stream buffer.
|
||||||
/// This function can be called from any thread.
|
/// This function can be called from any thread.
|
||||||
|
/// This function can be called regardless of whether the outstream is paused
|
||||||
|
/// or not.
|
||||||
/// Some backends do not support clearing the buffer. On these backends this
|
/// Some backends do not support clearing the buffer. On these backends this
|
||||||
/// function will return SoundIoErrorIncompatibleBackend.
|
/// function will return SoundIoErrorIncompatibleBackend.
|
||||||
|
/// Some devices do not support clearing the buffer. On these devices this
|
||||||
|
/// function might return SoundIoErrorIncompatibleDevice.
|
||||||
/// Possible errors:
|
/// Possible errors:
|
||||||
///
|
///
|
||||||
/// * #SoundIoErrorStreaming
|
/// * #SoundIoErrorStreaming
|
||||||
/// * #SoundIoErrorIncompatibleBackend
|
/// * #SoundIoErrorIncompatibleBackend
|
||||||
|
/// * #SoundIoErrorIncompatibleDevice
|
||||||
SOUNDIO_EXPORT int soundio_outstream_clear_buffer(struct SoundIoOutStream *outstream);
|
SOUNDIO_EXPORT int soundio_outstream_clear_buffer(struct SoundIoOutStream *outstream);
|
||||||
|
|
||||||
/// If the underlying device supports pausing, this pauses the stream.
|
/// If the underlying device supports pausing, this pauses the stream.
|
||||||
|
|
|
@ -1138,6 +1138,7 @@ static void instream_thread_run(void *arg) {
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
case SND_PCM_STATE_RUNNING:
|
case SND_PCM_STATE_RUNNING:
|
||||||
|
case SND_PCM_STATE_PAUSED:
|
||||||
{
|
{
|
||||||
if ((err = instream_wait_for_poll(is)) < 0) {
|
if ((err = instream_wait_for_poll(is)) < 0) {
|
||||||
if (!isa->thread_exit_flag.test_and_set())
|
if (!isa->thread_exit_flag.test_and_set())
|
||||||
|
@ -1176,7 +1177,6 @@ static void instream_thread_run(void *arg) {
|
||||||
continue;
|
continue;
|
||||||
case SND_PCM_STATE_OPEN:
|
case SND_PCM_STATE_OPEN:
|
||||||
case SND_PCM_STATE_DRAINING:
|
case SND_PCM_STATE_DRAINING:
|
||||||
case SND_PCM_STATE_PAUSED:
|
|
||||||
case SND_PCM_STATE_DISCONNECTED:
|
case SND_PCM_STATE_DISCONNECTED:
|
||||||
instream->error_callback(instream, SoundIoErrorStreaming);
|
instream->error_callback(instream, SoundIoErrorStreaming);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1246,6 +1246,38 @@ void outstream_shared_run(SoundIoOutStreamPrivate *os) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
soundio_os_mutex_unlock(osw->mutex);
|
soundio_os_mutex_unlock(osw->mutex);
|
||||||
|
bool reset_buffer = false;
|
||||||
|
if (!osw->clear_buffer_flag.test_and_set()) {
|
||||||
|
if (!osw->is_paused) {
|
||||||
|
if (FAILED(hr = IAudioClient_Stop(osw->audio_client))) {
|
||||||
|
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
osw->is_paused = true;
|
||||||
|
}
|
||||||
|
if (FAILED(hr = IAudioClient_Reset(osw->audio_client))) {
|
||||||
|
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
osw->pause_resume_flag.clear();
|
||||||
|
reset_buffer = true;
|
||||||
|
}
|
||||||
|
if (!osw->pause_resume_flag.test_and_set()) {
|
||||||
|
bool pause = osw->desired_pause_state.load();
|
||||||
|
if (pause && !osw->is_paused) {
|
||||||
|
if (FAILED(hr = IAudioClient_Stop(osw->audio_client))) {
|
||||||
|
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
osw->is_paused = true;
|
||||||
|
} else if (!pause && osw->is_paused) {
|
||||||
|
if (FAILED(hr = IAudioClient_Start(osw->audio_client))) {
|
||||||
|
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
osw->is_paused = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (FAILED(hr = IAudioClient_GetCurrentPadding(osw->audio_client, &frames_used))) {
|
if (FAILED(hr = IAudioClient_GetCurrentPadding(osw->audio_client, &frames_used))) {
|
||||||
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
||||||
|
@ -1253,7 +1285,7 @@ void outstream_shared_run(SoundIoOutStreamPrivate *os) {
|
||||||
}
|
}
|
||||||
osw->writable_frame_count = osw->buffer_frame_count - frames_used;
|
osw->writable_frame_count = osw->buffer_frame_count - frames_used;
|
||||||
if (osw->writable_frame_count > 0) {
|
if (osw->writable_frame_count > 0) {
|
||||||
if (frames_used == 0)
|
if (frames_used == 0 && !reset_buffer)
|
||||||
outstream->underflow_callback(outstream);
|
outstream->underflow_callback(outstream);
|
||||||
outstream->write_callback(outstream, 0, osw->writable_frame_count);
|
outstream->write_callback(outstream, 0, osw->writable_frame_count);
|
||||||
}
|
}
|
||||||
|
@ -1277,6 +1309,22 @@ void outstream_raw_run(SoundIoOutStreamPrivate *os) {
|
||||||
WaitForSingleObject(osw->h_event, INFINITE);
|
WaitForSingleObject(osw->h_event, INFINITE);
|
||||||
if (!osw->thread_exit_flag.test_and_set())
|
if (!osw->thread_exit_flag.test_and_set())
|
||||||
return;
|
return;
|
||||||
|
if (!osw->pause_resume_flag.test_and_set()) {
|
||||||
|
bool pause = osw->desired_pause_state.load();
|
||||||
|
if (pause && !osw->is_paused) {
|
||||||
|
if (FAILED(hr = IAudioClient_Stop(osw->audio_client))) {
|
||||||
|
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
osw->is_paused = true;
|
||||||
|
} else if (!pause && osw->is_paused) {
|
||||||
|
if (FAILED(hr = IAudioClient_Start(osw->audio_client))) {
|
||||||
|
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
osw->is_paused = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
outstream->write_callback(outstream, osw->buffer_frame_count, osw->buffer_frame_count);
|
outstream->write_callback(outstream, osw->buffer_frame_count, osw->buffer_frame_count);
|
||||||
}
|
}
|
||||||
|
@ -1331,6 +1379,10 @@ static int outstream_open_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStr
|
||||||
SoundIoDevice *device = outstream->device;
|
SoundIoDevice *device = outstream->device;
|
||||||
SoundIo *soundio = &si->pub;
|
SoundIo *soundio = &si->pub;
|
||||||
|
|
||||||
|
osw->pause_resume_flag.test_and_set();
|
||||||
|
osw->clear_buffer_flag.test_and_set();
|
||||||
|
osw->desired_pause_state.store(false);
|
||||||
|
|
||||||
// All the COM functions are supposed to be called from the same thread. libsoundio API does not
|
// All the COM functions are supposed to be called from the same thread. libsoundio API does not
|
||||||
// restrict the calling thread context in this way. Furthermore, the user might have called
|
// restrict the calling thread context in this way. Furthermore, the user might have called
|
||||||
// CoInitializeEx with a different threading model than Single Threaded Apartment.
|
// CoInitializeEx with a different threading model than Single Threaded Apartment.
|
||||||
|
@ -1385,19 +1437,19 @@ static int outstream_open_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStr
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int outstream_pause_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
|
static int outstream_pause_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
|
||||||
SoundIoOutStreamWasapi *osw = &os->backend_data.wasapi;
|
SoundIoOutStreamWasapi *osw = &os->backend_data.wasapi;
|
||||||
HRESULT hr;
|
|
||||||
if (pause && !osw->is_paused) {
|
osw->desired_pause_state.store(pause);
|
||||||
if (FAILED(hr = IAudioClient_Stop(osw->audio_client)))
|
osw->pause_resume_flag.clear();
|
||||||
return SoundIoErrorStreaming;
|
if (osw->h_event) {
|
||||||
osw->is_paused = true;
|
SetEvent(osw->h_event);
|
||||||
} else if (!pause && osw->is_paused) {
|
} else {
|
||||||
if (FAILED(hr = IAudioClient_Start(osw->audio_client)))
|
soundio_os_mutex_lock(osw->mutex);
|
||||||
return SoundIoErrorStreaming;
|
soundio_os_cond_signal(osw->cond, osw->mutex);
|
||||||
osw->is_paused = false;
|
soundio_os_mutex_unlock(osw->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1450,9 +1502,15 @@ static int outstream_end_write_wasapi(struct SoundIoPrivate *si, struct SoundIoO
|
||||||
|
|
||||||
static int outstream_clear_buffer_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
static int outstream_clear_buffer_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamWasapi *osw = &os->backend_data.wasapi;
|
SoundIoOutStreamWasapi *osw = &os->backend_data.wasapi;
|
||||||
HRESULT hr;
|
|
||||||
if (FAILED(hr = IAudioClient_Reset(osw->audio_client)))
|
if (osw->h_event) {
|
||||||
return SoundIoErrorStreaming;
|
return SoundIoErrorIncompatibleDevice;
|
||||||
|
} else {
|
||||||
|
osw->clear_buffer_flag.clear();
|
||||||
|
soundio_os_mutex_lock(osw->mutex);
|
||||||
|
soundio_os_cond_signal(osw->cond, osw->mutex);
|
||||||
|
soundio_os_mutex_unlock(osw->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,9 @@ struct SoundIoOutStreamWasapi {
|
||||||
UINT32 buffer_frame_count;
|
UINT32 buffer_frame_count;
|
||||||
int write_frame_count;
|
int write_frame_count;
|
||||||
HANDLE h_event;
|
HANDLE h_event;
|
||||||
|
atomic_bool desired_pause_state;
|
||||||
|
atomic_flag pause_resume_flag;
|
||||||
|
atomic_flag clear_buffer_flag;
|
||||||
bool is_paused;
|
bool is_paused;
|
||||||
bool open_complete;
|
bool open_complete;
|
||||||
int open_err;
|
int open_err;
|
||||||
|
|
Loading…
Reference in a new issue