aboutsummaryrefslogtreecommitdiffhomepage
path: root/test
diff options
context:
space:
mode:
authorJean-Yves Avenard <[email protected]>2018-03-19 14:57:07 +0100
committerPaul Adenot <[email protected]>2018-03-19 14:57:07 +0100
commit789eaaa3b0d77b55e110353972d6713889f510ea (patch)
treefbeb48958ab83c329193f37c54133c9bc68aac4a /test
parentc88a484e1aac878419946334c49d35d6948beec7 (diff)
downloadcubeb-789eaaa3b0d77b55e110353972d6713889f510ea.tar.gz
cubeb-789eaaa3b0d77b55e110353972d6713889f510ea.zip
Multi-channels support for windows/mac/linux (#426)
* Add QUAD and QUAD_LFE layouts. * Remove dual mono layout. It makes no sense to have a case for those as the data structure used (a bitmask) do not allow to represent this channel layout (a channel can only be present once). As such it was a non-functional layout * Fix up cubeb_pulse compilation using C++ keyword. * Remove the concept of preferred layout. Channel layout is derived by the content being played. The concept of preferred layout is meaningless. Either we have a layout defined, or we don't. There's no in-between. So we remove it. * Remove CHANNEL_MONO concept. * Add cubeb_sample_size convenience method. * Rework cubeb_mixer. This completely replace the existing remixer which had serious limitations: 1- Had no memory bound checks 2- Could only downmix 5.1 and 7.1 to stereo. This mixer allows to convert from any sane layout to any other and work directly on interleaved samples. This cubeb_mixer doesn't have an API compatible with the previous one. This commit is non-fonctional, and was split for ease of review. * Fix remixing on mac, windows and pulse backend. * Make cubeb_mixer creation infallible. Rather than ignore nonsensical layouts, we attempt to play it according to the stream channels count instead. The audio data will be played as-is, dropping the extra channels or inserting silence where needed. * User proper sample size when calculating offsets. Should the user data be of a different type to what the AudioUnit output is set to, we would have written outside the end of our allocated buffer. * Fix input mixing and clarify frames vs samples terminology * If a layout is unknown or invalid, always treat it as plain stereo or mono.
Diffstat (limited to 'test')
-rw-r--r--test/common.h24
-rw-r--r--test/test_audio.cpp14
-rw-r--r--test/test_mixer.cpp222
-rw-r--r--test/test_sanity.cpp6
4 files changed, 6 insertions, 260 deletions
diff --git a/test/common.h b/test/common.h
index 1419528..032c635 100644
--- a/test/common.h
+++ b/test/common.h
@@ -44,31 +44,9 @@ void delay(unsigned int ms)
typedef struct {
char const * name;
unsigned int const channels;
- cubeb_channel_layout const layout;
+ uint32_t const layout;
} layout_info;
-layout_info const layout_infos[CUBEB_LAYOUT_MAX] = {
- { "undefined", 0, CUBEB_LAYOUT_UNDEFINED },
- { "dual mono", 2, CUBEB_LAYOUT_DUAL_MONO },
- { "dual mono lfe", 3, CUBEB_LAYOUT_DUAL_MONO_LFE },
- { "mono", 1, CUBEB_LAYOUT_MONO },
- { "mono lfe", 2, CUBEB_LAYOUT_MONO_LFE },
- { "stereo", 2, CUBEB_LAYOUT_STEREO },
- { "stereo lfe", 3, CUBEB_LAYOUT_STEREO_LFE },
- { "3f", 3, CUBEB_LAYOUT_3F },
- { "3f lfe", 4, CUBEB_LAYOUT_3F_LFE },
- { "2f1", 3, CUBEB_LAYOUT_2F1 },
- { "2f1 lfe", 4, CUBEB_LAYOUT_2F1_LFE },
- { "3f1", 4, CUBEB_LAYOUT_3F1 },
- { "3f1 lfe", 5, CUBEB_LAYOUT_3F1_LFE },
- { "2f2", 4, CUBEB_LAYOUT_2F2 },
- { "2f2 lfe", 5, CUBEB_LAYOUT_2F2_LFE },
- { "3f2", 5, CUBEB_LAYOUT_3F2 },
- { "3f2 lfe", 6, CUBEB_LAYOUT_3F2_LFE },
- { "3f3r lfe", 7, CUBEB_LAYOUT_3F3R_LFE },
- { "3f4 lfe", 8, CUBEB_LAYOUT_3F4_LFE }
-};
-
int has_available_input_device(cubeb * ctx)
{
cubeb_device_collection devices;
diff --git a/test/test_audio.cpp b/test/test_audio.cpp
index df51366..2e6c34a 100644
--- a/test/test_audio.cpp
+++ b/test/test_audio.cpp
@@ -94,7 +94,7 @@ int supports_channel_count(string backend_id, int nchannels)
(backend_id != "opensl" && backend_id != "audiotrack");
}
-int run_test(int num_channels, layout_info layout, int sampling_rate, int is_float)
+int run_test(int num_channels, int sampling_rate, int is_float)
{
int r = CUBEB_OK;
@@ -116,13 +116,13 @@ int run_test(int num_channels, layout_info layout, int sampling_rate, int is_flo
return CUBEB_OK;
}
- fprintf(stderr, "Testing %d channel(s), layout: %s, %d Hz, %s (%s)\n", num_channels, layout.name, sampling_rate, is_float ? "float" : "short", cubeb_get_backend_id(ctx));
+ fprintf(stderr, "Testing %d channel(s), %d Hz, %s (%s)\n", num_channels, sampling_rate, is_float ? "float" : "short", cubeb_get_backend_id(ctx));
cubeb_stream_params params;
params.format = is_float ? CUBEB_SAMPLE_FLOAT32NE : CUBEB_SAMPLE_S16NE;
params.rate = sampling_rate;
params.channels = num_channels;
- params.layout = layout.layout;
+ params.layout = CUBEB_LAYOUT_UNDEFINED;
params.prefs = CUBEB_STREAM_PREF_NONE;
synth_state synth(params.channels, params.rate);
@@ -246,12 +246,8 @@ TEST(cubeb, run_channel_rate_test)
for(auto freq : freq_values) {
ASSERT_TRUE(channels < MAX_NUM_CHANNELS);
fprintf(stderr, "--------------------------\n");
- for (auto layout : layout_infos) {
- if (layout.channels == channels) {
- ASSERT_EQ(run_test(channels, layout, freq, 0), CUBEB_OK);
- ASSERT_EQ(run_test(channels, layout, freq, 1), CUBEB_OK);
- }
- }
+ ASSERT_EQ(run_test(channels, freq, 0), CUBEB_OK);
+ ASSERT_EQ(run_test(channels, freq, 1), CUBEB_OK);
}
}
}
diff --git a/test/test_mixer.cpp b/test/test_mixer.cpp
deleted file mode 100644
index b7daea9..0000000
--- a/test/test_mixer.cpp
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright © 2016 Mozilla Foundation
- *
- * This program is made available under an ISC-style license. See the
- * accompanying file LICENSE for details.
- */
-#include "gtest/gtest.h"
-#include "cubeb/cubeb.h"
-#include "cubeb_mixer.h"
-#include "common.h"
-#include <memory>
-#include <vector>
-
-using std::vector;
-
-#define STREAM_FREQUENCY 48000
-#define STREAM_FORMAT CUBEB_SAMPLE_FLOAT32LE
-
-float const M = 1.0f; // Mono
-float const L = 2.0f; // Left
-float const R = 3.0f; // Right
-float const C = 4.0f; // Center
-float const LS = 5.0f; // Left Surround
-float const RS = 6.0f; // Right Surround
-float const RLS = 7.0f; // Rear Left Surround
-float const RC = 8.0f; // Rear Center
-float const RRS = 9.0f; // Rear Right Surround
-float const LFE = 10.0f; // Low Frequency Effects
-
-float const INV_SQRT_2 = 0.707106f; // 1/sqrt(2)
-static float const DOWNMIX_3F2_RESULTS[2][12][5] = {
- // 3F2
- {
- { INV_SQRT_2*(L+R) + C + 0.5f*(LS+RS) }, // Mono
- { INV_SQRT_2*(L+R) + C + 0.5f*(LS+RS), 0 }, // Mono-LFE
- { L + INV_SQRT_2*(C+LS), R + INV_SQRT_2*(C+RS) }, // Stereo
- { L + INV_SQRT_2*(C+LS), R + INV_SQRT_2*(C+RS), 0 }, // Stereo-LFE
- { L + INV_SQRT_2*LS, R + INV_SQRT_2*RS, C }, // 3F
- { L + INV_SQRT_2*LS, R + INV_SQRT_2*RS, C, 0 }, // 3F-LFE
- { L + C*INV_SQRT_2, R + C*INV_SQRT_2, INV_SQRT_2*(LS+RS) }, // 2F1
- { L + C*INV_SQRT_2, R + C*INV_SQRT_2, 0, INV_SQRT_2*(LS+RS) }, // 2F1-LFE
- { L, R, C, INV_SQRT_2*(LS+RS) }, // 3F1
- { L, R, C, 0, INV_SQRT_2*(LS+RS) }, // 3F1-LFE
- { L + INV_SQRT_2*C, R + INV_SQRT_2*C, LS, RS }, // 2F2
- { L + INV_SQRT_2*C, R + INV_SQRT_2*C, 0, LS, RS } // 2F2-LFE
- },
- // 3F2-LFE
- {
- { INV_SQRT_2*(L+R) + C + 0.5f*(LS+RS) }, // Mono
- { INV_SQRT_2*(L+R) + C + 0.5f*(LS+RS), LFE }, // Mono-LFE
- { L + INV_SQRT_2*(C+LS), R + INV_SQRT_2*(C+RS) }, // Stereo
- { L + INV_SQRT_2*(C+LS), R + INV_SQRT_2*(C+RS), LFE }, // Stereo-LFE
- { L + INV_SQRT_2*LS, R + INV_SQRT_2*RS, C }, // 3F
- { L + INV_SQRT_2*LS, R + INV_SQRT_2*RS, C, LFE }, // 3F-LFE
- { L + C*INV_SQRT_2, R + C*INV_SQRT_2, INV_SQRT_2*(LS+RS) }, // 2F1
- { L + C*INV_SQRT_2, R + C*INV_SQRT_2, LFE, INV_SQRT_2*(LS+RS) }, // 2F1-LFE
- { L, R, C, INV_SQRT_2*(LS+RS) }, // 3F1
- { L, R, C, LFE, INV_SQRT_2*(LS+RS) }, // 3F1-LFE
- { L + INV_SQRT_2*C, R + INV_SQRT_2*C, LS, RS }, // 2F2
- { L + INV_SQRT_2*C, R + INV_SQRT_2*C, LFE, LS, RS } // 2F2-LFE
- }
-};
-
-typedef struct {
- cubeb_channel_layout layout;
- float data[10];
-} audio_input;
-
-audio_input audio_inputs[CUBEB_LAYOUT_MAX] = {
- { CUBEB_LAYOUT_UNDEFINED, { } },
- { CUBEB_LAYOUT_DUAL_MONO, { L, R } },
- { CUBEB_LAYOUT_DUAL_MONO_LFE, { L, R, LFE } },
- { CUBEB_LAYOUT_MONO, { M } },
- { CUBEB_LAYOUT_MONO_LFE, { M, LFE } },
- { CUBEB_LAYOUT_STEREO, { L, R } },
- { CUBEB_LAYOUT_STEREO_LFE, { L, R, LFE } },
- { CUBEB_LAYOUT_3F, { L, R, C } },
- { CUBEB_LAYOUT_3F_LFE, { L, R, C, LFE } },
- { CUBEB_LAYOUT_2F1, { L, R, RC } },
- { CUBEB_LAYOUT_2F1_LFE, { L, R, LFE, RC } },
- { CUBEB_LAYOUT_3F1, { L, R, C, RC } },
- { CUBEB_LAYOUT_3F1_LFE, { L, R, C, LFE, RC } },
- { CUBEB_LAYOUT_2F2, { L, R, LS, RS } },
- { CUBEB_LAYOUT_2F2_LFE, { L, R, LFE, LS, RS } },
- { CUBEB_LAYOUT_3F2, { L, R, C, LS, RS } },
- { CUBEB_LAYOUT_3F2_LFE, { L, R, C, LFE, LS, RS } },
- { CUBEB_LAYOUT_3F3R_LFE, { L, R, C, LFE, RC, LS, RS } },
- { CUBEB_LAYOUT_3F4_LFE, { L, R, C, LFE, RLS, RRS, LS, RS } }
-};
-
-char const * channel_names[CHANNEL_UNMAPPED + 1] = {
- "mono", // CHANNEL_MONO
- "left", // CHANNEL_LEFT
- "right", // CHANNEL_RIGHT
- "center", // CHANNEL_CENTER
- "left surround", // CHANNEL_LS
- "right surround", // CHANNEL_RS
- "rear left surround", // CHANNEL_RLS
- "rear center", // CHANNEL_RCENTER
- "rear right surround", // CHANNEL_RRS
- "low frequency effects", // CHANNEL_LFE
- "unmapped" // CHANNEL_UNMAPPED
-};
-
-// The test cases must be aligned with cubeb_downmix.
-void
-downmix_test(float const * data, cubeb_channel_layout in_layout, cubeb_channel_layout out_layout)
-{
- if (in_layout == CUBEB_LAYOUT_UNDEFINED) {
- return; // Only possible output layout would be UNDEFINED.
- }
-
- cubeb_stream_params in_params = {
- STREAM_FORMAT,
- STREAM_FREQUENCY,
- layout_infos[in_layout].channels,
- in_layout,
- CUBEB_STREAM_PREF_NONE
- };
-
- cubeb_stream_params out_params = {
- STREAM_FORMAT,
- STREAM_FREQUENCY,
- // To downmix audio data with undefined layout, its channel number must be
- // smaller than or equal to the input channels.
- (out_layout == CUBEB_LAYOUT_UNDEFINED) ?
- layout_infos[in_layout].channels : layout_infos[out_layout].channels,
- out_layout,
- CUBEB_STREAM_PREF_NONE
- };
-
- if (!cubeb_should_downmix(&in_params, &out_params)) {
- return;
- }
-
- fprintf(stderr, "Downmix from %s to %s\n", layout_infos[in_layout].name, layout_infos[out_layout].name);
-
- unsigned int const inframes = 10;
- vector<float> in(in_params.channels * inframes);
-#if defined(__APPLE__)
- // The mixed buffer size doesn't be changed based on the channel layout set on OSX.
- // Please see the comment above downmix_3f2 in cubeb_mixer.cpp.
- vector<float> out(in_params.channels * inframes);
-#else
- // In normal case, the mixed buffer size is based on the mixing channel layout.
- vector<float> out(out_params.channels * inframes);
-#endif
-
- for (unsigned int offset = 0 ; offset < inframes * in_params.channels ; offset += in_params.channels) {
- for (unsigned int i = 0 ; i < in_params.channels ; ++i) {
- in[offset + i] = data[i];
- }
- }
-
- // Create a mixer for downmix only.
- std::unique_ptr<cubeb_mixer, decltype(&cubeb_mixer_destroy)>
- mixer(cubeb_mixer_create(in_params.format, CUBEB_MIXER_DIRECTION_DOWNMIX), cubeb_mixer_destroy);
-
- assert(!in.empty() && !out.empty() && out.size() <= in.size());
- cubeb_mixer_mix(mixer.get(), inframes, in.data(), in.size(), out.data(), out.size(), &in_params, &out_params);
-
- uint32_t in_layout_mask = 0;
- for (unsigned int i = 0 ; i < in_params.channels; ++i) {
- in_layout_mask |= 1 << CHANNEL_INDEX_TO_ORDER[in_layout][i];
- }
-
- uint32_t out_layout_mask = 0;
- for (unsigned int i = 0 ; out_layout != CUBEB_LAYOUT_UNDEFINED && i < out_params.channels; ++i) {
- out_layout_mask |= 1 << CHANNEL_INDEX_TO_ORDER[out_layout][i];
- }
-
- for (unsigned int i = 0 ; i < out.size() ; ++i) {
- assert(in_params.channels && out_params.channels); // to pass the scan-build warning: Division by zero.
-#if defined(__APPLE__)
- // The size of audio mix buffer(vector out above) on OS X is same as input,
- // so we need to check whether the out[i] will be dropped or not.
- unsigned int index = i % in_params.channels;
- if (index >= out_params.channels) {
- // The out[i] will be dropped, so we don't care the data inside.
- fprintf(stderr, "\tOS X: %d will be dropped. Ignore it.\n", i);
- continue;
- }
-#else
- unsigned int index = i % out_params.channels;
-#endif
-
- // downmix_3f2
- if ((in_layout == CUBEB_LAYOUT_3F2 || in_layout == CUBEB_LAYOUT_3F2_LFE) &&
- out_layout >= CUBEB_LAYOUT_MONO && out_layout <= CUBEB_LAYOUT_2F2_LFE) {
- auto & downmix_results = DOWNMIX_3F2_RESULTS[in_layout - CUBEB_LAYOUT_3F2][out_layout - CUBEB_LAYOUT_MONO];
- fprintf(stderr, "\t[3f2] %d(%s) - Expect: %lf, Get: %lf\n", i, channel_names[ CHANNEL_INDEX_TO_ORDER[out_layout][index] ], downmix_results[index], out[i]);
- ASSERT_EQ(downmix_results[index], out[i]);
- continue;
- }
-
-#if defined(__APPLE__)
- fprintf(stderr, "\tOS X: We only support downmix for audio 5.1 currently.\n");
- return;
-#endif
-
- // mix_remap
- if (out_layout_mask & in_layout_mask) {
- uint32_t mask = 1 << CHANNEL_INDEX_TO_ORDER[out_layout][index];
- fprintf(stderr, "\t[remap] %d(%s) - Expect: %lf, Get: %lf\n", i, channel_names[ CHANNEL_INDEX_TO_ORDER[out_layout][index] ], (mask & in_layout_mask) ? audio_inputs[out_layout].data[index] : 0, out[i]);
- ASSERT_EQ((mask & in_layout_mask) ? audio_inputs[out_layout].data[index] : 0, out[i]);
- continue;
- }
-
- // downmix_fallback
- fprintf(stderr, "\t[fallback] %d - Expect: %lf, Get: %lf\n", i, audio_inputs[in_layout].data[index], out[i]);
- ASSERT_EQ(audio_inputs[in_layout].data[index], out[i]);
- }
-}
-
-TEST(cubeb, mixer)
-{
- for (auto audio_input : audio_inputs) {
- for (auto audio_output : layout_infos) {
- downmix_test(audio_input.data, audio_input.layout, audio_output.layout);
- }
- }
-}
diff --git a/test/test_sanity.cpp b/test/test_sanity.cpp
index d3546d6..d33666f 100644
--- a/test/test_sanity.cpp
+++ b/test/test_sanity.cpp
@@ -114,7 +114,6 @@ TEST(cubeb, context_variables)
int r;
cubeb * ctx;
uint32_t value;
- cubeb_channel_layout layout;
cubeb_stream_params params;
r = common_init(&ctx, "test_context_variables");
@@ -139,11 +138,6 @@ TEST(cubeb, context_variables)
ASSERT_TRUE(value > 0);
}
- r = cubeb_get_preferred_channel_layout(ctx, &layout);
- ASSERT_TRUE(r == CUBEB_ERROR_NOT_SUPPORTED ||
- (r == CUBEB_OK && layout != CUBEB_LAYOUT_UNDEFINED) ||
- (r == CUBEB_ERROR && layout == CUBEB_LAYOUT_UNDEFINED));
-
cubeb_destroy(ctx);
}