| /* |
| * Copyright 2017 The Emscripten Authors. All rights reserved. |
| * Emscripten is available under two separate licenses, the MIT license and the |
| * University of Illinois/NCSA Open Source License. Both these licenses can be |
| * found in the LICENSE file. |
| */ |
| |
| // This test attempts to open all possible capture devices, each one |
| // several times with a combination of "reasonable" parameters, and |
| // checks some basic conformance to expectations w.r.t the spec. |
| // |
| // Wishlist: |
| // - Any operation a closed device should fail; |
| // - Trying to open multiple devices with the same name at the same time |
| // and different settings should be fine; |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <stdint.h> |
| #include <stdbool.h> |
| #include <assert.h> |
| #include <unistd.h> |
| #ifdef __EMSCRIPTEN__ |
| #include <emscripten.h> |
| #define ASSUME_AL_FLOAT32 |
| #endif |
| #include <AL/al.h> |
| #include <AL/alc.h> |
| |
| #ifdef ASSUME_AL_FLOAT32 |
| // We, in particular, are expected to support this, since |
| // this is the data type used by Web Audio. |
| #define AL_FORMAT_MONO_FLOAT32 0x10010 |
| #define AL_FORMAT_STEREO_FLOAT32 0x10011 |
| #endif |
| |
| #define countof(x) (sizeof(x)/sizeof((x)[0])) |
| |
| static int result = EXIT_SUCCESS; |
| |
| static void end_test() { |
| #ifdef __EMSCRIPTEN__ |
| REPORT_RESULT(result); |
| #endif |
| exit(result); |
| } |
| |
| // OfflineAudioContexts are required to support sample rates ranging |
| // from 22050 to 96000. |
| // Should we test for purposefully-ugly sample rates within that range, too ? |
| static const ALCuint SAMPLE_RATES[] = { |
| 22050, 32000, 37800, 44100, 48000, 88200, 96000 |
| }; |
| |
| static const ALenum FORMATS[] = { |
| AL_FORMAT_MONO8, |
| AL_FORMAT_MONO16, |
| AL_FORMAT_STEREO8, |
| AL_FORMAT_STEREO16, |
| #ifdef ASSUME_AL_FLOAT32 |
| AL_FORMAT_MONO_FLOAT32, |
| AL_FORMAT_STEREO_FLOAT32, |
| #endif |
| }; |
| |
| static const char* alformat_string(ALenum format) { |
| switch(format) { |
| #define CASE(X) case X: return #X; |
| CASE(AL_FORMAT_MONO8) |
| CASE(AL_FORMAT_MONO16) |
| CASE(AL_FORMAT_STEREO8) |
| CASE(AL_FORMAT_STEREO16) |
| #ifdef ASSUME_AL_FLOAT32 |
| CASE(AL_FORMAT_MONO_FLOAT32) |
| CASE(AL_FORMAT_STEREO_FLOAT32) |
| #endif |
| #undef CASE |
| } |
| return "<no_string_available>"; |
| } |
| |
| static void check_device_sanity_with_params(const char *name, ALCuint sample_rate, ALenum format, ALCsizei buffer_size) { |
| |
| printf( |
| "Testing \"%s\" @%uHz with %u sample-frames (format: %s)...\n", |
| name, (unsigned)sample_rate, (unsigned) buffer_size, |
| alformat_string(format) |
| ); |
| |
| ALCdevice* dev = alcCaptureOpenDevice(name, sample_rate, format, buffer_size); |
| |
| if(dev) { |
| const char *claimed = alcGetString(dev, ALC_CAPTURE_DEVICE_SPECIFIER); |
| if(strcmp(name, claimed)) { |
| fprintf(stderr, "The device \"%s\" claims to be actually named \"%s\", which is not correct behavior.\n", name, claimed); |
| result = EXIT_FAILURE; |
| } |
| ALCboolean could_close = alcCaptureCloseDevice(dev); |
| if(!could_close) { |
| fprintf(stderr, "alcCaptureCloseDevice() with \"%s\" failed!\n", name); |
| result = EXIT_FAILURE; |
| } |
| return; |
| } |
| |
| ALCenum err = alcGetError(dev); |
| fprintf(stderr, |
| "alcCaptureOpenDevice(\"%s\", sample_rate=%u, format=%s, " |
| "buffer_size=%u) failed with ALC error %x (%s)\n", |
| name, (unsigned)sample_rate, alformat_string(format), |
| (unsigned) buffer_size, |
| (unsigned) err, alcGetString(NULL, err) |
| ); |
| result = EXIT_FAILURE; |
| } |
| |
| static void check_device_sanity(const char *name) { |
| for(int si=0 ; si<countof(SAMPLE_RATES) ; ++si) { |
| for(int fi=0 ; fi<countof(FORMATS) ; ++fi) { |
| // 8 seconds of data |
| check_device_sanity_with_params( |
| name, SAMPLE_RATES[si], FORMATS[fi], 8*SAMPLE_RATES[si] |
| ); |
| } |
| } |
| } |
| |
| static bool is_defaultname_in_names(const char *dft, const char *names) { |
| for(const char *name = names; *name ; name += 1+strlen(name)) { |
| if(!strcmp(dft, name)) |
| return true; |
| } |
| return false; |
| } |
| |
| int main() { |
| |
| const char *dft = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); |
| const char *names = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); |
| |
| if(!is_defaultname_in_names(dft, names)) { |
| printf( |
| "The default device specifier (\"%s\") was not found amongst the device specifier list : ...\n" |
| , dft |
| ); |
| for(const char *name = names; *name ; name += 1+strlen(name)) { |
| printf("- \"%s\";\n", name); |
| } |
| printf("... this is not an error, though.\n\n"); |
| } |
| |
| for(const char *name = names; *name ; name += 1+strlen(name)) { |
| check_device_sanity(name); |
| } |
| |
| end_test(); |
| } |