diff --git a/addons/audio/allegro5/allegro_audio.h b/addons/audio/allegro5/allegro_audio.h index 505b6f8a38..c614035b1c 100644 --- a/addons/audio/allegro5/allegro_audio.h +++ b/addons/audio/allegro5/allegro_audio.h @@ -368,6 +368,8 @@ ALLEGRO_KCM_AUDIO_FUNC(void, al_fill_silence, (void *buf, unsigned int samples, ALLEGRO_KCM_AUDIO_FUNC(int, al_get_num_audio_output_devices, (void)); ALLEGRO_KCM_AUDIO_FUNC(const ALLEGRO_AUDIO_DEVICE *, al_get_audio_output_device, (int index)); ALLEGRO_KCM_AUDIO_FUNC(const char *, al_get_audio_device_name, (const ALLEGRO_AUDIO_DEVICE * device)); +ALLEGRO_KCM_AUDIO_FUNC(const bool, al_set_audio_output_device, (const ALLEGRO_AUDIO_DEVICE* device)); + /* Simple audio layer */ ALLEGRO_KCM_AUDIO_FUNC(bool, al_reserve_samples, (int reserve_samples)); diff --git a/addons/audio/allegro5/internal/aintern_audio.h b/addons/audio/allegro5/internal/aintern_audio.h index b7fe5f4617..3795994e2a 100644 --- a/addons/audio/allegro5/internal/aintern_audio.h +++ b/addons/audio/allegro5/internal/aintern_audio.h @@ -86,6 +86,7 @@ struct ALLEGRO_AUDIO_DRIVER { void (*deallocate_recorder)(struct ALLEGRO_AUDIO_RECORDER *); _AL_LIST* (*get_output_devices)(void); + int (*set_output_device)(ALLEGRO_AUDIO_DEVICE*); }; extern ALLEGRO_AUDIO_DRIVER *_al_kcm_driver; diff --git a/addons/audio/alsa.c b/addons/audio/alsa.c index cc369717fd..4ec9afb6f4 100644 --- a/addons/audio/alsa.c +++ b/addons/audio/alsa.c @@ -1021,7 +1021,8 @@ ALLEGRO_AUDIO_DRIVER _al_kcm_alsa_driver = alsa_allocate_recorder, alsa_deallocate_recorder, - alsa_get_output_devices + alsa_get_output_devices, + NULL, }; /* vim: set sts=3 sw=3 et: */ diff --git a/addons/audio/aqueue.m b/addons/audio/aqueue.m index d27f3e5628..4a92b44cfa 100644 --- a/addons/audio/aqueue.m +++ b/addons/audio/aqueue.m @@ -129,6 +129,16 @@ static void property_listener(void *inClientData, AudioSessionPropertyID inID, U } #endif +static int _aqueue_set_audio_output_device(ALLEGRO_AUDIO_DEVICE* output_device) { + AudioObjectPropertyAddress propertyAddress; + propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; + propertyAddress.mScope = kAudioDevicePropertyScopeOutput; + propertyAddress.mElement = kAudioObjectPropertyElementMaster; + + return AudioObjectSetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, + sizeof(AudioDeviceID), output_device->identifier) != noErr; +} + static bool _aqueue_device_has_scope(AudioObjectID deviceID, AudioObjectPropertyScope scope) { AudioObjectPropertyAddress propertyAddress = { @@ -679,5 +689,6 @@ static void _aqueue_deallocate_recorder(ALLEGRO_AUDIO_RECORDER *recorder) _aqueue_deallocate_recorder, _aqueue_get_output_devices, + _aqueue_set_audio_output_device, }; diff --git a/addons/audio/audio.c b/addons/audio/audio.c index 6a2a94a6a4..e60cb07368 100644 --- a/addons/audio/audio.c +++ b/addons/audio/audio.c @@ -233,9 +233,18 @@ const ALLEGRO_AUDIO_DEVICE* al_get_audio_output_device(int index) return NULL; } +/* Function: al_set_audio_output_device + */ +const bool al_set_audio_output_device(const ALLEGRO_AUDIO_DEVICE *device) +{ + if (!al_is_audio_installed()) return false; + if (_al_kcm_driver->set_output_device) return _al_kcm_driver->set_output_device(device) == 0; + return false; +} + /* Function: al_get_audio_device_name */ -const char* al_get_audio_device_name(const ALLEGRO_AUDIO_DEVICE * device) +const char* al_get_audio_device_name(const ALLEGRO_AUDIO_DEVICE *device) { return device ? device->name : NULL; } diff --git a/addons/audio/dsound.cpp b/addons/audio/dsound.cpp index a9a851e1f9..c98c8861d2 100644 --- a/addons/audio/dsound.cpp +++ b/addons/audio/dsound.cpp @@ -265,6 +265,52 @@ static void* _dsound_update(ALLEGRO_THREAD *self, void *arg) return NULL; } +static int _dsound_set_audio_output_device(ALLEGRO_AUDIO_DEVICE* output_device) { + ALLEGRO_VOICE* voice = al_get_default_voice(); + ALLEGRO_DS_DATA* ex_data = (ALLEGRO_DS_DATA*)voice->extra; + MAKE_UNION(&ex_data->ds8_buffer, LPDIRECTSOUNDBUFFER8*); + + HRESULT hr; + LPVOID ptr1, ptr2; + DWORD block1_bytes, block2_bytes; + + IDirectSound8* old_device = device; + LPDIRECTSOUNDBUFFER8 old_buffer = ex_data->ds8_buffer; + + hr = old_buffer->Lock(0, voice->buffer_size, &ptr1, &block1_bytes, &ptr2, &block2_bytes, DSBLOCK_ENTIREBUFFER); + if (FAILED(hr)) { + ALLEGRO_ERROR("Failed to lock DIRECTSOUNDBUFFER8: %s\n", ds_get_error(hr)); + printf(ds_get_error(hr)); + return 1; + } + + hr = DirectSoundCreate8((LPCGUID)output_device->identifier, &device, NULL); + if (FAILED(hr)) { + ALLEGRO_ERROR("DirectSoundCreate8 failed: %s\n", ds_get_error(hr)); + return 1; + } + + hr = device->SetCooperativeLevel(get_window(), DSSCL_PRIORITY); + if (FAILED(hr)) { + ALLEGRO_ERROR("SetCooperativeLevel failed: %s\n", ds_get_error(hr)); + return 1; + } + + hr = device->CreateSoundBuffer(&ex_data->desc, &ex_data->ds_buffer, NULL); + if (FAILED(hr)) { + ALLEGRO_ERROR("CreateSoundBuffer failed: %s\n", ds_get_error(hr)); + return 1; + } + + ex_data->ds_buffer->QueryInterface(_al_IID_IDirectSoundBuffer8, u.v); + ex_data->ds8_buffer->SetVolume(DSBVOLUME_MAX); + + old_buffer->Unlock(ptr1, block1_bytes, ptr2, block2_bytes); + old_buffer->Stop(); + old_device->Release(); + + return 0; +} /* The open method starts up the driver and should lock the device, using the previously set parameters, or defaults. It shouldn't need to start sending @@ -879,6 +925,7 @@ ALLEGRO_AUDIO_DRIVER _al_kcm_dsound_driver = { _dsound_close_recorder, _dsound_get_output_devices, + _dsound_set_audio_output_device, }; } /* End extern "C" */ diff --git a/addons/audio/openal.c b/addons/audio/openal.c index 7635ebefd9..c07359e319 100644 --- a/addons/audio/openal.c +++ b/addons/audio/openal.c @@ -663,7 +663,8 @@ ALLEGRO_AUDIO_DRIVER _al_kcm_openal_driver = { NULL, NULL, - NULL + NULL, + NULL, }; /* vim: set sts=3 sw=3 et: */ diff --git a/addons/audio/opensl.c b/addons/audio/opensl.c index b04fc76d48..14138589a2 100644 --- a/addons/audio/opensl.c +++ b/addons/audio/opensl.c @@ -722,5 +722,6 @@ ALLEGRO_AUDIO_DRIVER _al_kcm_opensl_driver = { NULL, NULL, - NULL + NULL, + NULL, }; diff --git a/addons/audio/oss.c b/addons/audio/oss.c index dad698aa10..d87c6cea22 100644 --- a/addons/audio/oss.c +++ b/addons/audio/oss.c @@ -623,7 +623,8 @@ ALLEGRO_AUDIO_DRIVER _al_kcm_oss_driver = NULL, NULL, - NULL + NULL, + NULL, }; /* vim: set sts=3 sw=3 et: */ diff --git a/addons/audio/pulseaudio.c b/addons/audio/pulseaudio.c index 1b9b55de7f..758789b7f0 100644 --- a/addons/audio/pulseaudio.c +++ b/addons/audio/pulseaudio.c @@ -575,7 +575,8 @@ ALLEGRO_AUDIO_DRIVER _al_kcm_pulseaudio_driver = pulseaudio_allocate_recorder, pulseaudio_deallocate_recorder, - pulseaudio_get_output_devices + pulseaudio_get_output_devices, + NULL, }; /* vim: set sts=3 sw=3 et: */ diff --git a/addons/audio/sdl_audio.c b/addons/audio/sdl_audio.c index 777324259c..b7c298d26b 100644 --- a/addons/audio/sdl_audio.c +++ b/addons/audio/sdl_audio.c @@ -269,4 +269,5 @@ ALLEGRO_AUDIO_DRIVER _al_kcm_sdl_driver = sdl_deallocate_recorder, sdl_get_output_devices, + NULL, }; diff --git a/docs/src/refman/audio.txt b/docs/src/refman/audio.txt index abce66b52b..19048cca6d 100644 --- a/docs/src/refman/audio.txt +++ b/docs/src/refman/audio.txt @@ -1412,7 +1412,11 @@ Get the user friendly display name of the device. Since: 5.2.8 +### API: al_set_audio_output_device +Select the audio output device to use. Currently only implemented on Windows and MacOS/iOS. + +Since: 5.2.10 ## Voices diff --git a/examples/ex_audio_simple.c b/examples/ex_audio_simple.c index 9a34500e92..d3f3ecd983 100644 --- a/examples/ex_audio_simple.c +++ b/examples/ex_audio_simple.c @@ -94,8 +94,19 @@ int main(int argc, const char *argv[]) } } + { + int count = al_get_num_audio_output_devices(); // returns -1 for unsupported backends + log_printf("audio device count: %d\n", count); + for (int i = 0; i < count; i++) + { + const ALLEGRO_AUDIO_DEVICE* device = al_get_audio_output_device(i); + log_printf(" --- audio device: %s\n", al_get_audio_device_name(device)); + } + } + log_printf( "Press digits to play sounds.\n" + "Press F1-F12 keys to select audio output device\n" "Space to stop sounds.\n" "Add Alt to play sounds repeatedly.\n" "'p' to pan the last played sound.\n" @@ -115,6 +126,17 @@ int main(int argc, const char *argv[]) } } + if (event.keyboard.keycode >= ALLEGRO_KEY_F1 && event.keyboard.keycode <= ALLEGRO_KEY_F12) { + int device_index = (event.keyboard.keycode - ALLEGRO_KEY_F1 + 12) % 12; + const ALLEGRO_AUDIO_DEVICE* device = al_get_audio_output_device(device_index); + + if (device) { + log_printf("Selected device #%d %s\n", device_index, al_get_audio_device_name(device)); + + al_set_audio_output_device(device); + } + } + if (event.keyboard.keycode >= ALLEGRO_KEY_0 && event.keyboard.keycode <= ALLEGRO_KEY_9) { bool loop = event.keyboard.modifiers & ALLEGRO_KEYMOD_ALT; bool bidir = event.keyboard.modifiers & ALLEGRO_KEYMOD_CTRL; @@ -208,6 +230,9 @@ int main(int argc, const char *argv[]) al_draw_text(font, al_map_rgb_f(1., 0.5, 0.5), 12, y, ALLEGRO_ALIGN_LEFT, "1-9 - play the sounds"); y += dy; + al_draw_text(font, al_map_rgb_f(1., 0.5, 0.5), 12, y, + ALLEGRO_ALIGN_LEFT, "F1 - F12 select audio output device"); + y += dy; al_draw_text(font, al_map_rgb_f(1., 0.5, 0.5), 12, y, ALLEGRO_ALIGN_LEFT, "SPACE - stop all sounds"); y += dy;