зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1357683 - Update cubeb from upstream to 6e52314. r=padenot
MozReview-Commit-ID: FKxbO0W50Xk
This commit is contained in:
Родитель
a7fa6eb9b7
Коммит
939147b2d1
|
@ -5,4 +5,4 @@ Makefile.in build files for the Mozilla build system.
|
|||
|
||||
The cubeb git repository is: git://github.com/kinetiknz/cubeb.git
|
||||
|
||||
The git commit ID used was 04826edb13c23a2b53732d63b09b24e05ca83d87 (2017-03-31 09:05:07 -0700)
|
||||
The git commit ID used was 6e52314f24bba463d6ca97951f7d9fcc677d76a4 (2017-04-18 17:28:50 +0200)
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <memory>
|
||||
#include <string.h>
|
||||
#include "cubeb/cubeb.h"
|
||||
#include "common.h"
|
||||
|
@ -75,20 +76,6 @@ long data_cb(cubeb_stream * /*stream*/, void * user, const void * /*inputbuffer*
|
|||
return nframes;
|
||||
}
|
||||
|
||||
struct CubebCleaner
|
||||
{
|
||||
CubebCleaner(cubeb* ctx_) : ctx(ctx_) {}
|
||||
~CubebCleaner() { cubeb_destroy(ctx); }
|
||||
cubeb* ctx;
|
||||
};
|
||||
|
||||
struct CubebStreamCleaner
|
||||
{
|
||||
CubebStreamCleaner(cubeb_stream* ctx_) : ctx(ctx_) {}
|
||||
~CubebStreamCleaner() { cubeb_stream_destroy(ctx); }
|
||||
cubeb_stream* ctx;
|
||||
};
|
||||
|
||||
void state_cb_audio(cubeb_stream * /*stream*/, void * /*user*/, cubeb_state /*state*/)
|
||||
{
|
||||
}
|
||||
|
@ -100,12 +87,6 @@ int supports_float32(string backend_id)
|
|||
&& backend_id != "audiotrack";
|
||||
}
|
||||
|
||||
/* The WASAPI backend only supports float. */
|
||||
int supports_int16(string backend_id)
|
||||
{
|
||||
return backend_id != "wasapi";
|
||||
}
|
||||
|
||||
/* Some backends don't have code to deal with more than mono or stereo. */
|
||||
int supports_channel_count(string backend_id, int nchannels)
|
||||
{
|
||||
|
@ -124,12 +105,12 @@ int run_test(int num_channels, layout_info layout, int sampling_rate, int is_flo
|
|||
fprintf(stderr, "Error initializing cubeb library\n");
|
||||
return r;
|
||||
}
|
||||
CubebCleaner cleanup_cubeb_at_exit(ctx);
|
||||
std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
|
||||
cleanup_cubeb_at_exit(ctx, cubeb_destroy);
|
||||
|
||||
const char * backend_id = cubeb_get_backend_id(ctx);
|
||||
|
||||
if ((is_float && !supports_float32(backend_id)) ||
|
||||
(!is_float && !supports_int16(backend_id)) ||
|
||||
!supports_channel_count(backend_id, num_channels)) {
|
||||
/* don't treat this as a test failure. */
|
||||
return CUBEB_OK;
|
||||
|
@ -153,7 +134,8 @@ int run_test(int num_channels, layout_info layout, int sampling_rate, int is_flo
|
|||
return r;
|
||||
}
|
||||
|
||||
CubebStreamCleaner cleanup_stream_at_exit(stream);
|
||||
std::unique_ptr<cubeb_stream, decltype(&cubeb_stream_destroy)>
|
||||
cleanup_stream_at_exit(stream, cubeb_stream_destroy);
|
||||
|
||||
cubeb_stream_start(stream);
|
||||
delay(200);
|
||||
|
@ -174,12 +156,12 @@ int run_panning_volume_test(int is_float)
|
|||
return r;
|
||||
}
|
||||
|
||||
CubebCleaner cleanup_cubeb_at_exit(ctx);
|
||||
std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
|
||||
cleanup_cubeb_at_exit(ctx, cubeb_destroy);
|
||||
|
||||
const char * backend_id = cubeb_get_backend_id(ctx);
|
||||
|
||||
if ((is_float && !supports_float32(backend_id)) ||
|
||||
(!is_float && !supports_int16(backend_id))) {
|
||||
if ((is_float && !supports_float32(backend_id))) {
|
||||
/* don't treat this as a test failure. */
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
@ -201,7 +183,8 @@ int run_panning_volume_test(int is_float)
|
|||
return r;
|
||||
}
|
||||
|
||||
CubebStreamCleaner cleanup_stream_at_exit(stream);
|
||||
std::unique_ptr<cubeb_stream, decltype(&cubeb_stream_destroy)>
|
||||
cleanup_stream_at_exit(stream, cubeb_stream_destroy);
|
||||
|
||||
fprintf(stderr, "Testing: volume\n");
|
||||
for(int i=0;i <= 4; ++i)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <memory>
|
||||
#include "cubeb/cubeb.h"
|
||||
|
||||
static void
|
||||
|
@ -110,10 +111,10 @@ TEST(cubeb, enumerate_devices)
|
|||
cubeb_device_collection * collection = NULL;
|
||||
|
||||
r = cubeb_init(&ctx, "Cubeb audio test", NULL);
|
||||
if (r != CUBEB_OK) {
|
||||
fprintf(stderr, "Error initializing cubeb library\n");
|
||||
ASSERT_EQ(r, CUBEB_OK);
|
||||
}
|
||||
ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb library";
|
||||
|
||||
std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
|
||||
cleanup_cubeb_at_exit(ctx, cubeb_destroy);
|
||||
|
||||
fprintf(stdout, "Enumerating input devices for backend %s\n",
|
||||
cubeb_get_backend_id(ctx));
|
||||
|
@ -123,12 +124,8 @@ TEST(cubeb, enumerate_devices)
|
|||
fprintf(stderr, "Device enumeration not supported"
|
||||
" for this backend, skipping this test.\n");
|
||||
r = CUBEB_OK;
|
||||
goto cleanup;
|
||||
}
|
||||
if (r != CUBEB_OK) {
|
||||
fprintf(stderr, "Error enumerating devices %d\n", r);
|
||||
goto cleanup;
|
||||
}
|
||||
ASSERT_EQ(r, CUBEB_OK) << "Error enumerating devices " << r;
|
||||
|
||||
fprintf(stdout, "Found %u input devices\n", collection->count);
|
||||
print_device_collection(collection, stdout);
|
||||
|
@ -138,17 +135,9 @@ TEST(cubeb, enumerate_devices)
|
|||
cubeb_get_backend_id(ctx));
|
||||
|
||||
r = cubeb_enumerate_devices(ctx, CUBEB_DEVICE_TYPE_OUTPUT, &collection);
|
||||
if (r != CUBEB_OK) {
|
||||
fprintf(stderr, "Error enumerating devices %d\n", r);
|
||||
goto cleanup;
|
||||
}
|
||||
ASSERT_EQ(r, CUBEB_OK) << "Error enumerating devices " << r;
|
||||
|
||||
fprintf(stdout, "Found %u output devices\n", collection->count);
|
||||
print_device_collection(collection, stdout);
|
||||
cubeb_device_collection_destroy(collection);
|
||||
|
||||
cleanup:
|
||||
cubeb_destroy(ctx);
|
||||
ASSERT_EQ(r, CUBEB_OK);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <memory>
|
||||
#include "cubeb/cubeb.h"
|
||||
#include "common.h"
|
||||
|
||||
|
@ -60,13 +61,13 @@ void state_cb_duplex(cubeb_stream * stream, void * /*user*/, cubeb_state state)
|
|||
|
||||
switch (state) {
|
||||
case CUBEB_STATE_STARTED:
|
||||
printf("stream started\n"); break;
|
||||
fprintf(stderr, "stream started\n"); break;
|
||||
case CUBEB_STATE_STOPPED:
|
||||
printf("stream stopped\n"); break;
|
||||
fprintf(stderr, "stream stopped\n"); break;
|
||||
case CUBEB_STATE_DRAINED:
|
||||
printf("stream drained\n"); break;
|
||||
fprintf(stderr, "stream drained\n"); break;
|
||||
default:
|
||||
printf("unknown stream state %d\n", state);
|
||||
fprintf(stderr, "unknown stream state %d\n", state);
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -83,10 +84,10 @@ TEST(cubeb, duplex)
|
|||
uint32_t latency_frames = 0;
|
||||
|
||||
r = cubeb_init(&ctx, "Cubeb duplex example", NULL);
|
||||
if (r != CUBEB_OK) {
|
||||
fprintf(stderr, "Error initializing cubeb library\n");
|
||||
ASSERT_EQ(r, CUBEB_OK);
|
||||
}
|
||||
ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb library";
|
||||
|
||||
std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
|
||||
cleanup_cubeb_at_exit(ctx, cubeb_destroy);
|
||||
|
||||
/* This test needs an available input device, skip it if this host does not
|
||||
* have one. */
|
||||
|
@ -105,26 +106,19 @@ TEST(cubeb, duplex)
|
|||
output_params.layout = CUBEB_LAYOUT_STEREO;
|
||||
|
||||
r = cubeb_get_min_latency(ctx, output_params, &latency_frames);
|
||||
|
||||
if (r != CUBEB_OK) {
|
||||
fprintf(stderr, "Could not get minimal latency\n");
|
||||
ASSERT_EQ(r, CUBEB_OK);
|
||||
}
|
||||
ASSERT_EQ(r, CUBEB_OK) << "Could not get minimal latency";
|
||||
|
||||
r = cubeb_stream_init(ctx, &stream, "Cubeb duplex",
|
||||
NULL, &input_params, NULL, &output_params,
|
||||
latency_frames, data_cb_duplex, state_cb_duplex, &stream_state);
|
||||
if (r != CUBEB_OK) {
|
||||
fprintf(stderr, "Error initializing cubeb stream\n");
|
||||
ASSERT_EQ(r, CUBEB_OK);
|
||||
}
|
||||
ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb stream";
|
||||
|
||||
std::unique_ptr<cubeb_stream, decltype(&cubeb_stream_destroy)>
|
||||
cleanup_stream_at_exit(stream, cubeb_stream_destroy);
|
||||
|
||||
cubeb_stream_start(stream);
|
||||
delay(500);
|
||||
cubeb_stream_stop(stream);
|
||||
|
||||
cubeb_stream_destroy(stream);
|
||||
cubeb_destroy(ctx);
|
||||
|
||||
ASSERT_TRUE(stream_state.seen_audio);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "gtest/gtest.h"
|
||||
#include <stdlib.h>
|
||||
#include <memory>
|
||||
#include "cubeb/cubeb.h"
|
||||
|
||||
TEST(cubeb, latency)
|
||||
|
@ -14,6 +15,9 @@ TEST(cubeb, latency)
|
|||
r = cubeb_init(&ctx, "Cubeb audio test", NULL);
|
||||
ASSERT_EQ(r, CUBEB_OK);
|
||||
|
||||
std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
|
||||
cleanup_cubeb_at_exit(ctx, cubeb_destroy);
|
||||
|
||||
r = cubeb_get_max_channel_count(ctx, &max_channels);
|
||||
ASSERT_TRUE(r == CUBEB_OK || r == CUBEB_ERROR_NOT_SUPPORTED);
|
||||
if (r == CUBEB_OK) {
|
||||
|
@ -44,6 +48,4 @@ TEST(cubeb, latency)
|
|||
if (r == CUBEB_OK) {
|
||||
ASSERT_GT(latency_frames, 0u);
|
||||
}
|
||||
|
||||
cubeb_destroy(ctx);
|
||||
}
|
||||
|
|
|
@ -153,7 +153,7 @@ downmix_test(float const * data, cubeb_channel_layout in_layout, cubeb_channel_l
|
|||
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, "[3f2] Expect: %lf, Get: %lf\n", downmix_results[index], out[index]);
|
||||
ASSERT_EQ(out[index], downmix_results[index]);
|
||||
ASSERT_EQ(downmix_results[index], out[index]);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -161,21 +161,21 @@ downmix_test(float const * data, cubeb_channel_layout in_layout, cubeb_channel_l
|
|||
if (out_layout_mask & in_layout_mask) {
|
||||
uint32_t mask = 1 << CHANNEL_INDEX_TO_ORDER[out_layout][index];
|
||||
fprintf(stderr, "[map channels] Expect: %lf, Get: %lf\n", (mask & in_layout_mask) ? audio_inputs[out_layout].data[index] : 0, out[index]);
|
||||
ASSERT_EQ(out[index], (mask & in_layout_mask) ? audio_inputs[out_layout].data[index] : 0);
|
||||
ASSERT_EQ((mask & in_layout_mask) ? audio_inputs[out_layout].data[index] : 0, out[index]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// downmix_fallback
|
||||
fprintf(stderr, "[fallback] Expect: %lf, Get: %lf\n", audio_inputs[in_layout].data[index], out[index]);
|
||||
ASSERT_EQ(out[index], audio_inputs[in_layout].data[index]);
|
||||
ASSERT_EQ(audio_inputs[in_layout].data[index], out[index]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(cubeb, run_mixing_test)
|
||||
TEST(cubeb, mixer)
|
||||
{
|
||||
for (unsigned int i = 0 ; i < ARRAY_LENGTH(audio_inputs) ; ++i) {
|
||||
for (unsigned int j = 0 ; j < ARRAY_LENGTH(layout_infos) ; ++j) {
|
||||
downmix_test(audio_inputs[i].data, audio_inputs[i].layout, layout_infos[j].layout);
|
||||
for (auto audio_input : audio_inputs) {
|
||||
for (auto audio_output : layout_infos) {
|
||||
downmix_test(audio_input.data, audio_input.layout, audio_output.layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,16 +12,13 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include "cubeb/cubeb.h"
|
||||
#include "common.h"
|
||||
|
||||
#define SAMPLE_FREQUENCY 48000
|
||||
#if (defined(_WIN32) || defined(__WIN32__))
|
||||
#define STREAM_FORMAT CUBEB_SAMPLE_FLOAT32LE
|
||||
#else
|
||||
#define STREAM_FORMAT CUBEB_SAMPLE_S16LE
|
||||
#endif
|
||||
|
||||
std::atomic<bool> load_callback{ false };
|
||||
|
||||
|
@ -64,6 +61,9 @@ TEST(cubeb, overload_callback)
|
|||
r = cubeb_init(&ctx, "Cubeb callback overload", NULL);
|
||||
ASSERT_EQ(r, CUBEB_OK);
|
||||
|
||||
std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
|
||||
cleanup_cubeb_at_exit(ctx, cubeb_destroy);
|
||||
|
||||
output_params.format = STREAM_FORMAT;
|
||||
output_params.rate = 48000;
|
||||
output_params.channels = 2;
|
||||
|
@ -77,13 +77,13 @@ TEST(cubeb, overload_callback)
|
|||
latency_frames, data_cb, state_cb, NULL);
|
||||
ASSERT_EQ(r, CUBEB_OK);
|
||||
|
||||
std::unique_ptr<cubeb_stream, decltype(&cubeb_stream_destroy)>
|
||||
cleanup_stream_at_exit(stream, cubeb_stream_destroy);
|
||||
|
||||
cubeb_stream_start(stream);
|
||||
delay(500);
|
||||
// This causes the callback to sleep for a large number of seconds.
|
||||
load_callback = true;
|
||||
delay(500);
|
||||
cubeb_stream_stop(stream);
|
||||
|
||||
cubeb_stream_destroy(stream);
|
||||
cubeb_destroy(ctx);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <memory>
|
||||
#include "cubeb/cubeb.h"
|
||||
#include "common.h"
|
||||
|
||||
|
@ -53,13 +54,13 @@ void state_cb_record(cubeb_stream * stream, void * /*user*/, cubeb_state state)
|
|||
|
||||
switch (state) {
|
||||
case CUBEB_STATE_STARTED:
|
||||
printf("stream started\n"); break;
|
||||
fprintf(stderr, "stream started\n"); break;
|
||||
case CUBEB_STATE_STOPPED:
|
||||
printf("stream stopped\n"); break;
|
||||
fprintf(stderr, "stream stopped\n"); break;
|
||||
case CUBEB_STATE_DRAINED:
|
||||
printf("stream drained\n"); break;
|
||||
fprintf(stderr, "stream drained\n"); break;
|
||||
default:
|
||||
printf("unknown stream state %d\n", state);
|
||||
fprintf(stderr, "unknown stream state %d\n", state);
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -68,7 +69,7 @@ void state_cb_record(cubeb_stream * stream, void * /*user*/, cubeb_state state)
|
|||
TEST(cubeb, record)
|
||||
{
|
||||
if (cubeb_set_log_callback(CUBEB_LOG_DISABLED, nullptr /*print_log*/) != CUBEB_OK) {
|
||||
printf("Set log callback failed\n");
|
||||
fprintf(stderr, "Set log callback failed\n");
|
||||
}
|
||||
cubeb *ctx;
|
||||
cubeb_stream *stream;
|
||||
|
@ -77,10 +78,10 @@ TEST(cubeb, record)
|
|||
user_state_record stream_state = { false };
|
||||
|
||||
r = cubeb_init(&ctx, "Cubeb record example", NULL);
|
||||
if (r != CUBEB_OK) {
|
||||
fprintf(stderr, "Error initializing cubeb library\n");
|
||||
ASSERT_EQ(r, CUBEB_OK);
|
||||
}
|
||||
ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb library";
|
||||
|
||||
std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
|
||||
cleanup_cubeb_at_exit(ctx, cubeb_destroy);
|
||||
|
||||
/* This test needs an available input device, skip it if this host does not
|
||||
* have one. */
|
||||
|
@ -95,21 +96,18 @@ TEST(cubeb, record)
|
|||
|
||||
r = cubeb_stream_init(ctx, &stream, "Cubeb record (mono)", NULL, ¶ms, NULL, nullptr,
|
||||
4096, data_cb_record, state_cb_record, &stream_state);
|
||||
if (r != CUBEB_OK) {
|
||||
fprintf(stderr, "Error initializing cubeb stream\n");
|
||||
ASSERT_EQ(r, CUBEB_OK);
|
||||
}
|
||||
ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb stream";
|
||||
|
||||
std::unique_ptr<cubeb_stream, decltype(&cubeb_stream_destroy)>
|
||||
cleanup_stream_at_exit(stream, cubeb_stream_destroy);
|
||||
|
||||
cubeb_stream_start(stream);
|
||||
delay(500);
|
||||
cubeb_stream_stop(stream);
|
||||
|
||||
cubeb_stream_destroy(stream);
|
||||
cubeb_destroy(ctx);
|
||||
|
||||
#ifdef __linux__
|
||||
// user callback does not arrive in Linux, silence the error
|
||||
printf("Check is disabled in Linux\n");
|
||||
fprintf(stderr, "Check is disabled in Linux\n");
|
||||
#else
|
||||
ASSERT_TRUE(stream_state.seen_audio);
|
||||
#endif
|
||||
|
|
|
@ -410,7 +410,7 @@ TEST(cubeb, resampler_one_way)
|
|||
for (uint32_t source_rate = 0; source_rate < array_size(sample_rates); source_rate++) {
|
||||
for (uint32_t dest_rate = 0; dest_rate < array_size(sample_rates); dest_rate++) {
|
||||
for (uint32_t chunk_duration = min_chunks; chunk_duration < max_chunks; chunk_duration+=chunk_increment) {
|
||||
printf("one_way: channels: %d, source_rate: %d, dest_rate: %d, chunk_duration: %d\n",
|
||||
fprintf(stderr, "one_way: channels: %d, source_rate: %d, dest_rate: %d, chunk_duration: %d\n",
|
||||
channels, sample_rates[source_rate], sample_rates[dest_rate], chunk_duration);
|
||||
test_resampler_one_way<float>(channels, sample_rates[source_rate],
|
||||
sample_rates[dest_rate], chunk_duration);
|
||||
|
@ -428,7 +428,7 @@ TEST(cubeb, DISABLED_resampler_duplex)
|
|||
for (uint32_t source_rate_output = 0; source_rate_output < array_size(sample_rates); source_rate_output++) {
|
||||
for (uint32_t dest_rate = 0; dest_rate < array_size(sample_rates); dest_rate++) {
|
||||
for (uint32_t chunk_duration = min_chunks; chunk_duration < max_chunks; chunk_duration+=chunk_increment) {
|
||||
printf("input channels:%d output_channels:%d input_rate:%d "
|
||||
fprintf(stderr, "input channels:%d output_channels:%d input_rate:%d "
|
||||
"output_rate:%d target_rate:%d chunk_ms:%d\n",
|
||||
input_channels, output_channels,
|
||||
sample_rates[source_rate_input],
|
||||
|
@ -453,7 +453,7 @@ TEST(cubeb, resampler_delay_line)
|
|||
for (uint32_t channel = 1; channel <= 2; channel++) {
|
||||
for (uint32_t delay_frames = 4; delay_frames <= 40; delay_frames+=chunk_increment) {
|
||||
for (uint32_t chunk_size = 10; chunk_size <= 30; chunk_size++) {
|
||||
printf("channel: %d, delay_frames: %d, chunk_size: %d\n",
|
||||
fprintf(stderr, "channel: %d, delay_frames: %d, chunk_size: %d\n",
|
||||
channel, delay_frames, chunk_size);
|
||||
test_delay_lines(delay_frames, channel, chunk_size);
|
||||
}
|
||||
|
|
|
@ -19,16 +19,12 @@
|
|||
#define STREAM_LATENCY 100 * STREAM_RATE / 1000
|
||||
#define STREAM_CHANNELS 1
|
||||
#define STREAM_LAYOUT CUBEB_LAYOUT_MONO
|
||||
#if (defined(_WIN32) || defined(__WIN32__))
|
||||
#define STREAM_FORMAT CUBEB_SAMPLE_FLOAT32LE
|
||||
#else
|
||||
#define STREAM_FORMAT CUBEB_SAMPLE_S16LE
|
||||
#endif
|
||||
|
||||
int is_windows_7()
|
||||
{
|
||||
#ifdef __MINGW32__
|
||||
printf("Warning: this test was built with MinGW.\n"
|
||||
fprintf(stderr, "Warning: this test was built with MinGW.\n"
|
||||
"MinGW does not contain necessary version checking infrastructure. Claiming to be Windows 7, even if we're not.\n");
|
||||
return 1;
|
||||
#endif
|
||||
|
@ -61,11 +57,7 @@ test_data_callback(cubeb_stream * stm, void * user_ptr, const void * /*inputbuff
|
|||
{
|
||||
EXPECT_TRUE(stm && user_ptr == &dummy && outputbuffer && nframes > 0);
|
||||
assert(outputbuffer);
|
||||
#if (defined(_WIN32) || defined(__WIN32__))
|
||||
memset(outputbuffer, 0, nframes * sizeof(float));
|
||||
#else
|
||||
memset(outputbuffer, 0, nframes * sizeof(short));
|
||||
#endif
|
||||
|
||||
total_frames_written += nframes;
|
||||
if (delay_callback) {
|
||||
|
@ -545,11 +537,7 @@ test_drain_data_callback(cubeb_stream * stm, void * user_ptr, const void * /*inp
|
|||
}
|
||||
/* once drain has started, callback must never be called again */
|
||||
EXPECT_TRUE(do_drain != 2);
|
||||
#if (defined(_WIN32) || defined(__WIN32__))
|
||||
memset(outputbuffer, 0, nframes * sizeof(float));
|
||||
#else
|
||||
memset(outputbuffer, 0, nframes * sizeof(short));
|
||||
#endif
|
||||
total_frames_written += nframes;
|
||||
return nframes;
|
||||
}
|
||||
|
|
|
@ -13,16 +13,13 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <memory>
|
||||
#include <limits.h>
|
||||
#include "cubeb/cubeb.h"
|
||||
#include "common.h"
|
||||
|
||||
#define SAMPLE_FREQUENCY 48000
|
||||
#if (defined(_WIN32) || defined(__WIN32__))
|
||||
#define STREAM_FORMAT CUBEB_SAMPLE_FLOAT32LE
|
||||
#else
|
||||
#define STREAM_FORMAT CUBEB_SAMPLE_S16LE
|
||||
#endif
|
||||
|
||||
/* store the phase of the generated waveform */
|
||||
struct cb_user_data {
|
||||
|
@ -32,11 +29,7 @@ struct cb_user_data {
|
|||
long data_cb_tone(cubeb_stream *stream, void *user, const void* /*inputbuffer*/, void *outputbuffer, long nframes)
|
||||
{
|
||||
struct cb_user_data *u = (struct cb_user_data *)user;
|
||||
#if (defined(_WIN32) || defined(__WIN32__))
|
||||
float *b = (float *)outputbuffer;
|
||||
#else
|
||||
short *b = (short *)outputbuffer;
|
||||
#endif
|
||||
float t1, t2;
|
||||
int i;
|
||||
|
||||
|
@ -48,21 +41,12 @@ long data_cb_tone(cubeb_stream *stream, void *user, const void* /*inputbuffer*/,
|
|||
/* North American dial tone */
|
||||
t1 = sin(2*M_PI*(i + u->position)*350/SAMPLE_FREQUENCY);
|
||||
t2 = sin(2*M_PI*(i + u->position)*440/SAMPLE_FREQUENCY);
|
||||
#if (defined(_WIN32) || defined(__WIN32__))
|
||||
b[i] = 0.5 * t1;
|
||||
b[i] += 0.5 * t2;
|
||||
#else
|
||||
b[i] = (SHRT_MAX / 2) * t1;
|
||||
b[i] += (SHRT_MAX / 2) * t2;
|
||||
#endif
|
||||
/* European dial tone */
|
||||
/*
|
||||
t1 = sin(2*M_PI*(i + u->position)*425/SAMPLE_FREQUENCY);
|
||||
#if (defined(_WIN32) || defined(__WIN32__))
|
||||
b[i] = t1;
|
||||
#else
|
||||
b[i] = SHRT_MAX * t1;
|
||||
#endif
|
||||
*/
|
||||
}
|
||||
/* remember our phase to avoid clicking on buffer transitions */
|
||||
|
@ -81,13 +65,13 @@ void state_cb_tone(cubeb_stream *stream, void *user, cubeb_state state)
|
|||
|
||||
switch (state) {
|
||||
case CUBEB_STATE_STARTED:
|
||||
printf("stream started\n"); break;
|
||||
fprintf(stderr, "stream started\n"); break;
|
||||
case CUBEB_STATE_STOPPED:
|
||||
printf("stream stopped\n"); break;
|
||||
fprintf(stderr, "stream stopped\n"); break;
|
||||
case CUBEB_STATE_DRAINED:
|
||||
printf("stream drained\n"); break;
|
||||
fprintf(stderr, "stream drained\n"); break;
|
||||
default:
|
||||
printf("unknown stream state %d\n", state);
|
||||
fprintf(stderr, "unknown stream state %d\n", state);
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -98,42 +82,34 @@ TEST(cubeb, tone)
|
|||
cubeb *ctx;
|
||||
cubeb_stream *stream;
|
||||
cubeb_stream_params params;
|
||||
struct cb_user_data *user_data;
|
||||
int r;
|
||||
|
||||
r = cubeb_init(&ctx, "Cubeb tone example", NULL);
|
||||
if (r != CUBEB_OK) {
|
||||
fprintf(stderr, "Error initializing cubeb library\n");
|
||||
ASSERT_EQ(r, CUBEB_OK);
|
||||
}
|
||||
ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb library";
|
||||
|
||||
std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
|
||||
cleanup_cubeb_at_exit(ctx, cubeb_destroy);
|
||||
|
||||
params.format = STREAM_FORMAT;
|
||||
params.rate = SAMPLE_FREQUENCY;
|
||||
params.channels = 1;
|
||||
params.layout = CUBEB_LAYOUT_MONO;
|
||||
|
||||
user_data = (struct cb_user_data *) malloc(sizeof(*user_data));
|
||||
if (user_data == NULL) {
|
||||
fprintf(stderr, "Error allocating user data\n");
|
||||
FAIL();
|
||||
}
|
||||
std::unique_ptr<cb_user_data> user_data(new cb_user_data());
|
||||
ASSERT_TRUE(!!user_data) << "Error allocating user data";
|
||||
|
||||
user_data->position = 0;
|
||||
|
||||
r = cubeb_stream_init(ctx, &stream, "Cubeb tone (mono)", NULL, NULL, NULL, ¶ms,
|
||||
4096, data_cb_tone, state_cb_tone, user_data);
|
||||
if (r != CUBEB_OK) {
|
||||
fprintf(stderr, "Error initializing cubeb stream\n");
|
||||
ASSERT_EQ(r, CUBEB_OK);
|
||||
}
|
||||
4096, data_cb_tone, state_cb_tone, user_data.get());
|
||||
ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb stream";
|
||||
|
||||
std::unique_ptr<cubeb_stream, decltype(&cubeb_stream_destroy)>
|
||||
cleanup_stream_at_exit(stream, cubeb_stream_destroy);
|
||||
|
||||
cubeb_stream_start(stream);
|
||||
delay(500);
|
||||
cubeb_stream_stop(stream);
|
||||
|
||||
cubeb_stream_destroy(stream);
|
||||
cubeb_destroy(ctx);
|
||||
|
||||
ASSERT_TRUE(user_data->position);
|
||||
|
||||
free(user_data);
|
||||
}
|
||||
|
|
|
@ -318,15 +318,24 @@ cubeb_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_n
|
|||
return r;
|
||||
}
|
||||
|
||||
return context->ops->stream_init(context, stream, stream_name,
|
||||
input_device,
|
||||
input_stream_params,
|
||||
output_device,
|
||||
output_stream_params,
|
||||
latency,
|
||||
data_callback,
|
||||
state_callback,
|
||||
user_ptr);
|
||||
r = context->ops->stream_init(context, stream, stream_name,
|
||||
input_device,
|
||||
input_stream_params,
|
||||
output_device,
|
||||
output_stream_params,
|
||||
latency,
|
||||
data_callback,
|
||||
state_callback,
|
||||
user_ptr);
|
||||
|
||||
if (r == CUBEB_ERROR_INVALID_FORMAT) {
|
||||
LOG("Invalid format, %p %p %d %d",
|
||||
output_stream_params, input_stream_params,
|
||||
output_stream_params && output_stream_params->format,
|
||||
input_stream_params && input_stream_params->format);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -553,7 +562,7 @@ int cubeb_enumerate_devices(cubeb * context,
|
|||
|
||||
rv = context->ops->enumerate_devices(context, devtype, collection);
|
||||
|
||||
if (g_log_callback) {
|
||||
if (g_cubeb_log_callback) {
|
||||
for (uint32_t i = 0; i < (*collection)->count; i++) {
|
||||
log_device((*collection)->device[i]);
|
||||
}
|
||||
|
@ -617,12 +626,12 @@ int cubeb_set_log_callback(cubeb_log_level log_level,
|
|||
return CUBEB_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (g_log_callback && log_callback) {
|
||||
if (g_cubeb_log_callback && log_callback) {
|
||||
return CUBEB_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
g_log_callback = log_callback;
|
||||
g_log_level = log_level;
|
||||
g_cubeb_log_callback = log_callback;
|
||||
g_cubeb_log_level = log_level;
|
||||
|
||||
// Logging a message here allows to initialize the asynchronous logger from a
|
||||
// thread that is not the audio rendering thread, and especially to not
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
#include <sys/time.h>
|
||||
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
|
||||
typedef UInt32 AudioFormatFlags;
|
||||
|
@ -82,63 +83,6 @@ struct cubeb {
|
|||
cubeb_channel_layout layout;
|
||||
};
|
||||
|
||||
struct auto_array_wrapper {
|
||||
virtual void push(void * elements, size_t length) = 0;
|
||||
virtual size_t length() = 0;
|
||||
virtual void push_silence(size_t length) = 0;
|
||||
virtual bool pop(size_t length) = 0;
|
||||
virtual void * data() = 0;
|
||||
virtual void clear() = 0;
|
||||
virtual ~auto_array_wrapper() {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct auto_array_wrapper_impl : public auto_array_wrapper {
|
||||
explicit auto_array_wrapper_impl(uint32_t size)
|
||||
: ar(size)
|
||||
{}
|
||||
|
||||
void push(void * elements, size_t length) override {
|
||||
auto_lock l(lock);
|
||||
ar.push(static_cast<T *>(elements), length);
|
||||
}
|
||||
|
||||
size_t length() override {
|
||||
auto_lock l(lock);
|
||||
return ar.length();
|
||||
}
|
||||
|
||||
void push_silence(size_t length) override {
|
||||
auto_lock l(lock);
|
||||
ar.push_silence(length);
|
||||
}
|
||||
|
||||
bool pop(size_t length) override {
|
||||
auto_lock l(lock);
|
||||
return ar.pop(nullptr, length);
|
||||
}
|
||||
|
||||
// XXX: Taking the lock here is pointless.
|
||||
void * data() override {
|
||||
auto_lock l(lock);
|
||||
return ar.data();
|
||||
}
|
||||
|
||||
void clear() override {
|
||||
auto_lock l(lock);
|
||||
ar.clear();
|
||||
}
|
||||
|
||||
~auto_array_wrapper_impl() {
|
||||
auto_lock l(lock);
|
||||
ar.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
owned_critical_section lock;
|
||||
auto_array<T> ar;
|
||||
};
|
||||
|
||||
static std::unique_ptr<AudioChannelLayout, decltype(&free)>
|
||||
make_sized_audio_channel_layout(size_t sz)
|
||||
{
|
||||
|
@ -148,36 +92,36 @@ make_sized_audio_channel_layout(size_t sz)
|
|||
return std::unique_ptr<AudioChannelLayout, decltype(&free)>(acl, free);
|
||||
}
|
||||
|
||||
struct mixing_wrapper {
|
||||
virtual void downmix(void * output_buffer, long output_frames,
|
||||
cubeb_channel_layout output_layout,
|
||||
cubeb_channel_layout mixing_layout) = 0;
|
||||
virtual ~mixing_wrapper() {};
|
||||
struct mixer_proxy {
|
||||
virtual void downmix(void * buffer, long frames,
|
||||
cubeb_channel_layout input_layout,
|
||||
cubeb_channel_layout output_layout) = 0;
|
||||
virtual ~mixer_proxy() {};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct mixing_impl : public mixing_wrapper {
|
||||
struct mixer_impl : public mixer_proxy {
|
||||
|
||||
typedef void (*downmix_func)(T * const, long, T *,
|
||||
unsigned int, unsigned int,
|
||||
cubeb_channel_layout, cubeb_channel_layout);
|
||||
|
||||
mixing_impl(downmix_func dmfunc) {
|
||||
mixer_impl(downmix_func dmfunc) {
|
||||
downmix_wrapper = dmfunc;
|
||||
}
|
||||
|
||||
~mixing_impl() {}
|
||||
~mixer_impl() {}
|
||||
|
||||
void downmix(void * output_buffer, long output_frames,
|
||||
cubeb_channel_layout output_layout,
|
||||
cubeb_channel_layout mixing_layout) override {
|
||||
void downmix(void * buffer, long frames,
|
||||
cubeb_channel_layout input_layout,
|
||||
cubeb_channel_layout output_layout) override {
|
||||
uint32_t input_channels = CUBEB_CHANNEL_LAYOUT_MAPS[input_layout].channels;
|
||||
uint32_t output_channels = CUBEB_CHANNEL_LAYOUT_MAPS[output_layout].channels;
|
||||
uint32_t using_channels = CUBEB_CHANNEL_LAYOUT_MAPS[mixing_layout].channels;
|
||||
T* out = static_cast<T *>(output_buffer);
|
||||
T * out = static_cast<T*>(buffer);
|
||||
// By using same buffer for downmixing input and output, we allow downmixing
|
||||
// from 5.0/1 to 1.0/1, 2.0/1/2, 3.0/1, 4.0/1. Do nothing on other cases.
|
||||
downmix_wrapper(out, output_frames, out, output_channels, using_channels,
|
||||
output_layout, mixing_layout);
|
||||
downmix_wrapper(out, frames, out, input_channels, output_channels,
|
||||
input_layout, output_layout);
|
||||
}
|
||||
|
||||
downmix_func downmix_wrapper;
|
||||
|
@ -230,6 +174,7 @@ struct cubeb_stream {
|
|||
/* Hold the input samples in every
|
||||
* input callback iteration */
|
||||
std::unique_ptr<auto_array_wrapper> input_linear_buffer;
|
||||
owned_critical_section input_linear_buffer_lock;
|
||||
// After the resampling some input data remains stored inside
|
||||
// the resampler. This number is used in order to calculate
|
||||
// the number of extra silence frames in input.
|
||||
|
@ -253,8 +198,8 @@ struct cubeb_stream {
|
|||
std::atomic<bool> buffer_size_change_state{ false };
|
||||
AudioDeviceID aggregate_device_id = 0; // the aggregate device id
|
||||
AudioObjectID plugin_id = 0; // used to create aggregate device
|
||||
/* Mixing interface */
|
||||
std::unique_ptr<mixing_wrapper> mixing;
|
||||
/* Mixer interface */
|
||||
std::unique_ptr<mixer_proxy> mixer;
|
||||
};
|
||||
|
||||
bool has_input(cubeb_stream * stm)
|
||||
|
@ -386,8 +331,11 @@ audiounit_render_input(cubeb_stream * stm,
|
|||
}
|
||||
|
||||
/* Copy input data in linear buffer. */
|
||||
stm->input_linear_buffer->push(input_buffer_list.mBuffers[0].mData,
|
||||
input_frames * stm->input_desc.mChannelsPerFrame);
|
||||
{
|
||||
auto_lock l(stm->input_linear_buffer_lock);
|
||||
stm->input_linear_buffer->push(input_buffer_list.mBuffers[0].mData,
|
||||
input_frames * stm->input_desc.mChannelsPerFrame);
|
||||
}
|
||||
|
||||
/* Advance input frame counter. */
|
||||
assert(input_frames > 0);
|
||||
|
@ -435,19 +383,19 @@ audiounit_input_callback(void * user_ptr,
|
|||
|
||||
/* Input only. Call the user callback through resampler.
|
||||
Resampler will deliver input buffer in the correct rate. */
|
||||
assert(input_frames <= stm->input_linear_buffer->length() / stm->input_desc.mChannelsPerFrame);
|
||||
long total_input_frames = stm->input_linear_buffer->length() / stm->input_desc.mChannelsPerFrame;
|
||||
long outframes = cubeb_resampler_fill(stm->resampler.get(),
|
||||
stm->input_linear_buffer->data(),
|
||||
&total_input_frames,
|
||||
NULL,
|
||||
0);
|
||||
// Reset input buffer
|
||||
stm->input_linear_buffer->clear();
|
||||
{
|
||||
auto_lock l(stm->input_linear_buffer_lock);
|
||||
assert(input_frames <= stm->input_linear_buffer->length() / stm->input_desc.mChannelsPerFrame);
|
||||
long total_input_frames = stm->input_linear_buffer->length() / stm->input_desc.mChannelsPerFrame;
|
||||
long outframes = cubeb_resampler_fill(stm->resampler.get(),
|
||||
stm->input_linear_buffer->data(),
|
||||
&total_input_frames,
|
||||
NULL,
|
||||
0);
|
||||
assert(outframes >= 0);
|
||||
|
||||
if (outframes < 0 || (UInt32) outframes != input_frames) {
|
||||
stm->shutdown = true;
|
||||
return noErr;
|
||||
// Reset input buffer
|
||||
stm->input_linear_buffer->clear();
|
||||
}
|
||||
|
||||
return noErr;
|
||||
|
@ -480,7 +428,7 @@ audiounit_mix_output_buffer(cubeb_stream * stm,
|
|||
// the channels that audio device can provide, so we need to downmix the
|
||||
// audio data by ourselves to keep all the information.
|
||||
|
||||
cubeb_stream_params mixed_params = {
|
||||
cubeb_stream_params dest_params = {
|
||||
stm->output_stream_params.format,
|
||||
stm->output_stream_params.rate,
|
||||
CUBEB_CHANNEL_LAYOUT_MAPS[stm->context->layout].channels,
|
||||
|
@ -488,9 +436,9 @@ audiounit_mix_output_buffer(cubeb_stream * stm,
|
|||
};
|
||||
|
||||
// We only handle downmixing for now.
|
||||
if (cubeb_should_downmix(&stm->output_stream_params, &mixed_params)) {
|
||||
stm->mixing->downmix(output_buffer, output_frames,
|
||||
stm->output_stream_params.layout, mixed_params.layout);
|
||||
if (cubeb_should_downmix(&stm->output_stream_params, &dest_params)) {
|
||||
stm->mixer->downmix(output_buffer, output_frames,
|
||||
stm->output_stream_params.layout, dest_params.layout);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -542,7 +490,10 @@ audiounit_output_callback(void * user_ptr,
|
|||
if (stm->input_unit != NULL) {
|
||||
if (is_extra_input_needed(stm)) {
|
||||
uint32_t min_input_frames = minimum_resampling_input_frames(stm);
|
||||
stm->input_linear_buffer->push_silence(min_input_frames * stm->input_desc.mChannelsPerFrame);
|
||||
{
|
||||
auto_lock l(stm->input_linear_buffer_lock);
|
||||
stm->input_linear_buffer->push_silence(min_input_frames * stm->input_desc.mChannelsPerFrame);
|
||||
}
|
||||
stm->available_input_frames += min_input_frames;
|
||||
|
||||
ALOG("(%p) %s pushed %u frames of input silence.", stm, stm->frames_read == 0 ? "Input hasn't started," :
|
||||
|
@ -568,6 +519,7 @@ audiounit_output_callback(void * user_ptr,
|
|||
stm->available_input_frames -= input_frames;
|
||||
assert(stm->available_input_frames.load() >= 0);
|
||||
// Pop from the buffer the frames pushed to the resampler.
|
||||
auto_lock l(stm->input_linear_buffer_lock);
|
||||
stm->input_linear_buffer->pop(input_frames_before_fill * stm->input_desc.mChannelsPerFrame);
|
||||
}
|
||||
|
||||
|
@ -1308,12 +1260,12 @@ audio_stream_desc_init(AudioStreamBasicDescription * ss,
|
|||
}
|
||||
|
||||
void
|
||||
audiounit_init_mixed_buffer(cubeb_stream * stm)
|
||||
audiounit_init_mixer(cubeb_stream * stm)
|
||||
{
|
||||
if (stm->output_desc.mFormatFlags & kAudioFormatFlagIsFloat) {
|
||||
stm->mixing.reset(new mixing_impl<float>(&cubeb_downmix_float));
|
||||
stm->mixer.reset(new mixer_impl<float>(&cubeb_downmix_float));
|
||||
} else { // stm->output_desc.mFormatFlags & kAudioFormatFlagIsSignedInteger
|
||||
stm->mixing.reset(new mixing_impl<short>(&cubeb_downmix_short));
|
||||
stm->mixer.reset(new mixer_impl<short>(&cubeb_downmix_short));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1336,45 +1288,45 @@ audiounit_set_channel_layout(AudioUnit unit,
|
|||
switch (stream_params->layout) {
|
||||
case CUBEB_LAYOUT_DUAL_MONO:
|
||||
case CUBEB_LAYOUT_STEREO:
|
||||
layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
|
||||
layout->mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
|
||||
break;
|
||||
case CUBEB_LAYOUT_MONO:
|
||||
layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
|
||||
layout->mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
|
||||
break;
|
||||
case CUBEB_LAYOUT_3F:
|
||||
layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_ITU_3_0;
|
||||
layout->mChannelLayoutTag = kAudioChannelLayoutTag_ITU_3_0;
|
||||
break;
|
||||
case CUBEB_LAYOUT_2F1:
|
||||
layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_ITU_2_1;
|
||||
layout->mChannelLayoutTag = kAudioChannelLayoutTag_ITU_2_1;
|
||||
break;
|
||||
case CUBEB_LAYOUT_3F1:
|
||||
layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_ITU_3_1;
|
||||
layout->mChannelLayoutTag = kAudioChannelLayoutTag_ITU_3_1;
|
||||
break;
|
||||
case CUBEB_LAYOUT_2F2:
|
||||
layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_ITU_2_2;
|
||||
layout->mChannelLayoutTag = kAudioChannelLayoutTag_ITU_2_2;
|
||||
break;
|
||||
case CUBEB_LAYOUT_3F2:
|
||||
layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_ITU_3_2;
|
||||
layout->mChannelLayoutTag = kAudioChannelLayoutTag_ITU_3_2;
|
||||
break;
|
||||
case CUBEB_LAYOUT_3F2_LFE:
|
||||
layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_AudioUnit_5_1;
|
||||
layout->mChannelLayoutTag = kAudioChannelLayoutTag_AudioUnit_5_1;
|
||||
break;
|
||||
default:
|
||||
layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_Unknown;
|
||||
layout->mChannelLayoutTag = kAudioChannelLayoutTag_Unknown;
|
||||
break;
|
||||
}
|
||||
|
||||
// For those layouts that can't be matched to coreaudio's predefined layout,
|
||||
// we use customized layout.
|
||||
if (layout.get()->mChannelLayoutTag == kAudioChannelLayoutTag_Unknown) {
|
||||
if (layout->mChannelLayoutTag == kAudioChannelLayoutTag_Unknown) {
|
||||
size = offsetof(AudioChannelLayout, mChannelDescriptions[stream_params->channels]);
|
||||
layout = make_sized_audio_channel_layout(size);
|
||||
layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
|
||||
layout.get()->mNumberChannelDescriptions = stream_params->channels;
|
||||
layout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
|
||||
layout->mNumberChannelDescriptions = stream_params->channels;
|
||||
for (UInt32 i = 0 ; i < stream_params->channels ; ++i) {
|
||||
layout.get()->mChannelDescriptions[i].mChannelLabel =
|
||||
layout->mChannelDescriptions[i].mChannelLabel =
|
||||
cubeb_channel_to_channel_label(CHANNEL_INDEX_TO_ORDER[stream_params->layout][i]);
|
||||
layout.get()->mChannelDescriptions[i].mChannelFlags = kAudioChannelFlags_AllOff;
|
||||
layout->mChannelDescriptions[i].mChannelFlags = kAudioChannelFlags_AllOff;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1496,12 +1448,16 @@ audiounit_create_blank_aggregate_device(AudioObjectID * plugin_id, AudioDeviceID
|
|||
CFMutableDictionaryRef aggregate_device_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
CFStringRef aggregate_device_name = CFSTR("CubebAggregateDevice");
|
||||
struct timeval timestamp;
|
||||
gettimeofday(×tamp, NULL);
|
||||
long long int time_id = timestamp.tv_sec * 1000000LL + timestamp.tv_usec;
|
||||
CFStringRef aggregate_device_name = CFStringCreateWithFormat(NULL, NULL, CFSTR("CubebAggregateDevice_%llx"), time_id);
|
||||
CFDictionaryAddValue(aggregate_device_dict, CFSTR(kAudioAggregateDeviceNameKey), aggregate_device_name);
|
||||
CFRelease(aggregate_device_name);
|
||||
|
||||
CFStringRef aggregate_device_UID = CFSTR("org.mozilla.CubebAggregateDevice");
|
||||
CFStringRef aggregate_device_UID = CFStringCreateWithFormat(NULL, NULL, CFSTR("org.mozilla.CubebAggregateDevice_%llx"), time_id);
|
||||
CFDictionaryAddValue(aggregate_device_dict, CFSTR(kAudioAggregateDeviceUIDKey), aggregate_device_UID);
|
||||
CFRelease(aggregate_device_UID);
|
||||
|
||||
int private_key = 1;
|
||||
CFNumberRef aggregate_device_private_key = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &private_key);
|
||||
|
@ -1541,6 +1497,8 @@ audiounit_set_aggregate_sub_device_list(AudioDeviceID aggregate_device_id,
|
|||
AudioDeviceID input_device_id,
|
||||
AudioDeviceID output_device_id)
|
||||
{
|
||||
LOG("Add devices input %u and output %u into aggregate device %u",
|
||||
input_device_id, output_device_id, aggregate_device_id);
|
||||
const std::vector<AudioDeviceID> input_sub_devices = audiounit_get_sub_devices(input_device_id);
|
||||
const std::vector<AudioDeviceID> output_sub_devices = audiounit_get_sub_devices(output_device_id);
|
||||
|
||||
|
@ -2292,7 +2250,7 @@ audiounit_configure_output(cubeb_stream * stm)
|
|||
}
|
||||
|
||||
audiounit_layout_init(stm, OUTPUT);
|
||||
audiounit_init_mixed_buffer(stm);
|
||||
audiounit_init_mixer(stm);
|
||||
|
||||
LOG("(%p) Output audiounit init successfully.", stm);
|
||||
return CUBEB_OK;
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
#include <time.h>
|
||||
#endif
|
||||
|
||||
cubeb_log_level g_log_level;
|
||||
cubeb_log_callback g_log_callback;
|
||||
cubeb_log_level g_cubeb_log_level;
|
||||
cubeb_log_callback g_cubeb_log_callback;
|
||||
|
||||
/** The maximum size of a log message, after having been formatted. */
|
||||
const size_t CUBEB_LOG_MESSAGE_MAX_SIZE = 256;
|
||||
|
@ -115,7 +115,7 @@ private:
|
|||
|
||||
void cubeb_async_log(char const * fmt, ...)
|
||||
{
|
||||
if (!g_log_callback) {
|
||||
if (!g_cubeb_log_callback) {
|
||||
return;
|
||||
}
|
||||
// This is going to copy a 256 bytes array around, which is fine.
|
||||
|
|
|
@ -20,8 +20,8 @@ extern "C" {
|
|||
#define PRINTF_FORMAT(fmt, args)
|
||||
#endif
|
||||
|
||||
extern cubeb_log_level g_log_level;
|
||||
extern cubeb_log_callback g_log_callback PRINTF_FORMAT(1, 2);
|
||||
extern cubeb_log_level g_cubeb_log_level;
|
||||
extern cubeb_log_callback g_cubeb_log_callback PRINTF_FORMAT(1, 2);
|
||||
void cubeb_async_log(const char * fmt, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -32,8 +32,8 @@ void cubeb_async_log(const char * fmt, ...);
|
|||
#define LOG(msg, ...) LOG_INTERNAL(CUBEB_LOG_NORMAL, msg, ##__VA_ARGS__)
|
||||
|
||||
#define LOG_INTERNAL(level, fmt, ...) do { \
|
||||
if (g_log_callback && level <= g_log_level) { \
|
||||
g_log_callback("%s:%d: " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \
|
||||
if (g_cubeb_log_callback && level <= g_cubeb_log_level) { \
|
||||
g_cubeb_log_callback("%s:%d: " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
|
|
@ -446,6 +446,12 @@ cubeb_should_downmix(cubeb_stream_params const * stream, cubeb_stream_params con
|
|||
mixer->layout == CUBEB_LAYOUT_3F1_LFE));
|
||||
}
|
||||
|
||||
bool
|
||||
cubeb_should_mix(cubeb_stream_params const * stream, cubeb_stream_params const * mixer)
|
||||
{
|
||||
return cubeb_should_upmix(stream, mixer) || cubeb_should_downmix(stream, mixer);
|
||||
}
|
||||
|
||||
void
|
||||
cubeb_downmix_float(float * const in, long inframes, float * out,
|
||||
unsigned int in_channels, unsigned int out_channels,
|
||||
|
@ -462,6 +468,14 @@ cubeb_downmix_short(short * const in, long inframes, short * out,
|
|||
cubeb_downmix(in, inframes, out, in_channels, out_channels, in_layout, out_layout);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cubeb_upmix_short(short * const in, long inframes, short * out,
|
||||
unsigned int in_channels, unsigned int out_channels)
|
||||
{
|
||||
cubeb_upmix(in, inframes, out, in_channels, out_channels);
|
||||
}
|
||||
|
||||
void
|
||||
cubeb_upmix_float(float * const in, long inframes, float * out,
|
||||
unsigned int in_channels, unsigned int out_channels)
|
||||
|
|
|
@ -63,6 +63,8 @@ bool cubeb_should_upmix(cubeb_stream_params const * stream, cubeb_stream_params
|
|||
|
||||
bool cubeb_should_downmix(cubeb_stream_params const * stream, cubeb_stream_params const * mixer);
|
||||
|
||||
bool cubeb_should_mix(cubeb_stream_params const * stream, cubeb_stream_params const * mixer);
|
||||
|
||||
void cubeb_downmix_float(float * const in, long inframes, float * out,
|
||||
unsigned int in_channels, unsigned int out_channels,
|
||||
cubeb_channel_layout in_layout, cubeb_channel_layout out_layout);
|
||||
|
@ -74,6 +76,11 @@ void cubeb_downmix_short(short * const in, long inframes, short * out,
|
|||
void cubeb_upmix_float(float * const in, long inframes, float * out,
|
||||
unsigned int in_channels, unsigned int out_channels);
|
||||
|
||||
void cubeb_upmix_short(short * const in, long inframes, short * out,
|
||||
unsigned int in_channels, unsigned int out_channels);
|
||||
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -614,16 +614,11 @@ convert_stream_type_to_sl_stream(cubeb_stream_type stream_type)
|
|||
static void opensl_destroy(cubeb * ctx);
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
|
||||
// The bionic header file on B2G contains the required
|
||||
// declarations on all releases.
|
||||
#ifndef MOZ_WIDGET_GONK
|
||||
|
||||
#if (__ANDROID_API__ >= ANDROID_VERSION_LOLLIPOP)
|
||||
typedef int (system_property_get)(const char*, char*);
|
||||
|
||||
static int
|
||||
__system_property_get(const char* name, char* value)
|
||||
wrap_system_property_get(const char* name, char* value)
|
||||
{
|
||||
void* libc = dlopen("libc.so", RTLD_LAZY);
|
||||
if (!libc) {
|
||||
|
@ -640,7 +635,6 @@ __system_property_get(const char* name, char* value)
|
|||
return ret;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static int
|
||||
get_android_version(void)
|
||||
|
@ -649,7 +643,11 @@ get_android_version(void)
|
|||
|
||||
memset(version_string, 0, PROP_VALUE_MAX);
|
||||
|
||||
#if (__ANDROID_API__ >= ANDROID_VERSION_LOLLIPOP)
|
||||
int len = wrap_system_property_get("ro.build.version.sdk", version_string);
|
||||
#else
|
||||
int len = __system_property_get("ro.build.version.sdk", version_string);
|
||||
#endif
|
||||
if (len <= 0) {
|
||||
LOG("Failed to get Android version!\n");
|
||||
return len;
|
||||
|
|
|
@ -877,7 +877,7 @@ pulse_stream_init(cubeb * context,
|
|||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
if (g_log_level) {
|
||||
if (g_cubeb_log_level) {
|
||||
if (output_stream_params){
|
||||
const pa_buffer_attr * output_att;
|
||||
output_att = WRAP(pa_stream_get_buffer_attr)(stm->output_stream);
|
||||
|
@ -1408,7 +1408,7 @@ pulse_subscribe_callback(pa_context * ctx,
|
|||
case PA_SUBSCRIPTION_EVENT_SOURCE:
|
||||
case PA_SUBSCRIPTION_EVENT_SINK:
|
||||
|
||||
if (g_log_level) {
|
||||
if (g_cubeb_log_level) {
|
||||
if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE &&
|
||||
(t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
|
||||
LOG("Removing sink index %d", index);
|
||||
|
|
|
@ -217,6 +217,8 @@ sndio_stream_init(cubeb * context,
|
|||
wpar.le = SIO_LE_NATIVE;
|
||||
break;
|
||||
default:
|
||||
sio_close(s->hdl);
|
||||
free(s);
|
||||
DPR("sndio_stream_init() unsupported format\n");
|
||||
return CUBEB_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
|
|
|
@ -124,6 +124,11 @@ public:
|
|||
return data_;
|
||||
}
|
||||
|
||||
T * end() const
|
||||
{
|
||||
return data_ + length_;
|
||||
}
|
||||
|
||||
const T& at(size_t index) const
|
||||
{
|
||||
assert(index < length_ && "out of range");
|
||||
|
@ -259,6 +264,71 @@ private:
|
|||
size_t length_;
|
||||
};
|
||||
|
||||
struct auto_array_wrapper {
|
||||
virtual void push(void * elements, size_t length) = 0;
|
||||
virtual size_t length() = 0;
|
||||
virtual void push_silence(size_t length) = 0;
|
||||
virtual bool pop(size_t length) = 0;
|
||||
virtual void * data() = 0;
|
||||
virtual void * end() = 0;
|
||||
virtual void clear() = 0;
|
||||
virtual bool reserve(size_t capacity) = 0;
|
||||
virtual void set_length(size_t length) = 0;
|
||||
virtual ~auto_array_wrapper() {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct auto_array_wrapper_impl : public auto_array_wrapper {
|
||||
auto_array_wrapper_impl() {}
|
||||
|
||||
explicit auto_array_wrapper_impl(uint32_t size)
|
||||
: ar(size)
|
||||
{}
|
||||
|
||||
void push(void * elements, size_t length) override {
|
||||
ar.push(static_cast<T *>(elements), length);
|
||||
}
|
||||
|
||||
size_t length() override {
|
||||
return ar.length();
|
||||
}
|
||||
|
||||
void push_silence(size_t length) override {
|
||||
ar.push_silence(length);
|
||||
}
|
||||
|
||||
bool pop(size_t length) override {
|
||||
return ar.pop(nullptr, length);
|
||||
}
|
||||
|
||||
void * data() override {
|
||||
return ar.data();
|
||||
}
|
||||
|
||||
void * end() override {
|
||||
return ar.end();
|
||||
}
|
||||
|
||||
void clear() override {
|
||||
ar.clear();
|
||||
}
|
||||
|
||||
bool reserve(size_t capacity) override {
|
||||
return ar.reserve(capacity);
|
||||
}
|
||||
|
||||
void set_length(size_t length) override {
|
||||
ar.set_length(length);
|
||||
}
|
||||
|
||||
~auto_array_wrapper_impl() {
|
||||
ar.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
auto_array<T> ar;
|
||||
};
|
||||
|
||||
using auto_lock = std::lock_guard<owned_critical_section>;
|
||||
|
||||
#endif /* CUBEB_UTILS */
|
||||
|
|
|
@ -160,6 +160,45 @@ private:
|
|||
HRESULT result;
|
||||
};
|
||||
|
||||
struct mixing_wrapper {
|
||||
virtual void mix(void * const input_buffer, long input_frames, void * output_buffer,
|
||||
cubeb_stream_params const * stream_params,
|
||||
cubeb_stream_params const * mixer_params) = 0;
|
||||
virtual ~mixing_wrapper() {};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct mixing_impl : public mixing_wrapper {
|
||||
|
||||
typedef void (*downmix_func)(T * const, long, T *,
|
||||
unsigned int, unsigned int,
|
||||
cubeb_channel_layout, cubeb_channel_layout);
|
||||
typedef void (*upmix_func)(T * const, long, T *,
|
||||
unsigned int, unsigned int);
|
||||
|
||||
mixing_impl(downmix_func dmfunc, upmix_func umfunc) {
|
||||
downmix_wrapper = dmfunc;
|
||||
upmix_wrapper = umfunc;
|
||||
}
|
||||
|
||||
~mixing_impl() {}
|
||||
|
||||
void mix(void * const input_buffer, long input_frames, void * output_buffer,
|
||||
cubeb_stream_params const * stream_params,
|
||||
cubeb_stream_params const * mixer_params) override {
|
||||
T * const in = static_cast<T *>(input_buffer);
|
||||
T * out = static_cast<T *>(output_buffer);
|
||||
if (cubeb_should_upmix(stream_params, mixer_params)) {
|
||||
upmix_wrapper(in, input_frames, out, stream_params->channels, mixer_params->channels);
|
||||
} else if (cubeb_should_downmix(stream_params, mixer_params)) {
|
||||
downmix_wrapper(in, input_frames, out, stream_params->channels, mixer_params->channels, stream_params->layout, mixer_params->layout);
|
||||
}
|
||||
}
|
||||
|
||||
downmix_func downmix_wrapper;
|
||||
upmix_func upmix_wrapper;
|
||||
};
|
||||
|
||||
extern cubeb_ops const wasapi_ops;
|
||||
|
||||
int wasapi_stream_stop(cubeb_stream * stm);
|
||||
|
@ -264,11 +303,18 @@ struct cubeb_stream {
|
|||
uint32_t output_buffer_frame_count = 0;
|
||||
/* Resampler instance. Resampling will only happen if necessary. */
|
||||
std::unique_ptr<cubeb_resampler, decltype(&cubeb_resampler_destroy)> resampler = { nullptr, cubeb_resampler_destroy };
|
||||
/* Mixing interface */
|
||||
std::unique_ptr<mixing_wrapper> mixing;
|
||||
/* A buffer for up/down mixing multi-channel audio. */
|
||||
std::vector<float> mix_buffer;
|
||||
std::vector<BYTE> mix_buffer;
|
||||
/* WASAPI input works in "packets". We re-linearize the audio packets
|
||||
* into this buffer before handing it to the resampler. */
|
||||
auto_array<float> linear_input_buffer;
|
||||
std::unique_ptr<auto_array_wrapper> linear_input_buffer;
|
||||
/* Bytes per sample. This multiplied by the number of channels is the number
|
||||
* of bytes per frame. */
|
||||
size_t bytes_per_sample = 0;
|
||||
/* WAVEFORMATEXTENSIBLE sub-format: either PCM or float. */
|
||||
GUID waveformatextensible_sub_format = GUID_NULL;
|
||||
/* Stream volume. Set via stream_set_volume and used to reset volume on
|
||||
device changes. */
|
||||
float volume = 1.0;
|
||||
|
@ -507,23 +553,21 @@ frames_to_bytes_before_mix(cubeb_stream * stm, size_t frames)
|
|||
{
|
||||
// This is called only when we has a output client.
|
||||
XASSERT(has_output(stm));
|
||||
size_t stream_frame_size = stm->output_stream_params.channels * sizeof(float);
|
||||
return stream_frame_size * frames;
|
||||
return stm->output_stream_params.channels * stm->bytes_per_sample * frames;
|
||||
}
|
||||
|
||||
/* This function handles the processing of the input and output audio,
|
||||
* converting it to rate and channel layout specified at initialization.
|
||||
* It then calls the data callback, via the resampler. */
|
||||
long
|
||||
refill(cubeb_stream * stm, float * input_buffer, long input_frames_count,
|
||||
float * output_buffer, long output_frames_needed)
|
||||
refill(cubeb_stream * stm, void * input_buffer, long input_frames_count,
|
||||
void * output_buffer, long output_frames_needed)
|
||||
{
|
||||
/* If we need to upmix after resampling, resample into the mix buffer to
|
||||
avoid a copy. */
|
||||
float * dest = nullptr;
|
||||
void * dest = nullptr;
|
||||
if (has_output(stm)) {
|
||||
if (cubeb_should_upmix(&stm->output_stream_params, &stm->output_mix_params) ||
|
||||
cubeb_should_downmix(&stm->output_stream_params, &stm->output_mix_params)) {
|
||||
if (cubeb_should_mix(&stm->output_stream_params, &stm->output_mix_params)) {
|
||||
dest = stm->mix_buffer.data();
|
||||
} else {
|
||||
dest = output_buffer;
|
||||
|
@ -553,15 +597,8 @@ refill(cubeb_stream * stm, float * input_buffer, long input_frames_count,
|
|||
It is alright to have produced less frames if we are draining, though. */
|
||||
XASSERT(out_frames == output_frames_needed || stm->draining || !has_output(stm));
|
||||
|
||||
if (has_output(stm)) {
|
||||
if (cubeb_should_upmix(&stm->output_stream_params, &stm->output_mix_params)) {
|
||||
cubeb_upmix_float(dest, out_frames, output_buffer,
|
||||
stm->output_stream_params.channels, stm->output_mix_params.channels);
|
||||
} else if (cubeb_should_downmix(&stm->output_stream_params, &stm->output_mix_params)) {
|
||||
cubeb_downmix_float(dest, out_frames, output_buffer,
|
||||
stm->output_stream_params.channels, stm->output_mix_params.channels,
|
||||
stm->output_stream_params.layout, stm->output_mix_params.layout);
|
||||
}
|
||||
if (has_output(stm) && cubeb_should_mix(&stm->output_stream_params, &stm->output_mix_params)) {
|
||||
stm->mixing->mix(dest, out_frames, output_buffer, &stm->output_stream_params, &stm->output_mix_params);
|
||||
}
|
||||
|
||||
return out_frames;
|
||||
|
@ -617,30 +654,19 @@ bool get_input_buffer(cubeb_stream * stm)
|
|||
XASSERT(packet_size == next);
|
||||
if (flags & AUDCLNT_BUFFERFLAGS_SILENT) {
|
||||
LOG("insert silence: ps=%u", packet_size);
|
||||
stm->linear_input_buffer.push_silence(packet_size * stm->input_stream_params.channels);
|
||||
stm->linear_input_buffer->push_silence(packet_size * stm->input_stream_params.channels);
|
||||
} else {
|
||||
if (cubeb_should_upmix(&stm->input_mix_params, &stm->input_stream_params)) {
|
||||
bool ok = stm->linear_input_buffer.reserve(stm->linear_input_buffer.length() +
|
||||
if (cubeb_should_mix(&stm->input_mix_params, &stm->input_stream_params)) {
|
||||
bool ok = stm->linear_input_buffer->reserve(stm->linear_input_buffer->length() +
|
||||
packet_size * stm->input_stream_params.channels);
|
||||
XASSERT(ok);
|
||||
cubeb_upmix_float(reinterpret_cast<float*>(input_packet), packet_size,
|
||||
stm->linear_input_buffer.data() + stm->linear_input_buffer.length(),
|
||||
stm->input_mix_params.channels,
|
||||
stm->input_stream_params.channels);
|
||||
stm->linear_input_buffer.set_length(stm->linear_input_buffer.length() + packet_size * stm->input_stream_params.channels);
|
||||
} else if (cubeb_should_downmix(&stm->input_mix_params, &stm->input_stream_params)) {
|
||||
bool ok = stm->linear_input_buffer.reserve(stm->linear_input_buffer.length() +
|
||||
packet_size * stm->input_stream_params.channels);
|
||||
XASSERT(ok);
|
||||
cubeb_downmix_float(reinterpret_cast<float*>(input_packet), packet_size,
|
||||
stm->linear_input_buffer.data() + stm->linear_input_buffer.length(),
|
||||
stm->input_mix_params.channels,
|
||||
stm->input_stream_params.channels,
|
||||
stm->input_mix_params.layout,
|
||||
stm->input_stream_params.layout);
|
||||
stm->linear_input_buffer.set_length(stm->linear_input_buffer.length() + packet_size * stm->input_stream_params.channels);
|
||||
stm->mixing->mix(input_packet, packet_size,
|
||||
stm->linear_input_buffer->end(),
|
||||
&stm->input_mix_params,
|
||||
&stm->input_stream_params);
|
||||
stm->linear_input_buffer->set_length(stm->linear_input_buffer->length() + packet_size * stm->input_stream_params.channels);
|
||||
} else {
|
||||
stm->linear_input_buffer.push(reinterpret_cast<float*>(input_packet),
|
||||
stm->linear_input_buffer->push(input_packet,
|
||||
packet_size * stm->input_stream_params.channels);
|
||||
}
|
||||
}
|
||||
|
@ -652,7 +678,7 @@ bool get_input_buffer(cubeb_stream * stm)
|
|||
offset += packet_size;
|
||||
}
|
||||
|
||||
XASSERT(stm->linear_input_buffer.length() >= total_available_input &&
|
||||
XASSERT(stm->linear_input_buffer->length() >= total_available_input &&
|
||||
offset == total_available_input);
|
||||
|
||||
return true;
|
||||
|
@ -660,7 +686,7 @@ bool get_input_buffer(cubeb_stream * stm)
|
|||
|
||||
/* Get an output buffer from the render_client. It has to be released before
|
||||
* exiting the callback. */
|
||||
bool get_output_buffer(cubeb_stream * stm, float *& buffer, size_t & frame_count)
|
||||
bool get_output_buffer(cubeb_stream * stm, void *& buffer, size_t & frame_count)
|
||||
{
|
||||
UINT32 padding_out;
|
||||
HRESULT hr;
|
||||
|
@ -693,7 +719,7 @@ bool get_output_buffer(cubeb_stream * stm, float *& buffer, size_t & frame_count
|
|||
return false;
|
||||
}
|
||||
|
||||
buffer = reinterpret_cast<float*>(output_buffer);
|
||||
buffer = output_buffer;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -705,7 +731,7 @@ bool
|
|||
refill_callback_duplex(cubeb_stream * stm)
|
||||
{
|
||||
HRESULT hr;
|
||||
float * output_buffer = nullptr;
|
||||
void * output_buffer = nullptr;
|
||||
size_t output_frames = 0;
|
||||
size_t input_frames;
|
||||
bool rv;
|
||||
|
@ -717,7 +743,7 @@ refill_callback_duplex(cubeb_stream * stm)
|
|||
return rv;
|
||||
}
|
||||
|
||||
input_frames = stm->linear_input_buffer.length() / stm->input_stream_params.channels;
|
||||
input_frames = stm->linear_input_buffer->length() / stm->input_stream_params.channels;
|
||||
if (!input_frames) {
|
||||
return true;
|
||||
}
|
||||
|
@ -736,15 +762,15 @@ refill_callback_duplex(cubeb_stream * stm)
|
|||
|
||||
|
||||
ALOGV("Duplex callback: input frames: %Iu, output frames: %Iu",
|
||||
stm->linear_input_buffer.length(), output_frames);
|
||||
stm->linear_input_buffer->length(), output_frames);
|
||||
|
||||
refill(stm,
|
||||
stm->linear_input_buffer.data(),
|
||||
stm->linear_input_buffer.length(),
|
||||
stm->linear_input_buffer->data(),
|
||||
stm->linear_input_buffer->length(),
|
||||
output_buffer,
|
||||
output_frames);
|
||||
|
||||
stm->linear_input_buffer.clear();
|
||||
stm->linear_input_buffer->clear();
|
||||
|
||||
hr = stm->render_client->ReleaseBuffer(output_frames, 0);
|
||||
if (FAILED(hr)) {
|
||||
|
@ -767,21 +793,21 @@ refill_callback_input(cubeb_stream * stm)
|
|||
}
|
||||
|
||||
// This can happen at the very beginning of the stream.
|
||||
if (!stm->linear_input_buffer.length()) {
|
||||
if (!stm->linear_input_buffer->length()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ALOGV("Input callback: input frames: %Iu", stm->linear_input_buffer.length());
|
||||
ALOGV("Input callback: input frames: %Iu", stm->linear_input_buffer->length());
|
||||
|
||||
long read = refill(stm,
|
||||
stm->linear_input_buffer.data(),
|
||||
stm->linear_input_buffer.length(),
|
||||
stm->linear_input_buffer->data(),
|
||||
stm->linear_input_buffer->length(),
|
||||
nullptr,
|
||||
0);
|
||||
|
||||
XASSERT(read >= 0);
|
||||
|
||||
stm->linear_input_buffer.clear();
|
||||
stm->linear_input_buffer->clear();
|
||||
|
||||
return !stm->draining;
|
||||
}
|
||||
|
@ -791,7 +817,7 @@ refill_callback_output(cubeb_stream * stm)
|
|||
{
|
||||
bool rv;
|
||||
HRESULT hr;
|
||||
float * output_buffer = nullptr;
|
||||
void * output_buffer = nullptr;
|
||||
size_t output_frames = 0;
|
||||
|
||||
XASSERT(!has_input(stm) && has_output(stm));
|
||||
|
@ -1271,7 +1297,7 @@ wasapi_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * laten
|
|||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
if (params.format != CUBEB_SAMPLE_FLOAT32NE) {
|
||||
if (params.format != CUBEB_SAMPLE_FLOAT32NE && params.format != CUBEB_SAMPLE_S16NE) {
|
||||
return CUBEB_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
|
||||
|
@ -1388,6 +1414,17 @@ wasapi_get_preferred_channel_layout(cubeb * context, cubeb_channel_layout * layo
|
|||
|
||||
void wasapi_stream_destroy(cubeb_stream * stm);
|
||||
|
||||
static void
|
||||
waveformatex_update_derived_properties(WAVEFORMATEX * format)
|
||||
{
|
||||
format->nBlockAlign = format->wBitsPerSample * format->nChannels / 8;
|
||||
format->nAvgBytesPerSec = format->nSamplesPerSec * format->nBlockAlign;
|
||||
if (format->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
|
||||
WAVEFORMATEXTENSIBLE * format_pcm = reinterpret_cast<WAVEFORMATEXTENSIBLE *>(format);
|
||||
format_pcm->Samples.wValidBitsPerSample = format->wBitsPerSample;
|
||||
}
|
||||
}
|
||||
|
||||
/* Based on the mix format and the stream format, try to find a way to play
|
||||
what the user requested. */
|
||||
static void
|
||||
|
@ -1411,13 +1448,8 @@ handle_channel_layout(cubeb_stream * stm, com_heap_ptr<WAVEFORMATEX> & mix_form
|
|||
/* Get the channel mask by the channel layout.
|
||||
If the layout is not supported, we will get a closest settings below. */
|
||||
format_pcm->dwChannelMask = channel_layout_to_mask(stream_params->layout);
|
||||
|
||||
mix_format->nChannels = stream_params->channels;
|
||||
mix_format->nBlockAlign = mix_format->wBitsPerSample * mix_format->nChannels / 8;
|
||||
mix_format->nAvgBytesPerSec = mix_format->nSamplesPerSec * mix_format->nBlockAlign;
|
||||
format_pcm->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
|
||||
mix_format->wBitsPerSample = 32;
|
||||
format_pcm->Samples.wValidBitsPerSample = mix_format->wBitsPerSample;
|
||||
waveformatex_update_derived_properties(mix_format.get());
|
||||
|
||||
/* Check if wasapi will accept our channel layout request. */
|
||||
WAVEFORMATEX * closest;
|
||||
|
@ -1425,12 +1457,14 @@ handle_channel_layout(cubeb_stream * stm, com_heap_ptr<WAVEFORMATEX> & mix_form
|
|||
mix_format.get(),
|
||||
&closest);
|
||||
if (hr == S_FALSE) {
|
||||
/* Not supported, but WASAPI gives us a suggestion. Use it, and handle the
|
||||
eventual upmix/downmix ourselves */
|
||||
/* Channel layout not supported, but WASAPI gives us a suggestion. Use it,
|
||||
and handle the eventual upmix/downmix ourselves. Ignore the subformat of
|
||||
the suggestion, since it seems to always be IEEE_FLOAT. */
|
||||
LOG("Using WASAPI suggested format: channels: %d", closest->nChannels);
|
||||
WAVEFORMATEXTENSIBLE * closest_pcm = reinterpret_cast<WAVEFORMATEXTENSIBLE *>(closest);
|
||||
XASSERT(closest_pcm->SubFormat == format_pcm->SubFormat);
|
||||
mix_format.reset(closest);
|
||||
format_pcm->dwChannelMask = closest_pcm->dwChannelMask;
|
||||
mix_format->nChannels = closest->nChannels;
|
||||
waveformatex_update_derived_properties(mix_format.get());
|
||||
} else if (hr == AUDCLNT_E_UNSUPPORTED_FORMAT) {
|
||||
/* Not supported, no suggestion. This should not happen, but it does in the
|
||||
field with some sound cards. We restore the mix format, and let the rest
|
||||
|
@ -1513,6 +1547,11 @@ int setup_wasapi_stream_one_side(cubeb_stream * stm,
|
|||
}
|
||||
com_heap_ptr<WAVEFORMATEX> mix_format(tmp);
|
||||
|
||||
WAVEFORMATEXTENSIBLE * format_pcm = reinterpret_cast<WAVEFORMATEXTENSIBLE *>(mix_format.get());
|
||||
mix_format->wBitsPerSample = stm->bytes_per_sample * 8;
|
||||
format_pcm->SubFormat = stm->waveformatextensible_sub_format;
|
||||
waveformatex_update_derived_properties(mix_format.get());
|
||||
|
||||
/* Set channel layout only when there're more than two channels. Otherwise,
|
||||
* use the default setting retrieved from the stream format of the audio
|
||||
* engine's internal processing by GetMixFormat. */
|
||||
|
@ -1525,12 +1564,9 @@ int setup_wasapi_stream_one_side(cubeb_stream * stm,
|
|||
handle_channel_layout(stm, mix_format, stream_params);
|
||||
}
|
||||
|
||||
/* Shared mode WASAPI always supports float32 sample format, so this
|
||||
* is safe. */
|
||||
mix_params->format = CUBEB_SAMPLE_FLOAT32NE;
|
||||
mix_params->format = stream_params->format;
|
||||
mix_params->rate = mix_format->nSamplesPerSec;
|
||||
mix_params->channels = mix_format->nChannels;
|
||||
WAVEFORMATEXTENSIBLE * format_pcm = reinterpret_cast<WAVEFORMATEXTENSIBLE *>(mix_format.get());
|
||||
mix_params->layout = mask_to_channel_layout(format_pcm->dwChannelMask);
|
||||
if (mix_params->layout == CUBEB_LAYOUT_UNDEFINED) {
|
||||
LOG("Output using undefined layout!\n");
|
||||
|
@ -1566,9 +1602,7 @@ int setup_wasapi_stream_one_side(cubeb_stream * stm,
|
|||
return CUBEB_ERROR;
|
||||
}
|
||||
// Input is up/down mixed when depacketized in get_input_buffer.
|
||||
if (has_output(stm) &&
|
||||
(cubeb_should_upmix(stream_params, mix_params) ||
|
||||
cubeb_should_downmix(stream_params, mix_params))) {
|
||||
if (has_output(stm) && cubeb_should_mix(stream_params, mix_params)) {
|
||||
stm->mix_buffer.resize(frames_to_bytes_before_mix(stm, *buffer_frame_count));
|
||||
}
|
||||
|
||||
|
@ -1628,7 +1662,7 @@ int setup_wasapi_stream(cubeb_stream * stm)
|
|||
#else
|
||||
const int silent_buffer_count = 4;
|
||||
#endif
|
||||
stm->linear_input_buffer.push_silence(stm->input_buffer_frame_count *
|
||||
stm->linear_input_buffer->push_silence(stm->input_buffer_frame_count *
|
||||
stm->input_stream_params.channels *
|
||||
silent_buffer_count);
|
||||
|
||||
|
@ -1746,12 +1780,8 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
|
|||
|
||||
XASSERT(context && stream && (input_stream_params || output_stream_params));
|
||||
|
||||
if ((output_stream_params && output_stream_params->format != CUBEB_SAMPLE_FLOAT32NE) ||
|
||||
(input_stream_params && input_stream_params->format != CUBEB_SAMPLE_FLOAT32NE)) {
|
||||
LOG("Invalid format, %p %p %d %d",
|
||||
output_stream_params, input_stream_params,
|
||||
output_stream_params && output_stream_params->format,
|
||||
input_stream_params && input_stream_params->format);
|
||||
if (output_stream_params && input_stream_params &&
|
||||
output_stream_params->format != input_stream_params->format) {
|
||||
return CUBEB_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
|
||||
|
@ -1774,6 +1804,23 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
|
|||
XASSERT(stm->output_stream_params.channels == CUBEB_CHANNEL_LAYOUT_MAPS[stm->output_stream_params.layout].channels);
|
||||
}
|
||||
|
||||
switch (output_stream_params ? output_stream_params->format : input_stream_params->format) {
|
||||
case CUBEB_SAMPLE_S16NE:
|
||||
stm->bytes_per_sample = sizeof(short);
|
||||
stm->waveformatextensible_sub_format = KSDATAFORMAT_SUBTYPE_PCM;
|
||||
stm->mixing.reset(new mixing_impl<short>(cubeb_downmix_short, cubeb_upmix_short));
|
||||
stm->linear_input_buffer.reset(new auto_array_wrapper_impl<short>);
|
||||
break;
|
||||
case CUBEB_SAMPLE_FLOAT32NE:
|
||||
stm->bytes_per_sample = sizeof(float);
|
||||
stm->waveformatextensible_sub_format = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
|
||||
stm->mixing.reset(new mixing_impl<float>(cubeb_downmix_float, cubeb_upmix_float));
|
||||
stm->linear_input_buffer.reset(new auto_array_wrapper_impl<float>);
|
||||
break;
|
||||
default:
|
||||
return CUBEB_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
|
||||
stm->latency = latency_frames;
|
||||
|
||||
stm->reconfigure_event = CreateEvent(NULL, 0, 0, NULL);
|
||||
|
@ -1839,6 +1886,8 @@ void close_wasapi_stream(cubeb_stream * stm)
|
|||
stm->resampler.reset();
|
||||
|
||||
stm->mix_buffer.clear();
|
||||
stm->mixing.reset();
|
||||
stm->linear_input_buffer.reset();
|
||||
}
|
||||
|
||||
void wasapi_stream_destroy(cubeb_stream * stm)
|
||||
|
@ -2207,7 +2256,7 @@ wasapi_create_device(IMMDeviceEnumerator * enumerator, IMMDevice * dev)
|
|||
break;
|
||||
};
|
||||
|
||||
ret->format = CUBEB_DEVICE_FMT_F32NE; /* cubeb only supports 32bit float at the moment */
|
||||
ret->format = static_cast<cubeb_device_fmt>(CUBEB_DEVICE_FMT_F32NE | CUBEB_DEVICE_FMT_S16NE);
|
||||
ret->default_format = CUBEB_DEVICE_FMT_F32NE;
|
||||
prop_variant fmtvar;
|
||||
hr = propstore->GetValue(PKEY_AudioEngine_DeviceFormat, &fmtvar);
|
||||
|
@ -2266,7 +2315,7 @@ wasapi_enumerate_devices(cubeb * context, cubeb_device_type type,
|
|||
|
||||
if (type == CUBEB_DEVICE_TYPE_OUTPUT) flow = eRender;
|
||||
else if (type == CUBEB_DEVICE_TYPE_INPUT) flow = eCapture;
|
||||
else if (type & (CUBEB_DEVICE_TYPE_INPUT | CUBEB_DEVICE_TYPE_INPUT)) flow = eAll;
|
||||
else if (type & (CUBEB_DEVICE_TYPE_INPUT | CUBEB_DEVICE_TYPE_OUTPUT)) flow = eAll;
|
||||
else return CUBEB_ERROR;
|
||||
|
||||
hr = enumerator->EnumAudioEndpoints(flow, DEVICE_STATEMASK_ALL, collection.receive());
|
||||
|
|
Загрузка…
Ссылка в новой задаче