media/libcubeb/tests/test_audio.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

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

mercurial