mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2024-12-22 22:15:29 +00:00
WASAPI: use stream name for session display name
This commit is contained in:
parent
1bb10e6a13
commit
d1f27fad83
17
README.md
17
README.md
|
@ -24,7 +24,7 @@ behavior on every platform.
|
||||||
- [PulseAudio](http://www.freedesktop.org/wiki/Software/PulseAudio/)
|
- [PulseAudio](http://www.freedesktop.org/wiki/Software/PulseAudio/)
|
||||||
- [ALSA](http://www.alsa-project.org/)
|
- [ALSA](http://www.alsa-project.org/)
|
||||||
- [CoreAudio](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/CoreAudioOverview/Introduction/Introduction.html)
|
- [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)
|
- Dummy (silence)
|
||||||
* Exposes both raw devices and shared devices. Raw devices give you the best
|
* Exposes both raw devices and shared devices. Raw devices give you the best
|
||||||
performance but prevent other applications from using them. Shared devices
|
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`
|
back correctly. If possible use the `--in-device` and `--out-device`
|
||||||
parameters to test a USB microphone in raw mode.
|
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
|
## Roadmap
|
||||||
|
|
||||||
0. implement WASAPI (Windows) backend, get examples working
|
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
|
- 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
|
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
|
weird thread-local com stuff, and all that com stuff really needs to be
|
||||||
|
|
|
@ -24,8 +24,13 @@ static void panic(const char *format, ...) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int usage(char *exe) {
|
static int usage(char *exe) {
|
||||||
fprintf(stderr, "Usage: %s [--backend dummy|alsa|pulseaudio|jack|coreaudio|wasapi] [--device id] [--raw]\n",
|
fprintf(stderr, "Usage: %s [options]\n"
|
||||||
exe);
|
"Options:\n"
|
||||||
|
" [--backend dummy|alsa|pulseaudio|jack|coreaudio|wasapi]\n"
|
||||||
|
" [--device id]\n"
|
||||||
|
" [--raw]\n"
|
||||||
|
" [--name stream_name]\n"
|
||||||
|
, exe);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,6 +112,7 @@ int main(int argc, char **argv) {
|
||||||
enum SoundIoBackend backend = SoundIoBackendNone;
|
enum SoundIoBackend backend = SoundIoBackendNone;
|
||||||
char *device_id = NULL;
|
char *device_id = NULL;
|
||||||
bool raw = false;
|
bool raw = false;
|
||||||
|
char *stream_name = NULL;
|
||||||
for (int i = 1; i < argc; i += 1) {
|
for (int i = 1; i < argc; i += 1) {
|
||||||
char *arg = argv[i];
|
char *arg = argv[i];
|
||||||
if (arg[0] == '-' && arg[1] == '-') {
|
if (arg[0] == '-' && arg[1] == '-') {
|
||||||
|
@ -135,6 +141,8 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
} else if (strcmp(arg, "--device") == 0) {
|
} else if (strcmp(arg, "--device") == 0) {
|
||||||
device_id = argv[i];
|
device_id = argv[i];
|
||||||
|
} else if (strcmp(arg, "--name") == 0) {
|
||||||
|
stream_name = argv[i];
|
||||||
} else {
|
} else {
|
||||||
return usage(exe);
|
return usage(exe);
|
||||||
}
|
}
|
||||||
|
@ -186,6 +194,7 @@ int main(int argc, char **argv) {
|
||||||
struct SoundIoOutStream *outstream = soundio_outstream_create(device);
|
struct SoundIoOutStream *outstream = soundio_outstream_create(device);
|
||||||
outstream->write_callback = write_callback;
|
outstream->write_callback = write_callback;
|
||||||
outstream->underflow_callback = underflow_callback;
|
outstream->underflow_callback = underflow_callback;
|
||||||
|
outstream->name = stream_name;
|
||||||
|
|
||||||
if (soundio_device_supports_format(device, SoundIoFormatFloat32NE)) {
|
if (soundio_device_supports_format(device, SoundIoFormatFloat32NE)) {
|
||||||
outstream->format = SoundIoFormatFloat32NE;
|
outstream->format = SoundIoFormatFloat32NE;
|
||||||
|
|
|
@ -453,6 +453,7 @@ struct SoundIoOutStream {
|
||||||
// PulseAudio uses this for the stream name.
|
// PulseAudio uses this for the stream name.
|
||||||
// JACK uses this for the client name of the client that connects when you
|
// JACK uses this for the client name of the client that connects when you
|
||||||
// open the stream.
|
// open the stream.
|
||||||
|
// WASAPI uses this for the session display name.
|
||||||
// Must not contain a colon (":").
|
// Must not contain a colon (":").
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
|
@ -521,6 +522,7 @@ struct SoundIoInStream {
|
||||||
// PulseAudio uses this for the stream name.
|
// PulseAudio uses this for the stream name.
|
||||||
// JACK uses this for the client name of the client that connects when you
|
// JACK uses this for the client name of the client that connects when you
|
||||||
// open the stream.
|
// open the stream.
|
||||||
|
// WASAPI uses this for the session display name.
|
||||||
// Must not contain a colon (":").
|
// Must not contain a colon (":").
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
|
|
|
@ -415,6 +415,9 @@ static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStrea
|
||||||
if (sij->is_shutdown)
|
if (sij->is_shutdown)
|
||||||
return SoundIoErrorBackendDisconnected;
|
return SoundIoErrorBackendDisconnected;
|
||||||
|
|
||||||
|
if (!outstream->name)
|
||||||
|
outstream->name = "SoundIoOutStream";
|
||||||
|
|
||||||
outstream->software_latency = device->software_latency_current;
|
outstream->software_latency = device->software_latency_current;
|
||||||
osj->period_size = sij->period_size;
|
osj->period_size = sij->period_size;
|
||||||
|
|
||||||
|
@ -617,6 +620,9 @@ static int instream_open_jack(struct SoundIoPrivate *si, struct SoundIoInStreamP
|
||||||
if (sij->is_shutdown)
|
if (sij->is_shutdown)
|
||||||
return SoundIoErrorBackendDisconnected;
|
return SoundIoErrorBackendDisconnected;
|
||||||
|
|
||||||
|
if (!instream->name)
|
||||||
|
instream->name = "SoundIoInStream";
|
||||||
|
|
||||||
instream->software_latency = device->software_latency_current;
|
instream->software_latency = device->software_latency_current;
|
||||||
isj->period_size = sij->period_size;
|
isj->period_size = sij->period_size;
|
||||||
|
|
||||||
|
|
|
@ -672,6 +672,9 @@ static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
if ((unsigned)outstream->layout.channel_count > PA_CHANNELS_MAX)
|
if ((unsigned)outstream->layout.channel_count > PA_CHANNELS_MAX)
|
||||||
return SoundIoErrorIncompatibleBackend;
|
return SoundIoErrorIncompatibleBackend;
|
||||||
|
|
||||||
|
if (!outstream->name)
|
||||||
|
outstream->name = "SoundIoOutStream";
|
||||||
|
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
ospa->stream_ready.store(false);
|
ospa->stream_ready.store(false);
|
||||||
|
|
||||||
|
@ -883,6 +886,8 @@ static int instream_open_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
return SoundIoErrorInvalid;
|
return SoundIoErrorInvalid;
|
||||||
if ((unsigned)instream->layout.channel_count > PA_CHANNELS_MAX)
|
if ((unsigned)instream->layout.channel_count > PA_CHANNELS_MAX)
|
||||||
return SoundIoErrorIncompatibleBackend;
|
return SoundIoErrorIncompatibleBackend;
|
||||||
|
if (!instream->name)
|
||||||
|
instream->name = "SoundIoInStream";
|
||||||
|
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
ispa->stream_ready = false;
|
ispa->stream_ready = false;
|
||||||
|
|
|
@ -473,9 +473,6 @@ int soundio_outstream_open(struct SoundIoOutStream *outstream) {
|
||||||
if (!outstream->sample_rate)
|
if (!outstream->sample_rate)
|
||||||
outstream->sample_rate = soundio_device_nearest_sample_rate(device, 48000);
|
outstream->sample_rate = soundio_device_nearest_sample_rate(device, 48000);
|
||||||
|
|
||||||
if (!outstream->name)
|
|
||||||
outstream->name = "SoundIoOutStream";
|
|
||||||
|
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
|
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
|
||||||
outstream->bytes_per_frame = soundio_get_bytes_per_frame(outstream->format, outstream->layout.channel_count);
|
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);
|
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)
|
if (!instream->sample_rate)
|
||||||
instream->sample_rate = soundio_device_nearest_sample_rate(device, 48000);
|
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_frame = soundio_get_bytes_per_frame(instream->format, instream->layout.channel_count);
|
||||||
instream->bytes_per_sample = soundio_get_bytes_per_sample(instream->format);
|
instream->bytes_per_sample = soundio_get_bytes_per_sample(instream->format);
|
||||||
|
|
|
@ -109,6 +109,25 @@ static int from_lpwstr(LPWSTR lpwstr, char **out_str, int *out_str_len) {
|
||||||
return 0;
|
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<wchar_t>(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) {
|
static void from_channel_mask_layout(UINT channel_mask, SoundIoChannelLayout *layout) {
|
||||||
layout->channel_count = 0;
|
layout->channel_count = 0;
|
||||||
if (channel_mask & SPEAKER_FRONT_LEFT)
|
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)
|
if (osw->audio_render_client)
|
||||||
IUnknown_Release(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)
|
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)
|
||||||
|
@ -1010,6 +1031,8 @@ static void outstream_destroy_wasapi(struct SoundIoPrivate *si, struct SoundIoOu
|
||||||
soundio_os_cond_destroy(osw->cond);
|
soundio_os_cond_destroy(osw->cond);
|
||||||
soundio_os_mutex_destroy(osw->mutex);
|
soundio_os_mutex_destroy(osw->mutex);
|
||||||
|
|
||||||
|
free(osw->stream_name);
|
||||||
|
|
||||||
CoUninitialize();
|
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,
|
if (FAILED(hr = IAudioClient_GetService(osw->audio_client, IID_IAudioRenderClient,
|
||||||
(void **)&osw->audio_render_client)))
|
(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,
|
if (FAILED(hr = IAudioClient_GetService(isw->audio_client, IID_IAudioCaptureClient,
|
||||||
(void **)&isw->audio_capture_client)))
|
(void **)&isw->audio_capture_client)))
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <mmreg.h>
|
#include <mmreg.h>
|
||||||
#include <audioclient.h>
|
#include <audioclient.h>
|
||||||
#include <audiosessiontypes.h>
|
#include <audiosessiontypes.h>
|
||||||
|
#include <audiopolicy.h>
|
||||||
|
|
||||||
int soundio_wasapi_init(struct SoundIoPrivate *si);
|
int soundio_wasapi_init(struct SoundIoPrivate *si);
|
||||||
|
|
||||||
|
@ -53,6 +54,8 @@ struct SoundIoOutStreamWasapi {
|
||||||
IAudioClient *audio_client;
|
IAudioClient *audio_client;
|
||||||
IAudioClockAdjustment *audio_clock_adjustment;
|
IAudioClockAdjustment *audio_clock_adjustment;
|
||||||
IAudioRenderClient *audio_render_client;
|
IAudioRenderClient *audio_render_client;
|
||||||
|
IAudioSessionControl *audio_session_control;
|
||||||
|
LPWSTR stream_name;
|
||||||
bool need_resample;
|
bool need_resample;
|
||||||
SoundIoOsThread *thread;
|
SoundIoOsThread *thread;
|
||||||
SoundIoOsMutex *mutex;
|
SoundIoOsMutex *mutex;
|
||||||
|
@ -70,6 +73,8 @@ struct SoundIoOutStreamWasapi {
|
||||||
struct SoundIoInStreamWasapi {
|
struct SoundIoInStreamWasapi {
|
||||||
IAudioClient *audio_client;
|
IAudioClient *audio_client;
|
||||||
IAudioCaptureClient *audio_capture_client;
|
IAudioCaptureClient *audio_capture_client;
|
||||||
|
IAudioSessionControl *audio_session_control;
|
||||||
|
LPWSTR stream_name;
|
||||||
SoundIoOsThread *thread;
|
SoundIoOsThread *thread;
|
||||||
SoundIoOsMutex *mutex;
|
SoundIoOsMutex *mutex;
|
||||||
SoundIoOsCond *cond;
|
SoundIoOsCond *cond;
|
||||||
|
|
Loading…
Reference in a new issue