mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2024-12-22 19:05:37 +00:00
Add hardware volume control support to OS X and WASAPI backends
This commit is contained in:
parent
90a4a2e4b7
commit
fe16567e37
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 *);
|
||||||
|
|
29
src/wasapi.c
29
src/wasapi.c
|
@ -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;
|
||||||
|
|
|
@ -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];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue