test_audio.cpp (6335B)
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 */ 7 8 /* libcubeb api/function exhaustive test. Plays a series of tones in different 9 * conditions. */ 10 #include "gtest/gtest.h" 11 #if !defined(_XOPEN_SOURCE) 12 #define _XOPEN_SOURCE 600 13 #endif 14 #include "cubeb/cubeb.h" 15 #include <math.h> 16 #include <memory> 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <string.h> 20 #include <string> 21 22 // #define ENABLE_NORMAL_LOG 23 // #define ENABLE_VERBOSE_LOG 24 #include "common.h" 25 26 using namespace std; 27 28 #define MAX_NUM_CHANNELS 32 29 #define VOLUME 0.2 30 31 float 32 get_frequency(int channel_index) 33 { 34 return 220.0f * (channel_index + 1); 35 } 36 37 template <typename T> 38 T 39 ConvertSample(double input); 40 template <> 41 float 42 ConvertSample(double input) 43 { 44 return input; 45 } 46 template <> 47 short 48 ConvertSample(double input) 49 { 50 return short(input * 32767.0f); 51 } 52 53 /* store the phase of the generated waveform */ 54 struct synth_state { 55 synth_state(int num_channels_, float sample_rate_) 56 : num_channels(num_channels_), sample_rate(sample_rate_) 57 { 58 for (int i = 0; i < MAX_NUM_CHANNELS; ++i) 59 phase[i] = 0.0f; 60 } 61 62 template <typename T> void run(T * audiobuffer, long nframes) 63 { 64 for (int c = 0; c < num_channels; ++c) { 65 float freq = get_frequency(c); 66 float phase_inc = 2.0 * M_PI * freq / sample_rate; 67 for (long n = 0; n < nframes; ++n) { 68 audiobuffer[n * num_channels + c] = 69 ConvertSample<T>(sin(phase[c]) * VOLUME); 70 phase[c] += phase_inc; 71 } 72 } 73 } 74 75 private: 76 int num_channels; 77 float phase[MAX_NUM_CHANNELS]; 78 float sample_rate; 79 }; 80 81 template <typename T> 82 long 83 data_cb(cubeb_stream * /*stream*/, void * user, const void * /*inputbuffer*/, 84 void * outputbuffer, long nframes) 85 { 86 synth_state * synth = (synth_state *)user; 87 synth->run((T *)outputbuffer, nframes); 88 return nframes; 89 } 90 91 void 92 state_cb_audio(cubeb_stream * /*stream*/, void * /*user*/, 93 cubeb_state /*state*/) 94 { 95 } 96 97 /* Our android backends don't support float, only int16. */ 98 int 99 supports_float32(string backend_id) 100 { 101 return backend_id != "opensl" && backend_id != "audiotrack"; 102 } 103 104 /* Some backends don't have code to deal with more than mono or stereo. */ 105 int 106 supports_channel_count(string backend_id, int nchannels) 107 { 108 return nchannels <= 2 || 109 (backend_id != "opensl" && backend_id != "audiotrack"); 110 } 111 112 int 113 run_test(int num_channels, int sampling_rate, int is_float) 114 { 115 int r = CUBEB_OK; 116 117 cubeb * ctx = NULL; 118 119 r = common_init(&ctx, "Cubeb audio test: channels"); 120 if (r != CUBEB_OK) { 121 fprintf(stderr, "Error initializing cubeb library\n"); 122 return r; 123 } 124 std::unique_ptr<cubeb, decltype(&cubeb_destroy)> cleanup_cubeb_at_exit( 125 ctx, cubeb_destroy); 126 127 const char * backend_id = cubeb_get_backend_id(ctx); 128 129 if ((is_float && !supports_float32(backend_id)) || 130 !supports_channel_count(backend_id, num_channels)) { 131 /* don't treat this as a test failure. */ 132 return CUBEB_OK; 133 } 134 135 fprintf(stderr, "Testing %d channel(s), %d Hz, %s (%s)\n", num_channels, 136 sampling_rate, is_float ? "float" : "short", 137 cubeb_get_backend_id(ctx)); 138 139 cubeb_stream_params params; 140 params.format = is_float ? CUBEB_SAMPLE_FLOAT32NE : CUBEB_SAMPLE_S16NE; 141 params.rate = sampling_rate; 142 params.channels = num_channels; 143 params.layout = CUBEB_LAYOUT_UNDEFINED; 144 params.prefs = CUBEB_STREAM_PREF_NONE; 145 146 synth_state synth(params.channels, params.rate); 147 148 cubeb_stream * stream = NULL; 149 r = cubeb_stream_init(ctx, &stream, "test tone", NULL, NULL, NULL, ¶ms, 150 4096, is_float ? &data_cb<float> : &data_cb<short>, 151 state_cb_audio, &synth); 152 if (r != CUBEB_OK) { 153 fprintf(stderr, "Error initializing cubeb stream: %d\n", r); 154 return r; 155 } 156 157 std::unique_ptr<cubeb_stream, decltype(&cubeb_stream_destroy)> 158 cleanup_stream_at_exit(stream, cubeb_stream_destroy); 159 160 cubeb_stream_start(stream); 161 delay(200); 162 cubeb_stream_stop(stream); 163 164 return r; 165 } 166 167 int 168 run_volume_test(int is_float) 169 { 170 int r = CUBEB_OK; 171 172 cubeb * ctx = NULL; 173 174 r = common_init(&ctx, "Cubeb audio test"); 175 if (r != CUBEB_OK) { 176 fprintf(stderr, "Error initializing cubeb library\n"); 177 return r; 178 } 179 180 std::unique_ptr<cubeb, decltype(&cubeb_destroy)> cleanup_cubeb_at_exit( 181 ctx, cubeb_destroy); 182 183 const char * backend_id = cubeb_get_backend_id(ctx); 184 185 if ((is_float && !supports_float32(backend_id))) { 186 /* don't treat this as a test failure. */ 187 return CUBEB_OK; 188 } 189 190 cubeb_stream_params params; 191 params.format = is_float ? CUBEB_SAMPLE_FLOAT32NE : CUBEB_SAMPLE_S16NE; 192 params.rate = 44100; 193 params.channels = 2; 194 params.layout = CUBEB_LAYOUT_STEREO; 195 params.prefs = CUBEB_STREAM_PREF_NONE; 196 197 synth_state synth(params.channels, params.rate); 198 199 cubeb_stream * stream = NULL; 200 r = cubeb_stream_init(ctx, &stream, "test tone", NULL, NULL, NULL, ¶ms, 201 4096, is_float ? &data_cb<float> : &data_cb<short>, 202 state_cb_audio, &synth); 203 if (r != CUBEB_OK) { 204 fprintf(stderr, "Error initializing cubeb stream: %d\n", r); 205 return r; 206 } 207 208 std::unique_ptr<cubeb_stream, decltype(&cubeb_stream_destroy)> 209 cleanup_stream_at_exit(stream, cubeb_stream_destroy); 210 211 fprintf(stderr, "Testing: volume\n"); 212 for (int i = 0; i <= 4; ++i) { 213 fprintf(stderr, "Volume: %d%%\n", i * 25); 214 215 cubeb_stream_set_volume(stream, i / 4.0f); 216 cubeb_stream_start(stream); 217 delay(400); 218 cubeb_stream_stop(stream); 219 delay(100); 220 } 221 222 return r; 223 } 224 225 TEST(cubeb, run_volume_test_short) { ASSERT_EQ(run_volume_test(0), CUBEB_OK); } 226 227 TEST(cubeb, run_volume_test_float) { ASSERT_EQ(run_volume_test(1), CUBEB_OK); } 228 229 TEST(cubeb, run_channel_rate_test) 230 { 231 unsigned int channel_values[] = { 232 1, 2, 3, 4, 6, 233 }; 234 235 int freq_values[] = { 236 16000, 237 24000, 238 44100, 239 48000, 240 }; 241 242 for (auto channels : channel_values) { 243 for (auto freq : freq_values) { 244 ASSERT_TRUE(channels < MAX_NUM_CHANNELS); 245 fprintf(stderr, "--------------------------\n"); 246 ASSERT_EQ(run_test(channels, freq, 0), CUBEB_OK); 247 ASSERT_EQ(run_test(channels, freq, 1), CUBEB_OK); 248 } 249 } 250 } 251 252 #undef MAX_NUM_CHANNELS 253 #undef VOLUME