Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* |
michael@0 | 2 | * Copyright © 2013 Sebastien Alaiwan <sebastien.alaiwan@gmail.com> |
michael@0 | 3 | * |
michael@0 | 4 | * This program is made available under an ISC-style license. See the |
michael@0 | 5 | * accompanying file LICENSE for details. |
michael@0 | 6 | */ |
michael@0 | 7 | |
michael@0 | 8 | /* libcubeb api/function exhaustive test. Plays a series of tones in different |
michael@0 | 9 | * conditions. */ |
michael@0 | 10 | #ifdef NDEBUG |
michael@0 | 11 | #undef NDEBUG |
michael@0 | 12 | #endif |
michael@0 | 13 | #define _XOPEN_SOURCE 500 |
michael@0 | 14 | #include <stdio.h> |
michael@0 | 15 | #include <stdlib.h> |
michael@0 | 16 | #include <math.h> |
michael@0 | 17 | #include <assert.h> |
michael@0 | 18 | #include <string.h> |
michael@0 | 19 | |
michael@0 | 20 | #include "cubeb/cubeb.h" |
michael@0 | 21 | #include "common.h" |
michael@0 | 22 | |
michael@0 | 23 | #define MAX_NUM_CHANNELS 32 |
michael@0 | 24 | |
michael@0 | 25 | #if !defined(M_PI) |
michael@0 | 26 | #define M_PI 3.14159265358979323846 |
michael@0 | 27 | #endif |
michael@0 | 28 | |
michael@0 | 29 | #define NELEMS(x) ((int) (sizeof(x) / sizeof(x[0]))) |
michael@0 | 30 | #define VOLUME 0.2 |
michael@0 | 31 | |
michael@0 | 32 | float get_frequency(int channel_index) |
michael@0 | 33 | { |
michael@0 | 34 | return 220.0f * (channel_index+1); |
michael@0 | 35 | } |
michael@0 | 36 | |
michael@0 | 37 | /* store the phase of the generated waveform */ |
michael@0 | 38 | typedef struct { |
michael@0 | 39 | int num_channels; |
michael@0 | 40 | float phase[MAX_NUM_CHANNELS]; |
michael@0 | 41 | float sample_rate; |
michael@0 | 42 | } synth_state; |
michael@0 | 43 | |
michael@0 | 44 | synth_state* synth_create(int num_channels, float sample_rate) |
michael@0 | 45 | { |
michael@0 | 46 | synth_state* synth = (synth_state *) malloc(sizeof(synth_state)); |
michael@0 | 47 | for(int i=0;i < MAX_NUM_CHANNELS;++i) |
michael@0 | 48 | synth->phase[i] = 0.0f; |
michael@0 | 49 | synth->num_channels = num_channels; |
michael@0 | 50 | synth->sample_rate = sample_rate; |
michael@0 | 51 | return synth; |
michael@0 | 52 | } |
michael@0 | 53 | |
michael@0 | 54 | void synth_destroy(synth_state* synth) |
michael@0 | 55 | { |
michael@0 | 56 | free(synth); |
michael@0 | 57 | } |
michael@0 | 58 | |
michael@0 | 59 | void synth_run_float(synth_state* synth, float* audiobuffer, long nframes) |
michael@0 | 60 | { |
michael@0 | 61 | for(int c=0;c < synth->num_channels;++c) { |
michael@0 | 62 | float freq = get_frequency(c); |
michael@0 | 63 | float phase_inc = 2.0 * M_PI * freq / synth->sample_rate; |
michael@0 | 64 | for(long n=0;n < nframes;++n) { |
michael@0 | 65 | audiobuffer[n*synth->num_channels+c] = sin(synth->phase[c]) * VOLUME; |
michael@0 | 66 | synth->phase[c] += phase_inc; |
michael@0 | 67 | } |
michael@0 | 68 | } |
michael@0 | 69 | } |
michael@0 | 70 | |
michael@0 | 71 | long data_cb_float(cubeb_stream *stream, void *user, void *buffer, long nframes) |
michael@0 | 72 | { |
michael@0 | 73 | synth_state *synth = (synth_state *)user; |
michael@0 | 74 | synth_run_float(synth, (float*)buffer, nframes); |
michael@0 | 75 | return nframes; |
michael@0 | 76 | } |
michael@0 | 77 | |
michael@0 | 78 | void synth_run_16bit(synth_state* synth, short* audiobuffer, long nframes) |
michael@0 | 79 | { |
michael@0 | 80 | for(int c=0;c < synth->num_channels;++c) { |
michael@0 | 81 | float freq = get_frequency(c); |
michael@0 | 82 | float phase_inc = 2.0 * M_PI * freq / synth->sample_rate; |
michael@0 | 83 | for(long n=0;n < nframes;++n) { |
michael@0 | 84 | audiobuffer[n*synth->num_channels+c] = sin(synth->phase[c]) * VOLUME * 32767.0f; |
michael@0 | 85 | synth->phase[c] += phase_inc; |
michael@0 | 86 | } |
michael@0 | 87 | } |
michael@0 | 88 | } |
michael@0 | 89 | |
michael@0 | 90 | long data_cb_short(cubeb_stream *stream, void *user, void *buffer, long nframes) |
michael@0 | 91 | { |
michael@0 | 92 | synth_state *synth = (synth_state *)user; |
michael@0 | 93 | synth_run_16bit(synth, (short*)buffer, nframes); |
michael@0 | 94 | return nframes; |
michael@0 | 95 | } |
michael@0 | 96 | |
michael@0 | 97 | void state_cb(cubeb_stream *stream, void *user, cubeb_state state) |
michael@0 | 98 | { |
michael@0 | 99 | } |
michael@0 | 100 | |
michael@0 | 101 | /* Our android backends don't support float, only int16. */ |
michael@0 | 102 | int supports_float32(const char* backend_id) |
michael@0 | 103 | { |
michael@0 | 104 | return (strcmp(backend_id, "opensl") != 0 && |
michael@0 | 105 | strcmp(backend_id, "audiotrack") != 0); |
michael@0 | 106 | } |
michael@0 | 107 | |
michael@0 | 108 | /* Some backends don't have code to deal with more than mono or stereo. */ |
michael@0 | 109 | int supports_channel_count(const char* backend_id, int nchannels) |
michael@0 | 110 | { |
michael@0 | 111 | return nchannels <= 2 || |
michael@0 | 112 | (strcmp(backend_id, "opensl") != 0 && strcmp(backend_id, "audiotrack") != 0); |
michael@0 | 113 | } |
michael@0 | 114 | |
michael@0 | 115 | int run_test(int num_channels, int sampling_rate, int is_float) |
michael@0 | 116 | { |
michael@0 | 117 | int ret = CUBEB_OK; |
michael@0 | 118 | |
michael@0 | 119 | cubeb *ctx = NULL; |
michael@0 | 120 | synth_state* synth = NULL; |
michael@0 | 121 | cubeb_stream *stream = NULL; |
michael@0 | 122 | const char * backend_id = NULL; |
michael@0 | 123 | |
michael@0 | 124 | ret = cubeb_init(&ctx, "Cubeb audio test"); |
michael@0 | 125 | if (ret != CUBEB_OK) { |
michael@0 | 126 | fprintf(stderr, "Error initializing cubeb library\n"); |
michael@0 | 127 | goto cleanup; |
michael@0 | 128 | } |
michael@0 | 129 | |
michael@0 | 130 | backend_id = cubeb_get_backend_id(ctx); |
michael@0 | 131 | |
michael@0 | 132 | if ((is_float && !supports_float32(backend_id)) || |
michael@0 | 133 | !supports_channel_count(backend_id, num_channels)) { |
michael@0 | 134 | /* don't treat this as a test failure. */ |
michael@0 | 135 | goto cleanup; |
michael@0 | 136 | } |
michael@0 | 137 | |
michael@0 | 138 | fprintf(stderr, "Testing %d channel(s), %d Hz, %s (%s)\n", num_channels, sampling_rate, is_float ? "float" : "short", cubeb_get_backend_id(ctx)); |
michael@0 | 139 | |
michael@0 | 140 | cubeb_stream_params params; |
michael@0 | 141 | params.format = is_float ? CUBEB_SAMPLE_FLOAT32NE : CUBEB_SAMPLE_S16NE; |
michael@0 | 142 | params.rate = sampling_rate; |
michael@0 | 143 | params.channels = num_channels; |
michael@0 | 144 | |
michael@0 | 145 | synth = synth_create(params.channels, params.rate); |
michael@0 | 146 | if (synth == NULL) { |
michael@0 | 147 | fprintf(stderr, "Out of memory\n"); |
michael@0 | 148 | goto cleanup; |
michael@0 | 149 | } |
michael@0 | 150 | |
michael@0 | 151 | ret = cubeb_stream_init(ctx, &stream, "test tone", params, |
michael@0 | 152 | 100, is_float ? data_cb_float : data_cb_short, state_cb, synth); |
michael@0 | 153 | if (ret != CUBEB_OK) { |
michael@0 | 154 | fprintf(stderr, "Error initializing cubeb stream: %d\n", ret); |
michael@0 | 155 | goto cleanup; |
michael@0 | 156 | } |
michael@0 | 157 | |
michael@0 | 158 | cubeb_stream_start(stream); |
michael@0 | 159 | delay(200); |
michael@0 | 160 | cubeb_stream_stop(stream); |
michael@0 | 161 | |
michael@0 | 162 | cleanup: |
michael@0 | 163 | cubeb_stream_destroy(stream); |
michael@0 | 164 | cubeb_destroy(ctx); |
michael@0 | 165 | synth_destroy(synth); |
michael@0 | 166 | |
michael@0 | 167 | return ret; |
michael@0 | 168 | } |
michael@0 | 169 | |
michael@0 | 170 | int main(int argc, char *argv[]) |
michael@0 | 171 | { |
michael@0 | 172 | int channel_values[] = { |
michael@0 | 173 | 1, |
michael@0 | 174 | 2, |
michael@0 | 175 | 3, |
michael@0 | 176 | 4, |
michael@0 | 177 | 6, |
michael@0 | 178 | }; |
michael@0 | 179 | |
michael@0 | 180 | int freq_values[] = { |
michael@0 | 181 | 16000, |
michael@0 | 182 | 24000, |
michael@0 | 183 | 44100, |
michael@0 | 184 | 48000, |
michael@0 | 185 | }; |
michael@0 | 186 | |
michael@0 | 187 | for(int j = 0; j < NELEMS(channel_values); ++j) { |
michael@0 | 188 | for(int i = 0; i < NELEMS(freq_values); ++i) { |
michael@0 | 189 | assert(channel_values[j] < MAX_NUM_CHANNELS); |
michael@0 | 190 | fprintf(stderr, "--------------------------\n"); |
michael@0 | 191 | assert(run_test(channel_values[j], freq_values[i], 0) == CUBEB_OK); |
michael@0 | 192 | assert(run_test(channel_values[j], freq_values[i], 1) == CUBEB_OK); |
michael@0 | 193 | } |
michael@0 | 194 | } |
michael@0 | 195 | |
michael@0 | 196 | return CUBEB_OK; |
michael@0 | 197 | } |
michael@0 | 198 | |
michael@0 | 199 |