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