summaryrefslogtreecommitdiffstats
path: root/media/libcubeb/test/test_logging.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libcubeb/test/test_logging.cpp')
-rw-r--r--media/libcubeb/test/test_logging.cpp196
1 files changed, 196 insertions, 0 deletions
diff --git a/media/libcubeb/test/test_logging.cpp b/media/libcubeb/test/test_logging.cpp
new file mode 100644
index 0000000000..54ff718152
--- /dev/null
+++ b/media/libcubeb/test/test_logging.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright © 2016 Mozilla Foundation
+ *
+ * This program is made available under an ISC-style license. See the
+ * accompanying file LICENSE for details.
+ */
+
+/* cubeb_logging test */
+#include "gtest/gtest.h"
+#if !defined(_XOPEN_SOURCE)
+#define _XOPEN_SOURCE 600
+#endif
+#include "cubeb/cubeb.h"
+#include "cubeb_log.h"
+#include <atomic>
+#include <math.h>
+#include <memory>
+#include <stdio.h>
+#include <stdlib.h>
+#include <thread>
+
+#include "common.h"
+
+#define PRINT_LOGS_TO_STDERR 0
+
+std::atomic<uint32_t> log_statements_received = {0};
+std::atomic<uint32_t> data_callback_call_count = {0};
+
+static void
+test_logging_callback(char const * fmt, ...)
+{
+ log_statements_received++;
+#if PRINT_LOGS_TO_STDERR == 1
+ char buf[1024];
+ va_list argslist;
+ va_start(argslist, fmt);
+ vsnprintf(buf, 1024, fmt, argslist);
+ fprintf(stderr, "%s\n", buf);
+ va_end(argslist);
+#endif // PRINT_LOGS_TO_STDERR
+}
+
+static long
+data_cb_load(cubeb_stream * stream, void * user, const void * inputbuffer,
+ void * outputbuffer, long nframes)
+{
+ data_callback_call_count++;
+ return nframes;
+}
+
+static void
+state_cb(cubeb_stream * stream, void * /*user*/, cubeb_state state)
+{
+ if (stream == NULL)
+ return;
+
+ switch (state) {
+ case CUBEB_STATE_STARTED:
+ fprintf(stderr, "stream started\n");
+ break;
+ case CUBEB_STATE_STOPPED:
+ fprintf(stderr, "stream stopped\n");
+ break;
+ case CUBEB_STATE_DRAINED:
+ fprintf(stderr, "stream drained\n");
+ break;
+ default:
+ fprintf(stderr, "unknown stream state %d\n", state);
+ }
+
+ return;
+}
+
+// Waits for at least one audio callback to have occured.
+void
+wait_for_audio_callback()
+{
+ uint32_t audio_callback_index =
+ data_callback_call_count.load(std::memory_order_acquire);
+ while (audio_callback_index ==
+ data_callback_call_count.load(std::memory_order_acquire)) {
+ delay(100);
+ }
+}
+
+TEST(cubeb, logging)
+{
+ cubeb * ctx;
+ cubeb_stream * stream;
+ cubeb_stream_params output_params;
+ int r;
+ uint32_t latency_frames = 0;
+
+ cubeb_set_log_callback(CUBEB_LOG_NORMAL, test_logging_callback);
+
+ r = common_init(&ctx, "Cubeb logging test");
+ ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb library";
+
+ std::unique_ptr<cubeb, decltype(&cubeb_destroy)> cleanup_cubeb_at_exit(
+ ctx, cubeb_destroy);
+
+ output_params.format = CUBEB_SAMPLE_FLOAT32LE;
+ output_params.rate = 48000;
+ output_params.channels = 2;
+ output_params.layout = CUBEB_LAYOUT_STEREO;
+ output_params.prefs = CUBEB_STREAM_PREF_NONE;
+
+ r = cubeb_get_min_latency(ctx, &output_params, &latency_frames);
+ if (r != CUBEB_OK) {
+ // not fatal
+ latency_frames = 1024;
+ }
+
+ r = cubeb_stream_init(ctx, &stream, "Cubeb logging", NULL, NULL, NULL,
+ &output_params, latency_frames, data_cb_load, state_cb,
+ NULL);
+ 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);
+
+ ASSERT_NE(log_statements_received.load(std::memory_order_acquire), 0u);
+
+ cubeb_set_log_callback(CUBEB_LOG_DISABLED, nullptr);
+ log_statements_received.store(0, std::memory_order_release);
+
+ // This is synchronous and we'll receive log messages on all backends that we
+ // test
+ cubeb_stream_start(stream);
+
+ ASSERT_EQ(log_statements_received.load(std::memory_order_acquire), 0u);
+
+ cubeb_set_log_callback(CUBEB_LOG_VERBOSE, test_logging_callback);
+
+ wait_for_audio_callback();
+
+ ASSERT_NE(log_statements_received.load(std::memory_order_acquire), 0u);
+
+ bool log_callback_set = true;
+ uint32_t iterations = 100;
+ while (iterations--) {
+ wait_for_audio_callback();
+
+ if (!log_callback_set) {
+ ASSERT_EQ(log_statements_received.load(std::memory_order_acquire), 0u);
+ // Set a logging callback, start logging
+ cubeb_set_log_callback(CUBEB_LOG_VERBOSE, test_logging_callback);
+ log_callback_set = true;
+ } else {
+ // Disable the logging callback, stop logging.
+ ASSERT_NE(log_statements_received.load(std::memory_order_acquire), 0u);
+ cubeb_set_log_callback(CUBEB_LOG_DISABLED, nullptr);
+ log_statements_received.store(0, std::memory_order_release);
+ // Disabling logging should flush any log message -- wait a bit and check
+ // that this is true.
+ ASSERT_EQ(log_statements_received.load(std::memory_order_acquire), 0u);
+ log_callback_set = false;
+ }
+ }
+
+ cubeb_stream_stop(stream);
+}
+
+TEST(cubeb, logging_stress)
+{
+ cubeb_set_log_callback(CUBEB_LOG_NORMAL, test_logging_callback);
+
+ std::atomic<bool> thread_done = {false};
+
+ auto t = std::thread([&thread_done]() {
+ uint32_t count = 0;
+ do {
+ while (rand() % 10) {
+ ALOG("Log message #%d!", count++);
+ }
+ } while (count < 1e4);
+ thread_done.store(true);
+ });
+
+ bool enabled = true;
+ while (!thread_done.load()) {
+ if (enabled) {
+ cubeb_set_log_callback(CUBEB_LOG_DISABLED, nullptr);
+ enabled = false;
+ } else {
+ cubeb_set_log_callback(CUBEB_LOG_NORMAL, test_logging_callback);
+ enabled = true;
+ }
+ }
+
+ cubeb_set_log_callback(CUBEB_LOG_DISABLED, nullptr);
+
+ t.join();
+
+ ASSERT_TRUE(true);
+}