Skip to content

Commit

Permalink
Implement audio driver/device selection
Browse files Browse the repository at this point in the history
  • Loading branch information
superctr committed Apr 8, 2021
1 parent ce1ed20 commit a86febd
Show file tree
Hide file tree
Showing 4 changed files with 221 additions and 72 deletions.
207 changes: 143 additions & 64 deletions src/audio_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

//! First time initialization
Audio_Manager::Audio_Manager()
: audio_enabled(0)
: driver_sig(-1)
, driver_id(-1)
, device_id(-1)
, sample_rate(44100)
Expand All @@ -22,32 +22,21 @@ Audio_Manager::Audio_Manager()
, window_handle(nullptr)
, driver_handle(nullptr)
, waiting_for_handle(false)
, audio_initialized(false)
, driver_opened(false)
, device_opened(false)
, driver_names()
, device_names()
, driver_list()
, device_list()
{
if (Audio_Init())
{
fprintf(stderr, "Warning: audio initialization failed. Muting audio\n");
set_audio_enabled(false);
}
else
{
set_audio_enabled(true);
audio_initialized = true;
enumerate_drivers();
}

enumerate_drivers();
while(driver_id < (int)driver_names.size())
{
if(!open_driver())
break;
driver_id++;
}
if(driver_opened)
open_device();
else
set_audio_enabled(false);
}

//! get the singleton instance of Audio_Manager
Expand All @@ -57,16 +46,121 @@ Audio_Manager& Audio_Manager::get()
return instance;
}

//! Set global volume
void Audio_Manager::set_audio_enabled(bool flag)
void Audio_Manager::set_driver(int new_driver_sig, int new_device_id)
{
std::string name = "";

if(!audio_initialized)
return;

// Reset device to default if we have already opened a device
device_id = new_device_id;

close_driver();

// Find a driver ID
driver_sig = new_driver_sig;
driver_id = -1;
if(driver_sig != -1)
{
auto it = driver_list.find(driver_sig);

if(it != driver_list.end())
{
driver_id = it->second.first;
name = it->second.second;
open_driver();
}
else
{
fprintf(stderr, "Warning: Driver id %02x unavailable, using default\n", driver_sig);
}
}

if(driver_id == -1)
{
// pick the next one automatically if loading fails
for(auto && i : driver_list)
{
driver_sig = i.first;
driver_id = i.second.first;
name = i.second.second;
if(!open_driver())
break;
}
}

if(driver_opened)
{
fprintf(stdout, "Loaded audio driver: '%s'\n", name.c_str());
enumerate_devices();
set_device(device_id);
}
else
{
if(driver_id == -1)
fprintf(stderr, "Warning: No available drivers\n");
else
fprintf(stderr, "Warning: Failed to open driver '%s'\n", name.c_str());
}
}

void Audio_Manager::set_device(int new_device_id)
{
audio_enabled = flag;
std::string name = "";

if(!driver_opened)
return;

close_device();

// Find a driver ID
device_id = -1;
if(new_device_id != -1)
{
auto it = device_list.find(new_device_id);

if(it != device_list.end())
{
device_id = it->first;
name = it->second;
open_device();
}
else
{
fprintf(stderr, "Warning: Device id %02x unavailable, using default\n", new_device_id);
}
}

if(device_id == -1)
{
// pick the next one automatically if loading fails
for(auto && i : device_list)
{
device_id = i.first;
name = i.second;
if(!open_device())
break;
}
}

if(!device_opened)
{
if(device_id == -1)
fprintf(stderr, "Warning: No available devices\n");
else
fprintf(stderr, "Warning: Failed to open device '%s'\n", name.c_str());
}
else
{
fprintf(stdout, "Loaded audio device: '%s'\n", name.c_str());
}
}

//! Get global volume
bool Audio_Manager::get_audio_enabled() const
{
return audio_enabled;
return audio_initialized && driver_opened && device_opened;
}

//! Set window handle (for APIs where this is required)
Expand All @@ -75,11 +169,8 @@ void Audio_Manager::set_window_handle(void* new_handle)
window_handle = new_handle;
if(waiting_for_handle)
{
waiting_for_handle = false;
if(open_driver())
set_audio_enabled(false);
else
set_audio_enabled(true);
if(!open_driver())
waiting_for_handle = false;
}
if(driver_opened && !device_opened)
{
Expand Down Expand Up @@ -130,77 +221,65 @@ int Audio_Manager::add_stream(std::shared_ptr<Audio_Stream> stream)
void Audio_Manager::clean_up()
{
close_driver();
if(audio_enabled)
if(audio_initialized)
Audio_Deinit();
}

//=====================================================================

void Audio_Manager::enumerate_drivers()
{
driver_list.clear();

unsigned int driver_count = Audio_GetDriverCount();
if(!driver_count)
{
fprintf(stderr, "Warning: no audio drivers available. Muting audio\n");
set_audio_enabled(0);
return;
}

printf("Available audio drivers ...\n");
for(unsigned int i = 0; i < driver_count; i++)
else
{
AUDDRV_INFO* info;
Audio_GetDriverInfo(i, &info);

if(info->drvType)
printf("Available audio drivers ...\n");
for(unsigned int i = 0; i < driver_count; i++)
{
printf("%d = '%s' (type = %02x, sig = %02x)\n", i, info->drvName, info->drvType, info->drvSig);
driver_names[i] = info->drvName;
}
AUDDRV_INFO* info;
Audio_GetDriverInfo(i, &info);

// Select the first available non-logging driver.
if(info->drvType == ADRVTYPE_OUT && driver_id == -1)
{
driver_id = i;
if(info->drvType == ADRVTYPE_OUT)
{
printf("%d = '%s' (type = %02x, sig = %02x)\n", i, info->drvName, info->drvType, info->drvSig);
driver_list[info->drvSig] = std::make_pair<int, std::string>(i, info->drvName);
}
}
}
printf("default = %d\n", driver_id);
}

void Audio_Manager::enumerate_devices()
{
if(driver_opened)
if(!driver_opened)
return;

const AUDIO_DEV_LIST* list;
list = AudioDrv_GetDeviceList(driver_handle);
device_list.clear();

const AUDIO_DEV_LIST* list = AudioDrv_GetDeviceList(driver_handle);
if(!list->devCount)
{
fprintf(stderr, "Warning: no audio devices available. Muting audio\n");
set_audio_enabled(0);
return;
}

printf("Available audio devices ...\n");
for(unsigned int i = 0; i < list->devCount; i++)
else
{
AUDDRV_INFO* info;
Audio_GetDriverInfo(i, &info);

if(info->drvType)
printf("Available audio devices ...\n");
for(unsigned int i = 0; i < list->devCount; i++)
{
printf("%d = '%s'\n", i, list->devNames[i]);
device_names[i] = list->devNames[i];
}
AUDDRV_INFO* info;
Audio_GetDriverInfo(i, &info);

// Select the first available device
if(device_id == -1)
{
device_id = i;
if(info->drvType)
{
printf("%d = '%s'\n", i, list->devNames[i]);
device_list[i] = list->devNames[i];
}
}
}
printf("default = %d\n", device_id);
}

//! Open a driver
Expand Down
21 changes: 15 additions & 6 deletions src/audio_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ class Audio_Manager

static Audio_Manager& get();

void set_audio_enabled(bool status);
bool get_audio_enabled() const;

void set_window_handle(void* new_handle);
Expand All @@ -87,8 +86,17 @@ class Audio_Manager
void set_volume(float new_volume);
float get_volume() const;

void set_driver(int new_driver_sig, int new_device_id = -1);
inline int get_driver() const { return driver_sig; };

void set_device(int new_device_id);
inline int get_device() const { return device_id; };

int add_stream(std::shared_ptr<Audio_Stream> stream);

const std::map<int, std::pair<int,std::string>>& get_driver_list() const { return driver_list; }
const std::map<int, std::string>& get_device_list() const { return device_list; }

void clean_up();

private:
Expand All @@ -107,10 +115,10 @@ class Audio_Manager

static uint32_t callback(void* drv_struct, void* user_param, uint32_t buf_size, void* data);

bool audio_enabled;
int driver_sig; // Actual driver signature, -1 if not loaded
int driver_id; // Actual driver id, -1 if not loaded
int device_id; // Actual device id, -1 if not loaded

int driver_id;
int device_id;
uint32_t sample_rate;
uint32_t sample_size;

Expand All @@ -122,11 +130,12 @@ class Audio_Manager
void* driver_handle;

bool waiting_for_handle;
bool audio_initialized;
bool driver_opened;
bool device_opened;

std::map<int, std::string> driver_names;
std::map<int, std::string> device_names;
std::map<int, std::pair<int,std::string>> driver_list;
std::map<int, std::string> device_list;

std::mutex mutex;
};
Expand Down
21 changes: 19 additions & 2 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <stdio.h>
#include <csignal>
#include <cstdlib>
#include <cstring>
#include <ctime>

// TODO : https://www.gnu.org/software/libc/manual/html_node/Backtraces.html
Expand Down Expand Up @@ -60,7 +61,6 @@ using namespace gl;
// Our state
Main_Window main_window;


static void sig_handler(int signal)
{
// dump current editor state
Expand Down Expand Up @@ -102,8 +102,24 @@ static void restyle_with_scale(float scale)
ImGui::GetIO().Fonts->AddFontDefault(&font_config);
}

int main(int, char**)
int main(int argc, char* argv[])
{
int driver_id = -1;
int device_id = -1;
int carg = 1;
while(carg < argc)
{
if(!std::strcmp(argv[carg], "--driver-id") && (argc > carg))
{
driver_id = strtol(argv[++carg], NULL, 0);
}
if(!std::strcmp(argv[carg], "--device-id") && (argc > carg))
{
device_id = strtol(argv[++carg], NULL, 0);
}
carg++;
}

// Setup window
glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit())
Expand Down Expand Up @@ -141,6 +157,7 @@ int main(int, char**)
// libvgm DSound support may require the window handle
Audio_Manager::get().set_window_handle(glfwGetWin32Window(window));
#endif
Audio_Manager::get().set_driver(driver_id, device_id);

// Initialize OpenGL loader
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
Expand Down
Loading

0 comments on commit a86febd

Please sign in to comment.