From d1f27fad83a8b1adcb8901b57bf9acfe72fc9993 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 24 Aug 2015 19:52:43 -0700 Subject: [PATCH] WASAPI: use stream name for session display name --- README.md | 17 +----------- example/sio_sine.c | 13 ++++++++-- soundio/soundio.h | 2 ++ src/jack.cpp | 6 +++++ src/pulseaudio.cpp | 5 ++++ src/soundio.cpp | 6 ----- src/wasapi.cpp | 65 ++++++++++++++++++++++++++++++++++++++++++++++ src/wasapi.hpp | 5 ++++ 8 files changed, 95 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 01ab0b4..b3e01ee 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ behavior on every platform. - [PulseAudio](http://www.freedesktop.org/wiki/Software/PulseAudio/) - [ALSA](http://www.alsa-project.org/) - [CoreAudio](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/CoreAudioOverview/Introduction/Introduction.html) - - (in progress) [WASAPI](https://msdn.microsoft.com/en-us/library/windows/desktop/dd371455%28v=vs.85%29.aspx) + - [WASAPI](https://msdn.microsoft.com/en-us/library/windows/desktop/dd371455%28v=vs.85%29.aspx) - Dummy (silence) * Exposes both raw devices and shared devices. Raw devices give you the best performance but prevent other applications from using them. Shared devices @@ -260,24 +260,9 @@ For each backend, do the following: back correctly. If possible use the `--in-device` and `--out-device` parameters to test a USB microphone in raw mode. -``` -make test -``` - -For more detailed output: - -``` -make -./unit_tests -``` - -To see test coverage, install lcov, run `make coverage` and then -view `coverage/index.html` in a browser. - ## Roadmap 0. implement WASAPI (Windows) backend, get examples working - - set display name of output stream - move the bulk of the `outstream_open_wasapi` code to the thread and have them communicate back and forth. because the thread has to do weird thread-local com stuff, and all that com stuff really needs to be diff --git a/example/sio_sine.c b/example/sio_sine.c index 3e21b12..29a041a 100644 --- a/example/sio_sine.c +++ b/example/sio_sine.c @@ -24,8 +24,13 @@ static void panic(const char *format, ...) { } static int usage(char *exe) { - fprintf(stderr, "Usage: %s [--backend dummy|alsa|pulseaudio|jack|coreaudio|wasapi] [--device id] [--raw]\n", - exe); + fprintf(stderr, "Usage: %s [options]\n" + "Options:\n" + " [--backend dummy|alsa|pulseaudio|jack|coreaudio|wasapi]\n" + " [--device id]\n" + " [--raw]\n" + " [--name stream_name]\n" + , exe); return EXIT_FAILURE; } @@ -107,6 +112,7 @@ int main(int argc, char **argv) { enum SoundIoBackend backend = SoundIoBackendNone; char *device_id = NULL; bool raw = false; + char *stream_name = NULL; for (int i = 1; i < argc; i += 1) { char *arg = argv[i]; if (arg[0] == '-' && arg[1] == '-') { @@ -135,6 +141,8 @@ int main(int argc, char **argv) { } } else if (strcmp(arg, "--device") == 0) { device_id = argv[i]; + } else if (strcmp(arg, "--name") == 0) { + stream_name = argv[i]; } else { return usage(exe); } @@ -186,6 +194,7 @@ int main(int argc, char **argv) { struct SoundIoOutStream *outstream = soundio_outstream_create(device); outstream->write_callback = write_callback; outstream->underflow_callback = underflow_callback; + outstream->name = stream_name; if (soundio_device_supports_format(device, SoundIoFormatFloat32NE)) { outstream->format = SoundIoFormatFloat32NE; diff --git a/soundio/soundio.h b/soundio/soundio.h index 806980d..19276d1 100644 --- a/soundio/soundio.h +++ b/soundio/soundio.h @@ -453,6 +453,7 @@ struct SoundIoOutStream { // PulseAudio uses this for the stream name. // JACK uses this for the client name of the client that connects when you // open the stream. + // WASAPI uses this for the session display name. // Must not contain a colon (":"). const char *name; @@ -521,6 +522,7 @@ struct SoundIoInStream { // PulseAudio uses this for the stream name. // JACK uses this for the client name of the client that connects when you // open the stream. + // WASAPI uses this for the session display name. // Must not contain a colon (":"). const char *name; diff --git a/src/jack.cpp b/src/jack.cpp index 975f6a7..4b7688a 100644 --- a/src/jack.cpp +++ b/src/jack.cpp @@ -415,6 +415,9 @@ static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStrea if (sij->is_shutdown) return SoundIoErrorBackendDisconnected; + if (!outstream->name) + outstream->name = "SoundIoOutStream"; + outstream->software_latency = device->software_latency_current; osj->period_size = sij->period_size; @@ -617,6 +620,9 @@ static int instream_open_jack(struct SoundIoPrivate *si, struct SoundIoInStreamP if (sij->is_shutdown) return SoundIoErrorBackendDisconnected; + if (!instream->name) + instream->name = "SoundIoInStream"; + instream->software_latency = device->software_latency_current; isj->period_size = sij->period_size; diff --git a/src/pulseaudio.cpp b/src/pulseaudio.cpp index e6183b0..8bec784 100644 --- a/src/pulseaudio.cpp +++ b/src/pulseaudio.cpp @@ -672,6 +672,9 @@ static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) { if ((unsigned)outstream->layout.channel_count > PA_CHANNELS_MAX) return SoundIoErrorIncompatibleBackend; + if (!outstream->name) + outstream->name = "SoundIoOutStream"; + SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; ospa->stream_ready.store(false); @@ -883,6 +886,8 @@ static int instream_open_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) { return SoundIoErrorInvalid; if ((unsigned)instream->layout.channel_count > PA_CHANNELS_MAX) return SoundIoErrorIncompatibleBackend; + if (!instream->name) + instream->name = "SoundIoInStream"; SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; ispa->stream_ready = false; diff --git a/src/soundio.cpp b/src/soundio.cpp index a0ea2db..d10e49b 100644 --- a/src/soundio.cpp +++ b/src/soundio.cpp @@ -473,9 +473,6 @@ int soundio_outstream_open(struct SoundIoOutStream *outstream) { if (!outstream->sample_rate) outstream->sample_rate = soundio_device_nearest_sample_rate(device, 48000); - if (!outstream->name) - outstream->name = "SoundIoOutStream"; - SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream; outstream->bytes_per_frame = soundio_get_bytes_per_frame(outstream->format, outstream->layout.channel_count); outstream->bytes_per_sample = soundio_get_bytes_per_sample(outstream->format); @@ -559,9 +556,6 @@ int soundio_instream_open(struct SoundIoInStream *instream) { if (!instream->sample_rate) instream->sample_rate = soundio_device_nearest_sample_rate(device, 48000); - if (!instream->name) - instream->name = "SoundIoInStream"; - instream->bytes_per_frame = soundio_get_bytes_per_frame(instream->format, instream->layout.channel_count); instream->bytes_per_sample = soundio_get_bytes_per_sample(instream->format); diff --git a/src/wasapi.cpp b/src/wasapi.cpp index bc93420..0c61933 100644 --- a/src/wasapi.cpp +++ b/src/wasapi.cpp @@ -109,6 +109,25 @@ static int from_lpwstr(LPWSTR lpwstr, char **out_str, int *out_str_len) { return 0; } +static int to_lpwstr(const char *str, int str_len, LPWSTR *out_lpwstr) { + DWORD flags = 0; + int w_len = MultiByteToWideChar(CP_UTF8, flags, str, str_len, nullptr, 0); + if (w_len <= 0) + return SoundIoErrorEncodingString; + + LPWSTR buf = allocate(w_len + 1); + if (!buf) + return SoundIoErrorNoMem; + + if (MultiByteToWideChar(CP_UTF8, flags, str, str_len, buf, w_len) != w_len) { + free(buf); + return SoundIoErrorEncodingString; + } + + *out_lpwstr = buf; + return 0; +} + static void from_channel_mask_layout(UINT channel_mask, SoundIoChannelLayout *layout) { layout->channel_count = 0; if (channel_mask & SPEAKER_FRONT_LEFT) @@ -1000,6 +1019,8 @@ static void outstream_destroy_wasapi(struct SoundIoPrivate *si, struct SoundIoOu if (osw->audio_render_client) IUnknown_Release(osw->audio_render_client); + if (osw->audio_session_control) + IUnknown_Release(osw->audio_session_control); if (osw->audio_clock_adjustment) IUnknown_Release(osw->audio_clock_adjustment); if (osw->audio_client) @@ -1010,6 +1031,8 @@ static void outstream_destroy_wasapi(struct SoundIoPrivate *si, struct SoundIoOu soundio_os_cond_destroy(osw->cond); soundio_os_mutex_destroy(osw->mutex); + free(osw->stream_name); + CoUninitialize(); } @@ -1172,6 +1195,27 @@ static int outstream_open_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStr } } + if (outstream->name) { + if (FAILED(hr = IAudioClient_GetService(osw->audio_client, IID_IAudioSessionControl, + (void **)&osw->audio_session_control))) + { + outstream_destroy_wasapi(si, os); + return SoundIoErrorOpeningDevice; + } + + int err; + if ((err = to_lpwstr(outstream->name, strlen(outstream->name), &osw->stream_name))) { + outstream_destroy_wasapi(si, os); + return err; + } + if (FAILED(hr = IAudioSessionControl_SetDisplayName(osw->audio_session_control, + osw->stream_name, nullptr))) + { + outstream_destroy_wasapi(si, os); + return SoundIoErrorOpeningDevice; + } + } + if (FAILED(hr = IAudioClient_GetService(osw->audio_client, IID_IAudioRenderClient, (void **)&osw->audio_render_client))) { @@ -1515,6 +1559,27 @@ static int instream_open_wasapi(struct SoundIoPrivate *si, struct SoundIoInStrea } } + if (instream->name) { + if (FAILED(hr = IAudioClient_GetService(isw->audio_client, IID_IAudioSessionControl, + (void **)&isw->audio_session_control))) + { + instream_destroy_wasapi(si, is); + return SoundIoErrorOpeningDevice; + } + + int err; + if ((err = to_lpwstr(instream->name, strlen(instream->name), &isw->stream_name))) { + instream_destroy_wasapi(si, is); + return err; + } + if (FAILED(hr = IAudioSessionControl_SetDisplayName(isw->audio_session_control, + isw->stream_name, nullptr))) + { + instream_destroy_wasapi(si, is); + return SoundIoErrorOpeningDevice; + } + } + if (FAILED(hr = IAudioClient_GetService(isw->audio_client, IID_IAudioCaptureClient, (void **)&isw->audio_capture_client))) { diff --git a/src/wasapi.hpp b/src/wasapi.hpp index 9753349..11d8f01 100644 --- a/src/wasapi.hpp +++ b/src/wasapi.hpp @@ -23,6 +23,7 @@ #include #include #include +#include int soundio_wasapi_init(struct SoundIoPrivate *si); @@ -53,6 +54,8 @@ struct SoundIoOutStreamWasapi { IAudioClient *audio_client; IAudioClockAdjustment *audio_clock_adjustment; IAudioRenderClient *audio_render_client; + IAudioSessionControl *audio_session_control; + LPWSTR stream_name; bool need_resample; SoundIoOsThread *thread; SoundIoOsMutex *mutex; @@ -70,6 +73,8 @@ struct SoundIoOutStreamWasapi { struct SoundIoInStreamWasapi { IAudioClient *audio_client; IAudioCaptureClient *audio_capture_client; + IAudioSessionControl *audio_session_control; + LPWSTR stream_name; SoundIoOsThread *thread; SoundIoOsMutex *mutex; SoundIoOsCond *cond;