Add hardware volume control support to OS X and WASAPI backends

This commit is contained in:
Ryan Walklin 2017-09-10 23:50:25 +10:00
parent 90a4a2e4b7
commit fe16567e37
7 changed files with 64 additions and 2 deletions

View file

@ -536,7 +536,8 @@ struct SoundIoOutStream {
/// For JACK, this value is always equal to /// For JACK, this value is always equal to
/// SoundIoDevice::software_latency_current of the device. /// SoundIoDevice::software_latency_current of the device.
double software_latency; double software_latency;
/// Core Audio and WASAPI only: current output Audio Unit volume. Float, 0.0-1.0.
float volume;
/// Defaults to NULL. Put whatever you want here. /// Defaults to NULL. Put whatever you want here.
void *userdata; void *userdata;
/// In this callback, you call ::soundio_outstream_begin_write and /// In this callback, you call ::soundio_outstream_begin_write and
@ -1057,6 +1058,9 @@ SOUNDIO_EXPORT int soundio_outstream_pause(struct SoundIoOutStream *outstream, b
SOUNDIO_EXPORT int soundio_outstream_get_latency(struct SoundIoOutStream *outstream, SOUNDIO_EXPORT int soundio_outstream_get_latency(struct SoundIoOutStream *outstream,
double *out_latency); double *out_latency);
SOUNDIO_EXPORT int soundio_outstream_set_volume(struct SoundIoOutStream *outstream,
double volume);
// Input Streams // Input Streams

View file

@ -1045,6 +1045,11 @@ static int outstream_open_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamP
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
if ((os_err = AudioUnitGetParameter (osca->instance, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, &outstream->volume))) {
outstream_destroy_ca(si, os);
return SoundIoErrorOpeningDevice;
}
osca->hardware_latency = dca->latency_frames / (double)outstream->sample_rate; osca->hardware_latency = dca->latency_frames / (double)outstream->sample_rate;
return 0; return 0;
@ -1115,6 +1120,18 @@ static int outstream_get_latency_ca(struct SoundIoPrivate *si, struct SoundIoOut
return 0; return 0;
} }
static int outstream_set_volume_ca(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, float volume) {
struct SoundIoOutStreamCoreAudio *osca = &os->backend_data.coreaudio;
struct SoundIoOutStream *outstream = &os->pub;
OSStatus os_err;
if ((os_err = AudioUnitSetParameter (osca->instance, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, volume, 0))) {
return SoundIoErrorIncompatibleDevice;
}
outstream->volume = volume;
return 0;
}
static OSStatus on_instream_device_overload(AudioObjectID in_object_id, UInt32 in_number_addresses, static OSStatus on_instream_device_overload(AudioObjectID in_object_id, UInt32 in_number_addresses,
const AudioObjectPropertyAddress in_addresses[], void *in_client_data) const AudioObjectPropertyAddress in_addresses[], void *in_client_data)
{ {
@ -1456,6 +1473,7 @@ int soundio_coreaudio_init(struct SoundIoPrivate *si) {
si->outstream_clear_buffer = outstream_clear_buffer_ca; si->outstream_clear_buffer = outstream_clear_buffer_ca;
si->outstream_pause = outstream_pause_ca; si->outstream_pause = outstream_pause_ca;
si->outstream_get_latency = outstream_get_latency_ca; si->outstream_get_latency = outstream_get_latency_ca;
si->outstream_set_volume = outstream_set_volume_ca;
si->instream_open = instream_open_ca; si->instream_open = instream_open_ca;
si->instream_destroy = instream_destroy_ca; si->instream_destroy = instream_destroy_ca;

View file

@ -52,6 +52,7 @@ struct SoundIoOutStreamCoreAudio {
int frames_left; int frames_left;
int write_frame_count; int write_frame_count;
double hardware_latency; double hardware_latency;
float volume;
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS]; struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
}; };

View file

@ -272,6 +272,7 @@ void soundio_disconnect(struct SoundIo *soundio) {
si->outstream_clear_buffer = NULL; si->outstream_clear_buffer = NULL;
si->outstream_pause = NULL; si->outstream_pause = NULL;
si->outstream_get_latency = NULL; si->outstream_get_latency = NULL;
si->outstream_set_volume = NULL;
si->instream_open = NULL; si->instream_open = NULL;
si->instream_destroy = NULL; si->instream_destroy = NULL;
@ -560,6 +561,13 @@ int soundio_outstream_get_latency(struct SoundIoOutStream *outstream, double *ou
return si->outstream_get_latency(si, os, out_latency); return si->outstream_get_latency(si, os, out_latency);
} }
int soundio_outstream_set_volume(struct SoundIoOutStream *outstream, double volume) {
struct SoundIo *soundio = outstream->device->soundio;
struct SoundIoPrivate *si = (struct SoundIoPrivate *)soundio;
struct SoundIoOutStreamPrivate *os = (struct SoundIoOutStreamPrivate *)outstream;
return si->outstream_set_volume(si, os, volume);
}
static void default_instream_error_callback(struct SoundIoInStream *is, int err) { static void default_instream_error_callback(struct SoundIoInStream *is, int err) {
soundio_panic("libsoundio: %s", soundio_strerror(err)); soundio_panic("libsoundio: %s", soundio_strerror(err));
} }

View file

@ -152,7 +152,7 @@ struct SoundIoPrivate {
int (*outstream_clear_buffer)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *); int (*outstream_clear_buffer)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
int (*outstream_pause)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, bool pause); int (*outstream_pause)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, bool pause);
int (*outstream_get_latency)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, double *out_latency); int (*outstream_get_latency)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, double *out_latency);
int (*outstream_set_volume)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, float volume);
int (*instream_open)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *); int (*instream_open)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
void (*instream_destroy)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *); void (*instream_destroy)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);

View file

@ -1181,6 +1181,8 @@ static void force_device_scan_wasapi(struct SoundIoPrivate *si) {
static void outstream_thread_deinit(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) { static void outstream_thread_deinit(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
struct SoundIoOutStreamWasapi *osw = &os->backend_data.wasapi; struct SoundIoOutStreamWasapi *osw = &os->backend_data.wasapi;
if (osw->audio_volume_control)
IUnknown_Release(osw->audio_volume_control);
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) if (osw->audio_session_control)
@ -1378,6 +1380,17 @@ static int outstream_do_open(struct SoundIoPrivate *si, struct SoundIoOutStreamP
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
if (FAILED(hr = IAudioClient_GetService(osw->audio_client, IID_ISimpleAudioVolume,
(void **)&osw->audio_volume_control)))
{
return SoundIoErrorOpeningDevice;
}
if (FAILED(hr = osw->audio_volume_control->GetMasterVolume(&volume)))
{
return SoundIoErrorOpeningDevice;
}
return 0; return 0;
} }
@ -1706,6 +1719,21 @@ static int outstream_get_latency_wasapi(struct SoundIoPrivate *si, struct SoundI
return 0; return 0;
} }
static int outstream_set_volume_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, float volume)
{
struct SoundIoOutStream *outstream = &os->pub;
struct SoundIoOutStreamWasapi *osw = &os->backend_data.wasapi;
HRESULT hr;
if (FAILED(hr = osw->audio_volume_control->SetMasterVolume(&volume)))
{
return SoundIoErrorIncompatibleDevice;
}
outstream->volume = volume;
return 0;
}
static void instream_thread_deinit(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) { static void instream_thread_deinit(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
struct SoundIoInStreamWasapi *isw = &is->backend_data.wasapi; struct SoundIoInStreamWasapi *isw = &is->backend_data.wasapi;
@ -2295,6 +2323,7 @@ int soundio_wasapi_init(struct SoundIoPrivate *si) {
si->outstream_clear_buffer = outstream_clear_buffer_wasapi; si->outstream_clear_buffer = outstream_clear_buffer_wasapi;
si->outstream_pause = outstream_pause_wasapi; si->outstream_pause = outstream_pause_wasapi;
si->outstream_get_latency = outstream_get_latency_wasapi; si->outstream_get_latency = outstream_get_latency_wasapi;
si->outstream_set_volume = outstream_set_volume_wasapi;
si->instream_open = instream_open_wasapi; si->instream_open = instream_open_wasapi;
si->instream_destroy = instream_destroy_wasapi; si->instream_destroy = instream_destroy_wasapi;

View file

@ -56,6 +56,7 @@ struct SoundIoOutStreamWasapi {
IAudioClockAdjustment *audio_clock_adjustment; IAudioClockAdjustment *audio_clock_adjustment;
IAudioRenderClient *audio_render_client; IAudioRenderClient *audio_render_client;
IAudioSessionControl *audio_session_control; IAudioSessionControl *audio_session_control;
ISimpleAudioVolume *audio_volume_control;
LPWSTR stream_name; LPWSTR stream_name;
bool need_resample; bool need_resample;
struct SoundIoOsThread *thread; struct SoundIoOsThread *thread;
@ -76,6 +77,7 @@ struct SoundIoOutStreamWasapi {
int open_err; int open_err;
bool started; bool started;
UINT32 min_padding_frames; UINT32 min_padding_frames;
float volume;
struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS]; struct SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
}; };