Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Listing all devices open AL does not work

Tags:

c++

audio

openal

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));
}
like image 841
David Karlsson Avatar asked Oct 31 '22 08:10

David Karlsson


1 Answers

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
like image 66
Scott Stensland Avatar answered Nov 15 '22 04:11

Scott Stensland