[SCM] libsoundio/master: Imported Upstream version 1.0.2
andrewrk-guest at users.alioth.debian.org
andrewrk-guest at users.alioth.debian.org
Thu Sep 24 17:07:43 UTC 2015
The following commit has been merged in the master branch:
commit 2ac53b1c3d8b68e03f3d85b91b0e9438ab962cc5
Author: Andrew Kelley <superjoe30 at gmail.com>
Date: Thu Sep 24 09:59:28 2015 -0700
Imported Upstream version 1.0.2
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..ed434bd
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,38 @@
+### Version 1.0.2 (2015-09-24)
+
+ * build: fix GNUInstallDirs not working.
+ * docs: fix incorrect docs for `soundio_instream_pause`.
+ * PulseAudio: fix `soundio_outstream_pause` triggering assertion when called
+ from within `write_callback`.
+ * fix mirrored memory not working on Linux (fixes corrupted data in ring
+ buffer).
+ * os: fix crash when creating non high priority thread fails.
+ * docs: fix typos and cleanup.
+ * fix and add test for `soundio_device_nearest_sample_rate`.
+
+### Version 1.0.1 (2015-09-11)
+
+ * libsoundio no longer depends on or links against libm.
+ * ALSA: treat ALSA as unavailable when /dev/snd does not exist.
+ * ALSA: remove duplicate assert.
+ * ALSA: remove stray print statement.
+ * ALSA: pausing returns error code when state is invalid instead of reaching
+ assertion failure in pcm.c.
+ * JACK: fix infinite loop when refreshing devices.
+ * PulseAudio: better clear buffer implementation.
+ * dummy backend: fix sometimes calling `write_callback` with
+ `frame_count_max` equal to 0.
+ * os: fix some variables accidentally not declared static.
+ * macos: fix not cleaning up condition variables.
+ * macos: avoid allocation when getting time.
+ * docs: note that `read_callback` and `write_callback` must be real time safe.
+ * docs: record example demonstrates proper real time safety by not calling
+ fwrite in `read_callback`.
+ * docs: add note to record example about shutting down.
+ * docs: make microphone example latency a command line argument.
+ * build: fix build on linux with clang.
+ * build: static libs, examples, and tests are optional.
+
+### Version 1.0.0 (2015-09-03)
+
+ * Initial public release.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 30f8199..a4abb7e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,6 @@
cmake_minimum_required(VERSION 2.8.5)
+project(libsoundio C CXX)
+set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
if(CMAKE_VERSION VERSION_LESS 3.0.0)
set(CMAKE_INSTALL_LIBDIR "lib" CACHE PATH "library install dir (lib)")
@@ -15,12 +17,9 @@ if(NOT CMAKE_BUILD_TYPE)
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
endif()
-project(libsoundio C CXX)
-set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
-
set(LIBSOUNDIO_VERSION_MAJOR 1)
set(LIBSOUNDIO_VERSION_MINOR 0)
-set(LIBSOUNDIO_VERSION_PATCH 1)
+set(LIBSOUNDIO_VERSION_PATCH 2)
set(LIBSOUNDIO_VERSION "${LIBSOUNDIO_VERSION_MAJOR}.${LIBSOUNDIO_VERSION_MINOR}.${LIBSOUNDIO_VERSION_PATCH}")
message("Configuring libsoundio version ${LIBSOUNDIO_VERSION}")
diff --git a/README.md b/README.md
index 6235cc1..6aabf99 100644
--- a/README.md
+++ b/README.md
@@ -274,8 +274,3 @@ make doc
```
Then look at `html/index.html` in a browser.
-
-## Projects Using libsoundio
-
- * [Genesis](https://github.com/andrewrk/genesis)
- * [Groove Basin](https://github.com/andrewrk/groovebasin) (via [libgroove](https://github.com/andrewrk/libgroove))
diff --git a/soundio/soundio.h b/soundio/soundio.h
index e964636..e39af12 100644
--- a/soundio/soundio.h
+++ b/soundio/soundio.h
@@ -359,7 +359,8 @@ struct SoundIo {
/// This callback is fired when making thread real-time priority failed. By
/// default, it will print to stderr only the first time it is called
/// a message instructing the user how to configure their system to allow
- /// real-time priority threads.
+ /// real-time priority threads. This must be set to a function not NULL.
+ /// To silence the warning, assign this to a function that does nothing.
void (*emit_rtprio_warning)(void);
/// Optional: JACK info callback.
@@ -422,10 +423,10 @@ struct SoundIoDevice {
/// whatever format is most convenient
/// for you which is supported by the device, because when you are the only
/// application left, the mixer might decide to switch
- /// current_format to yours. You can learn the supported formats via formats and
- /// SoundIoDevice::format_count. If this information is missing due to a
- /// probe error, formats will be `NULL`. If current_format
- /// is unavailable, it will be set to #SoundIoFormatInvalid.
+ /// current_format to yours. You can learn the supported formats via
+ /// formats and SoundIoDevice::format_count. If this information is missing
+ /// due to a probe error, formats will be `NULL`. If current_format is
+ /// unavailable, it will be set to #SoundIoFormatInvalid.
/// Devices are guaranteed to have at least 1 format available.
enum SoundIoFormat current_format;
@@ -489,14 +490,16 @@ struct SoundIoOutStream {
/// Populated automatically when you call ::soundio_outstream_create.
struct SoundIoDevice *device;
- /// Defaults to #SoundIoFormatFloat32NE, followed by the first one supported.
+ /// Defaults to #SoundIoFormatFloat32NE, followed by the first one
+ /// supported.
enum SoundIoFormat format;
/// Sample rate is the number of frames per second.
/// Defaults to 48000 (and then clamped into range).
int sample_rate;
- /// Defaults to Stereo, if available, followed by the first layout supported.
+ /// Defaults to Stereo, if available, followed by the first layout
+ /// supported.
struct SoundIoChannelLayout layout;
/// Ignoring hardware latency, this is the number of seconds it takes for
@@ -546,9 +549,9 @@ struct SoundIoOutStream {
/// pthread_join, pthread_cond_wait, etc.
void (*write_callback)(struct SoundIoOutStream *,
int frame_count_min, int frame_count_max);
- /// This optional callback happens when the sound device runs out of buffered
- /// audio data to play. After this occurs, the outstream waits until the
- /// buffer is full to resume playback.
+ /// This optional callback happens when the sound device runs out of
+ /// buffered audio data to play. After this occurs, the outstream waits
+ /// until the buffer is full to resume playback.
/// This is called from the SoundIoOutStream::write_callback thread context.
void (*underflow_callback)(struct SoundIoOutStream *);
/// Optional callback. `err` is always SoundIoErrorStreaming.
@@ -579,7 +582,8 @@ struct SoundIoOutStream {
int bytes_per_sample;
/// If setting the channel layout fails for some reason, this field is set
- /// to an error code. Possible error codes are: #SoundIoErrorIncompatibleDevice
+ /// to an error code. Possible error codes are:
+ /// * #SoundIoErrorIncompatibleDevice
int layout_error;
};
@@ -588,14 +592,16 @@ struct SoundIoInStream {
/// Populated automatically when you call ::soundio_outstream_create.
struct SoundIoDevice *device;
- /// Defaults to SoundIoFormatFloat32NE, followed by the first one supported.
+ /// Defaults to #SoundIoFormatFloat32NE, followed by the first one
+ /// supported.
enum SoundIoFormat format;
/// Sample rate is the number of frames per second.
/// Defaults to max(sample_rate_min, min(sample_rate_max, 48000))
int sample_rate;
- /// Defaults to Stereo, if available, followed by the first layout supported.
+ /// Defaults to Stereo, if available, followed by the first layout
+ /// supported.
struct SoundIoChannelLayout layout;
/// Ignoring hardware latency, this is the number of seconds it takes for a
@@ -651,7 +657,6 @@ struct SoundIoInStream {
/// Optional: Hint that this input stream is nonterminal. This is used by
/// JACK and it means that the data received by the stream will be
/// passed on or made available to another stream. Defaults to `false`.
- /// stream. Defaults to `false`.
bool non_terminal_hint;
/// computed automatically when you call ::soundio_instream_open
@@ -1005,7 +1010,7 @@ SOUNDIO_EXPORT int soundio_outstream_clear_buffer(struct SoundIoOutStream *outst
/// buffer is not full.
/// Pausing might put the hardware into a low power state which is ideal if your
/// software is silent for some time.
-/// This function may be called any thread.
+/// This function may be called from any thread.
/// Pausing when already paused or unpausing when already unpaused has no
/// effect and always returns SoundIoErrorNone.
///
@@ -1116,7 +1121,7 @@ SOUNDIO_EXPORT int soundio_instream_end_read(struct SoundIoInStream *instream);
/// If the underyling device supports pausing, this pauses the stream and
/// prevents SoundIoInStream::read_callback from being called. Otherwise this returns
/// #SoundIoErrorIncompatibleDevice.
-/// You must call this function only from the SoundIoInStream::read_callback thread context.
+/// This function may be called from any thread.
/// Pausing when already paused or unpausing when already unpaused has no
/// effect and always returns SoundIoErrorNone.
///
diff --git a/src/alsa.cpp b/src/alsa.cpp
index 27f55d3..d1f675c 100644
--- a/src/alsa.cpp
+++ b/src/alsa.cpp
@@ -9,7 +9,6 @@
#include "soundio.hpp"
#include <sys/inotify.h>
-#include <math.h>
static snd_pcm_stream_t stream_types[] = {SND_PCM_STREAM_PLAYBACK, SND_PCM_STREAM_CAPTURE};
diff --git a/src/dummy.cpp b/src/dummy.cpp
index 2383f7b..da5a871 100644
--- a/src/dummy.cpp
+++ b/src/dummy.cpp
@@ -10,7 +10,6 @@
#include <stdio.h>
#include <string.h>
-#include <math.h>
static void playback_thread_run(void *arg) {
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg;
diff --git a/src/os.cpp b/src/os.cpp
index 742e747..8f3f8a6 100644
--- a/src/os.cpp
+++ b/src/os.cpp
@@ -8,14 +8,12 @@
#include "os.h"
#include "soundio_private.h"
#include "util.hpp"
-#include "atomics.hpp"
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
-#include <math.h>
#if defined(_WIN32)
#define SOUNDIO_OS_WINDOWS
@@ -125,7 +123,7 @@ static INIT_ONCE win32_init_once = INIT_ONCE_STATIC_INIT;
static double win32_time_resolution;
static SYSTEM_INFO win32_system_info;
#else
-static atomic_bool initialized = ATOMIC_VAR_INIT(false);
+static bool initialized = false;
static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;
#if defined(__MACH__)
static clock_serv_t cclock;
@@ -236,7 +234,7 @@ int soundio_os_thread_create(
}
if ((err = pthread_create(&thread->id, &thread->attr, run_pthread, thread))) {
- if (err == EPERM) {
+ if (err == EPERM && emit_rtprio_warning) {
emit_rtprio_warning();
err = pthread_create(&thread->id, NULL, run_pthread, thread);
}
@@ -586,15 +584,12 @@ int soundio_os_init(void) {
if (!InitOnceComplete(&win32_init_once, INIT_ONCE_ASYNC, nullptr))
return SoundIoErrorSystemResources;
#else
- if (initialized.load())
- return 0;
-
assert_no_err(pthread_mutex_lock(&init_mutex));
- if (initialized.load()) {
+ if (initialized) {
assert_no_err(pthread_mutex_unlock(&init_mutex));
return 0;
}
- initialized.store(true);
+ initialized = true;
if ((err = internal_init()))
return err;
assert_no_err(pthread_mutex_unlock(&init_mutex));
@@ -668,26 +663,56 @@ int soundio_os_init_mirrored_memory(struct SoundIoOsMirroredMemory *mem, size_t
break;
}
#else
+ char shm_path[] = "/dev/shm/soundio-XXXXXX";
+ char tmp_path[] = "/tmp/soundio-XXXXXX";
+ char *chosen_path;
+
+ int fd = mkstemp(shm_path);
+ if (fd < 0) {
+ fd = mkstemp(tmp_path);
+ if (fd < 0) {
+ return SoundIoErrorSystemResources;
+ } else {
+ chosen_path = tmp_path;
+ }
+ } else {
+ chosen_path = shm_path;
+ }
+
+ if (unlink(chosen_path)) {
+ close(fd);
+ return SoundIoErrorSystemResources;
+ }
+
+ if (ftruncate(fd, actual_capacity)) {
+ close(fd);
+ return SoundIoErrorSystemResources;
+ }
+
char *address = (char*)mmap(NULL, actual_capacity * 2, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (address == MAP_FAILED)
return SoundIoErrorNoMem;
char *other_address = (char*)mmap(address, actual_capacity, PROT_READ|PROT_WRITE,
- MAP_ANONYMOUS|MAP_FIXED|MAP_SHARED, -1, 0);
+ MAP_FIXED|MAP_SHARED, fd, 0);
if (other_address != address) {
munmap(address, 2 * actual_capacity);
+ close(fd);
return SoundIoErrorNoMem;
}
other_address = (char*)mmap(address + actual_capacity, actual_capacity,
- PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_FIXED|MAP_SHARED, -1, 0);
+ PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, fd, 0);
if (other_address != address + actual_capacity) {
munmap(address, 2 * actual_capacity);
+ close(fd);
return SoundIoErrorNoMem;
}
mem->address = address;
+ if (close(fd))
+ return SoundIoErrorSystemResources;
#endif
mem->capacity = actual_capacity;
diff --git a/src/pulseaudio.cpp b/src/pulseaudio.cpp
index 6561014..3aea0b6 100644
--- a/src/pulseaudio.cpp
+++ b/src/pulseaudio.cpp
@@ -9,7 +9,6 @@
#include "soundio.hpp"
#include <string.h>
-#include <math.h>
#include <stdio.h>
@@ -800,7 +799,9 @@ static int outstream_pause_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, b
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
- pa_threaded_mainloop_lock(sipa->main_loop);
+ if (!pa_threaded_mainloop_in_thread(sipa->main_loop)) {
+ pa_threaded_mainloop_lock(sipa->main_loop);
+ }
if (pause != pa_stream_is_corked(ospa->stream)) {
pa_operation *op = pa_stream_cork(ospa->stream, pause, NULL, NULL);
@@ -811,7 +812,9 @@ static int outstream_pause_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, b
pa_operation_unref(op);
}
- pa_threaded_mainloop_unlock(sipa->main_loop);
+ if (!pa_threaded_mainloop_in_thread(sipa->main_loop)) {
+ pa_threaded_mainloop_unlock(sipa->main_loop);
+ }
return 0;
}
@@ -1026,7 +1029,9 @@ static int instream_pause_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is, boo
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
- pa_threaded_mainloop_lock(sipa->main_loop);
+ if (!pa_threaded_mainloop_in_thread(sipa->main_loop)) {
+ pa_threaded_mainloop_lock(sipa->main_loop);
+ }
if (pause != pa_stream_is_corked(ispa->stream)) {
pa_operation *op = pa_stream_cork(ispa->stream, pause, NULL, NULL);
@@ -1035,7 +1040,9 @@ static int instream_pause_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is, boo
pa_operation_unref(op);
}
- pa_threaded_mainloop_unlock(sipa->main_loop);
+ if (!pa_threaded_mainloop_in_thread(sipa->main_loop)) {
+ pa_threaded_mainloop_unlock(sipa->main_loop);
+ }
return 0;
}
diff --git a/src/soundio.cpp b/src/soundio.cpp
index e06c2d8..d6c017a 100644
--- a/src/soundio.cpp
+++ b/src/soundio.cpp
@@ -763,21 +763,29 @@ bool soundio_device_supports_sample_rate(struct SoundIoDevice *device, int sampl
return false;
}
+static int abs_diff_int(int a, int b) {
+ int x = a - b;
+ return (x >= 0) ? x : -x;
+}
+
int soundio_device_nearest_sample_rate(struct SoundIoDevice *device, int sample_rate) {
int best_rate = -1;
int best_delta = -1;
for (int i = 0; i < device->sample_rate_count; i += 1) {
SoundIoSampleRateRange *range = &device->sample_rates[i];
- if (sample_rate < range->min) {
- int delta = range->min - sample_rate;
- if (best_delta == -1 || delta < best_delta) {
- best_delta = delta;
- best_rate = range->min;
- }
- } else if (best_rate == -1 && sample_rate > range->max) {
- best_rate = range->max;
- } else {
- return sample_rate;
+ int candidate_rate = clamp(range->min, sample_rate, range->max);
+ if (candidate_rate == sample_rate)
+ return candidate_rate;
+
+ int delta = abs_diff_int(candidate_rate, sample_rate);
+ bool best_rate_too_small = best_rate < sample_rate;
+ bool candidate_rate_too_small = candidate_rate < sample_rate;
+ if (best_rate == -1 ||
+ (best_rate_too_small && !candidate_rate_too_small) ||
+ ((best_rate_too_small || !candidate_rate_too_small) && delta < best_delta))
+ {
+ best_rate = candidate_rate;
+ best_delta = delta;
}
}
return best_rate;
diff --git a/test/unit_tests.cpp b/test/unit_tests.cpp
index d8a72c4..3a25255 100644
--- a/test/unit_tests.cpp
+++ b/test/unit_tests.cpp
@@ -15,7 +15,7 @@ static inline void ok_or_panic(int err) {
}
static void test_os_get_time(void) {
- soundio_os_init();
+ ok_or_panic(soundio_os_init());
double prev_time = soundio_os_get_time();
for (int i = 0; i < 1000; i += 1) {
double time = soundio_os_get_time();
@@ -165,6 +165,51 @@ static void test_ring_buffer_threaded(void) {
soundio_destroy(soundio);
}
+static void test_mirrored_memory(void) {
+ struct SoundIoOsMirroredMemory mem;
+ ok_or_panic(soundio_os_init());
+
+ static const int requested_bytes = 1024;
+ ok_or_panic(soundio_os_init_mirrored_memory(&mem, requested_bytes));
+ const int size_bytes = mem.capacity;
+
+ for (int i = 0; i < size_bytes; i += 1) {
+ mem.address[i] = rand() % CHAR_MAX;
+ }
+ for (int i = 0; i < size_bytes; i += 1) {
+ assert(mem.address[i] == mem.address[size_bytes+i]);
+ }
+
+ soundio_os_deinit_mirrored_memory(&mem);
+}
+
+static void test_nearest_sample_rate(void) {
+ struct SoundIoDevice device;
+ struct SoundIoSampleRateRange sample_rates[2] = {
+ {
+ 44100,
+ 48000
+ },
+ {
+ 96000,
+ 96000,
+ },
+ };
+
+ device.sample_rate_count = 2;
+ device.sample_rates = sample_rates;
+
+ assert(soundio_device_nearest_sample_rate(&device, 100) == 44100);
+ assert(soundio_device_nearest_sample_rate(&device, 44099) == 44100);
+ assert(soundio_device_nearest_sample_rate(&device, 44100) == 44100);
+ assert(soundio_device_nearest_sample_rate(&device, 45000) == 45000);
+ assert(soundio_device_nearest_sample_rate(&device, 48000) == 48000);
+ assert(soundio_device_nearest_sample_rate(&device, 48001) == 96000);
+ assert(soundio_device_nearest_sample_rate(&device, 90000) == 96000);
+ assert(soundio_device_nearest_sample_rate(&device, 96001) == 96000);
+ assert(soundio_device_nearest_sample_rate(&device, 9999999) == 96000);
+}
+
struct Test {
const char *name;
void (*fn)(void);
@@ -175,6 +220,8 @@ static struct Test tests[] = {
{"create output stream", test_create_outstream},
{"ring buffer basic", test_ring_buffer_basic},
{"ring buffer threaded", test_ring_buffer_threaded},
+ {"mirrored memory", test_mirrored_memory},
+ {"soundio_device_nearest_sample_rate", test_nearest_sample_rate},
{NULL, NULL},
};
--
libsoundio packaging
More information about the pkg-multimedia-commits
mailing list