5

I have found some examples that claims to list all output devices for audio using openAL, however I can only get them to list the currently selected device on OSX (Yosemite, Maverick). I am using a mac and have the default sound card (Built-in Output) as well as an airplay device and some sound flower devices.

(Note: On windows it lists all devices)

I am expecting s = (char *)alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); to list at least the default card and the sound flower devices. It returns nothing.

s = (char *)alcGetString(NULL, ALC_DEVICE_SPECIFIER); Returns the currently selected device.

Maybe there is some issue with the devices being virtual? however, selecting soundflower from mac settings as default output first make it show up instead o "Built-in Output". We also tried with an external DAC and got the same behaviour.

list of all available output devices: Built-in Output

list of all available input devices: Built-in Microphone

default output device: Built-in Output

default input device: Built-in Microphone

...

Here is the code:

#ifdef __APPLE__
# include <OpenAL/al.h>
# include <OpenAL/alc.h>
#else
# include <AL/al.h>
# include <AL/alc.h>
# include <AL/alext.h>
#endif

#ifndef AL_VERSION_1_1
# ifdef __APPLE__
#  include <OpenAL/altypes.h>
#  include <OpenAL/alctypes.h>
#else
#  include <AL/altypes.h>
#  include <AL/alctypes.h>
# endif
#endif

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <string>

using std::string;

#ifndef ALC_ALL_DEVICES_SPECIFIER
# define ALC_ALL_DEVICES_SPECIFIER      0x1013
#endif

#define MAX_DATA    16
static const int indentation = 4;
static const int maxmimumWidth = 79;

void printExtensions (const char *, char, const char *);
void displayDevices(const char *, const char *);
char *getDeviceName(int, char **);
void testForError(void *, const string&);
void testForALCError(ALCdevice *);

int main(int argc, char **argv)
{
  ALCint data[MAX_DATA];
  ALCdevice *device = NULL;
  ALCcontext *context = NULL;
  ALenum error;
  char *s;
  
  if (alcIsExtensionPresent(NULL, "ALC_enumeration_EXT") == AL_TRUE)
  {
    if (alcIsExtensionPresent(NULL, "ALC_enumerate_all_EXT") == AL_FALSE)
      s = (char *)alcGetString(NULL, ALC_DEVICE_SPECIFIER);
    else
      s = (char *)alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
    displayDevices("output", s);
    
    s = (char *)alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
    displayDevices("input", s);
  }
  
  s = getDeviceName(argc, argv);
  device = alcOpenDevice(s);
  testForError(device, "Audio device not available.");
  
  context = alcCreateContext(device, NULL);
  testForError(context, "Unable to create a valid context.");
  
  alcMakeContextCurrent(context);
  testForALCError(device);
  
  s = (char *)alcGetString(device, ALC_DEFAULT_DEVICE_SPECIFIER);
  printf("default output device: %s\n", s);
  testForALCError(device);
  
  error = alcIsExtensionPresent(device, "ALC_EXT_capture");
  if (error)
  {
    s = (char *)alcGetString(device, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
    printf("default input device:  %s\n", s);
    testForALCError(device);
  }
  printf("capture support: %s\n", (error) ? "yes" : "no");
  
  alcGetIntegerv(device, ALC_FREQUENCY, 1, data);
  printf("mixer frequency: %u hz\n", data[0]);
  testForALCError(device);
  
  alcGetIntegerv(device, ALC_REFRESH, 1, data+1);
  printf("refresh rate : %u hz\n", data[0]/data[1]);
  testForALCError(device);
  
  data[0] = 0;
  alcGetIntegerv(device, ALC_MONO_SOURCES, 1, data);
  error = alcGetError(device);
  if (error == AL_NONE) {
    printf("supported sources; mono: %u, ", data[0]);
    
    data[0] = 0;
    alcGetIntegerv(device, ALC_STEREO_SOURCES, 1, data);
    printf("stereo: %u\n", data[0]);
    testForALCError(device);
  }
  
  printf("ALC version: ");
  alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, data);
  printf("%i.", *data);
  alcGetIntegerv(device, ALC_MINOR_VERSION, 1, data);
  printf("%i\n", *data);
  testForALCError(device);
  
  s = (char *)alcGetString(device, ALC_EXTENSIONS);
  printExtensions ("ALC extensions", ' ', s);
  testForALCError(device);
  
  s = (char *)alGetString(AL_VENDOR);
  error = alGetError();
  if ((error = alGetError()) != AL_NO_ERROR)
    printf("Error #%x: %s\n", error, alGetString(error));
  else
    printf("OpenAL vendor string: %s\n", s);
  
  s = (char *)alGetString(AL_RENDERER);
  if ((error = alGetError()) != AL_NO_ERROR)
    printf("Error #%x: %s\n", error, alGetString(error));
  else
    printf("OpenAL renderer string: %s\n", s);
  
  s = (char *)alGetString(AL_VERSION);
  if ((error = alGetError()) != AL_NO_ERROR)
    printf("Error #%x: %s\n", error, alGetString(error));
  else if (!s)
    printf("Quering AL_VERSION returned NULL pointer!\n");
  else
    printf("OpenAL version string: %s\n", s);
  
  s = (char *)alGetString(AL_EXTENSIONS);
  printExtensions ("OpenAL extensions", ' ', s);
  testForALCError(device);
  
  /* alut testing mechanism */
  context = alcGetCurrentContext();
  if (context == NULL)
  {
    printf("Error: no current context\n");
  }
  else
  {
    if (alGetError () != AL_NO_ERROR)
    {
      printf("Alert: AL error on entry\n");
    }
    else
    {
      if (alcGetError (alcGetContextsDevice (context)) != ALC_NO_ERROR)
      {
        printf("Alert: ALC error on entry\n");
      }
    }
  }
  /* end of alut test */
  
  
  if (alcMakeContextCurrent(NULL) == 0)
    printf("alcMakeContextCurrent failed.\n");
  
  device = alcGetContextsDevice(context);
  alcDestroyContext(context);
  testForALCError(device);
  
  if (alcCloseDevice(device) == 0)
    printf("alcCloseDevice failed.\n");
  
  return 0;
}

/* -------------------------------------------------------------------------- */

void
printChar (int c, int *width)
{
  putchar (c);
  *width = (c == '\n') ? 0 : (*width + 1);
}

void
indent (int *width)
{
  int i;
  for (i = 0; i < indentation; i++)
  {
    printChar (' ', width);
  }
}

void
printExtensions (const char *header, char separator, const char *extensions)
{
  int width = 0, start = 0, end = 0;
  
  printf ("%s:\n", header);
  if (extensions == NULL || extensions[0] == '\0')
  {
    return;
  }
  
  indent (&width);
  while (1)
  {
    if (extensions[end] == separator || extensions[end] == '\0')
    {
      if (width + end - start + 2 > maxmimumWidth)
      {
        printChar ('\n', &width);
        indent (&width);
      }
      while (start < end)
      {
        printChar (extensions[start], &width);
        start++;
      }
      if (extensions[end] == '\0')
      {
        break;
      }
      start++;
      end++;
      if (extensions[end] == '\0')
      {
        break;
      }
      printChar (',', &width);
      printChar (' ', &width);
    }
    end++;
  }
  printChar ('\n', &width);
}

char *
getCommandLineOption(int argc, char **argv, const string& option)
{
  int slen = option.size();
  char *rv = 0;
  int i;
  
  for (i=0; i<argc; i++)
  {
    if (strncmp(argv[i], option.c_str(), slen) == 0)
    {
      i++;
      if (i<argc) rv = argv[i];
    }
  }
  
  return rv;
}

char *
getDeviceName(int argc, char **argv)
{
  static char devname[255];
  int len = 255;
  char *s;
  
  s = getCommandLineOption(argc, argv, "-d");
  if (s)
  {
    strncpy((char *)&devname, s, len);
    len -= strlen(s);
    
    s = getCommandLineOption(argc, argv, "-r");
    if (s)
    {
      strncat((char *)&devname, " on ", len);
      len -= 4;
      
      strncat((char *)&devname, s, len);
    }
    s = (char *)&devname;
  }
  
  return s;
}

void
displayDevices(const char *type, const char *list)
{
  ALCchar *ptr, *nptr;
  
  ptr = (ALCchar *)list;
  printf("list of all available %s devices:\n", type);
  if (!list)
  {
    printf("none\n");
  }
  else
  {
    nptr = ptr;
    while (*(nptr += strlen(ptr)+1) != 0)
    {
      printf("  %s\n", ptr);
      ptr = nptr;
    }
    printf("  %s\n", ptr);
  }
}

void
testForError(void *p, const string& s)
{
  if (p == NULL)
  {
    printf("\nError: %s\n\n", s.c_str());
    exit(-1);
  }
}

void
testForALCError(ALCdevice *device)
{
  ALenum error;
  error = alcGetError(device);
  if (error != ALC_NO_ERROR)
    printf("\nALC Error %x occurred: %s\n", error, alcGetString(device, error));
}
Community
  • 1
  • 1
David Karlsson
  • 9,396
  • 9
  • 58
  • 103
  • 1
    I just tested this on my MacBook Pro (OS X Yosemite). `alcIsExtensionPresent(NULL, "ALC_enumerate_all_EXT")` returns `AL_FALSE`, [which means](http://comments.gmane.org/gmane.comp.lib.openal/6390) `ALC_ALL_DEVICES_SPECIFIER` is not supported. It's an extension, not part of "core" OpenAL. – Cornstalks Mar 10 '15 at 11:25
  • 1
    http://playcontrol.net/ewing/jibberjabber/defective_core_audio_mac_os.html – David Karlsson Mar 10 '15 at 13:38
  • For linux, if a similar issue leads you here, I recommend checking whether the audio backend in use is capable of splitting outputs or not. For example, JACK Audio Connection Kit doesn't, and it's usually the first backend OpenAL looks for. In that case, edit the `drivers` section your `/etc/openal/alsoft.conf` (global) or `~/.alsoftrc` (user specifcic) file to prioritize other backends. – Kiloku Jun 14 '22 at 16:22
  • I had similar issue on windows, and install openAL runtime fixed my issue (the installer is in the link below) https://www.openal.org/downloads/ – Jim Pp Jul 09 '22 at 08:52

1 Answers1

2

Just to give you ammunition ... here I compiled your above code and give its console output as executed on linux ubuntu 14.04 g++ (Ubuntu 4.9.1-16ubuntu6) 4.9.1

g++ -o openal_list_audio_devices openal_list_audio_devices.cpp -lopenal


stens@kamchatka ~/Dropbox/Documents/code/c++ λ 
stens@kamchatka ~/Dropbox/Documents/code/c++ λ ./openal_list_audio_devices

list of all available output devices:
  Built-in Audio Analog Stereo
list of all available input devices:
  Built-in Audio Analog Stereo
  Monitor of Built-in Audio Analog Stereo
default output device: OpenAL Soft
default input device:  Built-in Audio Analog Stereo
capture support: yes
mixer frequency: 44100 hz
refresh rate : 1025 hz
supported sources; mono: 255, stereo: 1
ALC version: 1.1
ALC extensions:
    ALC_ENUMERATE_ALL_EXT, ALC_ENUMERATION_EXT, ALC_EXT_CAPTURE, 
    ALC_EXT_DEDICATED, ALC_EXT_disconnect, ALC_EXT_EFX, 
    ALC_EXT_thread_local_context, ALC_SOFT_loopback
OpenAL vendor string: OpenAL Community
OpenAL renderer string: OpenAL Soft
OpenAL version string: 1.1 ALSOFT 1.15.1
OpenAL extensions:
    AL_EXT_ALAW, AL_EXT_DOUBLE, AL_EXT_EXPONENT_DISTANCE, AL_EXT_FLOAT32, 
    AL_EXT_IMA4, AL_EXT_LINEAR_DISTANCE, AL_EXT_MCFORMATS, AL_EXT_MULAW, 
    AL_EXT_MULAW_MCFORMATS, AL_EXT_OFFSET, AL_EXT_source_distance_model, 
    AL_LOKI_quadriphonic, AL_SOFT_buffer_samples, AL_SOFT_buffer_sub_data, 
    AL_SOFTX_deferred_updates, AL_SOFT_direct_channels, AL_SOFT_loop_points, 
    AL_SOFT_source_latency
Scott Stensland
  • 26,870
  • 12
  • 93
  • 104