aml_amaudioutils: audio hal utilities library [1/1]
PD#SWPL-17555
Problem:
This is the initial import of the utility library
to support audio hal implementation on Linux.
Solution:
This library is added on Linux for:
1. The resampler routines from speex
2. The Android SPDIF encoder
3. Partial Android libcutils support needed
as dependencies for audio hal.
Verify:
Local
Change-Id: I28cbc154c82bf6c395aba2f066a2fe0e6f6349db
Signed-off-by: Tim Yao <tim.yao@amlogic.com>
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..10e9b30
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,62 @@
+OBJS=src/primitives.o \
+ src/resampler.o \
+ src/speexresample/resample.o \
+ src/spdif/AC3FrameScanner.o \
+ src/spdif/BitFieldParser.o \
+ src/spdif/DTSFrameScanner.o \
+ src/spdif/FrameScanner.o \
+ src/spdif/SPDIFEncoder.o
+
+CUTILS_OBJS=src/cutils/hashmap.o \
+ src/cutils/properties.o \
+ src/cutils/str_parms.o \
+ src/cutils/threads.o \
+ src/cutils/strlcpy.o
+
+CFLAGS+=-fPIC -O2 -I./include -I./include/speex -I. -I./src -I./src/ -mfpu=neon -DFIXED_POINT -DRESAMPLE_FORCE_FULL_SINC_TABLE -D_USE_NEON -DEXPORT=
+LDFLAGS+=-llog -ldl -lrt -lpthread -lstdc++
+
+%.o: %.cpp
+ $(CC) -c $(CFLAGS) $(CXXFLAGS) -o $@ $<
+
+%.o: %.cc
+ $(CC) -c $(CFLAGS) $(CXXFLAGS) -o $@ $<
+
+%.o: %.c
+ $(CC) -c $(CFLAGS) -o $@ $<
+
+all: libamaudioutils.so libcutils.so
+
+libamaudioutils.so: $(OBJS)
+ $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^
+
+libcutils.so: $(CUTILS_OBJS)
+ $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^
+
+.PHONY: install
+install:
+ install -m 644 -D libamaudioutils.so -t $(STAGING_DIR)/usr/lib
+ install -m 644 -D libamaudioutils.so -t $(TARGET_DIR)/usr/lib
+ install -m 644 -D libcutils.so -t $(STAGING_DIR)/usr/lib
+ install -m 644 -D libcutils.so -t $(TARGET_DIR)/usr/lib
+ for f in $(@D)/include/audio_utils/*.h; do \
+ install -m 644 -D $${f} -t $(STAGING_DIR)/usr/include/audio_utils; \
+ done
+ for f in $(@D)/include/audio_utils/spdif/*.h; do \
+ install -m 644 -D $${f} -t $(STAGING_DIR)/usr/include/audio_utils/spdif; \
+ done
+ for f in $(@D)/include/cutils/*.h; do \
+ install -m 644 -D $${f} -t $(STAGING_DIR)/usr/include/cutils; \
+ done
+ for f in $(@D)/include/android/*.h; do \
+ install -m 644 -D $${f} -t $(STAGING_DIR)/usr/include/android; \
+ done
+
+.PHONY: clean
+clean:
+ rm -rf $(STAGING_DIR)/usr/include/audio_utils
+ rm -rf $(STAGING_DIR)/usr/include/cutils
+ rm -f libamaudioutils.so
+ rm -f $(TARGET_DIR)/usr/lib/libamaudioutils.so
+ rm -f $(STAGING_DIR)/usr/lib/libamaudioutils.so
+
diff --git a/include/android/log.h b/include/android/log.h
new file mode 100644
index 0000000..1f96220
--- /dev/null
+++ b/include/android/log.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_LOG_H
+#define _ANDROID_LOG_H
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ * This file is part of Android's set of stable system headers
+ * exposed by the Android NDK (Native Development Kit) since
+ * platform release 1.5
+ *
+ * Third-party source AND binary code relies on the definitions
+ * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+/*
+ * Support routines to send messages to the Android in-kernel log buffer,
+ * which can later be accessed through the 'logcat' utility.
+ *
+ * Each log message must have
+ * - a priority
+ * - a log tag
+ * - some text
+ *
+ * The tag normally corresponds to the component that emits the log message,
+ * and should be reasonably small.
+ *
+ * Log message text may be truncated to less than an implementation-specific
+ * limit (e.g. 1023 characters max).
+ *
+ * Note that a newline character ("\n") will be appended automatically to your
+ * log message, if not already there. It is not possible to send several messages
+ * and have them appear on a single line in logcat.
+ *
+ * PLEASE USE LOGS WITH MODERATION:
+ *
+ * - Sending log messages eats CPU and slow down your application and the
+ * system.
+ *
+ * - The circular log buffer is pretty small (<64KB), sending many messages
+ * might push off other important log messages from the rest of the system.
+ *
+ * - In release builds, only send log messages to account for exceptional
+ * conditions.
+ *
+ * NOTE: These functions MUST be implemented by /system/lib/liblog.so
+ */
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Android log priority values, in ascending priority order.
+ */
+typedef enum android_LogPriority {
+ ANDROID_LOG_UNKNOWN = 0,
+ ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
+ ANDROID_LOG_VERBOSE,
+ ANDROID_LOG_DEBUG,
+ ANDROID_LOG_INFO,
+ ANDROID_LOG_WARN,
+ ANDROID_LOG_ERROR,
+ ANDROID_LOG_FATAL,
+ ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
+} android_LogPriority;
+
+/*
+ * Send a simple string to the log.
+ */
+int __android_log_write(int prio, const char *tag, const char *text);
+
+/*
+ * Send a formatted string to the log, used like printf(fmt,...)
+ */
+int __android_log_print(int prio, const char *tag, const char *fmt, ...)
+#if defined(__GNUC__)
+ __attribute__ ((format(printf, 3, 4)))
+#endif
+ ;
+
+/*
+ * A variant of __android_log_print() that takes a va_list to list
+ * additional parameters.
+ */
+int __android_log_vprint(int prio, const char *tag,
+ const char *fmt, va_list ap);
+
+/*
+ * Log an assertion failure and SIGTRAP the process to have a chance
+ * to inspect it, if a debugger is attached. This uses the FATAL priority.
+ */
+void __android_log_assert(const char *cond, const char *tag,
+ const char *fmt, ...)
+#if defined(__GNUC__)
+ __attribute__ ((noreturn))
+ __attribute__ ((format(printf, 3, 4)))
+#endif
+ ;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ANDROID_LOG_H */
diff --git a/include/audio_utils/channels.h b/include/audio_utils/channels.h
new file mode 100644
index 0000000..10026f4
--- /dev/null
+++ b/include/audio_utils/channels.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_CHANNELS_H
+#define ANDROID_AUDIO_CHANNELS_H
+
+/** \cond */
+__BEGIN_DECLS
+/** \endcond */
+
+/**
+ * Expands or contracts sample data from one interleaved channel format to another.
+ * Expanded channels are filled with zeros and put at the end of each audio frame.
+ * Contracted channels are omitted from the end of each audio frame.
+ *
+ * \param in_buff points to the buffer of samples
+ * \param in_buff_chans Specifies the number of channels in the input buffer.
+ * \param out_buff points to the buffer to receive converted samples.
+ * \param out_buff_chans Specifies the number of channels in the output buffer.
+ * \param sample_size_in_bytes Specifies the number of bytes per sample. 1, 2, 3, 4 are
+ * currently valid.
+ * \param num_in_bytes size of input buffer in BYTES
+ *
+ * \return
+ * the number of BYTES of output data or 0 if an error occurs.
+ *
+ * \note
+ * The out and sums buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+size_t adjust_channels(const void* in_buff, size_t in_buff_chans,
+ void* out_buff, size_t out_buff_chans,
+ unsigned sample_size_in_bytes, size_t num_in_bytes);
+
+/**
+ * Expands or contracts sample data from one interleaved channel format to another.
+ * Extra expanded channels are left alone in the output buffer.
+ * Contracted channels are omitted from the end of each audio frame.
+ *
+ * \param in_buff points to the buffer of samples
+ * \param in_buff_chans Specifies the number of channels in the input buffer.
+ * \param out_buff points to the buffer to receive converted samples.
+ * \param out_buff_chans Specifies the number of channels in the output buffer.
+ * \param sample_size_in_bytes Specifies the number of bytes per sample. 1, 2, 3, 4 are
+ * currently valid.
+ * \param num_in_bytes size of input buffer in BYTES
+ *
+ * \return
+ * the number of BYTES of output data or 0 if an error occurs.
+ *
+ * \note
+ * The out and in buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+size_t adjust_selected_channels(const void* in_buff, size_t in_buff_chans,
+ void* out_buff, size_t out_buff_chans,
+ unsigned sample_size_in_bytes, size_t num_in_bytes);
+
+/** \cond */
+__END_DECLS
+/** \endcond */
+
+#endif
diff --git a/include/audio_utils/primitives.h b/include/audio_utils/primitives.h
new file mode 100644
index 0000000..a3727d7
--- /dev/null
+++ b/include/audio_utils/primitives.h
@@ -0,0 +1,1199 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_PRIMITIVES_H
+#define ANDROID_AUDIO_PRIMITIVES_H
+
+#include <math.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/cdefs.h>
+
+/** \cond */
+__BEGIN_DECLS
+/** \endcond */
+
+/**
+ * \file primitives.h
+ * The memcpy_* conversion routines are designed to work in-place on same dst as src
+ * buffers only if the types shrink on copy, with the exception of memcpy_to_i16_from_u8().
+ * This allows the loops to go upwards for faster cache access (and may be more flexible
+ * for future optimization later).
+ */
+
+/**
+ * Deprecated. Use memcpy_to_i16_from_q4_27() instead (double the pairs for the count).
+ * Neither this function nor memcpy_to_i16_from_q4_27() actually dither.
+ *
+ * Dither and clamp pairs of 32-bit input samples (sums) to 16-bit output samples (out).
+ * Each 32-bit input sample can be viewed as a signed fixed-point Q19.12 of which the
+ * .12 fraction bits are dithered and the 19 integer bits are clamped to signed 16 bits.
+ * Alternatively the input can be viewed as Q4.27, of which the lowest .12 of the fraction
+ * is dithered and the remaining fraction is converted to the output Q.15, with clamping
+ * on the 4 integer guard bits.
+ *
+ * For interleaved stereo, pairs is the number of sample pairs,
+ * and out is an array of interleaved pairs of 16-bit samples per channel.
+ * For mono, pairs is the number of samples / 2, and out is an array of 16-bit samples.
+ * The name "dither" is a misnomer; the current implementation does not actually dither
+ * but uses truncation. This may change.
+ * The out and sums buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void ditherAndClamp(int32_t *out, const int32_t *sums, size_t pairs);
+
+/**
+ * Copy samples from signed fixed-point 32-bit Q4.27 to 16-bit Q0.15
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void memcpy_to_i16_from_q4_27(int16_t *dst, const int32_t *src, size_t count);
+
+/**
+ * Expand and copy samples from unsigned 8-bit offset by 0x80 to signed 16-bit.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void memcpy_to_i16_from_u8(int16_t *dst, const uint8_t *src, size_t count);
+
+/**
+ * Shrink and copy samples from signed 16-bit to unsigned 8-bit offset by 0x80.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ * The conversion is done by truncation, without dithering, so it loses resolution.
+ */
+void memcpy_to_u8_from_i16(uint8_t *dst, const int16_t *src, size_t count);
+
+/**
+ * Copy samples from float to unsigned 8-bit offset by 0x80.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ * The conversion is done by truncation, without dithering, so it loses resolution.
+ */
+void memcpy_to_u8_from_float(uint8_t *dst, const float *src, size_t count);
+
+/**
+ * Shrink and copy samples from signed 32-bit fixed-point Q0.31 to signed 16-bit Q0.15.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ * The conversion is done by truncation, without dithering, so it loses resolution.
+ */
+void memcpy_to_i16_from_i32(int16_t *dst, const int32_t *src, size_t count);
+
+/**
+ * Shrink and copy samples from single-precision floating-point to signed 16-bit.
+ * Each float should be in the range -1.0 to 1.0. Values outside that range are clamped,
+ * refer to clamp16_from_float().
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ * The conversion is done by truncation, without dithering, so it loses resolution.
+ */
+void memcpy_to_i16_from_float(int16_t *dst, const float *src, size_t count);
+
+/**
+ * Copy samples from signed fixed-point 32-bit Q4.27 to single-precision floating-point.
+ * The nominal output float range is [-1.0, 1.0] if the fixed-point range is
+ * [0xf8000000, 0x07ffffff]. The full float range is [-16.0, 16.0]. Note the closed range
+ * at 1.0 and 16.0 is due to rounding on conversion to float. See float_from_q4_27() for details.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void memcpy_to_float_from_q4_27(float *dst, const int32_t *src, size_t count);
+
+/**
+ * Copy samples from signed fixed-point 16 bit Q0.15 to single-precision floating-point.
+ * The output float range is [-1.0, 1.0) for the fixed-point range [0x8000, 0x7fff].
+ * No rounding is needed as the representation is exact.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void memcpy_to_float_from_i16(float *dst, const int16_t *src, size_t count);
+
+/**
+ * Copy samples from unsigned fixed-point 8 bit to single-precision floating-point.
+ * The output float range is [-1.0, 1.0) for the fixed-point range [0x00, 0xFF].
+ * No rounding is needed as the representation is exact.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void memcpy_to_float_from_u8(float *dst, const uint8_t *src, size_t count);
+
+/**
+ * Copy samples from signed fixed-point packed 24 bit Q0.23 to single-precision floating-point.
+ * The packed 24 bit input is stored in native endian format in a uint8_t byte array.
+ * The output float range is [-1.0, 1.0) for the fixed-point range [0x800000, 0x7fffff].
+ * No rounding is needed as the representation is exact.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void memcpy_to_float_from_p24(float *dst, const uint8_t *src, size_t count);
+
+/**
+ * Copy samples from signed fixed-point packed 24 bit Q0.23 to signed fixed point 16 bit Q0.15.
+ * The packed 24 bit output is stored in native endian format in a uint8_t byte array.
+ * The data is truncated without rounding.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void memcpy_to_i16_from_p24(int16_t *dst, const uint8_t *src, size_t count);
+
+/**
+ * Copy samples from signed fixed-point packed 24 bit Q0.23 to signed fixed-point 32-bit Q0.31.
+ * The packed 24 bit input is stored in native endian format in a uint8_t byte array.
+ * The output data range is [0x80000000, 0x7fffff00] at intervals of 0x100.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void memcpy_to_i32_from_p24(int32_t *dst, const uint8_t *src, size_t count);
+
+/**
+ * Copy samples from signed fixed point 16 bit Q0.15 to signed fixed-point packed 24 bit Q0.23.
+ * The packed 24 bit output is assumed to be a native-endian uint8_t byte array.
+ * The output data range is [0x800000, 0x7fff00] (not full).
+ * Nevertheless there is no DC offset on the output, if the input has no DC offset.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void memcpy_to_p24_from_i16(uint8_t *dst, const int16_t *src, size_t count);
+
+/**
+ * Copy samples from single-precision floating-point to signed fixed-point packed 24 bit Q0.23.
+ * The packed 24 bit output is assumed to be a native-endian uint8_t byte array.
+ * The data is clamped and rounded to nearest, ties away from zero. See clamp24_from_float()
+ * for details.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void memcpy_to_p24_from_float(uint8_t *dst, const float *src, size_t count);
+
+/**
+ * Copy samples from signed fixed-point 32-bit Q8.23 to signed fixed-point packed 24 bit Q0.23.
+ * The packed 24 bit output is assumed to be a native-endian uint8_t byte array.
+ * The data is clamped to the range is [0x800000, 0x7fffff].
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address.
+ */
+void memcpy_to_p24_from_q8_23(uint8_t *dst, const int32_t *src, size_t count);
+
+/**
+ * Shrink and copy samples from signed 32-bit fixed-point Q0.31
+ * to signed fixed-point packed 24 bit Q0.23.
+ * The packed 24 bit output is assumed to be a native-endian uint8_t byte array.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ * The conversion is done by truncation, without dithering, so it loses resolution.
+ */
+void memcpy_to_p24_from_i32(uint8_t *dst, const int32_t *src, size_t count);
+
+/**
+ * Copy samples from signed fixed point 16-bit Q0.15 to signed fixed-point 32-bit Q8.23.
+ * The output data range is [0xff800000, 0x007fff00] at intervals of 0x100.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void memcpy_to_q8_23_from_i16(int32_t *dst, const int16_t *src, size_t count);
+
+/**
+ * Copy samples from single-precision floating-point to signed fixed-point 32-bit Q8.23.
+ * This copy will clamp the Q8.23 representation to [0xff800000, 0x007fffff] even though there
+ * are guard bits available. Fractional lsb is rounded to nearest, ties away from zero.
+ * See clamp24_from_float() for details.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void memcpy_to_q8_23_from_float_with_clamp(int32_t *dst, const float *src, size_t count);
+
+/**
+ * Copy samples from signed fixed point packed 24-bit Q0.23 to signed fixed-point 32-bit Q8.23.
+ * The output data range is [0xff800000, 0x007fffff].
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void memcpy_to_q8_23_from_p24(int32_t *dst, const uint8_t *src, size_t count);
+
+/**
+ * Copy samples from single-precision floating-point to signed fixed-point 32-bit Q4.27.
+ * The conversion will use the full available Q4.27 range, including guard bits.
+ * Fractional lsb is rounded to nearest, ties away from zero.
+ * See clampq4_27_from_float() for details.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void memcpy_to_q4_27_from_float(int32_t *dst, const float *src, size_t count);
+
+/**
+ * Copy samples from signed fixed-point 32-bit Q8.23 to signed fixed point 16-bit Q0.15.
+ * The data is clamped, and truncated without rounding.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void memcpy_to_i16_from_q8_23(int16_t *dst, const int32_t *src, size_t count);
+
+/**
+ * Copy samples from signed fixed-point 32-bit Q8.23 to single-precision floating-point.
+ * The nominal output float range is [-1.0, 1.0) for the fixed-point
+ * range [0xff800000, 0x007fffff]. The maximum output float range is [-256.0, 256.0).
+ * No rounding is needed as the representation is exact for nominal values.
+ * Rounding for overflow values is to nearest, ties to even.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void memcpy_to_float_from_q8_23(float *dst, const int32_t *src, size_t count);
+
+/**
+ * Copy samples from signed fixed point 16-bit Q0.15 to signed fixed-point 32-bit Q0.31.
+ * The output data range is [0x80000000, 0x7fff0000] at intervals of 0x10000.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void memcpy_to_i32_from_i16(int32_t *dst, const int16_t *src, size_t count);
+
+/**
+ * Copy samples from single-precision floating-point to signed fixed-point 32-bit Q0.31.
+ * If rounding is needed on truncation, the fractional lsb is rounded to nearest,
+ * ties away from zero. See clamp32_from_float() for details.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void memcpy_to_i32_from_float(int32_t *dst, const float *src, size_t count);
+
+/**
+ * Copy samples from signed fixed-point 32-bit Q0.31 to single-precision floating-point.
+ * The float range is [-1.0, 1.0] for the fixed-point range [0x80000000, 0x7fffffff].
+ * Rounding is done according to float_from_i32().
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void memcpy_to_float_from_i32(float *dst, const int32_t *src, size_t count);
+
+/**
+ * Copy samples from unrestricted float to range restricted float [-absMax, absMax].
+ * Any float sample not in the range [-absMax, absMax] will be clamped in this range.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to copy
+ * \param absMax Maximum of the absolute value of the copied samples.
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ * Note: NAN is clamped to absMax and not 0 for performance reason (~2xfaster).
+ */
+void memcpy_to_float_from_float_with_clamping(float *dst, const float *src, size_t count,
+ float absMax);
+
+/**
+ * Downmix pairs of interleaved stereo input 16-bit samples to mono output 16-bit samples.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of stereo frames to downmix
+ *
+ * The destination and source buffers must be completely separate (non-overlapping).
+ * The current implementation truncates the mean rather than dither, but this may change.
+ */
+void downmix_to_mono_i16_from_stereo_i16(int16_t *dst, const int16_t *src, size_t count);
+
+/**
+ * Upmix mono input 16-bit samples to pairs of interleaved stereo output 16-bit samples by
+ * duplicating.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of mono samples to upmix
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void upmix_to_stereo_i16_from_mono_i16(int16_t *dst, const int16_t *src, size_t count);
+
+/**
+ * Downmix pairs of interleaved stereo input float samples to mono output float samples
+ * by averaging the stereo pair together.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of stereo frames to downmix
+ *
+ * The destination and source buffers must be completely separate (non-overlapping),
+ * or they must both start at the same address.
+ */
+void downmix_to_mono_float_from_stereo_float(float *dst, const float *src, size_t count);
+
+/**
+ * Upmix mono input float samples to pairs of interleaved stereo output float samples by
+ * duplicating.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of mono samples to upmix
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void upmix_to_stereo_float_from_mono_float(float *dst, const float *src, size_t count);
+
+/**
+ * \return the total number of non-zero 32-bit samples.
+ */
+size_t nonZeroMono32(const int32_t *samples, size_t count);
+
+/**
+ * \return the total number of non-zero 16-bit samples.
+ */
+size_t nonZeroMono16(const int16_t *samples, size_t count);
+
+/**
+ * \return the total number of non-zero stereo frames, where a frame is considered non-zero
+ * if either of its constituent 32-bit samples is non-zero.
+ */
+size_t nonZeroStereo32(const int32_t *frames, size_t count);
+
+/**
+ * \return the total number of non-zero stereo frames, where a frame is considered non-zero
+ * if either of its constituent 16-bit samples is non-zero.
+ */
+size_t nonZeroStereo16(const int16_t *frames, size_t count);
+
+/**
+ * Copy frames, selecting source samples based on a source channel mask to fit
+ * the destination channel mask. Unmatched channels in the destination channel mask
+ * are zero filled. Unmatched channels in the source channel mask are dropped.
+ * Channels present in the channel mask are represented by set bits in the
+ * uint32_t value and are matched without further interpretation.
+ *
+ * \param dst Destination buffer
+ * \param dst_mask Bit mask corresponding to destination channels present
+ * \param src Source buffer
+ * \param src_mask Bit mask corresponding to source channels present
+ * \param sample_size Size of each sample in bytes. Must be 1, 2, 3, or 4.
+ * \param count Number of frames to copy
+ *
+ * The destination and source buffers must be completely separate (non-overlapping).
+ * If the sample size is not in range, the function will abort.
+ */
+void memcpy_by_channel_mask(void *dst, uint32_t dst_mask,
+ const void *src, uint32_t src_mask, size_t sample_size, size_t count);
+
+/**
+ * Copy frames, selecting source samples based on an index array (idxary).
+ * The idxary[] consists of dst_channels number of elements.
+ * The ith element if idxary[] corresponds the ith destination channel.
+ * A non-negative value is the channel index in the source frame.
+ * A negative index (-1) represents filling with 0.
+ *
+ * Example: Swapping L and R channels for stereo streams
+ * <PRE>
+ * idxary[0] = 1;
+ * idxary[1] = 0;
+ * </PRE>
+ *
+ * Example: Copying a mono source to the front center 5.1 channel
+ * <PRE>
+ * idxary[0] = -1;
+ * idxary[1] = -1;
+ * idxary[2] = 0;
+ * idxary[3] = -1;
+ * idxary[4] = -1;
+ * idxary[5] = -1;
+ * </PRE>
+ *
+ * This copy allows swizzling of channels or replication of channels.
+ *
+ * \param dst Destination buffer
+ * \param dst_channels Number of destination channels per frame
+ * \param src Source buffer
+ * \param src_channels Number of source channels per frame
+ * \param idxary Array of indices representing channels in the source frame
+ * \param sample_size Size of each sample in bytes. Must be 1, 2, 3, or 4.
+ * \param count Number of frames to copy
+ *
+ * The destination and source buffers must be completely separate (non-overlapping).
+ * If the sample size is not in range, the function will abort.
+ */
+void memcpy_by_index_array(void *dst, uint32_t dst_channels,
+ const void *src, uint32_t src_channels,
+ const int8_t *idxary, size_t sample_size, size_t count);
+
+/**
+ * Prepares an index array (idxary) from channel masks, which can be later
+ * used by memcpy_by_index_array().
+ *
+ * \return the number of array elements required.
+ * This may be greater than idxcount, so the return value should be checked
+ * if idxary size is less than 32.
+ *
+ * Note that idxary is a caller allocated array
+ * of at least as many channels as present in the dst_mask.
+ * Channels present in the channel mask are represented by set bits in the
+ * uint32_t value and are matched without further interpretation.
+ *
+ * This function is typically used for converting audio data with different
+ * channel position masks.
+ *
+ * \param idxary Updated array of indices of channels in the src frame for the dst frame
+ * \param idxcount Number of caller allocated elements in idxary
+ * \param dst_mask Bit mask corresponding to destination channels present
+ * \param src_mask Bit mask corresponding to source channels present
+ */
+size_t memcpy_by_index_array_initialization(int8_t *idxary, size_t idxcount,
+ uint32_t dst_mask, uint32_t src_mask);
+
+/**
+ * Prepares an index array (idxary) from channel masks, which can be later
+ * used by memcpy_by_index_array().
+ *
+ * \return the number of array elements required.
+ *
+ * For a source channel index mask, the source channels will map to the destination
+ * channels as if counting the set bits in dst_mask in order from lsb to msb
+ * (zero bits are ignored). The ith bit of the src_mask corresponds to the
+ * ith SET bit of dst_mask and the ith destination channel. Hence, a zero ith
+ * bit of the src_mask indicates that the ith destination channel plays silence.
+ *
+ * \param idxary Updated array of indices of channels in the src frame for the dst frame
+ * \param idxcount Number of caller allocated elements in idxary
+ * \param dst_mask Bit mask corresponding to destination channels present
+ * \param src_mask Bit mask corresponding to source channels present
+ */
+size_t memcpy_by_index_array_initialization_src_index(int8_t *idxary, size_t idxcount,
+ uint32_t dst_mask, uint32_t src_mask);
+
+/**
+ * Prepares an index array (idxary) from channel mask bits, which can be later
+ * used by memcpy_by_index_array().
+ *
+ * \return the number of array elements required.
+ *
+ * This initialization is for a destination channel index mask from a positional
+ * source mask.
+ *
+ * For an destination channel index mask, the input channels will map
+ * to the destination channels, with the ith SET bit in the source bits corresponding
+ * to the ith bit in the destination bits. If there is a zero bit in the middle
+ * of set destination bits (unlikely), the corresponding source channel will
+ * be dropped.
+ *
+ * \param idxary Updated array of indices of channels in the src frame for the dst frame
+ * \param idxcount Number of caller allocated elements in idxary
+ * \param dst_mask Bit mask corresponding to destination channels present
+ * \param src_mask Bit mask corresponding to source channels present
+ */
+size_t memcpy_by_index_array_initialization_dst_index(int8_t *idxary, size_t idxcount,
+ uint32_t dst_mask, uint32_t src_mask);
+
+/**
+ * Add and clamp signed 16-bit samples.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to add
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void accumulate_i16(int16_t *dst, const int16_t *src, size_t count);
+
+/**
+ * Add and clamp unsigned 8-bit samples.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to add
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void accumulate_u8(uint8_t *dst, const uint8_t *src, size_t count);
+
+/**
+ * Add and clamp packed 24-bit Q0.23 samples.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to add
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void accumulate_p24(uint8_t *dst, const uint8_t *src, size_t count);
+
+/**
+ * Add and clamp 32-bit Q8.23 samples.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to add
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void accumulate_q8_23(int32_t *dst, const int32_t *src, size_t count);
+
+/**
+ * Add and clamp signed 32-bit Q0.31 samples.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to add
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void accumulate_i32(int32_t *dst, const int32_t *src, size_t count);
+
+/**
+ * Add float samples. Result is not clamped.
+ *
+ * \param dst Destination buffer
+ * \param src Source buffer
+ * \param count Number of samples to add
+ *
+ * The destination and source buffers must either be completely separate (non-overlapping), or
+ * they must both start at the same address. Partially overlapping buffers are not supported.
+ */
+void accumulate_float(float *dst, const float *src, size_t count);
+
+/**
+ * Clamp (aka hard limit or clip) a signed 32-bit sample to 16-bit range.
+ */
+static inline int16_t clamp16(int32_t sample)
+{
+ if ((sample>>15) ^ (sample>>31))
+ sample = 0x7FFF ^ (sample>>31);
+ return sample;
+}
+
+/**
+ * Clamp (aka hard limit or clip) a signed 64-bit sample to 32-bit range.
+ */
+static inline int32_t clamp32(int64_t sample)
+{
+ if ((sample>>31) ^ (sample>>63))
+ sample = 0x7fffffff ^ (sample>>63);
+ return sample;
+}
+
+/**
+ * Convert a IEEE 754 single precision float [-1.0, 1.0) to int16_t [-32768, 32767]
+ * with clamping. Note the open bound at 1.0, values within 1/65536 of 1.0 map
+ * to 32767 instead of 32768 (early clamping due to the smaller positive integer subrange).
+ *
+ * Values outside the range [-1.0, 1.0) are properly clamped to -32768 and 32767,
+ * including -Inf and +Inf. NaN will generally be treated either as -32768 or 32767,
+ * depending on the sign bit inside NaN (whose representation is not unique).
+ * Nevertheless, strictly speaking, NaN behavior should be considered undefined.
+ *
+ * OLD code disabled: Rounding of 0.5 lsb is to even (default for IEEE 754).
+ * NEW code enabled: Rounding of 0.5 lsb is away from 0.
+ */
+static inline int16_t clamp16_from_float(float f)
+{
+#if 0
+ /* Offset is used to expand the valid range of [-1.0, 1.0) into the 16 lsbs of the
+ * floating point significand. The normal shift is 3<<22, but the -15 offset
+ * is used to multiply by 32768.
+ */
+ static const float offset = (float)(3 << (22 - 15));
+ /* zero = (0x10f << 22) = 0x43c00000 (not directly used) */
+ static const int32_t limneg = (0x10f << 22) /*zero*/ - 32768; /* 0x43bf8000 */
+ static const int32_t limpos = (0x10f << 22) /*zero*/ + 32767; /* 0x43c07fff */
+
+ union {
+ float f;
+ int32_t i;
+ } u;
+
+ u.f = f + offset; /* recenter valid range */
+ /* Now the valid range is represented as integers between [limneg, limpos].
+ * Clamp using the fact that float representation (as an integer) is an ordered set.
+ */
+ if (u.i < limneg)
+ u.i = -32768;
+ else if (u.i > limpos)
+ u.i = 32767;
+ return u.i; /* Return lower 16 bits, the part of interest in the significand. */
+#else
+ static const float scale = 1 << 15;
+ return roundf(fmaxf(fminf(f * scale, scale - 1.f), -scale));
+#endif
+}
+
+/**
+ * Convert a IEEE 754 single precision float [-1.0, 1.0) to uint8_t [0, 0xff]
+ * with clamping. Note the open bound at 1.0, values within 1/128 of 1.0 map
+ * to 255 instead of 256 (early clamping due to the smaller positive integer subrange).
+ *
+ * Values outside the range [-1.0, 1.0) are properly clamped to 0 and 255,
+ * including -Inf and +Inf. NaN will generally be treated either as 0 or 255,
+ * depending on the sign bit inside NaN (whose representation is not unique).
+ * Nevertheless, strictly speaking, NaN behavior should be considered undefined.
+ *
+ * OLD code disabled: Rounding of 0.5 lsb is to even (default for IEEE 754).
+ * NEW code enabled: Rounding of 0.5 lsb is away from 0.
+ */
+static inline uint8_t clamp8_from_float(float f)
+{
+#if 0
+ /* Offset is used to expand the valid range of [-1.0, 1.0) into the 16 lsbs of the
+ * floating point significand. The normal shift is 3<<22, but the -7 offset
+ * is used to multiply by 128.
+ */
+ static const float offset = (float)((3 << (22 - 7)) + 1 /* to cancel -1.0 */);
+ /* zero = (0x11f << 22) = 0x47c00000 */
+ static const int32_t limneg = (0x11f << 22) /*zero*/;
+ static const int32_t limpos = (0x11f << 22) /*zero*/ + 255; /* 0x47c000ff */
+
+ union {
+ float f;
+ int32_t i;
+ } u;
+
+ u.f = f + offset; /* recenter valid range */
+ /* Now the valid range is represented as integers between [limneg, limpos].
+ * Clamp using the fact that float representation (as an integer) is an ordered set.
+ */
+ if (u.i < limneg)
+ return 0;
+ if (u.i > limpos)
+ return 255;
+ return u.i; /* Return lower 8 bits, the part of interest in the significand. */
+#else
+ return roundf(fmaxf(fminf(f * 128.f + 128.f, 255.f), 0.f));
+#endif
+}
+
+/**
+ * Convert a single-precision floating point value to a Q0.23 integer value, stored in a
+ * 32 bit signed integer (technically stored as Q8.23, but clamped to Q0.23).
+ *
+ * OLD code disabled: Rounds to nearest, ties away from 0.
+ * NEW code enabled: Rounding of 0.5 lsb is away from 0.
+ *
+ * Values outside the range [-1.0, 1.0) are properly clamped to -8388608 and 8388607,
+ * including -Inf and +Inf. NaN values are considered undefined, and behavior may change
+ * depending on hardware and future implementation of this function.
+ */
+static inline int32_t clamp24_from_float(float f)
+{
+#if 0
+ static const float scale = (float)(1 << 23);
+ static const float limpos = 0x7fffff / scale;
+ static const float limneg = -0x800000 / scale;
+
+ if (f <= limneg) {
+ return -0x800000;
+ } else if (f >= limpos) {
+ return 0x7fffff;
+ }
+ f *= scale;
+ /* integer conversion is through truncation (though int to float is not).
+ * ensure that we round to nearest, ties away from 0.
+ */
+ return f > 0 ? f + 0.5 : f - 0.5;
+#else
+ static const float scale = 1 << 23;
+ return roundf(fmaxf(fminf(f * scale, scale - 1.f), -scale));
+#endif
+}
+
+/**
+ * Convert a signed fixed-point 32-bit Q8.23 value to a Q0.23 integer value,
+ * stored in a 32-bit signed integer (technically stored as Q8.23, but clamped to Q0.23).
+ *
+ * Values outside the range [-0x800000, 0x7fffff] are clamped to that range.
+ */
+static inline int32_t clamp24_from_q8_23(int32_t ival)
+{
+ static const int32_t limpos = 0x7fffff;
+ static const int32_t limneg = -0x800000;
+ if (ival < limneg) {
+ return limneg;
+ } else if (ival > limpos) {
+ return limpos;
+ } else {
+ return ival;
+ }
+}
+
+/**
+ * Convert a single-precision floating point value to a Q4.27 integer value.
+ * Rounds to nearest, ties away from 0.
+ *
+ * Values outside the range [-16.0, 16.0) are properly clamped to -2147483648 and 2147483647,
+ * including -Inf and +Inf. NaN values are considered undefined, and behavior may change
+ * depending on hardware and future implementation of this function.
+ */
+static inline int32_t clampq4_27_from_float(float f)
+{
+ static const float scale = (float)(1UL << 27);
+ static const float limpos = 16.;
+ static const float limneg = -16.;
+
+ if (f <= limneg) {
+ return -0x80000000; /* or 0x80000000 */
+ } else if (f >= limpos) {
+ return 0x7fffffff;
+ }
+ f *= scale;
+ /* integer conversion is through truncation (though int to float is not).
+ * ensure that we round to nearest, ties away from 0.
+ */
+ return f > 0 ? f + 0.5 : f - 0.5;
+}
+
+/**
+ * Convert a single-precision floating point value to a Q0.31 integer value.
+ * Rounds to nearest, ties away from 0.
+ *
+ * Values outside the range [-1.0, 1.0) are properly clamped to -2147483648 and 2147483647,
+ * including -Inf and +Inf. NaN values are considered undefined, and behavior may change
+ * depending on hardware and future implementation of this function.
+ */
+static inline int32_t clamp32_from_float(float f)
+{
+ static const float scale = (float)(1UL << 31);
+ static const float limpos = 1.;
+ static const float limneg = -1.;
+
+ if (f <= limneg) {
+ return -0x80000000; /* or 0x80000000 */
+ } else if (f >= limpos) {
+ return 0x7fffffff;
+ }
+ f *= scale;
+ /* integer conversion is through truncation (though int to float is not).
+ * ensure that we round to nearest, ties away from 0.
+ */
+ return f > 0 ? f + 0.5 : f - 0.5;
+}
+
+/**
+ * Convert a signed fixed-point 32-bit Q4.27 value to single-precision floating-point.
+ * The nominal output float range is [-1.0, 1.0] if the fixed-point range is
+ * [0xf8000000, 0x07ffffff]. The full float range is [-16.0, 16.0].
+ *
+ * Note the closed range at 1.0 and 16.0 is due to rounding on conversion to float.
+ * In more detail: if the fixed-point integer exceeds 24 bit significand of single
+ * precision floating point, the 0.5 lsb in the significand conversion will round
+ * towards even, as per IEEE 754 default.
+ */
+static inline float float_from_q4_27(int32_t ival)
+{
+ /* The scale factor is the reciprocal of the fractional bits.
+ *
+ * Since the scale factor is a power of 2, the scaling is exact, and there
+ * is no rounding due to the multiplication - the bit pattern is preserved.
+ * However, there may be rounding due to the fixed-point to float conversion,
+ * as described above.
+ */
+ static const float scale = 1. / (float)(1UL << 27);
+
+ return ival * scale;
+}
+
+/**
+ * Convert an unsigned fixed-point 32-bit U4.28 value to single-precision floating-point.
+ * The nominal output float range is [0.0, 1.0] if the fixed-point range is
+ * [0x00000000, 0x10000000]. The full float range is [0.0, 16.0].
+ *
+ * Note the closed range at 1.0 and 16.0 is due to rounding on conversion to float.
+ * In more detail: if the fixed-point integer exceeds 24 bit significand of single
+ * precision floating point, the 0.5 lsb in the significand conversion will round
+ * towards even, as per IEEE 754 default.
+ */
+static inline float float_from_u4_28(uint32_t uval)
+{
+ static const float scale = 1. / (float)(1UL << 28);
+
+ return uval * scale;
+}
+
+/**
+ * Convert an unsigned fixed-point 16-bit U4.12 value to single-precision floating-point.
+ * The nominal output float range is [0.0, 1.0] if the fixed-point range is
+ * [0x0000, 0x1000]. The full float range is [0.0, 16.0).
+ */
+static inline float float_from_u4_12(uint16_t uval)
+{
+ static const float scale = 1. / (float)(1UL << 12);
+
+ return uval * scale;
+}
+
+/**
+ * Convert a single-precision floating point value to a U4.28 integer value.
+ * Rounds to nearest, ties away from 0.
+ *
+ * Values outside the range [0, 16.0] are properly clamped to [0, 4294967295]
+ * including -Inf and +Inf. NaN values are considered undefined, and behavior may change
+ * depending on hardware and future implementation of this function.
+ */
+static inline uint32_t u4_28_from_float(float f)
+{
+ static const float scale = (float)(1 << 28);
+ static const float limpos = 0xffffffffUL / scale;
+
+ if (f <= 0.) {
+ return 0;
+ } else if (f >= limpos) {
+ return 0xffffffff;
+ }
+ /* integer conversion is through truncation (though int to float is not).
+ * ensure that we round to nearest, ties away from 0.
+ */
+ return f * scale + 0.5;
+}
+
+/**
+ * Convert a single-precision floating point value to a U4.12 integer value.
+ * Rounds to nearest, ties away from 0.
+ *
+ * Values outside the range [0, 16.0) are properly clamped to [0, 65535]
+ * including -Inf and +Inf. NaN values are considered undefined, and behavior may change
+ * depending on hardware and future implementation of this function.
+ */
+static inline uint16_t u4_12_from_float(float f)
+{
+ static const float scale = (float)(1 << 12);
+ static const float limpos = 0xffff / scale;
+
+ if (f <= 0.) {
+ return 0;
+ } else if (f >= limpos) {
+ return 0xffff;
+ }
+ /* integer conversion is through truncation (though int to float is not).
+ * ensure that we round to nearest, ties away from 0.
+ */
+ return f * scale + 0.5;
+}
+
+/**
+ * Convert a signed fixed-point 16-bit Q0.15 value to single-precision floating-point.
+ * The output float range is [-1.0, 1.0) for the fixed-point range
+ * [0x8000, 0x7fff].
+ *
+ * There is no rounding, the conversion and representation is exact.
+ */
+static inline float float_from_i16(int16_t ival)
+{
+ /* The scale factor is the reciprocal of the nominal 16 bit integer
+ * half-sided range (32768).
+ *
+ * Since the scale factor is a power of 2, the scaling is exact, and there
+ * is no rounding due to the multiplication - the bit pattern is preserved.
+ */
+ static const float scale = 1. / (float)(1UL << 15);
+
+ return ival * scale;
+}
+
+/**
+ * Convert an unsigned fixed-point 8-bit U0.8 value to single-precision floating-point.
+ * The nominal output float range is [-1.0, 1.0) if the fixed-point range is
+ * [0x00, 0xff].
+ */
+static inline float float_from_u8(uint8_t uval)
+{
+ static const float scale = 1. / (float)(1UL << 7);
+
+ return ((int)uval - 128) * scale;
+}
+
+/**
+ * Convert a packed 24bit Q0.23 value stored native-endian in a uint8_t ptr
+ * to a signed fixed-point 32 bit integer Q0.31 value. The output Q0.31 range
+ * is [0x80000000, 0x7fffff00] for the fixed-point range [0x800000, 0x7fffff].
+ * Even though the output range is limited on the positive side, there is no
+ * DC offset on the output, if the input has no DC offset.
+ *
+ * Avoid relying on the limited output range, as future implementations may go
+ * to full range.
+ */
+static inline int32_t i32_from_p24(const uint8_t *packed24)
+{
+ /* convert to 32b */
+ return (packed24[0] << 8) | (packed24[1] << 16) | (packed24[2] << 24);
+}
+
+/**
+ * Convert a 32-bit Q0.31 value to single-precision floating-point.
+ * The output float range is [-1.0, 1.0] for the fixed-point range
+ * [0x80000000, 0x7fffffff].
+ *
+ * Rounding may occur in the least significant 8 bits for large fixed point
+ * values due to storage into the 24-bit floating-point significand.
+ * Rounding will be to nearest, ties to even.
+ */
+static inline float float_from_i32(int32_t ival)
+{
+ static const float scale = 1. / (float)(1UL << 31);
+
+ return ival * scale;
+}
+
+/**
+ * Convert a packed 24bit Q0.23 value stored native endian in a uint8_t ptr
+ * to single-precision floating-point. The output float range is [-1.0, 1.0)
+ * for the fixed-point range [0x800000, 0x7fffff].
+ *
+ * There is no rounding, the conversion and representation is exact.
+ */
+static inline float float_from_p24(const uint8_t *packed24)
+{
+ return float_from_i32(i32_from_p24(packed24));
+}
+
+/**
+ * Convert a 24-bit Q8.23 value to single-precision floating-point.
+ * The nominal output float range is [-1.0, 1.0) for the fixed-point
+ * range [0xff800000, 0x007fffff]. The maximum float range is [-256.0, 256.0).
+ *
+ * There is no rounding in the nominal range, the conversion and representation
+ * is exact. For values outside the nominal range, rounding is to nearest, ties to even.
+ */
+static inline float float_from_q8_23(int32_t ival)
+{
+ static const float scale = 1. / (float)(1UL << 23);
+
+ return ival * scale;
+}
+
+/**
+ * Multiply-accumulate 16-bit terms with 32-bit result: return a + in*v.
+ */
+static inline
+int32_t mulAdd(int16_t in, int16_t v, int32_t a)
+{
+#if defined(__arm__) && !defined(__thumb__)
+ int32_t out;
+ asm( "smlabb %[out], %[in], %[v], %[a] \n"
+ : [out]"=r"(out)
+ : [in]"%r"(in), [v]"r"(v), [a]"r"(a)
+ : );
+ return out;
+#else
+ return a + in * (int32_t)v;
+#endif
+}
+
+/**
+ * Multiply 16-bit terms with 32-bit result: return in*v.
+ */
+static inline
+int32_t mul(int16_t in, int16_t v)
+{
+#if defined(__arm__) && !defined(__thumb__)
+ int32_t out;
+ asm( "smulbb %[out], %[in], %[v] \n"
+ : [out]"=r"(out)
+ : [in]"%r"(in), [v]"r"(v)
+ : );
+ return out;
+#else
+ return in * (int32_t)v;
+#endif
+}
+
+/**
+ * Similar to mulAdd, but the 16-bit terms are extracted from a 32-bit interleaved stereo pair.
+ */
+static inline
+int32_t mulAddRL(int left, uint32_t inRL, uint32_t vRL, int32_t a)
+{
+#if defined(__arm__) && !defined(__thumb__)
+ int32_t out;
+ if (left) {
+ asm( "smlabb %[out], %[inRL], %[vRL], %[a] \n"
+ : [out]"=r"(out)
+ : [inRL]"%r"(inRL), [vRL]"r"(vRL), [a]"r"(a)
+ : );
+ } else {
+ asm( "smlatt %[out], %[inRL], %[vRL], %[a] \n"
+ : [out]"=r"(out)
+ : [inRL]"%r"(inRL), [vRL]"r"(vRL), [a]"r"(a)
+ : );
+ }
+ return out;
+#else
+ if (left) {
+ return a + (int16_t)(inRL&0xFFFF) * (int16_t)(vRL&0xFFFF);
+ } else {
+ return a + (int16_t)(inRL>>16) * (int16_t)(vRL>>16);
+ }
+#endif
+}
+
+/**
+ * Similar to mul, but the 16-bit terms are extracted from a 32-bit interleaved stereo pair.
+ */
+static inline
+int32_t mulRL(int left, uint32_t inRL, uint32_t vRL)
+{
+#if defined(__arm__) && !defined(__thumb__)
+ int32_t out;
+ if (left) {
+ asm( "smulbb %[out], %[inRL], %[vRL] \n"
+ : [out]"=r"(out)
+ : [inRL]"%r"(inRL), [vRL]"r"(vRL)
+ : );
+ } else {
+ asm( "smultt %[out], %[inRL], %[vRL] \n"
+ : [out]"=r"(out)
+ : [inRL]"%r"(inRL), [vRL]"r"(vRL)
+ : );
+ }
+ return out;
+#else
+ if (left) {
+ return (int16_t)(inRL&0xFFFF) * (int16_t)(vRL&0xFFFF);
+ } else {
+ return (int16_t)(inRL>>16) * (int16_t)(vRL>>16);
+ }
+#endif
+}
+
+/** \cond */
+__END_DECLS
+/** \endcond */
+
+#endif // ANDROID_AUDIO_PRIMITIVES_H
diff --git a/include/audio_utils/resampler.h b/include/audio_utils/resampler.h
new file mode 100644
index 0000000..559e020
--- /dev/null
+++ b/include/audio_utils/resampler.h
@@ -0,0 +1,109 @@
+/*
+** Copyright 2008, The Android Open-Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_RESAMPLER_H
+#define ANDROID_RESAMPLER_H
+
+#include <stdint.h>
+#include <sys/time.h>
+
+__BEGIN_DECLS
+
+
+#define RESAMPLER_QUALITY_MAX 10
+#define RESAMPLER_QUALITY_MIN 0
+#define RESAMPLER_QUALITY_DEFAULT 4
+#define RESAMPLER_QUALITY_VOIP 3
+#define RESAMPLER_QUALITY_DESKTOP 5
+
+struct resampler_buffer {
+ union {
+ void* raw;
+ short* i16;
+ int8_t* i8;
+ };
+ size_t frame_count;
+};
+
+/** call back interface used by the resampler to get new data */
+struct resampler_buffer_provider
+{
+ /**
+ * get a new buffer of data:
+ * as input: buffer->frame_count is the number of frames requested
+ * as output: buffer->frame_count is the number of frames returned
+ * buffer->raw points to data returned
+ */
+ int (*get_next_buffer)(struct resampler_buffer_provider *provider,
+ struct resampler_buffer *buffer);
+ /**
+ * release a consumed buffer of data:
+ * as input: buffer->frame_count is the number of frames released
+ * buffer->raw points to data released
+ */
+ void (*release_buffer)(struct resampler_buffer_provider *provider,
+ struct resampler_buffer *buffer);
+};
+
+/** resampler interface */
+struct resampler_itfe {
+ /**
+ * reset resampler state
+ */
+ void (*reset)(struct resampler_itfe *resampler);
+ /**
+ * resample input from buffer provider and output at most *outFrameCount to out buffer.
+ * *outFrameCount is updated with the actual number of frames produced.
+ */
+ int (*resample_from_provider)(struct resampler_itfe *resampler,
+ int16_t *out,
+ size_t *outFrameCount);
+ /**
+ * resample at most *inFrameCount frames from in buffer and output at most
+ * *outFrameCount to out buffer. *inFrameCount and *outFrameCount are updated respectively
+ * with the number of frames remaining in input and written to output.
+ */
+ int (*resample_from_input)(struct resampler_itfe *resampler,
+ int16_t *in,
+ size_t *inFrameCount,
+ int16_t *out,
+ size_t *outFrameCount);
+ /**
+ * \return the latency introduced by the resampler in ns.
+ */
+ int32_t (*delay_ns)(struct resampler_itfe *resampler);
+};
+
+/**
+ * create a resampler according to input parameters passed.
+ * If resampler_buffer_provider is not NULL only resample_from_provider() can be called.
+ * If resampler_buffer_provider is NULL only resample_from_input() can be called.
+ */
+int create_resampler(uint32_t inSampleRate,
+ uint32_t outSampleRate,
+ uint32_t channelCount,
+ uint32_t quality,
+ struct resampler_buffer_provider *provider,
+ struct resampler_itfe **);
+
+/**
+ * release resampler resources.
+ */
+void release_resampler(struct resampler_itfe *);
+
+__END_DECLS
+
+#endif // ANDROID_RESAMPLER_H
diff --git a/include/audio_utils/sndfile.h b/include/audio_utils/sndfile.h
new file mode 100644
index 0000000..6346295
--- /dev/null
+++ b/include/audio_utils/sndfile.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AUDIO_UTIL_SNDFILE_H
+#define __AUDIO_UTIL_SNDFILE_H
+
+// This is a C library for reading and writing PCM .wav files. It is
+// influenced by other libraries such as libsndfile and audiofile, except is
+// much smaller and has an Apache 2.0 license.
+// The API should be familiar to clients of similar libraries, but there is
+// no guarantee that it will stay exactly source-code compatible with other libraries.
+
+#include <stdio.h>
+#include <sys/cdefs.h>
+
+/** \cond */
+__BEGIN_DECLS
+/** \endcond */
+
+// visible to clients
+typedef int sf_count_t;
+
+typedef struct {
+ sf_count_t frames;
+ int samplerate;
+ int channels;
+ int format;
+} SF_INFO;
+
+// opaque to clients
+typedef struct SNDFILE_ SNDFILE;
+
+// Access modes
+#define SFM_READ 1
+#define SFM_WRITE 2
+
+// Format
+#define SF_FORMAT_TYPEMASK 1
+#define SF_FORMAT_WAV 1
+#define SF_FORMAT_SUBMASK 14
+#define SF_FORMAT_PCM_16 2
+#define SF_FORMAT_PCM_U8 4
+#define SF_FORMAT_FLOAT 6
+#define SF_FORMAT_PCM_32 8
+#define SF_FORMAT_PCM_24 10
+
+/** Open stream */
+SNDFILE *sf_open(const char *path, int mode, SF_INFO *info);
+
+/** Close stream */
+void sf_close(SNDFILE *handle);
+
+/**
+ * Read interleaved frames
+ * \return actual number of frames read
+ */
+sf_count_t sf_readf_short(SNDFILE *handle, int16_t *ptr, sf_count_t desired);
+sf_count_t sf_readf_float(SNDFILE *handle, float *ptr, sf_count_t desired);
+sf_count_t sf_readf_int(SNDFILE *handle, int *ptr, sf_count_t desired);
+
+/**
+ * Write interleaved frames
+ * \return actual number of frames written
+ */
+sf_count_t sf_writef_short(SNDFILE *handle, const int16_t *ptr, sf_count_t desired);
+sf_count_t sf_writef_float(SNDFILE *handle, const float *ptr, sf_count_t desired);
+sf_count_t sf_writef_int(SNDFILE *handle, const int *ptr, sf_count_t desired);
+
+/** \cond */
+__END_DECLS
+/** \endcond */
+
+#endif /* __AUDIO_UTIL_SNDFILE_H */
diff --git a/include/audio_utils/spdif/FrameScanner.h b/include/audio_utils/spdif/FrameScanner.h
new file mode 100644
index 0000000..6d391ee
--- /dev/null
+++ b/include/audio_utils/spdif/FrameScanner.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_FRAME_SCANNER_H
+#define ANDROID_AUDIO_FRAME_SCANNER_H
+
+#include <stdint.h>
+
+namespace android {
+
+
+/**
+ * Scan a byte stream looking for the start of an encoded frame.
+ * Parse the sample rate and the size of the encoded frame.
+ * Buffer the sync header so it can be prepended to the remaining data.
+ *
+ * This is used directly by the SPDIFEncoder. External clients will
+ * generally not call this class.
+ */
+class FrameScanner {
+public:
+ FrameScanner(int dataType,
+ const uint8_t *syncBytes,
+ uint32_t syncLength,
+ uint32_t headerLength
+ );
+ virtual ~FrameScanner();
+
+ /**
+ * Pass each byte of the encoded stream to this scanner.
+ * @return true if a complete and valid header was detected
+ */
+ virtual bool scan(uint8_t byte);
+
+ /**
+ * @return address of where the sync header was stored by scan()
+ */
+ const uint8_t *getHeaderAddress() const { return mHeaderBuffer; }
+
+ /**
+ * @return number of bytes in sync header stored by scan()
+ */
+ size_t getHeaderSizeBytes() const { return mHeaderLength; }
+
+ /**
+ * @return sample rate of the encoded audio
+ */
+ uint32_t getSampleRate() const { return mSampleRate; }
+
+ /**
+ * Some formats, for example EAC3, are wrapped in data bursts that have
+ * a sample rate that is a multiple of the encoded sample rate.
+ * The default multiplier is 1.
+ * @return sample rate multiplier for the SP/DIF PCM data bursts
+ */
+ uint32_t getRateMultiplier() const { return mRateMultiplier; }
+
+ size_t getFrameSizeBytes() const { return mFrameSizeBytes; }
+
+ /**
+ * dataType is defined by the SPDIF standard for each format
+ */
+ int getDataType() const { return mDataType; }
+ int getDataTypeInfo() const { return mDataTypeInfo; }
+
+ virtual int getMaxChannels() const = 0;
+
+ virtual void resetBurst() = 0;
+
+ /**
+ * @return the number of pcm frames that correspond to one encoded frame
+ */
+ virtual int getMaxSampleFramesPerSyncFrame() const = 0;
+ virtual int getSampleFramesPerSyncFrame() const = 0;
+
+ /**
+ * @return true if this parsed frame must be the first frame in a data burst.
+ */
+ virtual bool isFirstInBurst() = 0;
+
+ /**
+ * If this returns false then the previous frame may or may not be the last frame.
+ * @return true if this parsed frame is definitely the last frame in a data burst.
+ */
+ virtual bool isLastInBurst() = 0;
+
+ /**
+ * Most compression types use a lengthCode expressed in bits.
+ */
+ virtual uint16_t convertBytesToLengthCode(uint16_t numBytes) const { return numBytes * 8; }
+
+protected:
+ uint32_t mBytesSkipped; // how many bytes were skipped looking for the start of a frame
+ const uint8_t *mSyncBytes; // pointer to the sync word specific to a format
+ uint32_t mSyncLength; // number of bytes in sync word
+ uint8_t mHeaderBuffer[32]; // a place to gather the relevant header bytes for parsing
+ uint32_t mHeaderLength; // the number of bytes we need to parse
+ uint32_t mCursor; // position in the mHeaderBuffer
+ uint32_t mFormatDumpCount; // used to thin out the debug dumps
+ uint32_t mSampleRate; // encoded sample rate
+ uint32_t mRateMultiplier; // SPDIF output data burst rate = msampleRate * mRateMultiplier
+ size_t mFrameSizeBytes; // encoded frame size
+ int mDataType; // as defined in IEC61937-2 paragraph 4.2
+ int mDataTypeInfo; // as defined in IEC61937-2 paragraph 4.1
+
+ /**
+ * Parse data in mHeaderBuffer.
+ * Sets mDataType, mFrameSizeBytes, mSampleRate, mRateMultiplier.
+ * @return true if the header is valid.
+ */
+ virtual bool parseHeader() = 0;
+
+};
+
+
+} // namespace android
+#endif // ANDROID_AUDIO_FRAME_SCANNER_H
diff --git a/include/audio_utils/spdif/SPDIFEncoder.h b/include/audio_utils/spdif/SPDIFEncoder.h
new file mode 100644
index 0000000..3c84d73
--- /dev/null
+++ b/include/audio_utils/spdif/SPDIFEncoder.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_SPDIF_ENCODER_H
+#define ANDROID_AUDIO_SPDIF_ENCODER_H
+
+#include <stdint.h>
+#include <system/audio.h>
+#include <audio_utils/spdif/FrameScanner.h>
+
+namespace android {
+
+/**
+ * Scan the incoming byte stream for a frame sync.
+ * Then wrap the encoded frame in a data burst and send it as if it were PCM.
+ * The receiver will see the data burst header and decode the wrapped frame.
+ */
+#define SPDIF_MAX_CHANNELS 8
+#define SPDIF_ENCODED_CHANNEL_COUNT 2
+
+class SPDIFEncoder {
+public:
+
+ explicit SPDIFEncoder(audio_format_t format);
+ // Defaults to AC3 format. Was in original API.
+ SPDIFEncoder();
+
+ virtual ~SPDIFEncoder();
+
+ /**
+ * Write encoded data to be wrapped for SPDIF.
+ * The compressed frames do not have to be aligned.
+ * @return number of bytes written or negative error
+ */
+ ssize_t write( const void* buffer, size_t numBytes );
+
+ /**
+ * Called by SPDIFEncoder when it is ready to output a data burst.
+ * Must be implemented in the subclass.
+ * @return number of bytes written or negative error
+ */
+ virtual ssize_t writeOutput( const void* buffer, size_t numBytes ) = 0;
+
+ /**
+ * Get ratio of the encoded data burst sample rate to the encoded rate.
+ * For example, EAC3 data bursts are 4X the encoded rate.
+ */
+ uint32_t getRateMultiplier() const { return mRateMultiplier; }
+
+ /**
+ * @return number of PCM frames in a data burst
+ */
+ uint32_t getBurstFrames() const { return mBurstFrames; }
+
+ /**
+ * @return number of bytes per PCM frame for the data burst
+ */
+ int getBytesPerOutputFrame();
+
+ /**
+ * @return true if we can wrap this format in an SPDIF stream
+ */
+ static bool isFormatSupported(audio_format_t format);
+
+ /**
+ * Discard any data in the buffer. Reset frame scanners.
+ * This should be called when seeking to a new position in the stream.
+ */
+ void reset();
+
+protected:
+ void clearBurstBuffer();
+ void writeBurstBufferShorts(const uint16_t* buffer, size_t numBytes);
+ void writeBurstBufferBytes(const uint8_t* buffer, size_t numBytes);
+ void sendZeroPad();
+ void flushBurstBuffer();
+ void startDataBurst();
+ size_t startSyncFrame();
+
+ // Works with various formats including AC3.
+ FrameScanner *mFramer;
+
+ uint32_t mSampleRate;
+ size_t mFrameSize; // size of sync frame in bytes
+ uint16_t *mBurstBuffer; // ALSA wants to get SPDIF data as shorts.
+ size_t mBurstBufferSizeBytes;
+ uint32_t mRateMultiplier;
+ uint32_t mBurstFrames;
+ size_t mByteCursor; // cursor into data burst
+ int mBitstreamNumber;
+ size_t mPayloadBytesPending; // number of bytes needed to finish burst
+ // state variable, true if scanning for start of frame
+ bool mScanning;
+
+ static const uint16_t kSPDIFSync1; // Pa
+ static const uint16_t kSPDIFSync2; // Pb
+};
+
+} // namespace android
+
+#endif // ANDROID_AUDIO_SPDIF_ENCODER_H
diff --git a/include/cutils/abort_socket.h b/include/cutils/abort_socket.h
new file mode 100644
index 0000000..fbb1112
--- /dev/null
+++ b/include/cutils/abort_socket.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Helper to perform abortable blocking operations on a socket:
+ * asocket_connect()
+ * asocket_accept()
+ * asocket_read()
+ * asocket_write()
+ * These calls are similar to the regular syscalls, but can be aborted with:
+ * asocket_abort()
+ *
+ * Calling close() on a regular POSIX socket does not abort blocked syscalls on
+ * that socket in other threads.
+ *
+ * After calling asocket_abort() the socket cannot be reused.
+ *
+ * Call asocket_destory() *after* all threads have finished with the socket to
+ * finish closing the socket and free the asocket structure.
+ *
+ * The helper is implemented by setting the socket non-blocking to initiate
+ * syscalls connect(), accept(), read(), write(), then using a blocking poll()
+ * on both the primary socket and a local pipe. This makes the poll() abortable
+ * by writing a byte to the local pipe in asocket_abort().
+ *
+ * asocket_create() sets the fd to non-blocking mode. It must not be changed to
+ * blocking mode.
+ *
+ * Using asocket will triple the number of file descriptors required per
+ * socket, due to the local pipe. It may be possible to use a global pipe per
+ * process rather than per socket, but we have not been able to come up with a
+ * race-free implementation yet.
+ *
+ * All functions except asocket_init() and asocket_destroy() are thread safe.
+ */
+
+#include <stdlib.h>
+#include <sys/socket.h>
+
+#ifndef __CUTILS_ABORT_SOCKET_H__
+#define __CUTILS_ABORT_SOCKET_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct asocket {
+ int fd; /* primary socket fd */
+ int abort_fd[2]; /* pipe used to abort */
+};
+
+/* Create an asocket from fd.
+ * Sets the socket to non-blocking mode.
+ * Returns NULL on error with errno set.
+ */
+struct asocket *asocket_init(int fd);
+
+/* Blocking socket I/O with timeout.
+ * Calling asocket_abort() from another thread will cause each of these
+ * functions to immediately return with value -1 and errno ECANCELED.
+ * timeout is in ms, use -1 to indicate no timeout. On timeout -1 is returned
+ * with errno ETIMEDOUT.
+ * EINTR is handled in-call.
+ * Other semantics are identical to the regular syscalls.
+ */
+int asocket_connect(struct asocket *s, const struct sockaddr *addr,
+ socklen_t addrlen, int timeout);
+
+int asocket_accept(struct asocket *s, struct sockaddr *addr,
+ socklen_t *addrlen, int timeout);
+
+int asocket_read(struct asocket *s, void *buf, size_t count, int timeout);
+
+int asocket_write(struct asocket *s, const void *buf, size_t count,
+ int timeout);
+
+/* Abort above calls and shutdown socket.
+ * Further I/O operations on this socket will immediately fail after this call.
+ * asocket_destroy() should be used to release resources once all threads
+ * have returned from blocking calls on the socket.
+ */
+void asocket_abort(struct asocket *s);
+
+/* Close socket and free asocket structure.
+ * Must not be called until all calls on this structure have completed.
+ */
+void asocket_destroy(struct asocket *s);
+
+#ifdef __cplusplus
+}
+#endif
+#endif //__CUTILS_ABORT_SOCKET__H__
diff --git a/include/cutils/android_reboot.h b/include/cutils/android_reboot.h
new file mode 100644
index 0000000..0c79be7
--- /dev/null
+++ b/include/cutils/android_reboot.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_ANDROID_REBOOT_H__
+#define __CUTILS_ANDROID_REBOOT_H__
+
+__BEGIN_DECLS
+
+/* Commands */
+#define ANDROID_RB_RESTART 0xDEAD0001
+#define ANDROID_RB_POWEROFF 0xDEAD0002
+#define ANDROID_RB_RESTART2 0xDEAD0003
+
+/* Flags */
+#define ANDROID_RB_FLAG_NO_SYNC 0x1
+#define ANDROID_RB_FLAG_NO_REMOUNT_RO 0x2
+
+int android_reboot(int cmd, int flags, char *arg);
+
+__END_DECLS
+
+#endif /* __CUTILS_ANDROID_REBOOT_H__ */
diff --git a/include/cutils/array.h b/include/cutils/array.h
new file mode 100644
index 0000000..d8d6fe6
--- /dev/null
+++ b/include/cutils/array.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * A pointer array which intelligently expands its capacity ad needed.
+ */
+
+#ifndef __ARRAY_H
+#define __ARRAY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+
+/** An array. */
+typedef struct Array Array;
+
+/** Constructs a new array. Returns NULL if we ran out of memory. */
+Array* arrayCreate();
+
+/** Frees an array. Does not free elements themselves. */
+void arrayFree(Array* array);
+
+/** Adds a pointer. Returns 0 is successful, < 0 otherwise. */
+int arrayAdd(Array* array, void* pointer);
+
+/** Gets the pointer at the specified index. */
+void* arrayGet(Array* array, int index);
+
+/** Removes the pointer at the given index and returns it. */
+void* arrayRemove(Array* array, int index);
+
+/** Sets pointer at the given index. Returns old pointer. */
+void* arraySet(Array* array, int index, void* pointer);
+
+/** Sets the array size. Sets new pointers to NULL. Returns 0 if successful, < 0 otherwise . */
+int arraySetSize(Array* array, int size);
+
+/** Returns the size of the given array. */
+int arraySize(Array* array);
+
+/**
+ * Returns a pointer to a C-style array which will be valid until this array
+ * changes.
+ */
+const void** arrayUnwrap(Array* array);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ARRAY_H */
\ No newline at end of file
diff --git a/include/cutils/ashmem.h b/include/cutils/ashmem.h
new file mode 100644
index 0000000..25b233e
--- /dev/null
+++ b/include/cutils/ashmem.h
@@ -0,0 +1,45 @@
+/* cutils/ashmem.h
+ **
+ ** Copyright 2008 The Android Open Source Project
+ **
+ ** This file is dual licensed. It may be redistributed and/or modified
+ ** under the terms of the Apache 2.0 License OR version 2 of the GNU
+ ** General Public License.
+ */
+
+#ifndef _CUTILS_ASHMEM_H
+#define _CUTILS_ASHMEM_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int ashmem_create_region(const char *name, size_t size);
+int ashmem_set_prot_region(int fd, int prot);
+int ashmem_pin_region(int fd, size_t offset, size_t len);
+int ashmem_unpin_region(int fd, size_t offset, size_t len);
+int ashmem_get_size_region(int fd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifndef __ASHMEMIOC /* in case someone included <linux/ashmem.h> too */
+
+#define ASHMEM_NAME_LEN 256
+
+#define ASHMEM_NAME_DEF "dev/ashmem"
+
+/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */
+#define ASHMEM_NOT_PURGED 0
+#define ASHMEM_WAS_PURGED 1
+
+/* Return values from ASHMEM_UNPIN: Is the mapping now pinned or unpinned? */
+#define ASHMEM_IS_UNPINNED 0
+#define ASHMEM_IS_PINNED 1
+
+#endif /* ! __ASHMEMIOC */
+
+#endif /* _CUTILS_ASHMEM_H */
diff --git a/include/cutils/atomic-arm.h b/include/cutils/atomic-arm.h
new file mode 100644
index 0000000..b9d639d
--- /dev/null
+++ b/include/cutils/atomic-arm.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_CUTILS_ATOMIC_ARM_H
+#define ANDROID_CUTILS_ATOMIC_ARM_H
+
+#include <stdint.h>
+
+#ifndef ANDROID_ATOMIC_INLINE
+#define ANDROID_ATOMIC_INLINE inline /* __attribute__((always_inline)) */
+#endif
+
+extern ANDROID_ATOMIC_INLINE void android_compiler_barrier()
+{
+ __asm__ __volatile__ ("" : : : "memory");
+}
+
+extern ANDROID_ATOMIC_INLINE void android_memory_barrier()
+{
+#if ANDROID_SMP == 0
+ android_compiler_barrier();
+#else
+ __asm__ __volatile__ ("dmb" : : : "memory");
+#endif
+}
+
+extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier()
+{
+#if ANDROID_SMP == 0
+ android_compiler_barrier();
+#else
+ __asm__ __volatile__ ("dmb st" : : : "memory");
+#endif
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
+{
+ int32_t value = *ptr;
+ android_memory_barrier();
+ return value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_release_load(volatile const int32_t *ptr)
+{
+ android_memory_barrier();
+ return *ptr;
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
+{
+ *ptr = value;
+ android_memory_barrier();
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_release_store(int32_t value, volatile int32_t *ptr)
+{
+ android_memory_barrier();
+ *ptr = value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_cas(int32_t old_value, int32_t new_value,
+ volatile int32_t *ptr)
+{
+ int32_t prev, status;
+ do {
+ __asm__ __volatile__ ("ldrex %0, [%3]\n"
+ "mov %1, #0\n"
+ "teq %0, %4\n"
+#ifdef __thumb2__
+ "it eq\n"
+#endif
+ "strexeq %1, %5, [%3]"
+ : "=&r" (prev), "=&r" (status), "+m"(*ptr)
+ : "r" (ptr), "Ir" (old_value), "r" (new_value)
+ : "cc");
+ } while (__builtin_expect(status != 0, 0));
+ return prev != old_value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_acquire_cas(int32_t old_value, int32_t new_value,
+ volatile int32_t *ptr)
+{
+ int status = android_atomic_cas(old_value, new_value, ptr);
+ android_memory_barrier();
+ return status;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_release_cas(int32_t old_value, int32_t new_value,
+ volatile int32_t *ptr)
+{
+ android_memory_barrier();
+ return android_atomic_cas(old_value, new_value, ptr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr)
+{
+ int32_t prev, tmp, status;
+ android_memory_barrier();
+ do {
+ __asm__ __volatile__ ("ldrex %0, [%4]\n"
+ "add %1, %0, %5\n"
+ "strex %2, %1, [%4]"
+ : "=&r" (prev), "=&r" (tmp),
+ "=&r" (status), "+m" (*ptr)
+ : "r" (ptr), "Ir" (increment)
+ : "cc");
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+
+extern ANDROID_ATOMIC_INLINE int32_t android_atomic_inc(volatile int32_t *addr)
+{
+ return android_atomic_add(1, addr);
+}
+
+extern ANDROID_ATOMIC_INLINE int32_t android_atomic_dec(volatile int32_t *addr)
+{
+ return android_atomic_add(-1, addr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_and(int32_t value, volatile int32_t *ptr)
+{
+ int32_t prev, tmp, status;
+ android_memory_barrier();
+ do {
+ __asm__ __volatile__ ("ldrex %0, [%4]\n"
+ "and %1, %0, %5\n"
+ "strex %2, %1, [%4]"
+ : "=&r" (prev), "=&r" (tmp),
+ "=&r" (status), "+m" (*ptr)
+ : "r" (ptr), "Ir" (value)
+ : "cc");
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_or(int32_t value, volatile int32_t *ptr)
+{
+ int32_t prev, tmp, status;
+ android_memory_barrier();
+ do {
+ __asm__ __volatile__ ("ldrex %0, [%4]\n"
+ "orr %1, %0, %5\n"
+ "strex %2, %1, [%4]"
+ : "=&r" (prev), "=&r" (tmp),
+ "=&r" (status), "+m" (*ptr)
+ : "r" (ptr), "Ir" (value)
+ : "cc");
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+
+#endif /* ANDROID_CUTILS_ATOMIC_ARM_H */
diff --git a/include/cutils/atomic-arm64.h b/include/cutils/atomic-arm64.h
new file mode 100644
index 0000000..4562ad0
--- /dev/null
+++ b/include/cutils/atomic-arm64.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef ANDROID_CUTILS_ATOMIC_AARCH64_H
+#define ANDROID_CUTILS_ATOMIC_AARCH64_H
+
+#include <stdint.h>
+
+#ifndef ANDROID_ATOMIC_INLINE
+#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline))
+#endif
+
+/*
+ TODOAArch64: Revisit the below functions and check for potential
+ optimizations using assembly code or otherwise.
+*/
+
+extern ANDROID_ATOMIC_INLINE
+void android_compiler_barrier(void)
+{
+ __asm__ __volatile__ ("" : : : "memory");
+}
+
+#if ANDROID_SMP == 0
+extern ANDROID_ATOMIC_INLINE
+void android_memory_barrier(void)
+{
+ android_compiler_barrier();
+}
+extern ANDROID_ATOMIC_INLINE
+void android_memory_store_barrier(void)
+{
+ android_compiler_barrier();
+}
+#else
+extern ANDROID_ATOMIC_INLINE
+void android_memory_barrier(void)
+{
+ __asm__ __volatile__ ("dmb ish" : : : "memory");
+}
+extern ANDROID_ATOMIC_INLINE
+void android_memory_store_barrier(void)
+{
+ __asm__ __volatile__ ("dmb ishst" : : : "memory");
+}
+#endif
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
+{
+ int32_t value = *ptr;
+ android_memory_barrier();
+ return value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_acquire_load64(volatile const int64_t *ptr)
+{
+ int64_t value = *ptr;
+ android_memory_barrier();
+ return value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_release_load(volatile const int32_t *ptr)
+{
+ android_memory_barrier();
+ return *ptr;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_release_load64(volatile const int64_t *ptr)
+{
+ android_memory_barrier();
+ return *ptr;
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
+{
+ *ptr = value;
+ android_memory_barrier();
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_acquire_store64(int64_t value, volatile int64_t *ptr)
+{
+ *ptr = value;
+ android_memory_barrier();
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_release_store(int32_t value, volatile int32_t *ptr)
+{
+ android_memory_barrier();
+ *ptr = value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_release_store64(int64_t value, volatile int64_t *ptr)
+{
+ android_memory_barrier();
+ *ptr = value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_cas(int32_t old_value, int32_t new_value,
+ volatile int32_t *ptr)
+{
+ return __sync_val_compare_and_swap(ptr, old_value, new_value) != old_value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_cas64(int64_t old_value, int64_t new_value,
+ volatile int64_t *ptr)
+{
+ return __sync_val_compare_and_swap(ptr, old_value, new_value) != old_value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_acquire_cas(int32_t old_value, int32_t new_value,
+ volatile int32_t *ptr)
+{
+ int status = android_atomic_cas(old_value, new_value, ptr);
+ android_memory_barrier();
+ return status;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_acquire_cas64(int64_t old_value, int64_t new_value,
+ volatile int64_t *ptr)
+{
+ int status = android_atomic_cas64(old_value, new_value, ptr);
+ android_memory_barrier();
+ return status;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_release_cas(int32_t old_value, int32_t new_value,
+ volatile int32_t *ptr)
+{
+ android_memory_barrier();
+ return android_atomic_cas(old_value, new_value, ptr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_release_cas64(int64_t old_value, int64_t new_value,
+ volatile int64_t *ptr)
+{
+ android_memory_barrier();
+ return android_atomic_cas64(old_value, new_value, ptr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr)
+{
+ int32_t prev, status;
+ android_memory_barrier();
+ do {
+ prev = *ptr;
+ status = android_atomic_cas(prev, prev + increment, ptr);
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_inc(volatile int32_t *addr)
+{
+ return android_atomic_add(1, addr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_dec(volatile int32_t *addr)
+{
+ return android_atomic_add(-1, addr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_and(int32_t value, volatile int32_t *ptr)
+{
+ int32_t prev, status;
+ android_memory_barrier();
+ do {
+ prev = *ptr;
+ status = android_atomic_cas(prev, prev & value, ptr);
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_or(int32_t value, volatile int32_t *ptr)
+{
+ int32_t prev, status;
+ android_memory_barrier();
+ do {
+ prev = *ptr;
+ status = android_atomic_cas(prev, prev | value, ptr);
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+
+#endif /* ANDROID_CUTILS_ATOMIC_AARCH64_H */
diff --git a/include/cutils/atomic-inline.h b/include/cutils/atomic-inline.h
new file mode 100644
index 0000000..5c03bd6
--- /dev/null
+++ b/include/cutils/atomic-inline.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_CUTILS_ATOMIC_INLINE_H
+#define ANDROID_CUTILS_ATOMIC_INLINE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Inline declarations and macros for some special-purpose atomic
+ * operations. These are intended for rare circumstances where a
+ * memory barrier needs to be issued inline rather than as a function
+ * call.
+ *
+ * Most code should not use these.
+ *
+ * Anything that does include this file must set ANDROID_SMP to either
+ * 0 or 1, indicating compilation for UP or SMP, respectively.
+ *
+ * Macros defined in this header:
+ *
+ * void ANDROID_MEMBAR_FULL(void)
+ * Full memory barrier. Provides a compiler reordering barrier, and
+ * on SMP systems emits an appropriate instruction.
+ */
+
+#if !defined(ANDROID_SMP)
+# error "Must define ANDROID_SMP before including atomic-inline.h"
+#endif
+#if defined(__aarch64__)
+#include <cutils/atomic-arm64.h>
+#elif defined(__arm__)
+#include <cutils/atomic-arm.h>
+#elif defined(__i386__) || defined(__x86_64__)
+#include <cutils/atomic-x86.h>
+#elif defined(__sh__)
+/* implementation is in atomic-android-sh.c */
+#else
+#error atomic operations are unsupported
+#endif
+
+#if ANDROID_SMP == 0
+#define ANDROID_MEMBAR_FULL android_compiler_barrier
+#else
+#define ANDROID_MEMBAR_FULL android_memory_barrier
+#endif
+
+#if ANDROID_SMP == 0
+#define ANDROID_MEMBAR_STORE android_compiler_barrier
+#else
+#define ANDROID_MEMBAR_STORE android_memory_store_barrier
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ANDROID_CUTILS_ATOMIC_INLINE_H */
diff --git a/include/cutils/atomic-x86.h b/include/cutils/atomic-x86.h
new file mode 100644
index 0000000..438012e
--- /dev/null
+++ b/include/cutils/atomic-x86.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_CUTILS_ATOMIC_X86_H
+#define ANDROID_CUTILS_ATOMIC_X86_H
+
+#include <stdint.h>
+
+extern inline void android_compiler_barrier(void)
+{
+ __asm__ __volatile__ ("" : : : "memory");
+}
+
+#if ANDROID_SMP == 0
+extern inline void android_memory_barrier(void)
+{
+ android_compiler_barrier();
+}
+extern inline void android_memory_store_barrier(void)
+{
+ android_compiler_barrier();
+}
+#else
+extern inline void android_memory_barrier(void)
+{
+ __asm__ __volatile__ ("mfence" : : : "memory");
+}
+extern inline void android_memory_store_barrier(void)
+{
+ android_compiler_barrier();
+}
+#endif
+
+extern inline int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
+{
+ int32_t value = *ptr;
+ android_compiler_barrier();
+ return value;
+}
+
+extern inline int32_t android_atomic_release_load(volatile const int32_t *ptr)
+{
+ android_memory_barrier();
+ return *ptr;
+}
+
+extern inline void android_atomic_acquire_store(int32_t value,
+ volatile int32_t *ptr)
+{
+ *ptr = value;
+ android_memory_barrier();
+}
+
+extern inline void android_atomic_release_store(int32_t value,
+ volatile int32_t *ptr)
+{
+ android_compiler_barrier();
+ *ptr = value;
+}
+
+extern inline int android_atomic_cas(int32_t old_value, int32_t new_value,
+ volatile int32_t *ptr)
+{
+ int32_t prev;
+ __asm__ __volatile__ ("lock; cmpxchgl %1, %2"
+ : "=a" (prev)
+ : "q" (new_value), "m" (*ptr), "0" (old_value)
+ : "memory");
+ return prev != old_value;
+}
+
+extern inline int android_atomic_acquire_cas(int32_t old_value,
+ int32_t new_value,
+ volatile int32_t *ptr)
+{
+ /* Loads are not reordered with other loads. */
+ return android_atomic_cas(old_value, new_value, ptr);
+}
+
+extern inline int android_atomic_release_cas(int32_t old_value,
+ int32_t new_value,
+ volatile int32_t *ptr)
+{
+ /* Stores are not reordered with other stores. */
+ return android_atomic_cas(old_value, new_value, ptr);
+}
+
+extern inline int32_t android_atomic_add(int32_t increment,
+ volatile int32_t *ptr)
+{
+ __asm__ __volatile__ ("lock; xaddl %0, %1"
+ : "+r" (increment), "+m" (*ptr)
+ : : "memory");
+ /* increment now holds the old value of *ptr */
+ return increment;
+}
+
+extern inline int32_t android_atomic_inc(volatile int32_t *addr)
+{
+ return android_atomic_add(1, addr);
+}
+
+extern inline int32_t android_atomic_dec(volatile int32_t *addr)
+{
+ return android_atomic_add(-1, addr);
+}
+
+extern inline int32_t android_atomic_and(int32_t value,
+ volatile int32_t *ptr)
+{
+ int32_t prev, status;
+ do {
+ prev = *ptr;
+ status = android_atomic_cas(prev, prev & value, ptr);
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+
+extern inline int32_t android_atomic_or(int32_t value, volatile int32_t *ptr)
+{
+ int32_t prev, status;
+ do {
+ prev = *ptr;
+ status = android_atomic_cas(prev, prev | value, ptr);
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+
+#endif /* ANDROID_CUTILS_ATOMIC_X86_H */
diff --git a/include/cutils/atomic.h b/include/cutils/atomic.h
new file mode 100644
index 0000000..ae42eb8
--- /dev/null
+++ b/include/cutils/atomic.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_CUTILS_ATOMIC_H
+#define ANDROID_CUTILS_ATOMIC_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * A handful of basic atomic operations. The appropriate pthread
+ * functions should be used instead of these whenever possible.
+ *
+ * The "acquire" and "release" terms can be defined intuitively in terms
+ * of the placement of memory barriers in a simple lock implementation:
+ * - wait until compare-and-swap(lock-is-free --> lock-is-held) succeeds
+ * - barrier
+ * - [do work]
+ * - barrier
+ * - store(lock-is-free)
+ * In very crude terms, the initial (acquire) barrier prevents any of the
+ * "work" from happening before the lock is held, and the later (release)
+ * barrier ensures that all of the work happens before the lock is released.
+ * (Think of cached writes, cache read-ahead, and instruction reordering
+ * around the CAS and store instructions.)
+ *
+ * The barriers must apply to both the compiler and the CPU. Note it is
+ * legal for instructions that occur before an "acquire" barrier to be
+ * moved down below it, and for instructions that occur after a "release"
+ * barrier to be moved up above it.
+ *
+ * The ARM-driven implementation we use here is short on subtlety,
+ * and actually requests a full barrier from the compiler and the CPU.
+ * The only difference between acquire and release is in whether they
+ * are issued before or after the atomic operation with which they
+ * are associated. To ease the transition to C/C++ atomic intrinsics,
+ * you should not rely on this, and instead assume that only the minimal
+ * acquire/release protection is provided.
+ *
+ * NOTE: all int32_t* values are expected to be aligned on 32-bit boundaries.
+ * If they are not, atomicity is not guaranteed.
+ */
+
+/*
+ * Basic arithmetic and bitwise operations. These all provide a
+ * barrier with "release" ordering, and return the previous value.
+ *
+ * These have the same characteristics (e.g. what happens on overflow)
+ * as the equivalent non-atomic C operations.
+ */
+int32_t android_atomic_inc(volatile int32_t* addr);
+int32_t android_atomic_dec(volatile int32_t* addr);
+int32_t android_atomic_add(int32_t value, volatile int32_t* addr);
+int32_t android_atomic_and(int32_t value, volatile int32_t* addr);
+int32_t android_atomic_or(int32_t value, volatile int32_t* addr);
+
+/*
+ * Perform an atomic load with "acquire" or "release" ordering.
+ *
+ * This is only necessary if you need the memory barrier. A 32-bit read
+ * from a 32-bit aligned address is atomic on all supported platforms.
+ */
+int32_t android_atomic_acquire_load(volatile const int32_t* addr);
+int32_t android_atomic_release_load(volatile const int32_t* addr);
+
+/*
+ * Perform an atomic store with "acquire" or "release" ordering.
+ *
+ * This is only necessary if you need the memory barrier. A 32-bit write
+ * to a 32-bit aligned address is atomic on all supported platforms.
+ */
+void android_atomic_acquire_store(int32_t value, volatile int32_t* addr);
+void android_atomic_release_store(int32_t value, volatile int32_t* addr);
+
+/*
+ * Compare-and-set operation with "acquire" or "release" ordering.
+ *
+ * This returns zero if the new value was successfully stored, which will
+ * only happen when *addr == oldvalue.
+ *
+ * (The return value is inverted from implementations on other platforms,
+ * but matches the ARM ldrex/strex result.)
+ *
+ * Implementations that use the release CAS in a loop may be less efficient
+ * than possible, because we re-issue the memory barrier on each iteration.
+ */
+int android_atomic_acquire_cas(int32_t oldvalue, int32_t newvalue,
+ volatile int32_t* addr);
+int android_atomic_release_cas(int32_t oldvalue, int32_t newvalue,
+ volatile int32_t* addr);
+
+/*
+ * Aliases for code using an older version of this header. These are now
+ * deprecated and should not be used. The definitions will be removed
+ * in a future release.
+ */
+#define android_atomic_write android_atomic_release_store
+#define android_atomic_cmpxchg android_atomic_release_cas
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // ANDROID_CUTILS_ATOMIC_H
diff --git a/include/cutils/bitops.h b/include/cutils/bitops.h
new file mode 100644
index 0000000..38d2840
--- /dev/null
+++ b/include/cutils/bitops.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_BITOPS_H
+#define __CUTILS_BITOPS_H
+
+#include <stdbool.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+static inline int popcount(unsigned int x) {
+ return __builtin_popcount(x);
+}
+
+static inline int popcountl(unsigned long x) {
+ return __builtin_popcountl(x);
+}
+
+static inline int popcountll(unsigned long long x) {
+ return __builtin_popcountll(x);
+}
+
+__END_DECLS
+
+#endif /* __CUTILS_BITOPS_H */
diff --git a/include/cutils/compiler.h b/include/cutils/compiler.h
new file mode 100644
index 0000000..70f884a
--- /dev/null
+++ b/include/cutils/compiler.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_CUTILS_COMPILER_H
+#define ANDROID_CUTILS_COMPILER_H
+
+/*
+ * helps the compiler's optimizer predicting branches
+ */
+
+#ifdef __cplusplus
+# define CC_LIKELY( exp ) (__builtin_expect( !!(exp), true ))
+# define CC_UNLIKELY( exp ) (__builtin_expect( !!(exp), false ))
+#else
+# define CC_LIKELY( exp ) (__builtin_expect( !!(exp), 1 ))
+# define CC_UNLIKELY( exp ) (__builtin_expect( !!(exp), 0 ))
+#endif
+
+/**
+ * exports marked symbols
+ *
+ * if used on a C++ class declaration, this macro must be inserted
+ * after the "class" keyword. For instance:
+ *
+ * template <typename TYPE>
+ * class ANDROID_API Singleton { }
+ */
+
+#define ANDROID_API __attribute__((visibility("default")))
+
+#endif // ANDROID_CUTILS_COMPILER_H
diff --git a/include/cutils/config_utils.h b/include/cutils/config_utils.h
new file mode 100644
index 0000000..30e762f
--- /dev/null
+++ b/include/cutils/config_utils.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_CONFIG_UTILS_H
+#define __CUTILS_CONFIG_UTILS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct cnode cnode;
+
+
+struct cnode
+{
+ cnode *next;
+ cnode *first_child;
+ cnode *last_child;
+ const char *name;
+ const char *value;
+};
+
+/* parse a text string into a config node tree */
+void config_load(cnode *root, char *data);
+
+/* parse a file into a config node tree */
+void config_load_file(cnode *root, const char *fn);
+
+/* create a single config node */
+cnode* config_node(const char *name, const char *value);
+
+/* locate a named child of a config node */
+cnode* config_find(cnode *root, const char *name);
+
+/* look up a child by name and return the boolean value */
+int config_bool(cnode *root, const char *name, int _default);
+
+/* look up a child by name and return the string value */
+const char* config_str(cnode *root, const char *name, const char *_default);
+
+/* add a named child to a config node (or modify it if it already exists) */
+void config_set(cnode *root, const char *name, const char *value);
+
+/* free a config node tree */
+void config_free(cnode *root);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/cutils/cpu_info.h b/include/cutils/cpu_info.h
new file mode 100644
index 0000000..e1170e4
--- /dev/null
+++ b/include/cutils/cpu_info.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_CPU_INFO_H
+#define __CUTILS_CPU_INFO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* returns a string contiaining an ASCII representation of the CPU serial number,
+** or NULL if cpu info not available.
+** The string is a static variable, so don't call free() on it.
+*/
+extern const char* get_cpu_serial_number(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_CPU_INFO_H */
diff --git a/include/cutils/dir_hash.h b/include/cutils/dir_hash.h
new file mode 100644
index 0000000..fbb4d02
--- /dev/null
+++ b/include/cutils/dir_hash.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+typedef enum {
+ SHA_1,
+} HashAlgorithm;
+
+int get_file_hash(HashAlgorithm algorithm, const char *path,
+ char *output_string, size_t max_output_string);
+
+int get_recursive_hash_manifest(HashAlgorithm algorithm,
+ const char *directory_path,
+ char **output_string);
diff --git a/include/cutils/dlmalloc.h b/include/cutils/dlmalloc.h
new file mode 100644
index 0000000..1b642d2
--- /dev/null
+++ b/include/cutils/dlmalloc.h
@@ -0,0 +1,655 @@
+/*
+ Default header file for malloc-2.8.x, written by Doug Lea
+ and released to the public domain, as explained at
+ http://creativecommons.org/licenses/publicdomain.
+
+ last update: Mon Aug 15 08:55:52 2005 Doug Lea (dl at gee)
+
+ This header is for ANSI C/C++ only. You can set any of
+ the following #defines before including:
+
+ * If USE_DL_PREFIX is defined, it is assumed that malloc.c
+ was also compiled with this option, so all routines
+ have names starting with "dl".
+
+ * If HAVE_USR_INCLUDE_MALLOC_H is defined, it is assumed that this
+ file will be #included AFTER <malloc.h>. This is needed only if
+ your system defines a struct mallinfo that is incompatible with the
+ standard one declared here. Otherwise, you can include this file
+ INSTEAD of your system system <malloc.h>. At least on ANSI, all
+ declarations should be compatible with system versions
+
+ * If MSPACES is defined, declarations for mspace versions are included.
+*/
+
+#ifndef MALLOC_280_H
+#define MALLOC_280_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h> /* for size_t */
+
+#if !ONLY_MSPACES
+
+/* Check an additional macro for the five primary functions */
+#if !defined(USE_DL_PREFIX)
+#define dlcalloc calloc
+#define dlfree free
+#define dlmalloc malloc
+#define dlmemalign memalign
+#define dlrealloc realloc
+#endif
+
+#ifndef USE_DL_PREFIX
+#define dlvalloc valloc
+#define dlpvalloc pvalloc
+#define dlmallinfo mallinfo
+#define dlmallopt mallopt
+#define dlmalloc_trim malloc_trim
+#define dlmalloc_walk_free_pages \
+ malloc_walk_free_pages
+#define dlmalloc_walk_heap \
+ malloc_walk_heap
+#define dlmalloc_stats malloc_stats
+#define dlmalloc_usable_size malloc_usable_size
+#define dlmalloc_footprint malloc_footprint
+#define dlmalloc_max_allowed_footprint \
+ malloc_max_allowed_footprint
+#define dlmalloc_set_max_allowed_footprint \
+ malloc_set_max_allowed_footprint
+#define dlmalloc_max_footprint malloc_max_footprint
+#define dlindependent_calloc independent_calloc
+#define dlindependent_comalloc independent_comalloc
+#endif /* USE_DL_PREFIX */
+
+
+/*
+ malloc(size_t n)
+ Returns a pointer to a newly allocated chunk of at least n bytes, or
+ null if no space is available, in which case errno is set to ENOMEM
+ on ANSI C systems.
+
+ If n is zero, malloc returns a minimum-sized chunk. (The minimum
+ size is 16 bytes on most 32bit systems, and 32 bytes on 64bit
+ systems.) Note that size_t is an unsigned type, so calls with
+ arguments that would be negative if signed are interpreted as
+ requests for huge amounts of space, which will often fail. The
+ maximum supported value of n differs across systems, but is in all
+ cases less than the maximum representable value of a size_t.
+*/
+void* dlmalloc(size_t);
+
+/*
+ free(void* p)
+ Releases the chunk of memory pointed to by p, that had been previously
+ allocated using malloc or a related routine such as realloc.
+ It has no effect if p is null. If p was not malloced or already
+ freed, free(p) will by default cuase the current program to abort.
+*/
+void dlfree(void*);
+
+/*
+ calloc(size_t n_elements, size_t element_size);
+ Returns a pointer to n_elements * element_size bytes, with all locations
+ set to zero.
+*/
+void* dlcalloc(size_t, size_t);
+
+/*
+ realloc(void* p, size_t n)
+ Returns a pointer to a chunk of size n that contains the same data
+ as does chunk p up to the minimum of (n, p's size) bytes, or null
+ if no space is available.
+
+ The returned pointer may or may not be the same as p. The algorithm
+ prefers extending p in most cases when possible, otherwise it
+ employs the equivalent of a malloc-copy-free sequence.
+
+ If p is null, realloc is equivalent to malloc.
+
+ If space is not available, realloc returns null, errno is set (if on
+ ANSI) and p is NOT freed.
+
+ if n is for fewer bytes than already held by p, the newly unused
+ space is lopped off and freed if possible. realloc with a size
+ argument of zero (re)allocates a minimum-sized chunk.
+
+ The old unix realloc convention of allowing the last-free'd chunk
+ to be used as an argument to realloc is not supported.
+*/
+
+void* dlrealloc(void*, size_t);
+
+/*
+ memalign(size_t alignment, size_t n);
+ Returns a pointer to a newly allocated chunk of n bytes, aligned
+ in accord with the alignment argument.
+
+ The alignment argument should be a power of two. If the argument is
+ not a power of two, the nearest greater power is used.
+ 8-byte alignment is guaranteed by normal malloc calls, so don't
+ bother calling memalign with an argument of 8 or less.
+
+ Overreliance on memalign is a sure way to fragment space.
+*/
+void* dlmemalign(size_t, size_t);
+
+/*
+ valloc(size_t n);
+ Equivalent to memalign(pagesize, n), where pagesize is the page
+ size of the system. If the pagesize is unknown, 4096 is used.
+*/
+void* dlvalloc(size_t);
+
+/*
+ mallopt(int parameter_number, int parameter_value)
+ Sets tunable parameters The format is to provide a
+ (parameter-number, parameter-value) pair. mallopt then sets the
+ corresponding parameter to the argument value if it can (i.e., so
+ long as the value is meaningful), and returns 1 if successful else
+ 0. SVID/XPG/ANSI defines four standard param numbers for mallopt,
+ normally defined in malloc.h. None of these are use in this malloc,
+ so setting them has no effect. But this malloc also supports other
+ options in mallopt:
+
+ Symbol param # default allowed param values
+ M_TRIM_THRESHOLD -1 2*1024*1024 any (-1U disables trimming)
+ M_GRANULARITY -2 page size any power of 2 >= page size
+ M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support)
+*/
+int dlmallopt(int, int);
+
+#define M_TRIM_THRESHOLD (-1)
+#define M_GRANULARITY (-2)
+#define M_MMAP_THRESHOLD (-3)
+
+
+/*
+ malloc_footprint();
+ Returns the number of bytes obtained from the system. The total
+ number of bytes allocated by malloc, realloc etc., is less than this
+ value. Unlike mallinfo, this function returns only a precomputed
+ result, so can be called frequently to monitor memory consumption.
+ Even if locks are otherwise defined, this function does not use them,
+ so results might not be up to date.
+*/
+size_t dlmalloc_footprint();
+
+/*
+ malloc_max_allowed_footprint();
+ Returns the number of bytes that the heap is allowed to obtain
+ from the system. malloc_footprint() should always return a
+ size less than or equal to max_allowed_footprint, unless the
+ max_allowed_footprint was set to a value smaller than the
+ footprint at the time.
+
+ This function is only available if dlmalloc.c was compiled
+ with USE_MAX_ALLOWED_FOOTPRINT set.
+*/
+size_t dlmalloc_max_allowed_footprint();
+
+/*
+ malloc_set_max_allowed_footprint();
+ Set the maximum number of bytes that the heap is allowed to
+ obtain from the system. The size will be rounded up to a whole
+ page, and the rounded number will be returned from future calls
+ to malloc_max_allowed_footprint(). If the new max_allowed_footprint
+ is larger than the current footprint, the heap will never grow
+ larger than max_allowed_footprint. If the new max_allowed_footprint
+ is smaller than the current footprint, the heap will not grow
+ further.
+
+ This function is only available if dlmalloc.c was compiled
+ with USE_MAX_ALLOWED_FOOTPRINT set.
+
+ TODO: try to force the heap to give up memory in the shrink case,
+ and update this comment once that happens.
+*/
+void dlmalloc_set_max_allowed_footprint(size_t bytes);
+
+/*
+ malloc_max_footprint();
+ Returns the maximum number of bytes obtained from the system. This
+ value will be greater than current footprint if deallocated space
+ has been reclaimed by the system. The peak number of bytes allocated
+ by malloc, realloc etc., is less than this value. Unlike mallinfo,
+ this function returns only a precomputed result, so can be called
+ frequently to monitor memory consumption. Even if locks are
+ otherwise defined, this function does not use them, so results might
+ not be up to date.
+*/
+size_t dlmalloc_max_footprint(void);
+
+#if !NO_MALLINFO
+/*
+ mallinfo()
+ Returns (by copy) a struct containing various summary statistics:
+
+ arena: current total non-mmapped bytes allocated from system
+ ordblks: the number of free chunks
+ smblks: always zero.
+ hblks: current number of mmapped regions
+ hblkhd: total bytes held in mmapped regions
+ usmblks: the maximum total allocated space. This will be greater
+ than current total if trimming has occurred.
+ fsmblks: always zero
+ uordblks: current total allocated space (normal or mmapped)
+ fordblks: total free space
+ keepcost: the maximum number of bytes that could ideally be released
+ back to system via malloc_trim. ("ideally" means that
+ it ignores page restrictions etc.)
+
+ Because these fields are ints, but internal bookkeeping may
+ be kept as longs, the reported values may wrap around zero and
+ thus be inaccurate.
+*/
+#ifndef HAVE_USR_INCLUDE_MALLOC_H
+#ifndef _MALLOC_H_
+#ifndef MALLINFO_FIELD_TYPE
+#define MALLINFO_FIELD_TYPE size_t
+#endif /* MALLINFO_FIELD_TYPE */
+struct mallinfo {
+ MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */
+ MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */
+ MALLINFO_FIELD_TYPE smblks; /* always 0 */
+ MALLINFO_FIELD_TYPE hblks; /* always 0 */
+ MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */
+ MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */
+ MALLINFO_FIELD_TYPE fsmblks; /* always 0 */
+ MALLINFO_FIELD_TYPE uordblks; /* total allocated space */
+ MALLINFO_FIELD_TYPE fordblks; /* total free space */
+ MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */
+};
+#endif /* _MALLOC_H_ */
+#endif /* HAVE_USR_INCLUDE_MALLOC_H */
+
+struct mallinfo dlmallinfo(void);
+#endif /* NO_MALLINFO */
+
+/*
+ independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);
+
+ independent_calloc is similar to calloc, but instead of returning a
+ single cleared space, it returns an array of pointers to n_elements
+ independent elements that can hold contents of size elem_size, each
+ of which starts out cleared, and can be independently freed,
+ realloc'ed etc. The elements are guaranteed to be adjacently
+ allocated (this is not guaranteed to occur with multiple callocs or
+ mallocs), which may also improve cache locality in some
+ applications.
+
+ The "chunks" argument is optional (i.e., may be null, which is
+ probably the most typical usage). If it is null, the returned array
+ is itself dynamically allocated and should also be freed when it is
+ no longer needed. Otherwise, the chunks array must be of at least
+ n_elements in length. It is filled in with the pointers to the
+ chunks.
+
+ In either case, independent_calloc returns this pointer array, or
+ null if the allocation failed. If n_elements is zero and "chunks"
+ is null, it returns a chunk representing an array with zero elements
+ (which should be freed if not wanted).
+
+ Each element must be individually freed when it is no longer
+ needed. If you'd like to instead be able to free all at once, you
+ should instead use regular calloc and assign pointers into this
+ space to represent elements. (In this case though, you cannot
+ independently free elements.)
+
+ independent_calloc simplifies and speeds up implementations of many
+ kinds of pools. It may also be useful when constructing large data
+ structures that initially have a fixed number of fixed-sized nodes,
+ but the number is not known at compile time, and some of the nodes
+ may later need to be freed. For example:
+
+ struct Node { int item; struct Node* next; };
+
+ struct Node* build_list() {
+ struct Node** pool;
+ int n = read_number_of_nodes_needed();
+ if (n <= 0) return 0;
+ pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
+ if (pool == 0) die();
+ // organize into a linked list...
+ struct Node* first = pool[0];
+ for (i = 0; i < n-1; ++i)
+ pool[i]->next = pool[i+1];
+ free(pool); // Can now free the array (or not, if it is needed later)
+ return first;
+ }
+*/
+void** dlindependent_calloc(size_t, size_t, void**);
+
+/*
+ independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
+
+ independent_comalloc allocates, all at once, a set of n_elements
+ chunks with sizes indicated in the "sizes" array. It returns
+ an array of pointers to these elements, each of which can be
+ independently freed, realloc'ed etc. The elements are guaranteed to
+ be adjacently allocated (this is not guaranteed to occur with
+ multiple callocs or mallocs), which may also improve cache locality
+ in some applications.
+
+ The "chunks" argument is optional (i.e., may be null). If it is null
+ the returned array is itself dynamically allocated and should also
+ be freed when it is no longer needed. Otherwise, the chunks array
+ must be of at least n_elements in length. It is filled in with the
+ pointers to the chunks.
+
+ In either case, independent_comalloc returns this pointer array, or
+ null if the allocation failed. If n_elements is zero and chunks is
+ null, it returns a chunk representing an array with zero elements
+ (which should be freed if not wanted).
+
+ Each element must be individually freed when it is no longer
+ needed. If you'd like to instead be able to free all at once, you
+ should instead use a single regular malloc, and assign pointers at
+ particular offsets in the aggregate space. (In this case though, you
+ cannot independently free elements.)
+
+ independent_comallac differs from independent_calloc in that each
+ element may have a different size, and also that it does not
+ automatically clear elements.
+
+ independent_comalloc can be used to speed up allocation in cases
+ where several structs or objects must always be allocated at the
+ same time. For example:
+
+ struct Head { ... }
+ struct Foot { ... }
+
+ void send_message(char* msg) {
+ int msglen = strlen(msg);
+ size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
+ void* chunks[3];
+ if (independent_comalloc(3, sizes, chunks) == 0)
+ die();
+ struct Head* head = (struct Head*)(chunks[0]);
+ char* body = (char*)(chunks[1]);
+ struct Foot* foot = (struct Foot*)(chunks[2]);
+ // ...
+ }
+
+ In general though, independent_comalloc is worth using only for
+ larger values of n_elements. For small values, you probably won't
+ detect enough difference from series of malloc calls to bother.
+
+ Overuse of independent_comalloc can increase overall memory usage,
+ since it cannot reuse existing noncontiguous small chunks that
+ might be available for some of the elements.
+*/
+void** dlindependent_comalloc(size_t, size_t*, void**);
+
+
+/*
+ pvalloc(size_t n);
+ Equivalent to valloc(minimum-page-that-holds(n)), that is,
+ round up n to nearest pagesize.
+ */
+void* dlpvalloc(size_t);
+
+/*
+ malloc_trim(size_t pad);
+
+ If possible, gives memory back to the system (via negative arguments
+ to sbrk) if there is unused memory at the `high' end of the malloc
+ pool or in unused MMAP segments. You can call this after freeing
+ large blocks of memory to potentially reduce the system-level memory
+ requirements of a program. However, it cannot guarantee to reduce
+ memory. Under some allocation patterns, some large free blocks of
+ memory will be locked between two used chunks, so they cannot be
+ given back to the system.
+
+ The `pad' argument to malloc_trim represents the amount of free
+ trailing space to leave untrimmed. If this argument is zero, only
+ the minimum amount of memory to maintain internal data structures
+ will be left. Non-zero arguments can be supplied to maintain enough
+ trailing space to service future expected allocations without having
+ to re-obtain memory from the system.
+
+ Malloc_trim returns 1 if it actually released any memory, else 0.
+*/
+int dlmalloc_trim(size_t);
+
+/*
+ malloc_walk_free_pages(handler, harg)
+
+ Calls the provided handler on each free region in the heap. The
+ memory between start and end are guaranteed not to contain any
+ important data, so the handler is free to alter the contents
+ in any way. This can be used to advise the OS that large free
+ regions may be swapped out.
+
+ The value in harg will be passed to each call of the handler.
+ */
+void dlmalloc_walk_free_pages(void(*handler)(void *start, void *end, void *arg),
+ void *harg);
+
+/*
+ malloc_walk_heap(handler, harg)
+
+ Calls the provided handler on each object or free region in the
+ heap. The handler will receive the chunk pointer and length, the
+ object pointer and length, and the value in harg on each call.
+ */
+void dlmalloc_walk_heap(void(*handler)(const void *chunkptr, size_t chunklen,
+ const void *userptr, size_t userlen,
+ void *arg),
+ void *harg);
+
+/*
+ malloc_usable_size(void* p);
+
+ Returns the number of bytes you can actually use in
+ an allocated chunk, which may be more than you requested (although
+ often not) due to alignment and minimum size constraints.
+ You can use this many bytes without worrying about
+ overwriting other allocated objects. This is not a particularly great
+ programming practice. malloc_usable_size can be more useful in
+ debugging and assertions, for example:
+
+ p = malloc(n);
+ assert(malloc_usable_size(p) >= 256);
+*/
+size_t dlmalloc_usable_size(void*);
+
+/*
+ malloc_stats();
+ Prints on stderr the amount of space obtained from the system (both
+ via sbrk and mmap), the maximum amount (which may be more than
+ current if malloc_trim and/or munmap got called), and the current
+ number of bytes allocated via malloc (or realloc, etc) but not yet
+ freed. Note that this is the number of bytes allocated, not the
+ number requested. It will be larger than the number requested
+ because of alignment and bookkeeping overhead. Because it includes
+ alignment wastage as being in use, this figure may be greater than
+ zero even when no user-level chunks are allocated.
+
+ The reported current and maximum system memory can be inaccurate if
+ a program makes other calls to system memory allocation functions
+ (normally sbrk) outside of malloc.
+
+ malloc_stats prints only the most commonly interesting statistics.
+ More information can be obtained by calling mallinfo.
+*/
+void dlmalloc_stats();
+
+#endif /* !ONLY_MSPACES */
+
+#if MSPACES
+
+/*
+ mspace is an opaque type representing an independent
+ region of space that supports mspace_malloc, etc.
+*/
+typedef void* mspace;
+
+/*
+ create_mspace creates and returns a new independent space with the
+ given initial capacity, or, if 0, the default granularity size. It
+ returns null if there is no system memory available to create the
+ space. If argument locked is non-zero, the space uses a separate
+ lock to control access. The capacity of the space will grow
+ dynamically as needed to service mspace_malloc requests. You can
+ control the sizes of incremental increases of this space by
+ compiling with a different DEFAULT_GRANULARITY or dynamically
+ setting with mallopt(M_GRANULARITY, value).
+*/
+mspace create_mspace(size_t capacity, int locked);
+
+/*
+ destroy_mspace destroys the given space, and attempts to return all
+ of its memory back to the system, returning the total number of
+ bytes freed. After destruction, the results of access to all memory
+ used by the space become undefined.
+*/
+size_t destroy_mspace(mspace msp);
+
+/*
+ create_mspace_with_base uses the memory supplied as the initial base
+ of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
+ space is used for bookkeeping, so the capacity must be at least this
+ large. (Otherwise 0 is returned.) When this initial space is
+ exhausted, additional memory will be obtained from the system.
+ Destroying this space will deallocate all additionally allocated
+ space (if possible) but not the initial base.
+*/
+mspace create_mspace_with_base(void* base, size_t capacity, int locked);
+
+/*
+ mspace_malloc behaves as malloc, but operates within
+ the given space.
+*/
+void* mspace_malloc(mspace msp, size_t bytes);
+
+/*
+ mspace_free behaves as free, but operates within
+ the given space.
+
+ If compiled with FOOTERS==1, mspace_free is not actually needed.
+ free may be called instead of mspace_free because freed chunks from
+ any space are handled by their originating spaces.
+*/
+void mspace_free(mspace msp, void* mem);
+
+/*
+ mspace_realloc behaves as realloc, but operates within
+ the given space.
+
+ If compiled with FOOTERS==1, mspace_realloc is not actually
+ needed. realloc may be called instead of mspace_realloc because
+ realloced chunks from any space are handled by their originating
+ spaces.
+*/
+void* mspace_realloc(mspace msp, void* mem, size_t newsize);
+
+/*
+ mspace_merge_objects will merge allocated memory mema and memb
+ together, provided memb immediately follows mema. It is roughly as
+ if memb has been freed and mema has been realloced to a larger size.
+ On successfully merging, mema will be returned. If either argument
+ is null or memb does not immediately follow mema, null will be
+ returned.
+
+ Both mema and memb should have been previously allocated using
+ malloc or a related routine such as realloc. If either mema or memb
+ was not malloced or was previously freed, the result is undefined,
+ but like mspace_free, the default is to abort the program.
+*/
+void* mspace_merge_objects(mspace msp, void* mema, void* memb);
+
+/*
+ mspace_calloc behaves as calloc, but operates within
+ the given space.
+*/
+void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);
+
+/*
+ mspace_memalign behaves as memalign, but operates within
+ the given space.
+*/
+void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);
+
+/*
+ mspace_independent_calloc behaves as independent_calloc, but
+ operates within the given space.
+*/
+void** mspace_independent_calloc(mspace msp, size_t n_elements,
+ size_t elem_size, void* chunks[]);
+
+/*
+ mspace_independent_comalloc behaves as independent_comalloc, but
+ operates within the given space.
+*/
+void** mspace_independent_comalloc(mspace msp, size_t n_elements,
+ size_t sizes[], void* chunks[]);
+
+/*
+ mspace_footprint() returns the number of bytes obtained from the
+ system for this space.
+*/
+size_t mspace_footprint(mspace msp);
+
+/*
+ mspace_max_allowed_footprint() returns the number of bytes that
+ this space is allowed to obtain from the system. See
+ malloc_max_allowed_footprint() for a more in-depth description.
+
+ This function is only available if dlmalloc.c was compiled
+ with USE_MAX_ALLOWED_FOOTPRINT set.
+*/
+size_t mspace_max_allowed_footprint(mspace msp);
+
+/*
+ mspace_set_max_allowed_footprint() sets the maximum number of
+ bytes (rounded up to a page) that this space is allowed to
+ obtain from the system. See malloc_set_max_allowed_footprint()
+ for a more in-depth description.
+
+ This function is only available if dlmalloc.c was compiled
+ with USE_MAX_ALLOWED_FOOTPRINT set.
+*/
+void mspace_set_max_allowed_footprint(mspace msp, size_t bytes);
+
+/*
+ mspace_max_footprint() returns the maximum number of bytes obtained
+ from the system over the lifetime of this space.
+*/
+size_t mspace_max_footprint(mspace msp);
+
+
+#if !NO_MALLINFO
+/*
+ mspace_mallinfo behaves as mallinfo, but reports properties of
+ the given space.
+*/
+struct mallinfo mspace_mallinfo(mspace msp);
+#endif /* NO_MALLINFO */
+
+/*
+ mspace_malloc_stats behaves as malloc_stats, but reports
+ properties of the given space.
+*/
+void mspace_malloc_stats(mspace msp);
+
+/*
+ mspace_trim behaves as malloc_trim, but
+ operates within the given space.
+*/
+int mspace_trim(mspace msp, size_t pad);
+
+/*
+ An alias for mallopt.
+*/
+int mspace_mallopt(int, int);
+
+#endif /* MSPACES */
+
+#ifdef __cplusplus
+}; /* end of extern "C" */
+#endif
+
+#endif /* MALLOC_280_H */
diff --git a/include/cutils/event_tag_map.h b/include/cutils/event_tag_map.h
new file mode 100644
index 0000000..1653c61
--- /dev/null
+++ b/include/cutils/event_tag_map.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBS_CUTILS_EVENTTAGMAP_H
+#define _LIBS_CUTILS_EVENTTAGMAP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define EVENT_TAG_MAP_FILE "/system/etc/event-log-tags"
+
+struct EventTagMap;
+typedef struct EventTagMap EventTagMap;
+
+/*
+ * Open the specified file as an event log tag map.
+ *
+ * Returns NULL on failure.
+ */
+EventTagMap* android_openEventTagMap(const char* fileName);
+
+/*
+ * Close the map.
+ */
+void android_closeEventTagMap(EventTagMap* map);
+
+/*
+ * Look up a tag by index. Returns the tag string, or NULL if not found.
+ */
+const char* android_lookupEventTag(const EventTagMap* map, int tag);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*_LIBS_CUTILS_EVENTTAGMAP_H*/
diff --git a/include/cutils/hashmap.h b/include/cutils/hashmap.h
new file mode 100644
index 0000000..5cb344c
--- /dev/null
+++ b/include/cutils/hashmap.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Hash map.
+ */
+
+#ifndef __HASHMAP_H
+#define __HASHMAP_H
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** A hash map. */
+typedef struct Hashmap Hashmap;
+
+/**
+ * Creates a new hash map. Returns NULL if memory allocation fails.
+ *
+ * @param initialCapacity number of expected entries
+ * @param hash function which hashes keys
+ * @param equals function which compares keys for equality
+ */
+Hashmap* hashmapCreate(size_t initialCapacity,
+ int (*hash)(void* key), bool (*equals)(void* keyA, void* keyB));
+
+/**
+ * Frees the hash map. Does not free the keys or values themselves.
+ */
+void hashmapFree(Hashmap* map);
+
+/**
+ * Hashes the memory pointed to by key with the given size. Useful for
+ * implementing hash functions.
+ */
+int hashmapHash(void* key, size_t keySize);
+
+/**
+ * Puts value for the given key in the map. Returns pre-existing value if
+ * any.
+ *
+ * If memory allocation fails, this function returns NULL, the map's size
+ * does not increase, and errno is set to ENOMEM.
+ */
+void* hashmapPut(Hashmap* map, void* key, void* value);
+
+/**
+ * Gets a value from the map. Returns NULL if no entry for the given key is
+ * found or if the value itself is NULL.
+ */
+void* hashmapGet(Hashmap* map, void* key);
+
+/**
+ * Returns true if the map contains an entry for the given key.
+ */
+bool hashmapContainsKey(Hashmap* map, void* key);
+
+/**
+ * Gets the value for a key. If a value is not found, this function gets a
+ * value and creates an entry using the given callback.
+ *
+ * If memory allocation fails, the callback is not called, this function
+ * returns NULL, and errno is set to ENOMEM.
+ */
+void* hashmapMemoize(Hashmap* map, void* key,
+ void* (*initialValue)(void* key, void* context), void* context);
+
+/**
+ * Removes an entry from the map. Returns the removed value or NULL if no
+ * entry was present.
+ */
+void* hashmapRemove(Hashmap* map, void* key);
+
+/**
+ * Gets the number of entries in this map.
+ */
+size_t hashmapSize(Hashmap* map);
+
+/**
+ * Invokes the given callback on each entry in the map. Stops iterating if
+ * the callback returns false.
+ */
+void hashmapForEach(Hashmap* map,
+ bool (*callback)(void* key, void* value, void* context),
+ void* context);
+
+/**
+ * Concurrency support.
+ */
+
+/**
+ * Locks the hash map so only the current thread can access it.
+ */
+void hashmapLock(Hashmap* map);
+
+/**
+ * Unlocks the hash map so other threads can access it.
+ */
+void hashmapUnlock(Hashmap* map);
+
+/**
+ * Key utilities.
+ */
+
+/**
+ * Hashes int keys. 'key' is a pointer to int.
+ */
+int hashmapIntHash(void* key);
+
+/**
+ * Compares two int keys for equality.
+ */
+bool hashmapIntEquals(void* keyA, void* keyB);
+
+/**
+ * For debugging.
+ */
+
+/**
+ * Gets current capacity.
+ */
+size_t hashmapCurrentCapacity(Hashmap* map);
+
+/**
+ * Counts the number of entry collisions.
+ */
+size_t hashmapCountCollisions(Hashmap* map);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __HASHMAP_H */
diff --git a/include/cutils/iosched_policy.h b/include/cutils/iosched_policy.h
new file mode 100644
index 0000000..175494a
--- /dev/null
+++ b/include/cutils/iosched_policy.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_IOSCHED_POLICY_H
+#define __CUTILS_IOSCHED_POLICY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ IoSchedClass_NONE,
+ IoSchedClass_RT,
+ IoSchedClass_BE,
+ IoSchedClass_IDLE,
+} IoSchedClass;
+
+extern int android_set_ioprio(int pid, IoSchedClass clazz, int ioprio);
+extern int android_get_ioprio(int pid, IoSchedClass *clazz, int *ioprio);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_IOSCHED_POLICY_H */
diff --git a/include/cutils/jstring.h b/include/cutils/jstring.h
new file mode 100644
index 0000000..ee0018f
--- /dev/null
+++ b/include/cutils/jstring.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_STRING16_H
+#define __CUTILS_STRING16_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef uint16_t char16_t;
+
+extern char * strndup16to8 (const char16_t* s, size_t n);
+extern size_t strnlen16to8 (const char16_t* s, size_t n);
+extern char * strncpy16to8 (char *dest, const char16_t*s, size_t n);
+
+extern char16_t * strdup8to16 (const char* s, size_t *out_len);
+extern size_t strlen8to16 (const char* utf8Str);
+extern char16_t * strcpy8to16 (char16_t *dest, const char*s, size_t *out_len);
+extern char16_t * strcpylen8to16 (char16_t *dest, const char*s, int length,
+ size_t *out_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_STRING16_H */
diff --git a/include/cutils/klog.h b/include/cutils/klog.h
new file mode 100644
index 0000000..1335543
--- /dev/null
+++ b/include/cutils/klog.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CUTILS_KLOG_H_
+#define _CUTILS_KLOG_H_
+
+void klog_init(void);
+void klog_set_level(int level);
+void klog_close(void);
+void klog_write(int level, const char *fmt, ...)
+ __attribute__ ((format(printf, 2, 3)));
+
+#define KLOG_ERROR(tag,x...) klog_write(3, "<3>" tag ": " x)
+#define KLOG_WARNING(tag,x...) klog_write(4, "<4>" tag ": " x)
+#define KLOG_NOTICE(tag,x...) klog_write(5, "<5>" tag ": " x)
+#define KLOG_INFO(tag,x...) klog_write(6, "<6>" tag ": " x)
+#define KLOG_DEBUG(tag,x...) klog_write(7, "<7>" tag ": " x)
+
+#define KLOG_DEFAULT_LEVEL 3 /* messages <= this level are logged */
+
+#endif
diff --git a/include/cutils/list.h b/include/cutils/list.h
new file mode 100644
index 0000000..dfdc53b
--- /dev/null
+++ b/include/cutils/list.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2008-2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CUTILS_LIST_H_
+#define _CUTILS_LIST_H_
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+struct listnode
+{
+ struct listnode *next;
+ struct listnode *prev;
+};
+
+#define node_to_item(node, container, member) \
+ (container *) (((char*) (node)) - offsetof(container, member))
+
+#define list_declare(name) \
+ struct listnode name = { \
+ .next = &(name), \
+ .prev = &(name), \
+ }
+
+#define list_for_each(node, list) \
+ for ((node) = (list)->next; (node) != (list); (node) = (node)->next)
+
+#define list_for_each_reverse(node, list) \
+ for ((node) = (list)->prev; (node) != (list); (node) = (node)->prev)
+
+#define list_for_each_safe(node, n, list) \
+ for ((node) = (list)->next, (n) = (node)->next; \
+ (node) != (list); \
+ (node) = (n), (n) = (node)->next)
+
+static inline void list_init(struct listnode *node)
+{
+ node->next = node;
+ node->prev = node;
+}
+
+static inline void list_add_tail(struct listnode *head, struct listnode *item)
+{
+ item->next = head;
+ item->prev = head->prev;
+ head->prev->next = item;
+ head->prev = item;
+}
+
+static inline void list_add_head(struct listnode *head, struct listnode *item)
+{
+ item->next = head->next;
+ item->prev = head;
+ head->next->prev = item;
+ head->next = item;
+}
+
+static inline void list_remove(struct listnode *item)
+{
+ item->next->prev = item->prev;
+ item->prev->next = item->next;
+}
+
+#define list_empty(list) ((list) == (list)->next)
+#define list_head(list) ((list)->next)
+#define list_tail(list) ((list)->prev)
+
+#ifdef __cplusplus
+};
+#endif /* __cplusplus */
+
+#endif
diff --git a/include/cutils/log.h b/include/cutils/log.h
new file mode 100644
index 0000000..0339bce
--- /dev/null
+++ b/include/cutils/log.h
@@ -0,0 +1,549 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// C/C++ logging functions. See the logging documentation for API details.
+//
+// We'd like these to be available from C code (in case we import some from
+// somewhere), so this has a C interface.
+//
+// The output will be correct when the log file is shared between multiple
+// threads and/or multiple processes so long as the operating system
+// supports O_APPEND. These calls have mutex-protected data structures
+// and so are NOT reentrant. Do not use LOG in a signal handler.
+//
+#ifndef _LIBS_CUTILS_LOG_H
+#define _LIBS_CUTILS_LOG_H
+
+#include <stdio.h>
+#include <time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#ifdef HAVE_PTHREADS
+#include <pthread.h>
+#endif
+#include <stdarg.h>
+
+#include <cutils/uio.h>
+#include <cutils/logd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Normally we strip ALOGV (VERBOSE messages) from release builds.
+ * You can modify this (for example with "#define LOG_NDEBUG 0"
+ * at the top of your source file) to change that behavior.
+ */
+#ifndef LOG_NDEBUG
+#ifdef NDEBUG
+#define LOG_NDEBUG 1
+#else
+#define LOG_NDEBUG 0
+#endif
+#endif
+
+/*
+ * This is the local tag used for the following simplified
+ * logging macros. You can change this preprocessor definition
+ * before using the other macros to change the tag.
+ */
+#ifndef LOG_TAG
+#define LOG_TAG NULL
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Simplified macro to send a verbose log message using the current LOG_TAG.
+ */
+#ifndef ALOGV
+#if LOG_NDEBUG
+#define ALOGV(...) ((void)0)
+#else
+#define ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#endif
+// Temporary measure for code still using old LOG macros.
+#ifndef LOGV
+#define LOGV ALOGV
+#endif
+#endif
+
+#define CONDITION(cond) (__builtin_expect((cond)!=0, 0))
+
+#ifndef ALOGV_IF
+#if LOG_NDEBUG
+#define ALOGV_IF(cond, ...) ((void)0)
+#else
+#define ALOGV_IF(cond, ...) \
+ ( (CONDITION(cond)) \
+ ? ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
+ : (void)0 )
+#endif
+// Temporary measure for code still using old LOG macros.
+#ifndef LOGV_IF
+#define LOGV_IF ALOGV_IF
+#endif
+#endif
+
+/*
+ * Simplified macro to send a debug log message using the current LOG_TAG.
+ */
+#ifndef ALOGD
+#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
+// Temporary measure for code still using old LOG macros.
+#ifndef LOGD
+#define LOGD ALOGD
+#endif
+#endif
+
+#ifndef ALOGD_IF
+#define ALOGD_IF(cond, ...) \
+ ( (CONDITION(cond)) \
+ ? ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
+ : (void)0 )
+// Temporary measure for code still using old LOG macros.
+#ifndef LOGD_IF
+#define LOGD_IF ALOGD_IF
+#endif
+#endif
+
+/*
+ * Simplified macro to send an info log message using the current LOG_TAG.
+ */
+#ifndef ALOGI
+#define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__))
+// Temporary measure for code still using old LOG macros.
+#ifndef LOGI
+#define LOGI ALOGI
+#endif
+#endif
+
+#ifndef ALOGI_IF
+#define ALOGI_IF(cond, ...) \
+ ( (CONDITION(cond)) \
+ ? ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \
+ : (void)0 )
+// Temporary measure for code still using old LOG macros.
+#ifndef LOGI_IF
+#define LOGI_IF ALOGI_IF
+#endif
+#endif
+
+/*
+ * Simplified macro to send a warning log message using the current LOG_TAG.
+ */
+#ifndef ALOGW
+#define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
+// Temporary measure for code still using old LOG macros.
+#ifndef LOGW
+#define LOGW ALOGW
+#endif
+#endif
+
+#ifndef ALOGW_IF
+#define ALOGW_IF(cond, ...) \
+ ( (CONDITION(cond)) \
+ ? ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \
+ : (void)0 )
+// Temporary measure for code still using old LOG macros.
+#ifndef LOGW_IF
+#define LOGW_IF ALOGW_IF
+#endif
+#endif
+
+/*
+ * Simplified macro to send an error log message using the current LOG_TAG.
+ */
+#ifndef ALOGE
+#define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
+// Temporary measure for code still using old LOG macros.
+#ifndef LOGE
+#define LOGE ALOGE
+#endif
+#endif
+
+#ifndef ALOGE_IF
+#define ALOGE_IF(cond, ...) \
+ ( (CONDITION(cond)) \
+ ? ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
+ : (void)0 )
+// Temporary measure for code still using old LOG macros.
+#ifndef LOGE_IF
+#define LOGE_IF ALOGE_IF
+#endif
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * verbose priority.
+ */
+#ifndef IF_ALOGV
+#if LOG_NDEBUG
+#define IF_ALOGV() if (false)
+#else
+#define IF_ALOGV() IF_ALOG(LOG_VERBOSE, LOG_TAG)
+#endif
+// Temporary measure for code still using old LOG macros.
+#ifndef IF_LOGV
+#define IF_LOGV IF_ALOGV
+#endif
+#endif
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * debug priority.
+ */
+#ifndef IF_ALOGD
+#define IF_ALOGD() IF_ALOG(LOG_DEBUG, LOG_TAG)
+// Temporary measure for code still using old LOG macros.
+#ifndef IF_LOGD
+#define IF_LOGD IF_ALOGD
+#endif
+#endif
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * info priority.
+ */
+#ifndef IF_ALOGI
+#define IF_ALOGI() IF_ALOG(LOG_INFO, LOG_TAG)
+// Temporary measure for code still using old LOG macros.
+#ifndef IF_LOGI
+#define IF_LOGI IF_ALOGI
+#endif
+#endif
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * warn priority.
+ */
+#ifndef IF_ALOGW
+#define IF_ALOGW() IF_ALOG(LOG_WARN, LOG_TAG)
+// Temporary measure for code still using old LOG macros.
+#ifndef IF_LOGW
+#define IF_LOGW IF_ALOGW
+#endif
+#endif
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * error priority.
+ */
+#ifndef IF_ALOGE
+#define IF_ALOGE() IF_ALOG(LOG_ERROR, LOG_TAG)
+// Temporary measure for code still using old LOG macros.
+#ifndef IF_LOGE
+#define IF_LOGE IF_ALOGE
+#endif
+#endif
+
+
+// ---------------------------------------------------------------------
+
+/*
+ * Simplified macro to send a verbose system log message using the current LOG_TAG.
+ */
+#ifndef SLOGV
+#if LOG_NDEBUG
+#define SLOGV(...) ((void)0)
+#else
+#define SLOGV(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#endif
+#endif
+
+#define CONDITION(cond) (__builtin_expect((cond)!=0, 0))
+
+#ifndef SLOGV_IF
+#if LOG_NDEBUG
+#define SLOGV_IF(cond, ...) ((void)0)
+#else
+#define SLOGV_IF(cond, ...) \
+ ( (CONDITION(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
+ : (void)0 )
+#endif
+#endif
+
+/*
+ * Simplified macro to send a debug system log message using the current LOG_TAG.
+ */
+#ifndef SLOGD
+#define SLOGD(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGD_IF
+#define SLOGD_IF(cond, ...) \
+ ( (CONDITION(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
+ : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an info system log message using the current LOG_TAG.
+ */
+#ifndef SLOGI
+#define SLOGI(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGI_IF
+#define SLOGI_IF(cond, ...) \
+ ( (CONDITION(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
+ : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send a warning system log message using the current LOG_TAG.
+ */
+#ifndef SLOGW
+#define SLOGW(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGW_IF
+#define SLOGW_IF(cond, ...) \
+ ( (CONDITION(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
+ : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an error system log message using the current LOG_TAG.
+ */
+#ifndef SLOGE
+#define SLOGE(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGE_IF
+#define SLOGE_IF(cond, ...) \
+ ( (CONDITION(cond)) \
+ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
+ : (void)0 )
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Log a fatal error. If the given condition fails, this stops program
+ * execution like a normal assertion, but also generating the given message.
+ * It is NOT stripped from release builds. Note that the condition test
+ * is -inverted- from the normal assert() semantics.
+ */
+#ifndef LOG_ALWAYS_FATAL_IF
+#define LOG_ALWAYS_FATAL_IF(cond, ...) \
+ ( (CONDITION(cond)) \
+ ? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \
+ : (void)0 )
+#endif
+
+#ifndef LOG_ALWAYS_FATAL
+#define LOG_ALWAYS_FATAL(...) \
+ ( ((void)android_printAssert(NULL, LOG_TAG, ## __VA_ARGS__)) )
+#endif
+
+/*
+ * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that
+ * are stripped out of release builds.
+ */
+#if LOG_NDEBUG
+
+#ifndef LOG_FATAL_IF
+#define LOG_FATAL_IF(cond, ...) ((void)0)
+#endif
+#ifndef LOG_FATAL
+#define LOG_FATAL(...) ((void)0)
+#endif
+
+#else
+
+#ifndef LOG_FATAL_IF
+#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ## __VA_ARGS__)
+#endif
+#ifndef LOG_FATAL
+#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
+#endif
+
+#endif
+
+/*
+ * Assertion that generates a log message when the assertion fails.
+ * Stripped out of release builds. Uses the current LOG_TAG.
+ */
+#ifndef ALOG_ASSERT
+#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__)
+//#define ALOG_ASSERT(cond) LOG_FATAL_IF(!(cond), "Assertion failed: " #cond)
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Basic log message macro.
+ *
+ * Example:
+ * ALOG(LOG_WARN, NULL, "Failed with error %d", errno);
+ *
+ * The second argument may be NULL or "" to indicate the "global" tag.
+ */
+#ifndef ALOG
+#define ALOG(priority, tag, ...) \
+ LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
+#endif
+
+/*
+ * Log macro that allows you to specify a number for the priority.
+ */
+#ifndef LOG_PRI
+#define LOG_PRI(priority, tag, ...) \
+ android_printLog(priority, tag, __VA_ARGS__)
+#endif
+
+/*
+ * Log macro that allows you to pass in a varargs ("args" is a va_list).
+ */
+#ifndef LOG_PRI_VA
+#define LOG_PRI_VA(priority, tag, fmt, args) \
+ android_vprintLog(priority, NULL, tag, fmt, args)
+#endif
+
+/*
+ * Conditional given a desired logging priority and tag.
+ */
+#ifndef IF_ALOG
+#define IF_ALOG(priority, tag) \
+ if (android_testLog(ANDROID_##priority, tag))
+// Temporary measure for code still using old LOG macros.
+#ifndef IF_LOG
+#define IF_LOG IF_ALOG
+#endif
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Event logging.
+ */
+
+/*
+ * Event log entry types. These must match up with the declarations in
+ * java/android/android/util/EventLog.java.
+ */
+typedef enum {
+ EVENT_TYPE_INT = 0,
+ EVENT_TYPE_LONG = 1,
+ EVENT_TYPE_STRING = 2,
+ EVENT_TYPE_LIST = 3,
+} AndroidEventLogType;
+
+
+#ifndef LOG_EVENT_INT
+#define LOG_EVENT_INT(_tag, _value) { \
+ int intBuf = _value; \
+ (void) android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf, \
+ sizeof(intBuf)); \
+ }
+#endif
+#ifndef LOG_EVENT_LONG
+#define LOG_EVENT_LONG(_tag, _value) { \
+ long long longBuf = _value; \
+ (void) android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf, \
+ sizeof(longBuf)); \
+ }
+#endif
+#ifndef LOG_EVENT_STRING
+#define LOG_EVENT_STRING(_tag, _value) \
+ ((void) 0) /* not implemented -- must combine len with string */
+#endif
+/* TODO: something for LIST */
+
+/*
+ * ===========================================================================
+ *
+ * The stuff in the rest of this file should not be used directly.
+ */
+
+#define android_printLog(prio, tag, fmt...) \
+ __android_log_print(prio, tag, fmt)
+
+#define android_vprintLog(prio, cond, tag, fmt...) \
+ __android_log_vprint(prio, tag, fmt)
+
+/* XXX Macros to work around syntax errors in places where format string
+ * arg is not passed to ALOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF
+ * (happens only in debug builds).
+ */
+
+/* Returns 2nd arg. Used to substitute default value if caller's vararg list
+ * is empty.
+ */
+#define __android_second(dummy, second, ...) second
+
+/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise
+ * returns nothing.
+ */
+#define __android_rest(first, ...) , ## __VA_ARGS__
+
+#define android_printAssert(cond, tag, fmt...) \
+ __android_log_assert(cond, tag, \
+ __android_second(0, ## fmt, NULL) __android_rest(fmt))
+
+#define android_writeLog(prio, tag, text) \
+ __android_log_write(prio, tag, text)
+
+#define android_bWriteLog(tag, payload, len) \
+ __android_log_bwrite(tag, payload, len)
+#define android_btWriteLog(tag, type, payload, len) \
+ __android_log_btwrite(tag, type, payload, len)
+
+// TODO: remove these prototypes and their users
+#define android_testLog(prio, tag) (1)
+#define android_writevLog(vec,num) do{}while(0)
+#define android_write1Log(str,len) do{}while (0)
+#define android_setMinPriority(tag, prio) do{}while(0)
+//#define android_logToCallback(func) do{}while(0)
+#define android_logToFile(tag, file) (0)
+#define android_logToFd(tag, fd) (0)
+
+#define android_errorWriteLog(tag, subTag) do{}while(0)
+
+typedef enum {
+ LOG_ID_MAIN = 0,
+ LOG_ID_RADIO = 1,
+ LOG_ID_EVENTS = 2,
+ LOG_ID_SYSTEM = 3,
+
+ LOG_ID_MAX
+} log_id_t;
+
+/*
+ * Send a simple string to the log.
+ */
+int __android_log_buf_write(log_id_t bufID, int prio, const char *tag, const char *text);
+int __android_log_buf_print(log_id_t bufID, int prio, const char *tag, const char *fmt, ...);
+int __android_log_buf_vprint(log_id_t bufID, int prio, const char *tag, const char *fmt, va_list ap);
+
+/* Is this a secure build, - defined in liblog. */
+int is_secure_build();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _LIBS_CUTILS_LOG_H
diff --git a/include/cutils/logd.h b/include/cutils/logd.h
new file mode 100644
index 0000000..8737639
--- /dev/null
+++ b/include/cutils/logd.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_CUTILS_LOGD_H
+#define _ANDROID_CUTILS_LOGD_H
+
+/* the stable/frozen log-related definitions have been
+ * moved to this header, which is exposed by the NDK
+ */
+#include <android/log.h>
+
+/* the rest is only used internally by the system */
+#include <time.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/types.h>
+#ifdef HAVE_PTHREADS
+#include <pthread.h>
+#endif
+#include <cutils/uio.h>
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int __android_log_bwrite(int32_t tag, const void *payload, size_t len);
+int __android_log_btwrite(int32_t tag, char type, const void *payload,
+ size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LOGD_H */
diff --git a/include/cutils/logger.h b/include/cutils/logger.h
new file mode 100644
index 0000000..58523fb
--- /dev/null
+++ b/include/cutils/logger.h
@@ -0,0 +1,47 @@
+/* utils/logger.h
+**
+** Copyright 2007, The Android Open Source Project
+**
+** This file is dual licensed. It may be redistributed and/or modified
+** under the terms of the Apache 2.0 License OR version 2 of the GNU
+** General Public License.
+*/
+
+#ifndef _UTILS_LOGGER_H
+#define _UTILS_LOGGER_H
+
+#include <stdint.h>
+
+struct logger_entry {
+ uint16_t len; /* length of the payload */
+ uint16_t __pad; /* no matter what, we get 2 bytes of padding */
+ int32_t pid; /* generating process's pid */
+ int32_t tid; /* generating process's tid */
+ int32_t sec; /* seconds since Epoch */
+ int32_t nsec; /* nanoseconds */
+ char msg[0]; /* the entry's payload */
+};
+
+#define LOGGER_LOG_MAIN "log_main"
+#define LOGGER_LOG_RADIO "log_radio"
+#define LOGGER_LOG_EVENTS "log_events"
+#define LOGGER_LOG_SYSTEM "log_system"
+
+#define LOGGER_ENTRY_MAX_LEN (4*1024)
+#define LOGGER_ENTRY_MAX_PAYLOAD \
+ (LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry))
+
+#ifdef HAVE_IOCTL
+
+#include <sys/ioctl.h>
+
+#define __LOGGERIO 0xAE
+
+#define LOGGER_GET_LOG_BUF_SIZE _IO(__LOGGERIO, 1) /* size of log */
+#define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */
+#define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */
+#define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */
+
+#endif // HAVE_IOCTL
+
+#endif /* _UTILS_LOGGER_H */
diff --git a/include/cutils/logprint.h b/include/cutils/logprint.h
new file mode 100644
index 0000000..d1e4d81
--- /dev/null
+++ b/include/cutils/logprint.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LOGPRINT_H
+#define _LOGPRINT_H
+
+#include <cutils/log.h>
+#include <cutils/logger.h>
+#include <cutils/event_tag_map.h>
+#include <pthread.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ FORMAT_OFF = 0,
+ FORMAT_BRIEF,
+ FORMAT_PROCESS,
+ FORMAT_TAG,
+ FORMAT_THREAD,
+ FORMAT_RAW,
+ FORMAT_TIME,
+ FORMAT_THREADTIME,
+ FORMAT_LONG,
+} AndroidLogPrintFormat;
+
+typedef struct AndroidLogFormat_t AndroidLogFormat;
+
+typedef struct AndroidLogEntry_t {
+ time_t tv_sec;
+ long tv_nsec;
+ android_LogPriority priority;
+ pid_t pid;
+ pthread_t tid;
+ const char * tag;
+ size_t messageLen;
+ const char * message;
+} AndroidLogEntry;
+
+AndroidLogFormat *android_log_format_new();
+
+void android_log_format_free(AndroidLogFormat *p_format);
+
+void android_log_setPrintFormat(AndroidLogFormat *p_format,
+ AndroidLogPrintFormat format);
+
+/**
+ * Returns FORMAT_OFF on invalid string
+ */
+AndroidLogPrintFormat android_log_formatFromString(const char *s);
+
+/**
+ * filterExpression: a single filter expression
+ * eg "AT:d"
+ *
+ * returns 0 on success and -1 on invalid expression
+ *
+ * Assumes single threaded execution
+ *
+ */
+
+int android_log_addFilterRule(AndroidLogFormat *p_format,
+ const char *filterExpression);
+
+
+/**
+ * filterString: a whitespace-separated set of filter expressions
+ * eg "AT:d *:i"
+ *
+ * returns 0 on success and -1 on invalid expression
+ *
+ * Assumes single threaded execution
+ *
+ */
+
+int android_log_addFilterString(AndroidLogFormat *p_format,
+ const char *filterString);
+
+
+/**
+ * returns 1 if this log line should be printed based on its priority
+ * and tag, and 0 if it should not
+ */
+int android_log_shouldPrintLine (
+ AndroidLogFormat *p_format, const char *tag, android_LogPriority pri);
+
+
+/**
+ * Splits a wire-format buffer into an AndroidLogEntry
+ * entry allocated by caller. Pointers will point directly into buf
+ *
+ * Returns 0 on success and -1 on invalid wire format (entry will be
+ * in unspecified state)
+ */
+int android_log_processLogBuffer(struct logger_entry *buf,
+ AndroidLogEntry *entry);
+
+/**
+ * Like android_log_processLogBuffer, but for binary logs.
+ *
+ * If "map" is non-NULL, it will be used to convert the log tag number
+ * into a string.
+ */
+int android_log_processBinaryLogBuffer(struct logger_entry *buf,
+ AndroidLogEntry *entry, const EventTagMap* map, char* messageBuf,
+ int messageBufLen);
+
+
+/**
+ * Formats a log message into a buffer
+ *
+ * Uses defaultBuffer if it can, otherwise malloc()'s a new buffer
+ * If return value != defaultBuffer, caller must call free()
+ * Returns NULL on malloc error
+ */
+
+char *android_log_formatLogLine (
+ AndroidLogFormat *p_format,
+ char *defaultBuffer,
+ size_t defaultBufferSize,
+ const AndroidLogEntry *p_line,
+ size_t *p_outLength);
+
+
+/**
+ * Either print or do not print log line, based on filter
+ *
+ * Assumes single threaded execution
+ *
+ */
+int android_log_printLogLine(
+ AndroidLogFormat *p_format,
+ int fd,
+ const AndroidLogEntry *entry);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /*_LOGPRINT_H*/
diff --git a/include/cutils/memory.h b/include/cutils/memory.h
new file mode 100644
index 0000000..4d26882
--- /dev/null
+++ b/include/cutils/memory.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_CUTILS_MEMORY_H
+#define ANDROID_CUTILS_MEMORY_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* size is given in bytes and must be multiple of 2 */
+void android_memset16(uint16_t* dst, uint16_t value, size_t size);
+
+/* size is given in bytes and must be multiple of 4 */
+void android_memset32(uint32_t* dst, uint32_t value, size_t size);
+
+#if defined(__GLIBC__) || defined(_WIN32)
+/* Declaration of strlcpy() for platforms that don't already have it. */
+size_t strlcpy(char *dst, const char *src, size_t size);
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // ANDROID_CUTILS_MEMORY_H
diff --git a/include/cutils/misc.h b/include/cutils/misc.h
new file mode 100644
index 0000000..3574dfd
--- /dev/null
+++ b/include/cutils/misc.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_MISC_H
+#define __CUTILS_MISC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /* Load an entire file into a malloc'd chunk of memory
+ * that is length_of_file + 1 (null terminator). If
+ * sz is non-zero, return the size of the file via sz.
+ * Returns 0 on failure.
+ */
+extern void *load_file(const char *fn, unsigned *sz);
+
+ /* Connects your process to the system debugger daemon
+ * so that on a crash it may be logged or interactively
+ * debugged (depending on system settings).
+ */
+extern void debuggerd_connect(void);
+
+
+ /* This is the range of UIDs (and GIDs) that are reserved
+ * for assigning to applications.
+ */
+#define FIRST_APPLICATION_UID 10000
+#define LAST_APPLICATION_UID 99999
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_MISC_H */
diff --git a/include/cutils/mq.h b/include/cutils/mq.h
new file mode 100644
index 0000000..9e56de7
--- /dev/null
+++ b/include/cutils/mq.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * IPC messaging library.
+ */
+
+#ifndef __MQ_H
+#define __MQ_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** A message. */
+typedef struct MqMessage MqMessage;
+
+/** A destination to which messages can be sent. */
+typedef struct MqDestination MqDestination;
+
+/* Array of bytes. */
+typedef struct MqBytes MqBytes;
+
+/**
+ * Hears messages.
+ *
+ * @param destination to which the message was sent
+ * @param message the message to hear
+ */
+typedef void MqMessageListener(MqDestination* destination, MqMessage* message);
+
+/**
+ * Hears a destination close.
+ *
+ * @param destination that closed
+ */
+typedef void MqCloseListener(MqDestination* destination);
+
+/** Message functions. */
+
+/**
+ * Creates a new Message.
+ *
+ * @param header as defined by user
+ * @param body as defined by user
+ * @param replyTo destination to which replies should be sent, NULL if none
+ */
+MqMessage* mqCreateMessage(MqBytes header, MqBytes body,
+ MqDestination* replyTo);
+
+/** Sends a message to a destination. */
+void mqSendMessage(MqMessage* message, MqDestination* destination);
+
+/** Destination functions. */
+
+/**
+ * Creates a new destination. Acquires a reference implicitly.
+ *
+ * @param messageListener function to call when a message is recieved
+ * @param closeListener function to call when the destination closes
+ * @param userData user-specific data to associate with the destination.
+ * Retrieve using mqGetDestinationUserData().
+ */
+MqDestination* mqCreateDestination(MqMessageListener* messageListener,
+ MqCloseListener* closeListener, void* userData);
+
+/**
+ * Gets user data which was associated with the given destination at
+ * construction time.
+ *
+ * It is only valid to call this function in the same process that the
+ * given destination was created in.
+ * This function returns a null pointer if you call it on a destination
+ * created in a remote process.
+ */
+void* mqGetUserData(MqDestination* destination);
+
+/**
+ * Returns 1 if the destination was created in this process, or 0 if
+ * the destination was created in a different process, in which case you have
+ * a remote stub.
+ */
+int mqIsDestinationLocal(MqDestination* destination);
+
+/**
+ * Increments the destination's reference count.
+ */
+void mqKeepDestination(MqDesintation* destination);
+
+/**
+ * Decrements the destination's reference count.
+ */
+void mqFreeDestination(MqDestination* desintation);
+
+/** Registry API. */
+
+/**
+ * Gets the destination bound to a name.
+ */
+MqDestination* mqGetDestination(char* name);
+
+/**
+ * Binds a destination to a name.
+ */
+void mqPutDestination(char* name, MqDestination* desintation);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MQ_H */
diff --git a/include/cutils/mspace.h b/include/cutils/mspace.h
new file mode 100644
index 0000000..b22d9a4
--- /dev/null
+++ b/include/cutils/mspace.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* A wrapper file for dlmalloc.h that defines prototypes for the
+ * mspace_*() functions, which provide an interface for creating
+ * multiple heaps.
+ */
+
+#ifndef MSPACE_H_
+#define MSPACE_H_
+
+/* It's a pain getting the mallinfo stuff to work
+ * with Linux, OSX, and klibc, so just turn it off
+ * for now.
+ * TODO: make mallinfo work
+ */
+#define NO_MALLINFO 1
+
+/* Allow setting the maximum heap footprint.
+ */
+#define USE_MAX_ALLOWED_FOOTPRINT 1
+
+#define USE_CONTIGUOUS_MSPACES 1
+#if USE_CONTIGUOUS_MSPACES
+#define HAVE_MMAP 0
+#define HAVE_MORECORE 1
+#define MORECORE_CONTIGUOUS 0
+#endif
+
+#define MSPACES 1
+#define ONLY_MSPACES 1
+#include "dlmalloc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ mspace_usable_size(void* p);
+
+ Returns the number of bytes you can actually use in
+ an allocated chunk, which may be more than you requested (although
+ often not) due to alignment and minimum size constraints.
+ You can use this many bytes without worrying about
+ overwriting other allocated objects. This is not a particularly great
+ programming practice. mspace_usable_size can be more useful in
+ debugging and assertions, for example:
+
+ p = mspace_malloc(msp, n);
+ assert(mspace_usable_size(msp, p) >= 256);
+*/
+size_t mspace_usable_size(mspace, const void*);
+
+#if USE_CONTIGUOUS_MSPACES
+/*
+ Similar to create_mspace(), but the underlying memory is
+ guaranteed to be contiguous. No more than max_capacity
+ bytes is ever allocated to the mspace.
+ */
+mspace create_contiguous_mspace(size_t starting_capacity, size_t max_capacity,
+ int locked);
+
+/*
+ Identical to create_contiguous_mspace, but labels the mapping 'mspace/name'
+ instead of 'mspace'
+*/
+mspace create_contiguous_mspace_with_name(size_t starting_capacity,
+ size_t max_capacity, int locked, const char *name);
+
+/*
+ Identical to create_contiguous_mspace, but uses previously mapped memory.
+*/
+mspace create_contiguous_mspace_with_base(size_t starting_capacity,
+ size_t max_capacity, int locked, void *base);
+
+size_t destroy_contiguous_mspace(mspace msp);
+
+/*
+ Returns the position of the "break" within the given mspace.
+*/
+void *contiguous_mspace_sbrk0(mspace msp);
+#endif
+
+/*
+ Call the handler for each block in the specified mspace.
+ chunkptr and chunklen refer to the heap-level chunk including
+ the chunk overhead, and userptr and userlen refer to the
+ user-usable part of the chunk. If the chunk is free, userptr
+ will be NULL and userlen will be 0. userlen is not guaranteed
+ to be the same value passed into malloc() for a given chunk;
+ it is >= the requested size.
+ */
+void mspace_walk_heap(mspace msp,
+ void(*handler)(const void *chunkptr, size_t chunklen,
+ const void *userptr, size_t userlen, void *arg), void *harg);
+
+/*
+ mspace_walk_free_pages(handler, harg)
+
+ Calls the provided handler on each free region in the specified
+ mspace. The memory between start and end are guaranteed not to
+ contain any important data, so the handler is free to alter the
+ contents in any way. This can be used to advise the OS that large
+ free regions may be swapped out.
+
+ The value in harg will be passed to each call of the handler.
+ */
+void mspace_walk_free_pages(mspace msp,
+ void(*handler)(void *start, void *end, void *arg), void *harg);
+
+#ifdef __cplusplus
+}; /* end of extern "C" */
+#endif
+
+#endif /* MSPACE_H_ */
diff --git a/include/cutils/native_handle.h b/include/cutils/native_handle.h
new file mode 100644
index 0000000..10f5bc0
--- /dev/null
+++ b/include/cutils/native_handle.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef NATIVE_HANDLE_H_
+#define NATIVE_HANDLE_H_
+
+#include <stdalign.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Declare a char array for use with native_handle_init */
+#define NATIVE_HANDLE_DECLARE_STORAGE(name, maxFds, maxInts) \
+ alignas(native_handle_t) char (name)[ \
+ sizeof(native_handle_t) + sizeof(int) * ((maxFds) + (maxInts))]
+
+typedef struct native_handle
+{
+ int version; /* sizeof(native_handle_t) */
+ int numFds; /* number of file-descriptors at &data[0] */
+ int numInts; /* number of ints at &data[numFds] */
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wzero-length-array"
+#endif
+ int data[0]; /* numFds + numInts ints */
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+} native_handle_t;
+
+typedef const native_handle_t* buffer_handle_t;
+
+/*
+ * native_handle_close
+ *
+ * closes the file descriptors contained in this native_handle_t
+ *
+ * return 0 on success, or a negative error code on failure
+ *
+ */
+int native_handle_close(const native_handle_t* h);
+
+/*
+ * native_handle_init
+ *
+ * Initializes a native_handle_t from storage. storage must be declared with
+ * NATIVE_HANDLE_DECLARE_STORAGE. numFds and numInts must not respectively
+ * exceed maxFds and maxInts used to declare the storage.
+ */
+native_handle_t* native_handle_init(char* storage, int numFds, int numInts);
+
+/*
+ * native_handle_create
+ *
+ * creates a native_handle_t and initializes it. must be destroyed with
+ * native_handle_delete().
+ *
+ */
+native_handle_t* native_handle_create(int numFds, int numInts);
+
+/*
+ * native_handle_clone
+ *
+ * creates a native_handle_t and initializes it from another native_handle_t.
+ * Must be destroyed with native_handle_delete().
+ *
+ */
+native_handle_t* native_handle_clone(const native_handle_t* handle);
+
+/*
+ * native_handle_delete
+ *
+ * frees a native_handle_t allocated with native_handle_create().
+ * This ONLY frees the memory allocated for the native_handle_t, but doesn't
+ * close the file descriptors; which can be achieved with native_handle_close().
+ *
+ * return 0 on success, or a negative error code on failure
+ *
+ */
+int native_handle_delete(native_handle_t* h);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NATIVE_HANDLE_H_ */
diff --git a/include/cutils/open_memstream.h b/include/cutils/open_memstream.h
new file mode 100644
index 0000000..b7998be
--- /dev/null
+++ b/include/cutils/open_memstream.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_OPEN_MEMSTREAM_H__
+#define __CUTILS_OPEN_MEMSTREAM_H__
+
+#include <stdio.h>
+
+#ifndef HAVE_OPEN_MEMSTREAM
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+FILE* open_memstream(char** bufp, size_t* sizep);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*!HAVE_OPEN_MEMSTREAM*/
+
+#endif /*__CUTILS_OPEN_MEMSTREAM_H__*/
diff --git a/include/cutils/partition_utils.h b/include/cutils/partition_utils.h
new file mode 100644
index 0000000..597df92
--- /dev/null
+++ b/include/cutils/partition_utils.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_PARTITION_WIPED_H__
+#define __CUTILS_PARTITION_WIPED_H__
+
+__BEGIN_DECLS
+
+int partition_wiped(char *source);
+void erase_footer(const char *dev_path, long long size);
+
+__END_DECLS
+
+#endif /* __CUTILS_PARTITION_WIPED_H__ */
diff --git a/include/cutils/process_name.h b/include/cutils/process_name.h
new file mode 100644
index 0000000..04bd49d
--- /dev/null
+++ b/include/cutils/process_name.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Gives the current process a name.
+ */
+
+#ifndef __PROCESS_NAME_H
+#define __PROCESS_NAME_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Sets the current process name.
+ *
+ * Warning: This leaks a string every time you call it. Use judiciously!
+ */
+void set_process_name(const char* process_name);
+
+/** Gets the current process name. */
+const char* get_process_name(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PROCESS_NAME_H */
diff --git a/include/cutils/properties.h b/include/cutils/properties.h
new file mode 100644
index 0000000..96461c2
--- /dev/null
+++ b/include/cutils/properties.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_PROPERTIES_H
+#define __CUTILS_PROPERTIES_H
+
+#include <sys/cdefs.h>
+#include <stddef.h>
+//#include <sys/system_properties.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PROP_NAME_MAX 32
+#define PROP_VALUE_MAX 92
+
+/* System properties are *small* name value pairs managed by the
+** property service. If your data doesn't fit in the provided
+** space it is not appropriate for a system property.
+**
+** WARNING: system/bionic/include/sys/system_properties.h also defines
+** these, but with different names. (TODO: fix that)
+*/
+#define PROPERTY_KEY_MAX PROP_NAME_MAX
+#define PROPERTY_VALUE_MAX PROP_VALUE_MAX
+
+/* property_get: returns the length of the value which will never be
+** greater than PROPERTY_VALUE_MAX - 1 and will always be zero terminated.
+** (the length does not include the terminating zero).
+**
+** If the property read fails or returns an empty value, the default
+** value is used (if nonnull).
+*/
+int property_get(const char* key, char* value, const char* default_value);
+
+/* property_get_bool: returns the value of key coerced into a
+** boolean. If the property is not set, then the default value is returned.
+**
+* The following is considered to be true (1):
+** "1", "true", "y", "yes", "on"
+**
+** The following is considered to be false (0):
+** "0", "false", "n", "no", "off"
+**
+** The conversion is whitespace-sensitive (e.g. " off" will not be false).
+**
+** If no property with this key is set (or the key is NULL) or the boolean
+** conversion fails, the default value is returned.
+**/
+int8_t property_get_bool(const char *key, int8_t default_value);
+
+/* property_get_int64: returns the value of key truncated and coerced into a
+** int64_t. If the property is not set, then the default value is used.
+**
+** The numeric conversion is identical to strtoimax with the base inferred:
+** - All digits up to the first non-digit characters are read
+** - The longest consecutive prefix of digits is converted to a long
+**
+** Valid strings of digits are:
+** - An optional sign character + or -
+** - An optional prefix indicating the base (otherwise base 10 is assumed)
+** -- 0 prefix is octal
+** -- 0x / 0X prefix is hex
+**
+** Leading/trailing whitespace is ignored. Overflow/underflow will cause
+** numeric conversion to fail.
+**
+** If no property with this key is set (or the key is NULL) or the numeric
+** conversion fails, the default value is returned.
+**/
+int64_t property_get_int64(const char *key, int64_t default_value);
+
+/* property_get_int32: returns the value of key truncated and coerced into an
+** int32_t. If the property is not set, then the default value is used.
+**
+** The numeric conversion is identical to strtoimax with the base inferred:
+** - All digits up to the first non-digit characters are read
+** - The longest consecutive prefix of digits is converted to a long
+**
+** Valid strings of digits are:
+** - An optional sign character + or -
+** - An optional prefix indicating the base (otherwise base 10 is assumed)
+** -- 0 prefix is octal
+** -- 0x / 0X prefix is hex
+**
+** Leading/trailing whitespace is ignored. Overflow/underflow will cause
+** numeric conversion to fail.
+**
+** If no property with this key is set (or the key is NULL) or the numeric
+** conversion fails, the default value is returned.
+**/
+int32_t property_get_int32(const char *key, int32_t default_value);
+
+/* property_set: returns 0 on success, < 0 on failure
+*/
+int property_set(const char *key, const char *value);
+
+#if 0
+int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie);
+
+#if defined(__BIONIC_FORTIFY)
+#define __property_get_err_str "property_get() called with too small of a buffer"
+
+#if defined(__clang__)
+
+/* Some projects use -Weverything; diagnose_if is clang-specific. */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgcc-compat"
+int property_get(const char* key, char* value, const char* default_value)
+ __clang_error_if(__bos(value) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
+ __bos(value) < PROPERTY_VALUE_MAX,
+ __property_get_err_str);
+#pragma clang diagnostic pop
+
+#else /* defined(__clang__) */
+
+extern int __property_get_real(const char *, char *, const char *)
+ __asm__(__USER_LABEL_PREFIX__ "property_get");
+__errordecl(__property_get_too_small_error, __property_get_err_str);
+
+__BIONIC_FORTIFY_INLINE
+int property_get(const char *key, char *value, const char *default_value) {
+ size_t bos = __bos(value);
+ if (bos < PROPERTY_VALUE_MAX) {
+ __property_get_too_small_error();
+ }
+ return __property_get_real(key, value, default_value);
+}
+
+#endif /* defined(__clang__) */
+
+#undef __property_get_err_str
+#endif /* defined(__BIONIC_FORTIFY) */
+#endif
+
+int property_get(const char* key, char* value, const char* default_value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/cutils/qtaguid.h b/include/cutils/qtaguid.h
new file mode 100644
index 0000000..f8550fd
--- /dev/null
+++ b/include/cutils/qtaguid.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_QTAGUID_H
+#define __CUTILS_QTAGUID_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Set tags (and owning UIDs) for network sockets.
+*/
+extern int qtaguid_tagSocket(int sockfd, int tag, uid_t uid);
+
+/*
+ * Untag a network socket before closing.
+*/
+extern int qtaguid_untagSocket(int sockfd);
+
+/*
+ * For the given uid, switch counter sets.
+ * The kernel only keeps a limited number of sets.
+ * 2 for now.
+ */
+extern int qtaguid_setCounterSet(int counterSetNum, uid_t uid);
+
+/*
+ * Delete all tag info that relates to the given tag an uid.
+ * If the tag is 0, then ALL info about the uid is freeded.
+ * The delete data also affects active tagged socketd, which are
+ * then untagged.
+ * The calling process can only operate on its own tags.
+ * Unless it is part of the happy AID_NET_BW_ACCT group.
+ * In which case it can clobber everything.
+ */
+extern int qtaguid_deleteTagData(int tag, uid_t uid);
+
+/*
+ * Enable/disable qtaguid functionnality at a lower level.
+ * When pacified, the kernel will accept commands but do nothing.
+ */
+extern int qtaguid_setPacifier(int on);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_QTAG_UID_H */
diff --git a/include/cutils/record_stream.h b/include/cutils/record_stream.h
new file mode 100644
index 0000000..d86ecbe
--- /dev/null
+++ b/include/cutils/record_stream.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * A simple utility for reading fixed records out of a stream fd
+ */
+
+#ifndef _CUTILS_RECORD_STREAM_H
+#define _CUTILS_RECORD_STREAM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct RecordStream RecordStream;
+
+extern RecordStream *record_stream_new(int fd, size_t maxRecordLen);
+extern void record_stream_free(RecordStream *p_rs);
+
+extern int record_stream_get_next (RecordStream *p_rs, void ** p_outRecord,
+ size_t *p_outRecordLen);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /*_CUTILS_RECORD_STREAM_H*/
+
diff --git a/include/cutils/sched_policy.h b/include/cutils/sched_policy.h
new file mode 100644
index 0000000..218078e
--- /dev/null
+++ b/include/cutils/sched_policy.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_SCHED_POLICY_H
+#define __CUTILS_SCHED_POLICY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ SP_BACKGROUND = 0,
+ SP_FOREGROUND = 1,
+} SchedPolicy;
+
+extern int set_sched_policy(int tid, SchedPolicy policy);
+extern int get_sched_policy(int tid, SchedPolicy *policy);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_SCHED_POLICY_H */
diff --git a/include/cutils/selector.h b/include/cutils/selector.h
new file mode 100644
index 0000000..25b514c
--- /dev/null
+++ b/include/cutils/selector.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Framework for multiplexing I/O. A selector manages a set of file
+ * descriptors and calls out to user-provided callback functions to read and
+ * write data and handle errors.
+ */
+
+#ifndef __SELECTOR_H
+#define __SELECTOR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+
+/**
+ * Manages SelectableFds and invokes their callbacks at appropriate times.
+ */
+typedef struct Selector Selector;
+
+/**
+ * A selectable descriptor. Contains callbacks which the selector can invoke
+ * before calling select(), when the descriptor is readable or writable, and
+ * when the descriptor contains out-of-band data. Simply set a callback to
+ * NULL if you're not interested in that particular event.
+ *
+ * A selectable descriptor can indicate that it needs to be removed from the
+ * selector by setting the 'remove' flag. The selector will remove the
+ * descriptor at a later time and invoke the onRemove() callback.
+ *
+ * SelectableFd fields should only be modified from the selector loop.
+ */
+typedef struct SelectableFd SelectableFd;
+struct SelectableFd {
+
+ /** The file descriptor itself. */
+ int fd;
+
+ /** Pointer to user-specific data. Can be NULL. */
+ void* data;
+
+ /**
+ * Set this flag when you no longer wish to be selected. The selector
+ * will invoke onRemove() when the descriptor is actually removed.
+ */
+ bool remove;
+
+ /**
+ * Invoked by the selector before calling select. You can set up other
+ * callbacks from here as necessary.
+ */
+ void (*beforeSelect)(SelectableFd* self);
+
+ /**
+ * Invoked by the selector when the descriptor has data available. Set to
+ * NULL to indicate that you're not interested in reading.
+ */
+ void (*onReadable)(SelectableFd* self);
+
+ /**
+ * Invoked by the selector when the descriptor can accept data. Set to
+ * NULL to indicate that you're not interested in writing.
+ */
+ void (*onWritable)(SelectableFd* self);
+
+ /**
+ * Invoked by the selector when out-of-band (OOB) data is available. Set to
+ * NULL to indicate that you're not interested in OOB data.
+ */
+ void (*onExcept)(SelectableFd* self);
+
+ /**
+ * Invoked by the selector after the descriptor is removed from the
+ * selector but before the selector frees the SelectableFd memory.
+ */
+ void (*onRemove)(SelectableFd* self);
+
+ /**
+ * The selector which selected this fd. Set by the selector itself.
+ */
+ Selector* selector;
+};
+
+/**
+ * Creates a new selector
+ */
+Selector* selectorCreate(void);
+
+/**
+ * Creates a new selectable fd, adds it to the given selector and returns a
+ * pointer. Outside of 'selector' and 'fd', all fields are set to 0 or NULL
+ * by default.
+ *
+ * The selectable fd should only be modified from the selector loop thread.
+ */
+SelectableFd* selectorAdd(Selector* selector, int fd);
+
+/**
+ * Wakes up the selector even though no I/O events occurred. Use this
+ * to indicate that you're ready to write to a descriptor.
+ */
+void selectorWakeUp(Selector* selector);
+
+/**
+ * Loops continuously selecting file descriptors and firing events.
+ * Does not return.
+ */
+void selectorLoop(Selector* selector);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SELECTOR_H */
diff --git a/include/cutils/sockets.h b/include/cutils/sockets.h
new file mode 100644
index 0000000..6feccfe
--- /dev/null
+++ b/include/cutils/sockets.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_SOCKETS_H
+#define __CUTILS_SOCKETS_H
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+
+#include <sys/socket.h>
+
+#define ANDROID_SOCKET_ENV_PREFIX "ANDROID_SOCKET_"
+#define ANDROID_SOCKET_DIR "/dev/socket"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * android_get_control_socket - simple helper function to get the file
+ * descriptor of our init-managed Unix domain socket. `name' is the name of the
+ * socket, as given in init.rc. Returns -1 on error.
+ *
+ * This is inline and not in libcutils proper because we want to use this in
+ * third-party daemons with minimal modification.
+ */
+static inline int android_get_control_socket(const char *name)
+{
+ char key[64] = ANDROID_SOCKET_ENV_PREFIX;
+ const char *val;
+ int fd;
+
+ /* build our environment variable, counting cycles like a wolf ... */
+#if HAVE_STRLCPY
+ strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
+ name,
+ sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
+#else /* for the host, which may lack the almightly strncpy ... */
+ strncpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
+ name,
+ sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
+ key[sizeof(key)-1] = '\0';
+#endif
+
+ val = getenv(key);
+ if (!val)
+ return -1;
+
+ errno = 0;
+ fd = strtol(val, NULL, 10);
+ if (errno)
+ return -1;
+
+ return fd;
+}
+
+/*
+ * See also android.os.LocalSocketAddress.Namespace
+ */
+// Linux "abstract" (non-filesystem) namespace
+#define ANDROID_SOCKET_NAMESPACE_ABSTRACT 0
+// Android "reserved" (/dev/socket) namespace
+#define ANDROID_SOCKET_NAMESPACE_RESERVED 1
+// Normal filesystem namespace
+#define ANDROID_SOCKET_NAMESPACE_FILESYSTEM 2
+
+extern int socket_loopback_client(int port, int type);
+extern int socket_network_client(const char *host, int port, int type);
+extern int socket_loopback_server(int port, int type);
+extern int socket_local_server(const char *name, int namespaceId, int type);
+extern int socket_local_server_bind(int s, const char *name, int namespaceId);
+extern int socket_local_client_connect(int fd,
+ const char *name, int namespaceId, int type);
+extern int socket_local_client(const char *name, int namespaceId, int type);
+extern int socket_inaddr_any_server(int port, int type);
+
+/*
+ * socket_peer_is_trusted - Takes a socket which is presumed to be a
+ * connected local socket (e.g. AF_LOCAL) and returns whether the peer
+ * (the userid that owns the process on the other end of that socket)
+ * is one of the two trusted userids, root or shell.
+ *
+ * Note: This only works as advertised on the Android OS and always
+ * just returns true when called on other operating systems.
+ */
+extern bool socket_peer_is_trusted(int fd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_SOCKETS_H */
diff --git a/include/cutils/str_parms.h b/include/cutils/str_parms.h
new file mode 100644
index 0000000..aa1435a
--- /dev/null
+++ b/include/cutils/str_parms.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_STR_PARMS_H
+#define __CUTILS_STR_PARMS_H
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+struct str_parms;
+
+struct str_parms *str_parms_create(void);
+struct str_parms *str_parms_create_str(const char *_string);
+void str_parms_destroy(struct str_parms *str_parms);
+
+void str_parms_del(struct str_parms *str_parms, const char *key);
+
+int str_parms_add_str(struct str_parms *str_parms, const char *key,
+ const char *value);
+int str_parms_add_int(struct str_parms *str_parms, const char *key, int value);
+
+int str_parms_add_float(struct str_parms *str_parms, const char *key,
+ float value);
+
+// Returns non-zero if the str_parms contains the specified key.
+int str_parms_has_key(struct str_parms *str_parms, const char *key);
+
+// Gets value associated with the specified key (if present), placing it in the buffer
+// pointed to by the out_val parameter. Returns the length of the returned string value.
+// If 'key' isn't in the parms, then return -ENOENT (-2) and leave 'out_val' untouched.
+int str_parms_get_str(struct str_parms *str_parms, const char *key,
+ char *out_val, int len);
+int str_parms_get_int(struct str_parms *str_parms, const char *key,
+ int *out_val);
+int str_parms_get_float(struct str_parms *str_parms, const char *key,
+ float *out_val);
+
+char *str_parms_to_str(struct str_parms *str_parms);
+
+/* debug */
+void str_parms_dump(struct str_parms *str_parms);
+
+__END_DECLS
+
+#endif /* __CUTILS_STR_PARMS_H */
diff --git a/include/cutils/threads.h b/include/cutils/threads.h
new file mode 100644
index 0000000..5727494
--- /dev/null
+++ b/include/cutils/threads.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBS_CUTILS_THREADS_H
+#define _LIBS_CUTILS_THREADS_H
+
+#include <sys/types.h>
+
+#if !defined(_WIN32)
+#include <pthread.h>
+#else
+#include <windows.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***********************************************************************/
+/***********************************************************************/
+/***** *****/
+/***** local thread storage *****/
+/***** *****/
+/***********************************************************************/
+/***********************************************************************/
+
+extern pid_t gettid();
+
+#if !defined(_WIN32)
+
+typedef struct {
+ pthread_mutex_t lock;
+ int has_tls;
+ pthread_key_t tls;
+} thread_store_t;
+
+#define THREAD_STORE_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0, 0 }
+
+#else // !defined(_WIN32)
+
+typedef struct {
+ int lock_init;
+ int has_tls;
+ DWORD tls;
+ CRITICAL_SECTION lock;
+} thread_store_t;
+
+#define THREAD_STORE_INITIALIZER { 0, 0, 0, {0, 0, 0, 0, 0, 0} }
+
+#endif // !defined(_WIN32)
+
+typedef void (*thread_store_destruct_t)(void* value);
+
+extern void* thread_store_get(thread_store_t* store);
+
+extern void thread_store_set(thread_store_t* store,
+ void* value,
+ thread_store_destruct_t destroy);
+
+/***********************************************************************/
+/***********************************************************************/
+/***** *****/
+/***** mutexes *****/
+/***** *****/
+/***********************************************************************/
+/***********************************************************************/
+
+#if !defined(_WIN32)
+
+typedef pthread_mutex_t mutex_t;
+
+#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+
+static __inline__ void mutex_lock(mutex_t* lock)
+{
+ pthread_mutex_lock(lock);
+}
+static __inline__ void mutex_unlock(mutex_t* lock)
+{
+ pthread_mutex_unlock(lock);
+}
+static __inline__ int mutex_init(mutex_t* lock)
+{
+ return pthread_mutex_init(lock, NULL);
+}
+static __inline__ void mutex_destroy(mutex_t* lock)
+{
+ pthread_mutex_destroy(lock);
+}
+
+#else // !defined(_WIN32)
+
+typedef struct {
+ int init;
+ CRITICAL_SECTION lock[1];
+} mutex_t;
+
+#define MUTEX_INITIALIZER { 0, {{ NULL, 0, 0, NULL, NULL, 0 }} }
+
+static __inline__ void mutex_lock(mutex_t* lock)
+{
+ if (!lock->init) {
+ lock->init = 1;
+ InitializeCriticalSection( lock->lock );
+ lock->init = 2;
+ } else while (lock->init != 2)
+ Sleep(10);
+
+ EnterCriticalSection(lock->lock);
+}
+
+static __inline__ void mutex_unlock(mutex_t* lock)
+{
+ LeaveCriticalSection(lock->lock);
+}
+static __inline__ int mutex_init(mutex_t* lock)
+{
+ InitializeCriticalSection(lock->lock);
+ lock->init = 2;
+ return 0;
+}
+static __inline__ void mutex_destroy(mutex_t* lock)
+{
+ if (lock->init) {
+ lock->init = 0;
+ DeleteCriticalSection(lock->lock);
+ }
+}
+#endif // !defined(_WIN32)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBS_CUTILS_THREADS_H */
diff --git a/include/cutils/tztime.h b/include/cutils/tztime.h
new file mode 100644
index 0000000..14bbc1d
--- /dev/null
+++ b/include/cutils/tztime.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CUTILS_TZTIME_H
+#define _CUTILS_TZTIME_H
+
+#include <time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+time_t mktime_tz(struct tm * const tmp, char const * tz);
+void localtime_tz(const time_t * const timep, struct tm * tmp, const char* tz);
+
+#if !defined(HAVE_ANDROID_OS) || HAVE_GLIBC
+/* the following is defined in <time.h> in Bionic */
+
+struct strftime_locale {
+ const char *mon[12]; /* short names */
+ const char *month[12]; /* long names */
+ const char *standalone_month[12]; /* long standalone names */
+ const char *wday[7]; /* short names */
+ const char *weekday[7]; /* long names */
+ const char *X_fmt;
+ const char *x_fmt;
+ const char *c_fmt;
+ const char *am;
+ const char *pm;
+ const char *date_fmt;
+};
+
+size_t strftime_tz(char *s, size_t max, const char *format, const struct tm *tm, const struct strftime_locale *locale);
+
+#endif /* !HAVE_ANDROID_OS || HAVE_GLIBC */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_TZTIME_H */
diff --git a/include/cutils/uevent.h b/include/cutils/uevent.h
new file mode 100644
index 0000000..4ebc300
--- /dev/null
+++ b/include/cutils/uevent.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_UEVENT_H
+#define __CUTILS_UEVENT_H
+
+#include <stdbool.h>
+#include <sys/socket.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int uevent_open_socket(int buf_sz, bool passcred);
+ssize_t uevent_kernel_multicast_recv(int socket, void *buffer, size_t length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_UEVENT_H */
diff --git a/include/cutils/uio.h b/include/cutils/uio.h
new file mode 100644
index 0000000..4691a13
--- /dev/null
+++ b/include/cutils/uio.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// implementation of sys/uio.h for platforms that don't have it (Win32)
+//
+#ifndef _LIBS_CUTILS_UIO_H
+#define _LIBS_CUTILS_UIO_H
+
+#define HAVE_SYS_UIO_H
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#else
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h>
+/*
+struct iovec {
+ const void* iov_base;
+ size_t iov_len;
+};
+
+extern int readv( int fd, struct iovec* vecs, int count );
+*/
+extern int writev( int fd, const struct iovec* vecs, int count );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !HAVE_SYS_UIO_H */
+
+#endif /* _LIBS_UTILS_UIO_H */
+
diff --git a/include/cutils/zygote.h b/include/cutils/zygote.h
new file mode 100644
index 0000000..22721a6
--- /dev/null
+++ b/include/cutils/zygote.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_ZYGOTE_H
+#define __CUTILS_ZYGOTE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int zygote_run_oneshot(int sendStdio, int argc, const char **argv);
+int zygote_run(int argc, const char **argv);
+int zygote_run_wait(int argc, const char **argv, void (*post_run_func)(int));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_ZYGOTE_H */
diff --git a/include/media/AudioBufferProvider.h b/include/media/AudioBufferProvider.h
new file mode 100644
index 0000000..458d170
--- /dev/null
+++ b/include/media/AudioBufferProvider.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_BUFFER_PROVIDER_H
+#define ANDROID_AUDIO_BUFFER_PROVIDER_H
+
+#include <utils/Errors.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class AudioBufferProvider
+{
+public:
+
+ // FIXME merge with AudioTrackShared::Buffer, AudioTrack::Buffer, and AudioRecord::Buffer
+ // and rename getNextBuffer() to obtainBuffer()
+ struct Buffer {
+ Buffer() : raw(NULL), frameCount(0) { }
+ union {
+ void* raw;
+ short* i16;
+ int8_t* i8;
+ };
+ size_t frameCount;
+ };
+
+ virtual ~AudioBufferProvider() {}
+
+ // On entry:
+ // buffer != NULL
+ // buffer->raw unused
+ // buffer->frameCount maximum number of desired frames
+ // On successful return:
+ // status NO_ERROR
+ // buffer->raw non-NULL pointer to buffer->frameCount contiguous available frames
+ // buffer->frameCount number of contiguous available frames at buffer->raw,
+ // 0 < buffer->frameCount <= entry value
+ // On error return:
+ // status != NO_ERROR
+ // buffer->raw NULL
+ // buffer->frameCount 0
+ virtual status_t getNextBuffer(Buffer* buffer) = 0;
+
+ // Release (a portion of) the buffer previously obtained by getNextBuffer().
+ // It is permissible to call releaseBuffer() multiple times per getNextBuffer().
+ // On entry:
+ // buffer->frameCount number of frames to release, must be <= number of frames
+ // obtained but not yet released
+ // buffer->raw unused
+ // On return:
+ // buffer->frameCount 0; implementation MUST set to zero
+ // buffer->raw undefined; implementation is PERMITTED to set to any value,
+ // so if caller needs to continue using this buffer it must
+ // keep track of the pointer itself
+ virtual void releaseBuffer(Buffer* buffer) = 0;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_AUDIO_BUFFER_PROVIDER_H
diff --git a/include/media/AudioResampler.h b/include/media/AudioResampler.h
new file mode 100644
index 0000000..c4627e8
--- /dev/null
+++ b/include/media/AudioResampler.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_RESAMPLER_H
+#define ANDROID_AUDIO_RESAMPLER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <cutils/compiler.h>
+#include <utils/Compat.h>
+
+#include <media/AudioBufferProvider.h>
+#include <system/audio.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class ANDROID_API AudioResampler {
+public:
+ // Determines quality of SRC.
+ // LOW_QUALITY: linear interpolator (1st order)
+ // MED_QUALITY: cubic interpolator (3rd order)
+ // HIGH_QUALITY: fixed multi-tap FIR (e.g. 48KHz->44.1KHz)
+ // NOTE: high quality SRC will only be supported for
+ // certain fixed rate conversions. Sample rate cannot be
+ // changed dynamically.
+ enum src_quality {
+ DEFAULT_QUALITY=0,
+ LOW_QUALITY=1,
+ MED_QUALITY=2,
+ HIGH_QUALITY=3,
+ VERY_HIGH_QUALITY=4,
+ DYN_LOW_QUALITY=5,
+ DYN_MED_QUALITY=6,
+ DYN_HIGH_QUALITY=7,
+ };
+
+ static const CONSTEXPR float UNITY_GAIN_FLOAT = 1.0f;
+
+ static AudioResampler* create(audio_format_t format, int inChannelCount,
+ int32_t sampleRate, src_quality quality=DEFAULT_QUALITY);
+
+ virtual ~AudioResampler();
+
+ virtual void init() = 0;
+ virtual void setSampleRate(int32_t inSampleRate);
+ virtual void setVolume(float left, float right);
+
+ // Resample int16_t samples from provider and accumulate into 'out'.
+ // A mono provider delivers a sequence of samples.
+ // A stereo provider delivers a sequence of interleaved pairs of samples.
+ //
+ // In either case, 'out' holds interleaved pairs of fixed-point Q4.27.
+ // That is, for a mono provider, there is an implicit up-channeling.
+ // Since this method accumulates, the caller is responsible for clearing 'out' initially.
+ //
+ // For a float resampler, 'out' holds interleaved pairs of float samples.
+ //
+ // Multichannel interleaved frames for n > 2 is supported for quality DYN_LOW_QUALITY,
+ // DYN_MED_QUALITY, and DYN_HIGH_QUALITY.
+ //
+ // Returns the number of frames resampled into the out buffer.
+ virtual size_t resample(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider) = 0;
+
+ virtual void reset();
+ virtual size_t getUnreleasedFrames() const { return mInputIndex; }
+
+ // called from destructor, so must not be virtual
+ src_quality getQuality() const { return mQuality; }
+
+protected:
+ // number of bits for phase fraction - 30 bits allows nearly 2x downsampling
+ static const int kNumPhaseBits = 30;
+
+ // phase mask for fraction
+ static const uint32_t kPhaseMask = (1LU<<kNumPhaseBits)-1;
+
+ // multiplier to calculate fixed point phase increment
+ static const double kPhaseMultiplier;
+
+ AudioResampler(int inChannelCount, int32_t sampleRate, src_quality quality);
+
+ // prevent copying
+ AudioResampler(const AudioResampler&);
+ AudioResampler& operator=(const AudioResampler&);
+
+ const int32_t mChannelCount;
+ const int32_t mSampleRate;
+ int32_t mInSampleRate;
+ AudioBufferProvider::Buffer mBuffer;
+ union {
+ int16_t mVolume[2];
+ uint32_t mVolumeRL;
+ };
+ int16_t mTargetVolume[2];
+ size_t mInputIndex;
+ int32_t mPhaseIncrement;
+ uint32_t mPhaseFraction;
+
+ // returns the inFrameCount required to generate outFrameCount frames.
+ //
+ // Placed here to be a consistent for all resamplers.
+ //
+ // Right now, we use the upper bound without regards to the current state of the
+ // input buffer using integer arithmetic, as follows:
+ //
+ // (static_cast<uint64_t>(outFrameCount)*mInSampleRate + (mSampleRate - 1))/mSampleRate;
+ //
+ // The double precision equivalent (float may not be precise enough):
+ // ceil(static_cast<double>(outFrameCount) * mInSampleRate / mSampleRate);
+ //
+ // this relies on the fact that the mPhaseIncrement is rounded down from
+ // #phases * mInSampleRate/mSampleRate and the fact that Sum(Floor(x)) <= Floor(Sum(x)).
+ // http://www.proofwiki.org/wiki/Sum_of_Floors_Not_Greater_Than_Floor_of_Sums
+ //
+ // (so long as double precision is computed accurately enough to be considered
+ // greater than or equal to the Floor(x) value in int32_t arithmetic; thus this
+ // will not necessarily hold for floats).
+ //
+ // TODO:
+ // Greater accuracy and a tight bound is obtained by:
+ // 1) subtract and adjust for the current state of the AudioBufferProvider buffer.
+ // 2) using the exact integer formula where (ignoring 64b casting)
+ // inFrameCount = (mPhaseIncrement * (outFrameCount - 1) + mPhaseFraction) / phaseWrapLimit;
+ // phaseWrapLimit is the wraparound (1 << kNumPhaseBits), if not specified explicitly.
+ //
+ inline size_t getInFrameCountRequired(size_t outFrameCount) {
+ return (static_cast<uint64_t>(outFrameCount)*mInSampleRate
+ + (mSampleRate - 1))/mSampleRate;
+ }
+
+ inline float clampFloatVol(float volume) {
+ if (volume > UNITY_GAIN_FLOAT) {
+ return UNITY_GAIN_FLOAT;
+ } else if (volume >= 0.) {
+ return volume;
+ }
+ return 0.; // NaN or negative volume maps to 0.
+ }
+
+private:
+ const src_quality mQuality;
+
+ // Return 'true' if the quality level is supported without explicit request
+ static bool qualityIsSupported(src_quality quality);
+
+ // For pthread_once()
+ static void init_routine();
+
+ // Return the estimated CPU load for specific resampler in MHz.
+ // The absolute number is irrelevant, it's the relative values that matter.
+ static uint32_t qualityMHz(src_quality quality);
+};
+
+// ----------------------------------------------------------------------------
+} // namespace android
+
+#endif // ANDROID_AUDIO_RESAMPLER_H
diff --git a/include/private/private.h b/include/private/private.h
new file mode 100644
index 0000000..d10d1ea
--- /dev/null
+++ b/include/private/private.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_PRIVATE_H
+#define ANDROID_AUDIO_PRIVATE_H
+
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+/* Defines not necessary for external use but kept here to be common
+ * to the audio_utils library.
+ */
+
+/* struct representation of 3 bytes for packed PCM 24 bit data.
+ * The naming follows the ARM NEON convention.
+ */
+typedef struct {uint8_t c[3];} __attribute__((__packed__)) uint8x3_t;
+
+__END_DECLS
+
+#endif /*ANDROID_AUDIO_PRIVATE_H*/
diff --git a/include/resampler.h b/include/resampler.h
new file mode 100644
index 0000000..559e020
--- /dev/null
+++ b/include/resampler.h
@@ -0,0 +1,109 @@
+/*
+** Copyright 2008, The Android Open-Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_RESAMPLER_H
+#define ANDROID_RESAMPLER_H
+
+#include <stdint.h>
+#include <sys/time.h>
+
+__BEGIN_DECLS
+
+
+#define RESAMPLER_QUALITY_MAX 10
+#define RESAMPLER_QUALITY_MIN 0
+#define RESAMPLER_QUALITY_DEFAULT 4
+#define RESAMPLER_QUALITY_VOIP 3
+#define RESAMPLER_QUALITY_DESKTOP 5
+
+struct resampler_buffer {
+ union {
+ void* raw;
+ short* i16;
+ int8_t* i8;
+ };
+ size_t frame_count;
+};
+
+/** call back interface used by the resampler to get new data */
+struct resampler_buffer_provider
+{
+ /**
+ * get a new buffer of data:
+ * as input: buffer->frame_count is the number of frames requested
+ * as output: buffer->frame_count is the number of frames returned
+ * buffer->raw points to data returned
+ */
+ int (*get_next_buffer)(struct resampler_buffer_provider *provider,
+ struct resampler_buffer *buffer);
+ /**
+ * release a consumed buffer of data:
+ * as input: buffer->frame_count is the number of frames released
+ * buffer->raw points to data released
+ */
+ void (*release_buffer)(struct resampler_buffer_provider *provider,
+ struct resampler_buffer *buffer);
+};
+
+/** resampler interface */
+struct resampler_itfe {
+ /**
+ * reset resampler state
+ */
+ void (*reset)(struct resampler_itfe *resampler);
+ /**
+ * resample input from buffer provider and output at most *outFrameCount to out buffer.
+ * *outFrameCount is updated with the actual number of frames produced.
+ */
+ int (*resample_from_provider)(struct resampler_itfe *resampler,
+ int16_t *out,
+ size_t *outFrameCount);
+ /**
+ * resample at most *inFrameCount frames from in buffer and output at most
+ * *outFrameCount to out buffer. *inFrameCount and *outFrameCount are updated respectively
+ * with the number of frames remaining in input and written to output.
+ */
+ int (*resample_from_input)(struct resampler_itfe *resampler,
+ int16_t *in,
+ size_t *inFrameCount,
+ int16_t *out,
+ size_t *outFrameCount);
+ /**
+ * \return the latency introduced by the resampler in ns.
+ */
+ int32_t (*delay_ns)(struct resampler_itfe *resampler);
+};
+
+/**
+ * create a resampler according to input parameters passed.
+ * If resampler_buffer_provider is not NULL only resample_from_provider() can be called.
+ * If resampler_buffer_provider is NULL only resample_from_input() can be called.
+ */
+int create_resampler(uint32_t inSampleRate,
+ uint32_t outSampleRate,
+ uint32_t channelCount,
+ uint32_t quality,
+ struct resampler_buffer_provider *provider,
+ struct resampler_itfe **);
+
+/**
+ * release resampler resources.
+ */
+void release_resampler(struct resampler_itfe *);
+
+__END_DECLS
+
+#endif // ANDROID_RESAMPLER_H
diff --git a/include/speex/arch.h b/include/speex/arch.h
new file mode 100644
index 0000000..e911422
--- /dev/null
+++ b/include/speex/arch.h
@@ -0,0 +1,240 @@
+/* Copyright (C) 2003 Jean-Marc Valin */
+/**
+ @file arch.h
+ @brief Various architecture definitions Speex
+*/
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ - Neither the name of the Xiph.org Foundation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef ARCH_H
+#define ARCH_H
+
+#ifndef SPEEX_VERSION
+#define SPEEX_MAJOR_VERSION 1 /**< Major Speex version. */
+#define SPEEX_MINOR_VERSION 1 /**< Minor Speex version. */
+#define SPEEX_MICRO_VERSION 15 /**< Micro Speex version. */
+#define SPEEX_EXTRA_VERSION "" /**< Extra Speex version. */
+#define SPEEX_VERSION "speex-1.2beta3" /**< Speex version string. */
+#endif
+
+/* A couple test to catch stupid option combinations */
+#ifdef FIXED_POINT
+
+#ifdef FLOATING_POINT
+#error You cannot compile as floating point and fixed point at the same time
+#endif
+#ifdef _USE_SSE
+#error SSE is only for floating-point
+#endif
+#if ((defined (ARM4_ASM)||defined (ARM4_ASM)) && defined(BFIN_ASM)) || (defined (ARM4_ASM)&&defined(ARM5E_ASM))
+#error Make up your mind. What CPU do you have?
+#endif
+#ifdef VORBIS_PSYCHO
+#error Vorbis-psy model currently not implemented in fixed-point
+#endif
+
+#else
+
+#ifndef FLOATING_POINT
+#error You now need to define either FIXED_POINT or FLOATING_POINT
+#endif
+#if defined (ARM4_ASM) || defined(ARM5E_ASM) || defined(BFIN_ASM)
+#error I suppose you can have a [ARM4/ARM5E/Blackfin] that has float instructions?
+#endif
+#ifdef FIXED_POINT_DEBUG
+#error "Don't you think enabling fixed-point is a good thing to do if you want to debug that?"
+#endif
+
+
+#endif
+
+#ifndef OUTSIDE_SPEEX
+#include "speex/speex_types.h"
+#endif
+
+#define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */
+#define ABS16(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 16-bit value. */
+#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 16-bit value. */
+#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */
+#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */
+#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 32-bit value. */
+#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */
+
+#ifdef FIXED_POINT
+
+typedef spx_int16_t spx_word16_t;
+typedef spx_int32_t spx_word32_t;
+typedef spx_word32_t spx_mem_t;
+typedef spx_word16_t spx_coef_t;
+typedef spx_word16_t spx_lsp_t;
+typedef spx_word32_t spx_sig_t;
+
+#define Q15ONE 32767
+
+#define LPC_SCALING 8192
+#define SIG_SCALING 16384
+#define LSP_SCALING 8192.
+#define GAMMA_SCALING 32768.
+#define GAIN_SCALING 64
+#define GAIN_SCALING_1 0.015625
+
+#define LPC_SHIFT 13
+#define LSP_SHIFT 13
+#define SIG_SHIFT 14
+#define GAIN_SHIFT 6
+
+#define VERY_SMALL 0
+#define VERY_LARGE32 ((spx_word32_t)2147483647)
+#define VERY_LARGE16 ((spx_word16_t)32767)
+#define Q15_ONE ((spx_word16_t)32767)
+
+
+#ifdef FIXED_DEBUG
+#include "fixed_debug.h"
+#else
+
+#include "fixed_generic.h"
+
+#ifdef ARM5E_ASM
+#include "fixed_arm5e.h"
+#elif defined (ARM4_ASM)
+#include "fixed_arm4.h"
+#elif defined (BFIN_ASM)
+#include "fixed_bfin.h"
+#endif
+
+#endif
+
+
+#else
+
+typedef float spx_mem_t;
+typedef float spx_coef_t;
+typedef float spx_lsp_t;
+typedef float spx_sig_t;
+typedef float spx_word16_t;
+typedef float spx_word32_t;
+
+#define Q15ONE 1.0f
+#define LPC_SCALING 1.f
+#define SIG_SCALING 1.f
+#define LSP_SCALING 1.f
+#define GAMMA_SCALING 1.f
+#define GAIN_SCALING 1.f
+#define GAIN_SCALING_1 1.f
+
+
+#define VERY_SMALL 1e-15f
+#define VERY_LARGE32 1e15f
+#define VERY_LARGE16 1e15f
+#define Q15_ONE ((spx_word16_t)1.f)
+
+#define QCONST16(x,bits) (x)
+#define QCONST32(x,bits) (x)
+
+#define NEG16(x) (-(x))
+#define NEG32(x) (-(x))
+#define EXTRACT16(x) (x)
+#define EXTEND32(x) (x)
+#define SHR16(a,shift) (a)
+#define SHL16(a,shift) (a)
+#define SHR32(a,shift) (a)
+#define SHL32(a,shift) (a)
+#define PSHR16(a,shift) (a)
+#define PSHR32(a,shift) (a)
+#define VSHR32(a,shift) (a)
+#define SATURATE16(x,a) (x)
+#define SATURATE32(x,a) (x)
+#define SATURATE32PSHR(x,shift,a) (x)
+
+#define PSHR(a,shift) (a)
+#define SHR(a,shift) (a)
+#define SHL(a,shift) (a)
+#define SATURATE(x,a) (x)
+
+#define ADD16(a,b) ((a)+(b))
+#define SUB16(a,b) ((a)-(b))
+#define ADD32(a,b) ((a)+(b))
+#define SUB32(a,b) ((a)-(b))
+#define MULT16_16_16(a,b) ((a)*(b))
+#define MULT16_16(a,b) ((spx_word32_t)(a)*(spx_word32_t)(b))
+#define MAC16_16(c,a,b) ((c)+(spx_word32_t)(a)*(spx_word32_t)(b))
+
+#define MULT16_32_Q11(a,b) ((a)*(b))
+#define MULT16_32_Q13(a,b) ((a)*(b))
+#define MULT16_32_Q14(a,b) ((a)*(b))
+#define MULT16_32_Q15(a,b) ((a)*(b))
+#define MULT16_32_P15(a,b) ((a)*(b))
+
+#define MAC16_32_Q11(c,a,b) ((c)+(a)*(b))
+#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b))
+
+#define MAC16_16_Q11(c,a,b) ((c)+(a)*(b))
+#define MAC16_16_Q13(c,a,b) ((c)+(a)*(b))
+#define MAC16_16_P13(c,a,b) ((c)+(a)*(b))
+#define MULT16_16_Q11_32(a,b) ((a)*(b))
+#define MULT16_16_Q13(a,b) ((a)*(b))
+#define MULT16_16_Q14(a,b) ((a)*(b))
+#define MULT16_16_Q15(a,b) ((a)*(b))
+#define MULT16_16_P15(a,b) ((a)*(b))
+#define MULT16_16_P13(a,b) ((a)*(b))
+#define MULT16_16_P14(a,b) ((a)*(b))
+
+#define DIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b))
+#define PDIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b))
+#define DIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b))
+#define PDIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b))
+
+
+#endif
+
+
+#if defined (CONFIG_TI_C54X) || defined (CONFIG_TI_C55X)
+
+/* 2 on TI C5x DSP */
+#define BYTES_PER_CHAR 2
+#define BITS_PER_CHAR 16
+#define LOG2_BITS_PER_CHAR 4
+
+#else
+
+#define BYTES_PER_CHAR 1
+#define BITS_PER_CHAR 8
+#define LOG2_BITS_PER_CHAR 3
+
+#endif
+
+
+
+#ifdef FIXED_DEBUG
+extern long long spx_mips;
+#endif
+
+
+#endif
diff --git a/include/speex/fixed_generic.h b/include/speex/fixed_generic.h
new file mode 100644
index 0000000..0e012e9
--- /dev/null
+++ b/include/speex/fixed_generic.h
@@ -0,0 +1,110 @@
+/* Copyright (C) 2003 Jean-Marc Valin */
+/**
+ @file fixed_generic.h
+ @brief Generic fixed-point operations
+*/
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ - Neither the name of the Xiph.org Foundation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef FIXED_GENERIC_H
+#define FIXED_GENERIC_H
+
+#define QCONST16(x,bits) ((spx_word16_t)(.5+(x)*(((spx_word32_t)1)<<(bits))))
+#define QCONST32(x,bits) ((spx_word32_t)(.5+(x)*(((spx_word32_t)1)<<(bits))))
+
+#define NEG16(x) (-(x))
+#define NEG32(x) (-(x))
+#define EXTRACT16(x) ((spx_word16_t)(x))
+#define EXTEND32(x) ((spx_word32_t)(x))
+#define SHR16(a,shift) ((a) >> (shift))
+#define SHL16(a,shift) ((a) << (shift))
+#define SHR32(a,shift) ((a) >> (shift))
+#define SHL32(a,shift) ((a) << (shift))
+#define PSHR16(a,shift) (SHR16((a)+((1<<((shift))>>1)),shift))
+#define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift))
+#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift)))
+#define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
+#define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
+
+#define SATURATE32PSHR(x,shift,a) (((x)>=(SHL32(a,shift))) ? (a) : \
+ (x)<=-(SHL32(a,shift)) ? -(a) : \
+ (PSHR32(x, shift)))
+
+#define SHR(a,shift) ((a) >> (shift))
+#define SHL(a,shift) ((spx_word32_t)(a) << (shift))
+#define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift))
+#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
+
+
+#define ADD16(a,b) ((spx_word16_t)((spx_word16_t)(a)+(spx_word16_t)(b)))
+#define SUB16(a,b) ((spx_word16_t)(a)-(spx_word16_t)(b))
+#define ADD32(a,b) ((spx_word32_t)(a)+(spx_word32_t)(b))
+#define SUB32(a,b) ((spx_word32_t)(a)-(spx_word32_t)(b))
+
+
+/* result fits in 16 bits */
+#define MULT16_16_16(a,b) ((((spx_word16_t)(a))*((spx_word16_t)(b))))
+
+/* (spx_word32_t)(spx_word16_t) gives TI compiler a hint that it's 16x16->32 multiply */
+#define MULT16_16(a,b) (((spx_word32_t)(spx_word16_t)(a))*((spx_word32_t)(spx_word16_t)(b)))
+
+#define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b))))
+#define MULT16_32_Q12(a,b) ADD32(MULT16_16((a),SHR((b),12)), SHR(MULT16_16((a),((b)&0x00000fff)),12))
+#define MULT16_32_Q13(a,b) ADD32(MULT16_16((a),SHR((b),13)), SHR(MULT16_16((a),((b)&0x00001fff)),13))
+#define MULT16_32_Q14(a,b) ADD32(MULT16_16((a),SHR((b),14)), SHR(MULT16_16((a),((b)&0x00003fff)),14))
+
+#define MULT16_32_Q11(a,b) ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11))
+#define MAC16_32_Q11(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11)))
+
+#define MULT16_32_P15(a,b) ADD32(MULT16_16((a),SHR((b),15)), PSHR(MULT16_16((a),((b)&0x00007fff)),15))
+#define MULT16_32_Q15(a,b) ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))
+#define MAC16_32_Q15(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)))
+
+
+#define MAC16_16_Q11(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),11)))
+#define MAC16_16_Q13(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),13)))
+#define MAC16_16_P13(c,a,b) (ADD32((c),SHR(ADD32(4096,MULT16_16((a),(b))),13)))
+
+#define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11))
+#define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13))
+#define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14))
+#define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15))
+
+#define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13))
+#define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14))
+#define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15))
+
+#define MUL_16_32_R15(a,bh,bl) ADD32(MULT16_16((a),(bh)), SHR(MULT16_16((a),(bl)),15))
+
+#define DIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a))/((spx_word16_t)(b))))
+#define PDIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word16_t)(b))))
+#define DIV32(a,b) (((spx_word32_t)(a))/((spx_word32_t)(b)))
+#define PDIV32(a,b) (((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word32_t)(b)))
+
+#endif
diff --git a/include/speex/os_support.h b/include/speex/os_support.h
new file mode 100644
index 0000000..6b74b0c
--- /dev/null
+++ b/include/speex/os_support.h
@@ -0,0 +1,169 @@
+/* Copyright (C) 2007 Jean-Marc Valin
+
+ File: os_support.h
+ This is the (tiny) OS abstraction layer. Aside from math.h, this is the
+ only place where system headers are allowed.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef OS_SUPPORT_H
+#define OS_SUPPORT_H
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#ifdef OS_SUPPORT_CUSTOM
+#include "os_support_custom.h"
+#endif
+
+/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_free
+ NOTE: speex_alloc needs to CLEAR THE MEMORY */
+#ifndef OVERRIDE_SPEEX_ALLOC
+static inline void *speex_alloc (int size)
+{
+ /* WARNING: this is not equivalent to malloc(). If you want to use malloc()
+ or your own allocator, YOU NEED TO CLEAR THE MEMORY ALLOCATED. Otherwise
+ you will experience strange bugs */
+ return calloc(size,1);
+}
+#endif
+
+/** Same as speex_alloc, except that the area is only needed inside a Speex call (might cause problem with wideband though) */
+#ifndef OVERRIDE_SPEEX_ALLOC_SCRATCH
+static inline void *speex_alloc_scratch (int size)
+{
+ /* Scratch space doesn't need to be cleared */
+ return calloc(size,1);
+}
+#endif
+
+/** Speex wrapper for realloc. To do your own dynamic allocation, all you need to do is replace this function, speex_alloc and speex_free */
+#ifndef OVERRIDE_SPEEX_REALLOC
+static inline void *speex_realloc (void *ptr, int size)
+{
+ return realloc(ptr, size);
+}
+#endif
+
+/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_alloc */
+#ifndef OVERRIDE_SPEEX_FREE
+static inline void speex_free (void *ptr)
+{
+ free(ptr);
+}
+#endif
+
+/** Same as speex_free, except that the area is only needed inside a Speex call (might cause problem with wideband though) */
+#ifndef OVERRIDE_SPEEX_FREE_SCRATCH
+static inline void speex_free_scratch (void *ptr)
+{
+ free(ptr);
+}
+#endif
+
+/** Copy n bytes of memory from src to dst. The 0* term provides compile-time type checking */
+#ifndef OVERRIDE_SPEEX_COPY
+#define SPEEX_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) ))
+#endif
+
+/** Copy n bytes of memory from src to dst, allowing overlapping regions. The 0* term
+ provides compile-time type checking */
+#ifndef OVERRIDE_SPEEX_MOVE
+#define SPEEX_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) ))
+#endif
+
+/** Set n bytes of memory to value of c, starting at address s */
+#ifndef OVERRIDE_SPEEX_MEMSET
+#define SPEEX_MEMSET(dst, c, n) (memset((dst), (c), (n)*sizeof(*(dst))))
+#endif
+
+
+#ifndef OVERRIDE_SPEEX_FATAL
+static inline void _speex_fatal(const char *str, const char *file, int line)
+{
+ fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str);
+ exit(1);
+}
+#endif
+
+#ifndef OVERRIDE_SPEEX_WARNING
+static inline void speex_warning(const char *str)
+{
+#ifndef DISABLE_WARNINGS
+ fprintf (stderr, "warning: %s\n", str);
+#endif
+}
+#endif
+
+#ifndef OVERRIDE_SPEEX_WARNING_INT
+static inline void speex_warning_int(const char *str, int val)
+{
+#ifndef DISABLE_WARNINGS
+ fprintf (stderr, "warning: %s %d\n", str, val);
+#endif
+}
+#endif
+
+#ifndef OVERRIDE_SPEEX_NOTIFY
+static inline void speex_notify(const char *str)
+{
+#ifndef DISABLE_NOTIFICATIONS
+ fprintf (stderr, "notification: %s\n", str);
+#endif
+}
+#endif
+
+#ifndef OVERRIDE_SPEEX_PUTC
+/** Speex wrapper for putc */
+static inline void _speex_putc(int ch, void *file)
+{
+ FILE *f = (FILE *)file;
+ fprintf(f, "%c", ch);
+}
+#endif
+
+#define speex_fatal(str) _speex_fatal(str, __FILE__, __LINE__);
+#define speex_assert(cond) {if (!(cond)) {speex_fatal("assertion failed: " #cond);}}
+
+#ifndef RELEASE
+static inline void print_vec(float *vec, int len, char *name)
+{
+ int i;
+ printf ("%s ", name);
+ for (i=0;i<len;i++)
+ printf (" %f", vec[i]);
+ printf ("\n");
+}
+#endif
+
+#endif
+
diff --git a/include/speex/resample_neon.h b/include/speex/resample_neon.h
new file mode 100644
index 0000000..b651d5d
--- /dev/null
+++ b/include/speex/resample_neon.h
@@ -0,0 +1,188 @@
+/* Copyright (C) 2007-2008 Jean-Marc Valin
+ * Copyright (C) 2008 Thorvald Natvig
+ * Copyright (C) 2011 Jyri Sarha, Texas Instruments
+ */
+/**
+ @file resample_neon.h
+ @brief Resampler functions (NEON version)
+*/
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ - Neither the name of the Xiph.org Foundation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <arm_neon.h>
+
+#ifdef FIXED_POINT
+static inline int32_t saturate_32bit_to_16bit(int32_t a) {
+ int32_t ret;
+ asm volatile ("vmov.s32 d24[0], %[a]\n"
+ "vqmovn.s32 d24, q12\n"
+ "vmov.s16 %[ret], d24[0]\n"
+ : [ret] "=&r" (ret)
+ : [a] "r" (a)
+ : "q12", "d24", "d25" );
+ return ret;
+}
+#undef WORD2INT
+#define WORD2INT(x) (saturate_32bit_to_16bit(x))
+
+#define OVERRIDE_INNER_PRODUCT_SINGLE
+static inline int32_t inner_product_single(const int16_t *a, const int16_t *b, unsigned int len)
+{
+ int32_t ret;
+ uint32_t remainder = len % 16;
+ len = len - remainder;
+
+ asm volatile (" cmp %[len], #0\n"
+ " bne 1f\n"
+ " vld1.16 {d16}, [%[a]]!\n"
+ " vld1.16 {d20}, [%[b]]!\n"
+ " subs %[remainder], %[remainder], #4\n"
+ " vmull.s16 q0, d16, d20\n"
+ " beq 5f\n"
+ " b 4f\n"
+ "1:"
+ " vld1.16 {d16, d17, d18, d19}, [%[a]]!\n"
+ " vld1.16 {d20, d21, d22, d23}, [%[b]]!\n"
+ " subs %[len], %[len], #16\n"
+ " vmull.s16 q0, d16, d20\n"
+ " vmlal.s16 q0, d17, d21\n"
+ " vmlal.s16 q0, d18, d22\n"
+ " vmlal.s16 q0, d19, d23\n"
+ " beq 3f\n"
+ "2:"
+ " vld1.16 {d16, d17, d18, d19}, [%[a]]!\n"
+ " vld1.16 {d20, d21, d22, d23}, [%[b]]!\n"
+ " subs %[len], %[len], #16\n"
+ " vmlal.s16 q0, d16, d20\n"
+ " vmlal.s16 q0, d17, d21\n"
+ " vmlal.s16 q0, d18, d22\n"
+ " vmlal.s16 q0, d19, d23\n"
+ " bne 2b\n"
+ "3:"
+ " cmp %[remainder], #0\n"
+ " beq 5f\n"
+ "4:"
+ " vld1.16 {d16}, [%[a]]!\n"
+ " vld1.16 {d20}, [%[b]]!\n"
+ " subs %[remainder], %[remainder], #4\n"
+ " vmlal.s16 q0, d16, d20\n"
+ " bne 4b\n"
+ "5:"
+ " vaddl.s32 q0, d0, d1\n"
+ " vadd.s64 d0, d0, d1\n"
+ " vqmovn.s64 d0, q0\n"
+ " vqrshrn.s32 d0, q0, #15\n"
+ " vmov.s16 %[ret], d0[0]\n"
+ : [ret] "=&r" (ret), [a] "+r" (a), [b] "+r" (b),
+ [len] "+r" (len), [remainder] "+r" (remainder)
+ :
+ : "cc", "q0",
+ "d16", "d17", "d18", "d19",
+ "d20", "d21", "d22", "d23");
+ return ret;
+}
+
+#elif defined(FLOATING_POINT)
+
+static inline int32_t saturate_float_to_16bit(float a) {
+ int32_t ret;
+ asm ("vmov.f32 d24[0], %[a]\n"
+ "vcvt.s32.f32 d24, d24, #15\n"
+ "vqrshrn.s32 d24, q12, #15\n"
+ "vmov.s16 %[ret], d24[0]\n"
+ : [ret] "=&r" (ret)
+ : [a] "r" (a)
+ : "q12", "d24", "d25" );
+ return ret;
+}
+#undef WORD2INT
+#define WORD2INT(x) (saturate_float_to_16bit(x))
+
+#define OVERRIDE_INNER_PRODUCT_SINGLE
+static inline float inner_product_single(const float *a, const float *b, unsigned int len)
+{
+ float ret;
+ uint32_t remainder = len % 16;
+ len = len - remainder;
+
+ asm volatile (" cmp %[len], #0\n"
+ " bne 1f\n"
+ " vld1.32 {q4}, [%[a]]!\n"
+ " vld1.32 {q8}, [%[b]]!\n"
+ " subs %[remainder], %[remainder], #4\n"
+ " vmul.f32 q0, q4, q8\n"
+ " beq 5f\n"
+ " b 4f\n"
+ "1:"
+ " vld1.32 {q4, q5}, [%[a]]!\n"
+ " vld1.32 {q8, q9}, [%[b]]!\n"
+ " vld1.32 {q6, q7}, [%[a]]!\n"
+ " vld1.32 {q10, q11}, [%[b]]!\n"
+ " subs %[len], %[len], #16\n"
+ " vmul.f32 q0, q4, q8\n"
+ " vmul.f32 q1, q5, q9\n"
+ " vmul.f32 q2, q6, q10\n"
+ " vmul.f32 q3, q7, q11\n"
+ " beq 3f\n"
+ "2:"
+ " vld1.32 {q4, q5}, [%[a]]!\n"
+ " vld1.32 {q8, q9}, [%[b]]!\n"
+ " vld1.32 {q6, q7}, [%[a]]!\n"
+ " vld1.32 {q10, q11}, [%[b]]!\n"
+ " subs %[len], %[len], #16\n"
+ " vmla.f32 q0, q4, q8\n"
+ " vmla.f32 q1, q5, q9\n"
+ " vmla.f32 q2, q6, q10\n"
+ " vmla.f32 q3, q7, q11\n"
+ " bne 2b\n"
+ "3:"
+ " vadd.f32 q4, q0, q1\n"
+ " vadd.f32 q5, q2, q3\n"
+ " vadd.f32 q0, q4, q5\n"
+ " cmp %[remainder], #0\n"
+ " beq 5f\n"
+ "4:"
+ " vld1.32 {q6}, [%[a]]!\n"
+ " vld1.32 {q10}, [%[b]]!\n"
+ " subs %[remainder], %[remainder], #4\n"
+ " vmla.f32 q0, q6, q10\n"
+ " bne 4b\n"
+ "5:"
+ " vadd.f32 d0, d0, d1\n"
+ " vpadd.f32 d0, d0, d0\n"
+ " vmov.f32 %[ret], d0[0]\n"
+ : [ret] "=&r" (ret), [a] "+r" (a), [b] "+r" (b),
+ [len] "+l" (len), [remainder] "+l" (remainder)
+ :
+ : "cc", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8",
+ "q9", "q10", "q11");
+ return ret;
+}
+
+#endif
diff --git a/include/speex/speex_config_types.h b/include/speex/speex_config_types.h
new file mode 100644
index 0000000..bd54854
--- /dev/null
+++ b/include/speex/speex_config_types.h
@@ -0,0 +1,11 @@
+#ifndef __SPEEX_TYPES_H__
+#define __SPEEX_TYPES_H__
+
+/* these are filled in by configure */
+typedef short spx_int16_t;
+typedef unsigned short spx_uint16_t;
+typedef int spx_int32_t;
+typedef unsigned int spx_uint32_t;
+
+#endif
+
diff --git a/include/speex/speex_resampler.h b/include/speex/speex_resampler.h
new file mode 100644
index 0000000..54eef8d
--- /dev/null
+++ b/include/speex/speex_resampler.h
@@ -0,0 +1,340 @@
+/* Copyright (C) 2007 Jean-Marc Valin
+
+ File: speex_resampler.h
+ Resampling code
+
+ The design goals of this code are:
+ - Very fast algorithm
+ - Low memory requirement
+ - Good *perceptual* quality (and not best SNR)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef SPEEX_RESAMPLER_H
+#define SPEEX_RESAMPLER_H
+
+#ifdef OUTSIDE_SPEEX
+
+/********* WARNING: MENTAL SANITY ENDS HERE *************/
+
+/* If the resampler is defined outside of Speex, we change the symbol names so that
+ there won't be any clash if linking with Speex later on. */
+
+/* #define RANDOM_PREFIX your software name here */
+#ifndef RANDOM_PREFIX
+#error "Please define RANDOM_PREFIX (above) to something specific to your project to prevent symbol name clashes"
+#endif
+
+#define CAT_PREFIX2(a,b) a ## b
+#define CAT_PREFIX(a,b) CAT_PREFIX2(a, b)
+
+#define speex_resampler_init CAT_PREFIX(RANDOM_PREFIX,_resampler_init)
+#define speex_resampler_init_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_init_frac)
+#define speex_resampler_destroy CAT_PREFIX(RANDOM_PREFIX,_resampler_destroy)
+#define speex_resampler_process_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_float)
+#define speex_resampler_process_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_int)
+#define speex_resampler_process_interleaved_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_float)
+#define speex_resampler_process_interleaved_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_int)
+#define speex_resampler_set_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate)
+#define speex_resampler_get_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_get_rate)
+#define speex_resampler_set_rate_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate_frac)
+#define speex_resampler_get_ratio CAT_PREFIX(RANDOM_PREFIX,_resampler_get_ratio)
+#define speex_resampler_set_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_set_quality)
+#define speex_resampler_get_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_get_quality)
+#define speex_resampler_set_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_input_stride)
+#define speex_resampler_get_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_stride)
+#define speex_resampler_set_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_output_stride)
+#define speex_resampler_get_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_stride)
+#define speex_resampler_get_input_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_latency)
+#define speex_resampler_get_output_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_latency)
+#define speex_resampler_skip_zeros CAT_PREFIX(RANDOM_PREFIX,_resampler_skip_zeros)
+#define speex_resampler_reset_mem CAT_PREFIX(RANDOM_PREFIX,_resampler_reset_mem)
+#define speex_resampler_strerror CAT_PREFIX(RANDOM_PREFIX,_resampler_strerror)
+
+#define spx_int16_t short
+#define spx_int32_t int
+#define spx_uint16_t unsigned short
+#define spx_uint32_t unsigned int
+
+#else /* OUTSIDE_SPEEX */
+
+#include "speex/speex_types.h"
+
+#endif /* OUTSIDE_SPEEX */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SPEEX_RESAMPLER_QUALITY_MAX 10
+#define SPEEX_RESAMPLER_QUALITY_MIN 0
+#define SPEEX_RESAMPLER_QUALITY_DEFAULT 4
+#define SPEEX_RESAMPLER_QUALITY_VOIP 3
+#define SPEEX_RESAMPLER_QUALITY_DESKTOP 5
+
+enum {
+ RESAMPLER_ERR_SUCCESS = 0,
+ RESAMPLER_ERR_ALLOC_FAILED = 1,
+ RESAMPLER_ERR_BAD_STATE = 2,
+ RESAMPLER_ERR_INVALID_ARG = 3,
+ RESAMPLER_ERR_PTR_OVERLAP = 4,
+
+ RESAMPLER_ERR_MAX_ERROR
+};
+
+struct SpeexResamplerState_;
+typedef struct SpeexResamplerState_ SpeexResamplerState;
+
+/** Create a new resampler with integer input and output rates.
+ * @param nb_channels Number of channels to be processed
+ * @param in_rate Input sampling rate (integer number of Hz).
+ * @param out_rate Output sampling rate (integer number of Hz).
+ * @param quality Resampling quality between 0 and 10, where 0 has poor quality
+ * and 10 has very high quality.
+ * @return Newly created resampler state
+ * @retval NULL Error: not enough memory
+ */
+SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels,
+ spx_uint32_t in_rate,
+ spx_uint32_t out_rate,
+ int quality,
+ int *err);
+
+/** Create a new resampler with fractional input/output rates. The sampling
+ * rate ratio is an arbitrary rational number with both the numerator and
+ * denominator being 32-bit integers.
+ * @param nb_channels Number of channels to be processed
+ * @param ratio_num Numerator of the sampling rate ratio
+ * @param ratio_den Denominator of the sampling rate ratio
+ * @param in_rate Input sampling rate rounded to the nearest integer (in Hz).
+ * @param out_rate Output sampling rate rounded to the nearest integer (in Hz).
+ * @param quality Resampling quality between 0 and 10, where 0 has poor quality
+ * and 10 has very high quality.
+ * @return Newly created resampler state
+ * @retval NULL Error: not enough memory
+ */
+SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels,
+ spx_uint32_t ratio_num,
+ spx_uint32_t ratio_den,
+ spx_uint32_t in_rate,
+ spx_uint32_t out_rate,
+ int quality,
+ int *err);
+
+/** Destroy a resampler state.
+ * @param st Resampler state
+ */
+void speex_resampler_destroy(SpeexResamplerState *st);
+
+/** Resample a float array. The input and output buffers must *not* overlap.
+ * @param st Resampler state
+ * @param channel_index Index of the channel to process for the multi-channel
+ * base (0 otherwise)
+ * @param in Input buffer
+ * @param in_len Number of input samples in the input buffer. Returns the
+ * number of samples processed
+ * @param out Output buffer
+ * @param out_len Size of the output buffer. Returns the number of samples written
+ */
+int speex_resampler_process_float(SpeexResamplerState *st,
+ spx_uint32_t channel_index,
+ const float *in,
+ spx_uint32_t *in_len,
+ float *out,
+ spx_uint32_t *out_len);
+
+/** Resample an int array. The input and output buffers must *not* overlap.
+ * @param st Resampler state
+ * @param channel_index Index of the channel to process for the multi-channel
+ * base (0 otherwise)
+ * @param in Input buffer
+ * @param in_len Number of input samples in the input buffer. Returns the number
+ * of samples processed
+ * @param out Output buffer
+ * @param out_len Size of the output buffer. Returns the number of samples written
+ */
+int speex_resampler_process_int(SpeexResamplerState *st,
+ spx_uint32_t channel_index,
+ const spx_int16_t *in,
+ spx_uint32_t *in_len,
+ spx_int16_t *out,
+ spx_uint32_t *out_len);
+
+/** Resample an interleaved float array. The input and output buffers must *not* overlap.
+ * @param st Resampler state
+ * @param in Input buffer
+ * @param in_len Number of input samples in the input buffer. Returns the number
+ * of samples processed. This is all per-channel.
+ * @param out Output buffer
+ * @param out_len Size of the output buffer. Returns the number of samples written.
+ * This is all per-channel.
+ */
+int speex_resampler_process_interleaved_float(SpeexResamplerState *st,
+ const float *in,
+ spx_uint32_t *in_len,
+ float *out,
+ spx_uint32_t *out_len);
+
+/** Resample an interleaved int array. The input and output buffers must *not* overlap.
+ * @param st Resampler state
+ * @param in Input buffer
+ * @param in_len Number of input samples in the input buffer. Returns the number
+ * of samples processed. This is all per-channel.
+ * @param out Output buffer
+ * @param out_len Size of the output buffer. Returns the number of samples written.
+ * This is all per-channel.
+ */
+int speex_resampler_process_interleaved_int(SpeexResamplerState *st,
+ const spx_int16_t *in,
+ spx_uint32_t *in_len,
+ spx_int16_t *out,
+ spx_uint32_t *out_len);
+
+/** Set (change) the input/output sampling rates (integer value).
+ * @param st Resampler state
+ * @param in_rate Input sampling rate (integer number of Hz).
+ * @param out_rate Output sampling rate (integer number of Hz).
+ */
+int speex_resampler_set_rate(SpeexResamplerState *st,
+ spx_uint32_t in_rate,
+ spx_uint32_t out_rate);
+
+/** Get the current input/output sampling rates (integer value).
+ * @param st Resampler state
+ * @param in_rate Input sampling rate (integer number of Hz) copied.
+ * @param out_rate Output sampling rate (integer number of Hz) copied.
+ */
+void speex_resampler_get_rate(SpeexResamplerState *st,
+ spx_uint32_t *in_rate,
+ spx_uint32_t *out_rate);
+
+/** Set (change) the input/output sampling rates and resampling ratio
+ * (fractional values in Hz supported).
+ * @param st Resampler state
+ * @param ratio_num Numerator of the sampling rate ratio
+ * @param ratio_den Denominator of the sampling rate ratio
+ * @param in_rate Input sampling rate rounded to the nearest integer (in Hz).
+ * @param out_rate Output sampling rate rounded to the nearest integer (in Hz).
+ */
+int speex_resampler_set_rate_frac(SpeexResamplerState *st,
+ spx_uint32_t ratio_num,
+ spx_uint32_t ratio_den,
+ spx_uint32_t in_rate,
+ spx_uint32_t out_rate);
+
+/** Get the current resampling ratio. This will be reduced to the least
+ * common denominator.
+ * @param st Resampler state
+ * @param ratio_num Numerator of the sampling rate ratio copied
+ * @param ratio_den Denominator of the sampling rate ratio copied
+ */
+void speex_resampler_get_ratio(SpeexResamplerState *st,
+ spx_uint32_t *ratio_num,
+ spx_uint32_t *ratio_den);
+
+/** Set (change) the conversion quality.
+ * @param st Resampler state
+ * @param quality Resampling quality between 0 and 10, where 0 has poor
+ * quality and 10 has very high quality.
+ */
+int speex_resampler_set_quality(SpeexResamplerState *st,
+ int quality);
+
+/** Get the conversion quality.
+ * @param st Resampler state
+ * @param quality Resampling quality between 0 and 10, where 0 has poor
+ * quality and 10 has very high quality.
+ */
+void speex_resampler_get_quality(SpeexResamplerState *st,
+ int *quality);
+
+/** Set (change) the input stride.
+ * @param st Resampler state
+ * @param stride Input stride
+ */
+void speex_resampler_set_input_stride(SpeexResamplerState *st,
+ spx_uint32_t stride);
+
+/** Get the input stride.
+ * @param st Resampler state
+ * @param stride Input stride copied
+ */
+void speex_resampler_get_input_stride(SpeexResamplerState *st,
+ spx_uint32_t *stride);
+
+/** Set (change) the output stride.
+ * @param st Resampler state
+ * @param stride Output stride
+ */
+void speex_resampler_set_output_stride(SpeexResamplerState *st,
+ spx_uint32_t stride);
+
+/** Get the output stride.
+ * @param st Resampler state copied
+ * @param stride Output stride
+ */
+void speex_resampler_get_output_stride(SpeexResamplerState *st,
+ spx_uint32_t *stride);
+
+/** Get the latency in input samples introduced by the resampler.
+ * @param st Resampler state
+ */
+int speex_resampler_get_input_latency(SpeexResamplerState *st);
+
+/** Get the latency in output samples introduced by the resampler.
+ * @param st Resampler state
+ */
+int speex_resampler_get_output_latency(SpeexResamplerState *st);
+
+/** Make sure that the first samples to go out of the resamplers don't have
+ * leading zeros. This is only useful before starting to use a newly created
+ * resampler. It is recommended to use that when resampling an audio file, as
+ * it will generate a file with the same length. For real-time processing,
+ * it is probably easier not to use this call (so that the output duration
+ * is the same for the first frame).
+ * @param st Resampler state
+ */
+int speex_resampler_skip_zeros(SpeexResamplerState *st);
+
+/** Reset a resampler so a new (unrelated) stream can be processed.
+ * @param st Resampler state
+ */
+int speex_resampler_reset_mem(SpeexResamplerState *st);
+
+/** Returns the English meaning for an error code
+ * @param err Error code
+ * @return English string
+ */
+const char *speex_resampler_strerror(int err);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/speex/speex_types.h b/include/speex/speex_types.h
new file mode 100644
index 0000000..852fed8
--- /dev/null
+++ b/include/speex/speex_types.h
@@ -0,0 +1,126 @@
+/* speex_types.h taken from libogg */
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: #ifdef jail to whip a few platforms into the UNIX ideal.
+ last mod: $Id: os_types.h 7524 2004-08-11 04:20:36Z conrad $
+
+ ********************************************************************/
+/**
+ @file speex_types.h
+ @brief Speex types
+*/
+#ifndef _SPEEX_TYPES_H
+#define _SPEEX_TYPES_H
+
+#if defined(_WIN32)
+
+# if defined(__CYGWIN__)
+# include <_G_config.h>
+ typedef _G_int32_t spx_int32_t;
+ typedef _G_uint32_t spx_uint32_t;
+ typedef _G_int16_t spx_int16_t;
+ typedef _G_uint16_t spx_uint16_t;
+# elif defined(__MINGW32__)
+ typedef short spx_int16_t;
+ typedef unsigned short spx_uint16_t;
+ typedef int spx_int32_t;
+ typedef unsigned int spx_uint32_t;
+# elif defined(__MWERKS__)
+ typedef int spx_int32_t;
+ typedef unsigned int spx_uint32_t;
+ typedef short spx_int16_t;
+ typedef unsigned short spx_uint16_t;
+# else
+ /* MSVC/Borland */
+ typedef __int32 spx_int32_t;
+ typedef unsigned __int32 spx_uint32_t;
+ typedef __int16 spx_int16_t;
+ typedef unsigned __int16 spx_uint16_t;
+# endif
+
+#elif defined(__MACOS__)
+
+# include <sys/types.h>
+ typedef SInt16 spx_int16_t;
+ typedef UInt16 spx_uint16_t;
+ typedef SInt32 spx_int32_t;
+ typedef UInt32 spx_uint32_t;
+
+#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */
+
+# include <sys/types.h>
+ typedef int16_t spx_int16_t;
+ typedef u_int16_t spx_uint16_t;
+ typedef int32_t spx_int32_t;
+ typedef u_int32_t spx_uint32_t;
+
+#elif defined(__BEOS__)
+
+ /* Be */
+# include <inttypes.h>
+ typedef int16_t spx_int16_t;
+ typedef u_int16_t spx_uint16_t;
+ typedef int32_t spx_int32_t;
+ typedef u_int32_t spx_uint32_t;
+
+#elif defined (__EMX__)
+
+ /* OS/2 GCC */
+ typedef short spx_int16_t;
+ typedef unsigned short spx_uint16_t;
+ typedef int spx_int32_t;
+ typedef unsigned int spx_uint32_t;
+
+#elif defined (DJGPP)
+
+ /* DJGPP */
+ typedef short spx_int16_t;
+ typedef int spx_int32_t;
+ typedef unsigned int spx_uint32_t;
+
+#elif defined(R5900)
+
+ /* PS2 EE */
+ typedef int spx_int32_t;
+ typedef unsigned spx_uint32_t;
+ typedef short spx_int16_t;
+
+#elif defined(__SYMBIAN32__)
+
+ /* Symbian GCC */
+ typedef signed short spx_int16_t;
+ typedef unsigned short spx_uint16_t;
+ typedef signed int spx_int32_t;
+ typedef unsigned int spx_uint32_t;
+
+#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X)
+
+ typedef short spx_int16_t;
+ typedef unsigned short spx_uint16_t;
+ typedef long spx_int32_t;
+ typedef unsigned long spx_uint32_t;
+
+#elif defined(CONFIG_TI_C6X)
+
+ typedef short spx_int16_t;
+ typedef unsigned short spx_uint16_t;
+ typedef int spx_int32_t;
+ typedef unsigned int spx_uint32_t;
+
+#else
+
+# include <speex/speex_config_types.h>
+
+#endif
+
+#endif /* _SPEEX_TYPES_H */
diff --git a/include/speex/stack_alloc.h b/include/speex/stack_alloc.h
new file mode 100644
index 0000000..5264e66
--- /dev/null
+++ b/include/speex/stack_alloc.h
@@ -0,0 +1,115 @@
+/* Copyright (C) 2002 Jean-Marc Valin */
+/**
+ @file stack_alloc.h
+ @brief Temporary memory allocation on stack
+*/
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ - Neither the name of the Xiph.org Foundation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef STACK_ALLOC_H
+#define STACK_ALLOC_H
+
+#ifdef USE_ALLOCA
+# ifdef WIN32
+# include <malloc.h>
+# else
+# ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# include <stdlib.h>
+# endif
+# endif
+#endif
+
+/**
+ * @def ALIGN(stack, size)
+ *
+ * Aligns the stack to a 'size' boundary
+ *
+ * @param stack Stack
+ * @param size New size boundary
+ */
+
+/**
+ * @def PUSH(stack, size, type)
+ *
+ * Allocates 'size' elements of type 'type' on the stack
+ *
+ * @param stack Stack
+ * @param size Number of elements
+ * @param type Type of element
+ */
+
+/**
+ * @def VARDECL(var)
+ *
+ * Declare variable on stack
+ *
+ * @param var Variable to declare
+ */
+
+/**
+ * @def ALLOC(var, size, type)
+ *
+ * Allocate 'size' elements of 'type' on stack
+ *
+ * @param var Name of variable to allocate
+ * @param size Number of elements
+ * @param type Type of element
+ */
+
+#ifdef ENABLE_VALGRIND
+
+#include <valgrind/memcheck.h>
+
+#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
+
+#define PUSH(stack, size, type) (VALGRIND_MAKE_NOACCESS(stack, 1000),ALIGN((stack),sizeof(type)),VALGRIND_MAKE_WRITABLE(stack, ((size)*sizeof(type))),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type))))
+
+#else
+
+#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
+
+#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type))))
+
+#endif
+
+#if defined(VAR_ARRAYS)
+#define VARDECL(var)
+#define ALLOC(var, size, type) type var[size]
+#elif defined(USE_ALLOCA)
+#define VARDECL(var) var
+#define ALLOC(var, size, type) var = alloca(sizeof(type)*(size))
+#else
+#define VARDECL(var) var
+#define ALLOC(var, size, type) var = PUSH(stack, size, type)
+#endif
+
+
+#endif
diff --git a/include/system/audio-base-utils.h b/include/system/audio-base-utils.h
new file mode 100644
index 0000000..016a085
--- /dev/null
+++ b/include/system/audio-base-utils.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_BASE_UTILS_H
+#define ANDROID_AUDIO_BASE_UTILS_H
+
+#include "audio-base.h"
+
+/** Define helper values to iterate over enum, extend them or checking value validity.
+ * Those values are compatible with the O corresponding enum values.
+ * They are not macro like similar values in audio.h to avoid conflicting
+ * with the libhardware_legacy audio.h.
+ */
+enum {
+ /** Number of audio stream available to vendors. */
+ AUDIO_STREAM_PUBLIC_CNT = AUDIO_STREAM_ACCESSIBILITY + 1,
+
+#ifndef AUDIO_NO_SYSTEM_DECLARATIONS
+ /** Total number of stream handled by the policy*/
+ AUDIO_STREAM_FOR_POLICY_CNT= AUDIO_STREAM_REROUTING + 1,
+#endif
+
+ /** Total number of stream. */
+ AUDIO_STREAM_CNT = AUDIO_STREAM_PATCH + 1,
+
+ AUDIO_SOURCE_MAX = AUDIO_SOURCE_UNPROCESSED,
+ AUDIO_SOURCE_CNT = AUDIO_SOURCE_MAX + 1,
+
+ AUDIO_MODE_MAX = AUDIO_MODE_IN_COMMUNICATION,
+ AUDIO_MODE_CNT = AUDIO_MODE_MAX + 1,
+
+ /** For retrocompatibility AUDIO_MODE_* and AUDIO_STREAM_* must be signed. */
+ AUDIO_DETAIL_NEGATIVE_VALUE = -1,
+};
+
+enum {
+ AUDIO_CHANNEL_OUT_ALL = AUDIO_CHANNEL_OUT_FRONT_LEFT |
+ AUDIO_CHANNEL_OUT_FRONT_RIGHT |
+ AUDIO_CHANNEL_OUT_FRONT_CENTER |
+ AUDIO_CHANNEL_OUT_LOW_FREQUENCY |
+ AUDIO_CHANNEL_OUT_BACK_LEFT |
+ AUDIO_CHANNEL_OUT_BACK_RIGHT |
+ AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER |
+ AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER |
+ AUDIO_CHANNEL_OUT_BACK_CENTER |
+ AUDIO_CHANNEL_OUT_SIDE_LEFT |
+ AUDIO_CHANNEL_OUT_SIDE_RIGHT |
+ AUDIO_CHANNEL_OUT_TOP_CENTER |
+ AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT |
+ AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER |
+ AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT |
+ AUDIO_CHANNEL_OUT_TOP_BACK_LEFT |
+ AUDIO_CHANNEL_OUT_TOP_BACK_CENTER |
+ AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT |
+ AUDIO_CHANNEL_OUT_TOP_SIDE_LEFT |
+ AUDIO_CHANNEL_OUT_TOP_SIDE_RIGHT,
+
+ AUDIO_CHANNEL_IN_ALL = AUDIO_CHANNEL_IN_LEFT |
+ AUDIO_CHANNEL_IN_RIGHT |
+ AUDIO_CHANNEL_IN_FRONT |
+ AUDIO_CHANNEL_IN_BACK|
+ AUDIO_CHANNEL_IN_LEFT_PROCESSED |
+ AUDIO_CHANNEL_IN_RIGHT_PROCESSED |
+ AUDIO_CHANNEL_IN_FRONT_PROCESSED |
+ AUDIO_CHANNEL_IN_BACK_PROCESSED|
+ AUDIO_CHANNEL_IN_PRESSURE |
+ AUDIO_CHANNEL_IN_X_AXIS |
+ AUDIO_CHANNEL_IN_Y_AXIS |
+ AUDIO_CHANNEL_IN_Z_AXIS |
+ AUDIO_CHANNEL_IN_VOICE_UPLINK |
+ AUDIO_CHANNEL_IN_VOICE_DNLINK |
+ AUDIO_CHANNEL_IN_BACK_LEFT |
+ AUDIO_CHANNEL_IN_BACK_RIGHT |
+ AUDIO_CHANNEL_IN_CENTER |
+ AUDIO_CHANNEL_IN_LOW_FREQUENCY |
+ AUDIO_CHANNEL_IN_TOP_LEFT |
+ AUDIO_CHANNEL_IN_TOP_RIGHT,
+
+ AUDIO_DEVICE_OUT_ALL = AUDIO_DEVICE_OUT_EARPIECE |
+ AUDIO_DEVICE_OUT_SPEAKER |
+ AUDIO_DEVICE_OUT_WIRED_HEADSET |
+ AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO |
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT |
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER |
+ AUDIO_DEVICE_OUT_HDMI |
+ AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
+ AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET |
+ AUDIO_DEVICE_OUT_USB_ACCESSORY |
+ AUDIO_DEVICE_OUT_USB_DEVICE |
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX |
+ AUDIO_DEVICE_OUT_TELEPHONY_TX |
+ AUDIO_DEVICE_OUT_LINE |
+ AUDIO_DEVICE_OUT_HDMI_ARC |
+ AUDIO_DEVICE_OUT_SPDIF |
+ AUDIO_DEVICE_OUT_FM |
+ AUDIO_DEVICE_OUT_AUX_LINE |
+ AUDIO_DEVICE_OUT_SPEAKER_SAFE |
+ AUDIO_DEVICE_OUT_IP |
+ AUDIO_DEVICE_OUT_BUS |
+ AUDIO_DEVICE_OUT_PROXY |
+ AUDIO_DEVICE_OUT_USB_HEADSET |
+ AUDIO_DEVICE_OUT_HEARING_AID |
+ AUDIO_DEVICE_OUT_ECHO_CANCELLER |
+ AUDIO_DEVICE_OUT_DEFAULT,
+
+ AUDIO_DEVICE_OUT_ALL_A2DP = AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,
+
+ AUDIO_DEVICE_OUT_ALL_SCO = AUDIO_DEVICE_OUT_BLUETOOTH_SCO |
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT,
+
+ AUDIO_DEVICE_OUT_ALL_USB = AUDIO_DEVICE_OUT_USB_ACCESSORY |
+ AUDIO_DEVICE_OUT_USB_DEVICE |
+ AUDIO_DEVICE_OUT_USB_HEADSET,
+
+ AUDIO_DEVICE_IN_ALL = AUDIO_DEVICE_IN_COMMUNICATION |
+ AUDIO_DEVICE_IN_AMBIENT |
+ AUDIO_DEVICE_IN_BUILTIN_MIC |
+ AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET |
+ AUDIO_DEVICE_IN_WIRED_HEADSET |
+ AUDIO_DEVICE_IN_HDMI |
+ AUDIO_DEVICE_IN_TELEPHONY_RX |
+ AUDIO_DEVICE_IN_BACK_MIC |
+ AUDIO_DEVICE_IN_REMOTE_SUBMIX |
+ AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET |
+ AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET |
+ AUDIO_DEVICE_IN_USB_ACCESSORY |
+ AUDIO_DEVICE_IN_USB_DEVICE |
+ AUDIO_DEVICE_IN_FM_TUNER |
+ AUDIO_DEVICE_IN_TV_TUNER |
+ AUDIO_DEVICE_IN_LINE |
+ AUDIO_DEVICE_IN_SPDIF |
+ AUDIO_DEVICE_IN_BLUETOOTH_A2DP |
+ AUDIO_DEVICE_IN_LOOPBACK |
+ AUDIO_DEVICE_IN_IP |
+ AUDIO_DEVICE_IN_BUS |
+ AUDIO_DEVICE_IN_PROXY |
+ AUDIO_DEVICE_IN_USB_HEADSET |
+ AUDIO_DEVICE_IN_BLUETOOTH_BLE |
+ AUDIO_DEVICE_IN_DEFAULT,
+
+ AUDIO_DEVICE_IN_ALL_SCO = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,
+
+ AUDIO_DEVICE_IN_ALL_USB = AUDIO_DEVICE_IN_USB_ACCESSORY |
+ AUDIO_DEVICE_IN_USB_DEVICE |
+ AUDIO_DEVICE_IN_USB_HEADSET,
+
+ AUDIO_USAGE_MAX = AUDIO_USAGE_ASSISTANT,
+ AUDIO_USAGE_CNT = AUDIO_USAGE_ASSISTANT + 1,
+
+ AUDIO_PORT_CONFIG_ALL = AUDIO_PORT_CONFIG_SAMPLE_RATE |
+ AUDIO_PORT_CONFIG_CHANNEL_MASK |
+ AUDIO_PORT_CONFIG_FORMAT |
+ AUDIO_PORT_CONFIG_GAIN,
+}; // enum
+
+
+#endif // ANDROID_AUDIO_BASE_UTILS_H
diff --git a/include/system/audio-base.h b/include/system/audio-base.h
new file mode 100644
index 0000000..4eb2808
--- /dev/null
+++ b/include/system/audio-base.h
@@ -0,0 +1,457 @@
+// This file is autogenerated by hidl-gen
+// then manualy edited for retrocompatiblity
+// Source: android.hardware.audio.common@4.0
+// Root: android.hardware:hardware/interfaces
+
+#ifndef HIDL_GENERATED_ANDROID_HARDWARE_AUDIO_COMMON_V4_0_EXPORTED_CONSTANTS_H_
+#define HIDL_GENERATED_ANDROID_HARDWARE_AUDIO_COMMON_V4_0_EXPORTED_CONSTANTS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+ AUDIO_IO_HANDLE_NONE = 0,
+ AUDIO_MODULE_HANDLE_NONE = 0,
+ AUDIO_PORT_HANDLE_NONE = 0,
+ AUDIO_PATCH_HANDLE_NONE = 0,
+};
+
+typedef enum {
+ AUDIO_STREAM_DEFAULT = -1, // (-1)
+ AUDIO_STREAM_MIN = 0,
+ AUDIO_STREAM_VOICE_CALL = 0,
+ AUDIO_STREAM_SYSTEM = 1,
+ AUDIO_STREAM_RING = 2,
+ AUDIO_STREAM_MUSIC = 3,
+ AUDIO_STREAM_ALARM = 4,
+ AUDIO_STREAM_NOTIFICATION = 5,
+ AUDIO_STREAM_BLUETOOTH_SCO = 6,
+ AUDIO_STREAM_ENFORCED_AUDIBLE = 7,
+ AUDIO_STREAM_DTMF = 8,
+ AUDIO_STREAM_TTS = 9,
+ AUDIO_STREAM_ACCESSIBILITY = 10,
+#ifndef AUDIO_NO_SYSTEM_DECLARATIONS
+ /** For dynamic policy output mixes. Only used by the audio policy */
+ AUDIO_STREAM_REROUTING = 11,
+ /** For audio flinger tracks volume. Only used by the audioflinger */
+ AUDIO_STREAM_PATCH = 12,
+#endif // AUDIO_NO_SYSTEM_DECLARATIONS
+} audio_stream_type_t;
+
+typedef enum {
+ AUDIO_SOURCE_DEFAULT = 0,
+ AUDIO_SOURCE_MIC = 1,
+ AUDIO_SOURCE_VOICE_UPLINK = 2,
+ AUDIO_SOURCE_VOICE_DOWNLINK = 3,
+ AUDIO_SOURCE_VOICE_CALL = 4,
+ AUDIO_SOURCE_CAMCORDER = 5,
+ AUDIO_SOURCE_VOICE_RECOGNITION = 6,
+ AUDIO_SOURCE_VOICE_COMMUNICATION = 7,
+ AUDIO_SOURCE_REMOTE_SUBMIX = 8,
+ AUDIO_SOURCE_UNPROCESSED = 9,
+ AUDIO_SOURCE_FM_TUNER = 1998,
+#ifndef AUDIO_NO_SYSTEM_DECLARATIONS
+ /**
+ * A low-priority, preemptible audio source for for background software
+ * hotword detection. Same tuning as VOICE_RECOGNITION.
+ * Used only internally by the framework.
+ */
+ AUDIO_SOURCE_HOTWORD = 1999,
+#endif // AUDIO_NO_SYSTEM_DECLARATIONS
+} audio_source_t;
+
+typedef enum {
+ AUDIO_SESSION_OUTPUT_STAGE = -1, // (-1)
+ AUDIO_SESSION_OUTPUT_MIX = 0,
+ AUDIO_SESSION_ALLOCATE = 0,
+ AUDIO_SESSION_NONE = 0,
+} audio_session_t;
+
+typedef enum {
+ AUDIO_FORMAT_INVALID = 0xFFFFFFFFu,
+ AUDIO_FORMAT_DEFAULT = 0,
+ AUDIO_FORMAT_PCM = 0x00000000u,
+ AUDIO_FORMAT_MP3 = 0x01000000u,
+ AUDIO_FORMAT_AMR_NB = 0x02000000u,
+ AUDIO_FORMAT_AMR_WB = 0x03000000u,
+ AUDIO_FORMAT_AAC = 0x04000000u,
+ AUDIO_FORMAT_HE_AAC_V1 = 0x05000000u,
+ AUDIO_FORMAT_HE_AAC_V2 = 0x06000000u,
+ AUDIO_FORMAT_VORBIS = 0x07000000u,
+ AUDIO_FORMAT_OPUS = 0x08000000u,
+ AUDIO_FORMAT_AC3 = 0x09000000u,
+ AUDIO_FORMAT_E_AC3 = 0x0A000000u,
+ AUDIO_FORMAT_DTS = 0x0B000000u,
+ AUDIO_FORMAT_DTS_HD = 0x0C000000u,
+ AUDIO_FORMAT_IEC61937 = 0x0D000000u,
+ AUDIO_FORMAT_DOLBY_TRUEHD = 0x0E000000u,
+ AUDIO_FORMAT_EVRC = 0x10000000u,
+ AUDIO_FORMAT_EVRCB = 0x11000000u,
+ AUDIO_FORMAT_EVRCWB = 0x12000000u,
+ AUDIO_FORMAT_EVRCNW = 0x13000000u,
+ AUDIO_FORMAT_AAC_ADIF = 0x14000000u,
+ AUDIO_FORMAT_WMA = 0x15000000u,
+ AUDIO_FORMAT_WMA_PRO = 0x16000000u,
+ AUDIO_FORMAT_AMR_WB_PLUS = 0x17000000u,
+ AUDIO_FORMAT_MP2 = 0x18000000u,
+ AUDIO_FORMAT_QCELP = 0x19000000u,
+ AUDIO_FORMAT_DSD = 0x1A000000u,
+ AUDIO_FORMAT_FLAC = 0x1B000000u,
+ AUDIO_FORMAT_ALAC = 0x1C000000u,
+ AUDIO_FORMAT_APE = 0x1D000000u,
+ AUDIO_FORMAT_AAC_ADTS = 0x1E000000u,
+ AUDIO_FORMAT_SBC = 0x1F000000u,
+ AUDIO_FORMAT_APTX = 0x20000000u,
+ AUDIO_FORMAT_APTX_HD = 0x21000000u,
+ AUDIO_FORMAT_AC4 = 0x22000000u,
+ AUDIO_FORMAT_LDAC = 0x23000000u,
+ AUDIO_FORMAT_MAT = 0x24000000u,
+ AUDIO_FORMAT_MAIN_MASK = 0xFF000000u,
+ AUDIO_FORMAT_SUB_MASK = 0x00FFFFFFu,
+
+ /* Subformats */
+ AUDIO_FORMAT_PCM_SUB_16_BIT = 0x1u,
+ AUDIO_FORMAT_PCM_SUB_8_BIT = 0x2u,
+ AUDIO_FORMAT_PCM_SUB_32_BIT = 0x3u,
+ AUDIO_FORMAT_PCM_SUB_8_24_BIT = 0x4u,
+ AUDIO_FORMAT_PCM_SUB_FLOAT = 0x5u,
+ AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED = 0x6u,
+
+ AUDIO_FORMAT_MP3_SUB_NONE = 0x0u,
+
+ AUDIO_FORMAT_AMR_SUB_NONE = 0x0u,
+
+ AUDIO_FORMAT_AAC_SUB_MAIN = 0x1u,
+ AUDIO_FORMAT_AAC_SUB_LC = 0x2u,
+ AUDIO_FORMAT_AAC_SUB_SSR = 0x4u,
+ AUDIO_FORMAT_AAC_SUB_LTP = 0x8u,
+ AUDIO_FORMAT_AAC_SUB_HE_V1 = 0x10u,
+ AUDIO_FORMAT_AAC_SUB_SCALABLE = 0x20u,
+ AUDIO_FORMAT_AAC_SUB_ERLC = 0x40u,
+ AUDIO_FORMAT_AAC_SUB_LD = 0x80u,
+ AUDIO_FORMAT_AAC_SUB_HE_V2 = 0x100u,
+ AUDIO_FORMAT_AAC_SUB_ELD = 0x200u,
+ AUDIO_FORMAT_AAC_SUB_XHE = 0x300u,
+
+ AUDIO_FORMAT_VORBIS_SUB_NONE = 0x0u,
+
+ AUDIO_FORMAT_E_AC3_SUB_JOC = 0x1u,
+
+ AUDIO_FORMAT_MAT_SUB_1_0 = 0x1u,
+ AUDIO_FORMAT_MAT_SUB_2_0 = 0x2u,
+ AUDIO_FORMAT_MAT_SUB_2_1 = 0x3u,
+
+ /* Aliases */
+ AUDIO_FORMAT_PCM_16_BIT = 0x1u, // (PCM | PCM_SUB_16_BIT)
+ AUDIO_FORMAT_PCM_8_BIT = 0x2u, // (PCM | PCM_SUB_8_BIT)
+ AUDIO_FORMAT_PCM_32_BIT = 0x3u, // (PCM | PCM_SUB_32_BIT)
+ AUDIO_FORMAT_PCM_8_24_BIT = 0x4u, // (PCM | PCM_SUB_8_24_BIT)
+ AUDIO_FORMAT_PCM_FLOAT = 0x5u, // (PCM | PCM_SUB_FLOAT)
+ AUDIO_FORMAT_PCM_24_BIT_PACKED = 0x6u, // (PCM | PCM_SUB_24_BIT_PACKED)
+ AUDIO_FORMAT_AAC_MAIN = 0x4000001u, // (AAC | AAC_SUB_MAIN)
+ AUDIO_FORMAT_AAC_LC = 0x4000002u, // (AAC | AAC_SUB_LC)
+ AUDIO_FORMAT_AAC_SSR = 0x4000004u, // (AAC | AAC_SUB_SSR)
+ AUDIO_FORMAT_AAC_LTP = 0x4000008u, // (AAC | AAC_SUB_LTP)
+ AUDIO_FORMAT_AAC_HE_V1 = 0x4000010u, // (AAC | AAC_SUB_HE_V1)
+ AUDIO_FORMAT_AAC_SCALABLE = 0x4000020u, // (AAC | AAC_SUB_SCALABLE)
+ AUDIO_FORMAT_AAC_ERLC = 0x4000040u, // (AAC | AAC_SUB_ERLC)
+ AUDIO_FORMAT_AAC_LD = 0x4000080u, // (AAC | AAC_SUB_LD)
+ AUDIO_FORMAT_AAC_HE_V2 = 0x4000100u, // (AAC | AAC_SUB_HE_V2)
+ AUDIO_FORMAT_AAC_ELD = 0x4000200u, // (AAC | AAC_SUB_ELD)
+ AUDIO_FORMAT_AAC_XHE = 0x4000300u, // (AAC | AAC_SUB_XHE)
+ AUDIO_FORMAT_AAC_ADTS_MAIN = 0x1e000001u, // (AAC_ADTS | AAC_SUB_MAIN)
+ AUDIO_FORMAT_AAC_ADTS_LC = 0x1e000002u, // (AAC_ADTS | AAC_SUB_LC)
+ AUDIO_FORMAT_AAC_ADTS_SSR = 0x1e000004u, // (AAC_ADTS | AAC_SUB_SSR)
+ AUDIO_FORMAT_AAC_ADTS_LTP = 0x1e000008u, // (AAC_ADTS | AAC_SUB_LTP)
+ AUDIO_FORMAT_AAC_ADTS_HE_V1 = 0x1e000010u, // (AAC_ADTS | AAC_SUB_HE_V1)
+ AUDIO_FORMAT_AAC_ADTS_SCALABLE = 0x1e000020u, // (AAC_ADTS | AAC_SUB_SCALABLE)
+ AUDIO_FORMAT_AAC_ADTS_ERLC = 0x1e000040u, // (AAC_ADTS | AAC_SUB_ERLC)
+ AUDIO_FORMAT_AAC_ADTS_LD = 0x1e000080u, // (AAC_ADTS | AAC_SUB_LD)
+ AUDIO_FORMAT_AAC_ADTS_HE_V2 = 0x1e000100u, // (AAC_ADTS | AAC_SUB_HE_V2)
+ AUDIO_FORMAT_AAC_ADTS_ELD = 0x1e000200u, // (AAC_ADTS | AAC_SUB_ELD)
+ AUDIO_FORMAT_AAC_ADTS_XHE = 0x1e000300u, // (AAC_ADTS | AAC_SUB_XHE)
+ AUDIO_FORMAT_E_AC3_JOC = 0xA000001u, // (E_AC3 | E_AC3_SUB_JOC)
+ AUDIO_FORMAT_MAT_1_0 = 0x24000001u, // (MAT | MAT_SUB_1_0)
+ AUDIO_FORMAT_MAT_2_0 = 0x24000002u, // (MAT | MAT_SUB_2_0)
+ AUDIO_FORMAT_MAT_2_1 = 0x24000003u, // (MAT | MAT_SUB_2_1)
+} audio_format_t;
+
+enum {
+ FCC_2 = 2,
+ FCC_8 = 8,
+};
+
+enum {
+ AUDIO_CHANNEL_REPRESENTATION_POSITION = 0x0u,
+ AUDIO_CHANNEL_REPRESENTATION_INDEX = 0x2u,
+ AUDIO_CHANNEL_NONE = 0x0u,
+ AUDIO_CHANNEL_INVALID = 0xC0000000u,
+
+ AUDIO_CHANNEL_OUT_FRONT_LEFT = 0x1u,
+ AUDIO_CHANNEL_OUT_FRONT_RIGHT = 0x2u,
+ AUDIO_CHANNEL_OUT_FRONT_CENTER = 0x4u,
+ AUDIO_CHANNEL_OUT_LOW_FREQUENCY = 0x8u,
+ AUDIO_CHANNEL_OUT_BACK_LEFT = 0x10u,
+ AUDIO_CHANNEL_OUT_BACK_RIGHT = 0x20u,
+ AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x40u,
+ AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x80u,
+ AUDIO_CHANNEL_OUT_BACK_CENTER = 0x100u,
+ AUDIO_CHANNEL_OUT_SIDE_LEFT = 0x200u,
+ AUDIO_CHANNEL_OUT_SIDE_RIGHT = 0x400u,
+ AUDIO_CHANNEL_OUT_TOP_CENTER = 0x800u,
+ AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT = 0x1000u,
+ AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER = 0x2000u,
+ AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT = 0x4000u,
+ AUDIO_CHANNEL_OUT_TOP_BACK_LEFT = 0x8000u,
+ AUDIO_CHANNEL_OUT_TOP_BACK_CENTER = 0x10000u,
+ AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT = 0x20000u,
+ AUDIO_CHANNEL_OUT_TOP_SIDE_LEFT = 0x40000u,
+ AUDIO_CHANNEL_OUT_TOP_SIDE_RIGHT = 0x80000u,
+ AUDIO_CHANNEL_OUT_MONO = 0x1u, // OUT_FRONT_LEFT
+ AUDIO_CHANNEL_OUT_STEREO = 0x3u, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT
+ AUDIO_CHANNEL_OUT_2POINT1 = 0xBu, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_LOW_FREQUENCY
+ AUDIO_CHANNEL_OUT_2POINT0POINT2 = 0xC0003u, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT
+ AUDIO_CHANNEL_OUT_2POINT1POINT2 = 0xC000Bu, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT | OUT_LOW_FREQUENCY
+ AUDIO_CHANNEL_OUT_3POINT0POINT2 = 0xC0007u, // OUT_FRONT_LEFT | OUT_FRONT_CENTER | OUT_FRONT_RIGHT | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT
+ AUDIO_CHANNEL_OUT_3POINT1POINT2 = 0xC000Fu, // OUT_FRONT_LEFT | OUT_FRONT_CENTER | OUT_FRONT_RIGHT | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT | OUT_LOW_FREQUENCY
+ AUDIO_CHANNEL_OUT_QUAD = 0x33u, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_BACK_LEFT | OUT_BACK_RIGHT
+ AUDIO_CHANNEL_OUT_QUAD_BACK = 0x33u, // OUT_QUAD
+ AUDIO_CHANNEL_OUT_QUAD_SIDE = 0x603u, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_SIDE_LEFT | OUT_SIDE_RIGHT
+ AUDIO_CHANNEL_OUT_SURROUND = 0x107u, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_BACK_CENTER
+ AUDIO_CHANNEL_OUT_PENTA = 0x37u, // OUT_QUAD | OUT_FRONT_CENTER
+ AUDIO_CHANNEL_OUT_5POINT1 = 0x3Fu, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | OUT_BACK_LEFT | OUT_BACK_RIGHT
+ AUDIO_CHANNEL_OUT_5POINT1_BACK = 0x3Fu, // OUT_5POINT1
+ AUDIO_CHANNEL_OUT_5POINT1_SIDE = 0x60Fu, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | OUT_SIDE_LEFT | OUT_SIDE_RIGHT
+ AUDIO_CHANNEL_OUT_5POINT1POINT2 = 0xC003Fu, // OUT_5POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT
+ AUDIO_CHANNEL_OUT_5POINT1POINT4 = 0x2D03Fu, // OUT_5POINT1 | OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT | OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT
+ AUDIO_CHANNEL_OUT_6POINT1 = 0x13Fu, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | OUT_BACK_LEFT | OUT_BACK_RIGHT | OUT_BACK_CENTER
+ AUDIO_CHANNEL_OUT_7POINT1 = 0x63Fu, // OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | OUT_BACK_LEFT | OUT_BACK_RIGHT | OUT_SIDE_LEFT | OUT_SIDE_RIGHT
+ AUDIO_CHANNEL_OUT_7POINT1POINT2 = 0xC063Fu, // OUT_7POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT
+ AUDIO_CHANNEL_OUT_7POINT1POINT4 = 0x2D63Fu, // OUT_7POINT1 | OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT | OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT
+
+ AUDIO_CHANNEL_IN_LEFT = 0x4u,
+ AUDIO_CHANNEL_IN_RIGHT = 0x8u,
+ AUDIO_CHANNEL_IN_FRONT = 0x10u,
+ AUDIO_CHANNEL_IN_BACK = 0x20u,
+ AUDIO_CHANNEL_IN_LEFT_PROCESSED = 0x40u,
+ AUDIO_CHANNEL_IN_RIGHT_PROCESSED = 0x80u,
+ AUDIO_CHANNEL_IN_FRONT_PROCESSED = 0x100u,
+ AUDIO_CHANNEL_IN_BACK_PROCESSED = 0x200u,
+ AUDIO_CHANNEL_IN_PRESSURE = 0x400u,
+ AUDIO_CHANNEL_IN_X_AXIS = 0x800u,
+ AUDIO_CHANNEL_IN_Y_AXIS = 0x1000u,
+ AUDIO_CHANNEL_IN_Z_AXIS = 0x2000u,
+ AUDIO_CHANNEL_IN_BACK_LEFT = 0x10000u,
+ AUDIO_CHANNEL_IN_BACK_RIGHT = 0x20000u,
+ AUDIO_CHANNEL_IN_CENTER = 0x40000u,
+ AUDIO_CHANNEL_IN_LOW_FREQUENCY = 0x100000u,
+ AUDIO_CHANNEL_IN_TOP_LEFT = 0x200000u,
+ AUDIO_CHANNEL_IN_TOP_RIGHT = 0x400000u,
+ AUDIO_CHANNEL_IN_VOICE_UPLINK = 0x4000u,
+ AUDIO_CHANNEL_IN_VOICE_DNLINK = 0x8000u,
+ AUDIO_CHANNEL_IN_MONO = 0x10u, // IN_FRONT
+ AUDIO_CHANNEL_IN_STEREO = 0xCu, // IN_LEFT | IN_RIGHT
+ AUDIO_CHANNEL_IN_FRONT_BACK = 0x30u, // IN_FRONT | IN_BACK
+ AUDIO_CHANNEL_IN_6 = 0xFCu, // IN_LEFT | IN_RIGHT | IN_FRONT | IN_BACK | IN_LEFT_PROCESSED | IN_RIGHT_PROCESSED
+ AUDIO_CHANNEL_IN_2POINT0POINT2 = 0x60000Cu, // IN_LEFT | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT
+ AUDIO_CHANNEL_IN_2POINT1POINT2 = 0x70000Cu, // IN_LEFT | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT | IN_LOW_FREQUENCY
+ AUDIO_CHANNEL_IN_3POINT0POINT2 = 0x64000Cu, // IN_LEFT | IN_CENTER | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT
+ AUDIO_CHANNEL_IN_3POINT1POINT2 = 0x74000Cu, // IN_LEFT | IN_CENTER | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT | IN_LOW_FREQUENCY
+ AUDIO_CHANNEL_IN_5POINT1 = 0x17000Cu, // IN_LEFT | IN_CENTER | IN_RIGHT | IN_BACK_LEFT | IN_BACK_RIGHT | IN_LOW_FREQUENCY
+ AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO = 0x4010u, // IN_VOICE_UPLINK | IN_MONO
+ AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO = 0x8010u, // IN_VOICE_DNLINK | IN_MONO
+ AUDIO_CHANNEL_IN_VOICE_CALL_MONO = 0xC010u, // IN_VOICE_UPLINK_MONO | IN_VOICE_DNLINK_MONO
+
+ AUDIO_CHANNEL_COUNT_MAX = 30u,
+ AUDIO_CHANNEL_INDEX_HDR = 0x80000000u, // REPRESENTATION_INDEX << COUNT_MAX
+ AUDIO_CHANNEL_INDEX_MASK_1 = 0x80000001u, // INDEX_HDR | (1 << 1) - 1
+ AUDIO_CHANNEL_INDEX_MASK_2 = 0x80000003u, // INDEX_HDR | (1 << 2) - 1
+ AUDIO_CHANNEL_INDEX_MASK_3 = 0x80000007u, // INDEX_HDR | (1 << 3) - 1
+ AUDIO_CHANNEL_INDEX_MASK_4 = 0x8000000Fu, // INDEX_HDR | (1 << 4) - 1
+ AUDIO_CHANNEL_INDEX_MASK_5 = 0x8000001Fu, // INDEX_HDR | (1 << 5) - 1
+ AUDIO_CHANNEL_INDEX_MASK_6 = 0x8000003Fu, // INDEX_HDR | (1 << 6) - 1
+ AUDIO_CHANNEL_INDEX_MASK_7 = 0x8000007Fu, // INDEX_HDR | (1 << 7) - 1
+ AUDIO_CHANNEL_INDEX_MASK_8 = 0x800000FFu, // INDEX_HDR | (1 << 8) - 1
+};
+
+typedef enum {
+#ifndef AUDIO_NO_SYSTEM_DECLARATIONS
+ AUDIO_MODE_INVALID = -2, // (-2)
+ AUDIO_MODE_CURRENT = -1, // (-1)
+#endif // AUDIO_NO_SYSTEM_DECLARATIONS
+ AUDIO_MODE_NORMAL = 0,
+ AUDIO_MODE_RINGTONE = 1,
+ AUDIO_MODE_IN_CALL = 2,
+ AUDIO_MODE_IN_COMMUNICATION = 3,
+} audio_mode_t;
+
+enum {
+ AUDIO_DEVICE_NONE = 0x0u,
+ AUDIO_DEVICE_BIT_IN = 0x80000000u,
+ AUDIO_DEVICE_BIT_DEFAULT = 0x40000000u,
+
+ AUDIO_DEVICE_OUT_EARPIECE = 0x1u,
+ AUDIO_DEVICE_OUT_SPEAKER = 0x2u,
+ AUDIO_DEVICE_OUT_WIRED_HEADSET = 0x4u,
+ AUDIO_DEVICE_OUT_WIRED_HEADPHONE = 0x8u,
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO = 0x10u,
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20u,
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40u,
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP = 0x80u,
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100u,
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200u,
+ AUDIO_DEVICE_OUT_AUX_DIGITAL = 0x400u,
+ AUDIO_DEVICE_OUT_HDMI = 0x400u, // OUT_AUX_DIGITAL
+ AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800u,
+ AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000u,
+ AUDIO_DEVICE_OUT_USB_ACCESSORY = 0x2000u,
+ AUDIO_DEVICE_OUT_USB_DEVICE = 0x4000u,
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX = 0x8000u,
+ AUDIO_DEVICE_OUT_TELEPHONY_TX = 0x10000u,
+ AUDIO_DEVICE_OUT_LINE = 0x20000u,
+ AUDIO_DEVICE_OUT_HDMI_ARC = 0x40000u,
+ AUDIO_DEVICE_OUT_SPDIF = 0x80000u,
+ AUDIO_DEVICE_OUT_FM = 0x100000u,
+ AUDIO_DEVICE_OUT_AUX_LINE = 0x200000u,
+ AUDIO_DEVICE_OUT_SPEAKER_SAFE = 0x400000u,
+ AUDIO_DEVICE_OUT_IP = 0x800000u,
+ AUDIO_DEVICE_OUT_BUS = 0x1000000u,
+ AUDIO_DEVICE_OUT_PROXY = 0x2000000u,
+ AUDIO_DEVICE_OUT_USB_HEADSET = 0x4000000u,
+ AUDIO_DEVICE_OUT_HEARING_AID = 0x8000000u,
+ AUDIO_DEVICE_OUT_ECHO_CANCELLER = 0x10000000u,
+ AUDIO_DEVICE_OUT_DEFAULT = 0x40000000u, // BIT_DEFAULT
+
+ AUDIO_DEVICE_IN_COMMUNICATION = 0x80000001u, // BIT_IN | 0x1
+ AUDIO_DEVICE_IN_AMBIENT = 0x80000002u, // BIT_IN | 0x2
+ AUDIO_DEVICE_IN_BUILTIN_MIC = 0x80000004u, // BIT_IN | 0x4
+ AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x80000008u, // BIT_IN | 0x8
+ AUDIO_DEVICE_IN_WIRED_HEADSET = 0x80000010u, // BIT_IN | 0x10
+ AUDIO_DEVICE_IN_AUX_DIGITAL = 0x80000020u, // BIT_IN | 0x20
+ AUDIO_DEVICE_IN_HDMI = 0x80000020u, // IN_AUX_DIGITAL
+ AUDIO_DEVICE_IN_VOICE_CALL = 0x80000040u, // BIT_IN | 0x40
+ AUDIO_DEVICE_IN_TELEPHONY_RX = 0x80000040u, // IN_VOICE_CALL
+ AUDIO_DEVICE_IN_BACK_MIC = 0x80000080u, // BIT_IN | 0x80
+ AUDIO_DEVICE_IN_REMOTE_SUBMIX = 0x80000100u, // BIT_IN | 0x100
+ AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET = 0x80000200u, // BIT_IN | 0x200
+ AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET = 0x80000400u, // BIT_IN | 0x400
+ AUDIO_DEVICE_IN_USB_ACCESSORY = 0x80000800u, // BIT_IN | 0x800
+ AUDIO_DEVICE_IN_USB_DEVICE = 0x80001000u, // BIT_IN | 0x1000
+ AUDIO_DEVICE_IN_FM_TUNER = 0x80002000u, // BIT_IN | 0x2000
+ AUDIO_DEVICE_IN_TV_TUNER = 0x80004000u, // BIT_IN | 0x4000
+ AUDIO_DEVICE_IN_LINE = 0x80008000u, // BIT_IN | 0x8000
+ AUDIO_DEVICE_IN_SPDIF = 0x80010000u, // BIT_IN | 0x10000
+ AUDIO_DEVICE_IN_BLUETOOTH_A2DP = 0x80020000u, // BIT_IN | 0x20000
+ AUDIO_DEVICE_IN_LOOPBACK = 0x80040000u, // BIT_IN | 0x40000
+ AUDIO_DEVICE_IN_IP = 0x80080000u, // BIT_IN | 0x80000
+ AUDIO_DEVICE_IN_BUS = 0x80100000u, // BIT_IN | 0x100000
+ AUDIO_DEVICE_IN_PROXY = 0x81000000u, // BIT_IN | 0x1000000
+ AUDIO_DEVICE_IN_USB_HEADSET = 0x82000000u, // BIT_IN | 0x2000000
+ AUDIO_DEVICE_IN_BLUETOOTH_BLE = 0x84000000u, // BIT_IN | 0x4000000
+ AUDIO_DEVICE_IN_DEFAULT = 0xC0000000u, // BIT_IN | BIT_DEFAULT
+};
+
+typedef enum {
+ AUDIO_OUTPUT_FLAG_NONE = 0x0,
+ AUDIO_OUTPUT_FLAG_DIRECT = 0x1,
+ AUDIO_OUTPUT_FLAG_PRIMARY = 0x2,
+ AUDIO_OUTPUT_FLAG_FAST = 0x4,
+ AUDIO_OUTPUT_FLAG_DEEP_BUFFER = 0x8,
+ AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD = 0x10,
+ AUDIO_OUTPUT_FLAG_NON_BLOCKING = 0x20,
+ AUDIO_OUTPUT_FLAG_HW_AV_SYNC = 0x40,
+ AUDIO_OUTPUT_FLAG_TTS = 0x80,
+ AUDIO_OUTPUT_FLAG_RAW = 0x100,
+ AUDIO_OUTPUT_FLAG_SYNC = 0x200,
+ AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO = 0x400,
+ AUDIO_OUTPUT_FLAG_DIRECT_PCM = 0x2000,
+ AUDIO_OUTPUT_FLAG_MMAP_NOIRQ = 0x4000,
+ AUDIO_OUTPUT_FLAG_VOIP_RX = 0x8000,
+ AUDIO_OUTPUT_FLAG_INCALL_MUSIC = 0x10000,
+} audio_output_flags_t;
+
+typedef enum {
+ AUDIO_INPUT_FLAG_NONE = 0x0,
+ AUDIO_INPUT_FLAG_FAST = 0x1,
+ AUDIO_INPUT_FLAG_HW_HOTWORD = 0x2,
+ AUDIO_INPUT_FLAG_RAW = 0x4,
+ AUDIO_INPUT_FLAG_SYNC = 0x8,
+ AUDIO_INPUT_FLAG_MMAP_NOIRQ = 0x10,
+ AUDIO_INPUT_FLAG_VOIP_TX = 0x20,
+ AUDIO_INPUT_FLAG_HW_AV_SYNC = 0x40,
+#ifndef AUDIO_NO_SYSTEM_DECLARATIONS // TODO: Expose at HAL interface, remove FRAMEWORK_FLAGS mask
+ AUDIO_INPUT_FLAG_DIRECT = 0x80,
+ AUDIO_INPUT_FRAMEWORK_FLAGS = AUDIO_INPUT_FLAG_DIRECT,
+#endif
+} audio_input_flags_t;
+
+typedef enum {
+ AUDIO_USAGE_UNKNOWN = 0,
+ AUDIO_USAGE_MEDIA = 1,
+ AUDIO_USAGE_VOICE_COMMUNICATION = 2,
+ AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING = 3,
+ AUDIO_USAGE_ALARM = 4,
+ AUDIO_USAGE_NOTIFICATION = 5,
+ AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE = 6,
+#ifndef AUDIO_NO_SYSTEM_DECLARATIONS
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9,
+ AUDIO_USAGE_NOTIFICATION_EVENT = 10,
+#endif // AUDIO_NO_SYSTEM_DECLARATIONS
+ AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY = 11,
+ AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12,
+ AUDIO_USAGE_ASSISTANCE_SONIFICATION = 13,
+ AUDIO_USAGE_GAME = 14,
+ AUDIO_USAGE_VIRTUAL_SOURCE = 15,
+ AUDIO_USAGE_ASSISTANT = 16,
+} audio_usage_t;
+
+typedef enum {
+ AUDIO_CONTENT_TYPE_UNKNOWN = 0u,
+ AUDIO_CONTENT_TYPE_SPEECH = 1u,
+ AUDIO_CONTENT_TYPE_MUSIC = 2u,
+ AUDIO_CONTENT_TYPE_MOVIE = 3u,
+ AUDIO_CONTENT_TYPE_SONIFICATION = 4u,
+} audio_content_type_t;
+
+enum {
+ AUDIO_GAIN_MODE_JOINT = 0x1u,
+ AUDIO_GAIN_MODE_CHANNELS = 0x2u,
+ AUDIO_GAIN_MODE_RAMP = 0x4u,
+};
+
+typedef enum {
+ AUDIO_PORT_ROLE_NONE = 0,
+ AUDIO_PORT_ROLE_SOURCE = 1, // (::android::hardware::audio::common::V4_0::AudioPortRole.NONE implicitly + 1)
+ AUDIO_PORT_ROLE_SINK = 2, // (::android::hardware::audio::common::V4_0::AudioPortRole.SOURCE implicitly + 1)
+} audio_port_role_t;
+
+typedef enum {
+ AUDIO_PORT_TYPE_NONE = 0,
+ AUDIO_PORT_TYPE_DEVICE = 1, // (::android::hardware::audio::common::V4_0::AudioPortType.NONE implicitly + 1)
+ AUDIO_PORT_TYPE_MIX = 2, // (::android::hardware::audio::common::V4_0::AudioPortType.DEVICE implicitly + 1)
+ AUDIO_PORT_TYPE_SESSION = 3, // (::android::hardware::audio::common::V4_0::AudioPortType.MIX implicitly + 1)
+} audio_port_type_t;
+
+enum {
+ AUDIO_PORT_CONFIG_SAMPLE_RATE = 0x1u,
+ AUDIO_PORT_CONFIG_CHANNEL_MASK = 0x2u,
+ AUDIO_PORT_CONFIG_FORMAT = 0x4u,
+ AUDIO_PORT_CONFIG_GAIN = 0x8u,
+#ifndef AUDIO_NO_SYSTEM_DECLARATIONS
+ AUDIO_PORT_CONFIG_FLAGS = 0x10u, // Absent from AudioPortConfigMask, framework only.
+#endif
+};
+
+typedef enum {
+ AUDIO_LATENCY_LOW = 0,
+ AUDIO_LATENCY_NORMAL = 1, // (::android::hardware::audio::common::V4_0::AudioMixLatencyClass.LOW implicitly + 1)
+} audio_mix_latency_class_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // HIDL_GENERATED_ANDROID_HARDWARE_AUDIO_COMMON_V4_0_EXPORTED_CONSTANTS_H_
diff --git a/include/system/audio.h b/include/system/audio.h
new file mode 100644
index 0000000..2295c3d
--- /dev/null
+++ b/include/system/audio.h
@@ -0,0 +1,1390 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef ANDROID_AUDIO_CORE_H
+#define ANDROID_AUDIO_CORE_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <cutils/bitops.h>
+
+#include "audio-base.h"
+#include "audio-base-utils.h"
+
+__BEGIN_DECLS
+
+/* The enums were moved here mostly from
+ * frameworks/base/include/media/AudioSystem.h
+ */
+
+/* represents an invalid uid for tracks; the calling or client uid is often substituted. */
+#define AUDIO_UID_INVALID ((uid_t)-1)
+
+/* device address used to refer to the standard remote submix */
+#define AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS "0"
+
+/* AudioFlinger and AudioPolicy services use I/O handles to identify audio sources and sinks */
+typedef int audio_io_handle_t;
+
+typedef uint32_t audio_flags_mask_t;
+
+/* Do not change these values without updating their counterparts
+ * in frameworks/base/media/java/android/media/AudioAttributes.java
+ */
+enum {
+ AUDIO_FLAG_NONE = 0x0,
+ AUDIO_FLAG_AUDIBILITY_ENFORCED = 0x1,
+ AUDIO_FLAG_SECURE = 0x2,
+ AUDIO_FLAG_SCO = 0x4,
+ AUDIO_FLAG_BEACON = 0x8,
+ AUDIO_FLAG_HW_AV_SYNC = 0x10,
+ AUDIO_FLAG_HW_HOTWORD = 0x20,
+ AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY = 0x40,
+ AUDIO_FLAG_BYPASS_MUTE = 0x80,
+ AUDIO_FLAG_LOW_LATENCY = 0x100,
+ AUDIO_FLAG_DEEP_BUFFER = 0x200,
+};
+
+/* Audio attributes */
+#define AUDIO_ATTRIBUTES_TAGS_MAX_SIZE 256
+typedef struct {
+ audio_content_type_t content_type;
+ audio_usage_t usage;
+ audio_source_t source;
+ audio_flags_mask_t flags;
+ char tags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE]; /* UTF8 */
+} __attribute__((packed)) audio_attributes_t; // sent through Binder;
+
+/* a unique ID allocated by AudioFlinger for use as an audio_io_handle_t, audio_session_t,
+ * effect ID (int), audio_module_handle_t, and audio_patch_handle_t.
+ * Audio port IDs (audio_port_handle_t) are allocated by AudioPolicy
+ * in a different namespace than AudioFlinger unique IDs.
+ */
+typedef int audio_unique_id_t;
+
+/* Possible uses for an audio_unique_id_t */
+typedef enum {
+ AUDIO_UNIQUE_ID_USE_UNSPECIFIED = 0,
+ AUDIO_UNIQUE_ID_USE_SESSION = 1, // for allocated sessions, not special AUDIO_SESSION_*
+ AUDIO_UNIQUE_ID_USE_MODULE = 2,
+ AUDIO_UNIQUE_ID_USE_EFFECT = 3,
+ AUDIO_UNIQUE_ID_USE_PATCH = 4,
+ AUDIO_UNIQUE_ID_USE_OUTPUT = 5,
+ AUDIO_UNIQUE_ID_USE_INPUT = 6,
+ AUDIO_UNIQUE_ID_USE_PLAYER = 7,
+ AUDIO_UNIQUE_ID_USE_MAX = 8, // must be a power-of-two
+ AUDIO_UNIQUE_ID_USE_MASK = AUDIO_UNIQUE_ID_USE_MAX - 1
+} audio_unique_id_use_t;
+
+/* Return the use of an audio_unique_id_t */
+static inline audio_unique_id_use_t audio_unique_id_get_use(audio_unique_id_t id)
+{
+ return (audio_unique_id_use_t) (id & AUDIO_UNIQUE_ID_USE_MASK);
+}
+
+/* Reserved audio_unique_id_t values. FIXME: not a complete list. */
+#define AUDIO_UNIQUE_ID_ALLOCATE AUDIO_SESSION_ALLOCATE
+
+/* A channel mask per se only defines the presence or absence of a channel, not the order.
+ * But see AUDIO_INTERLEAVE_* below for the platform convention of order.
+ *
+ * audio_channel_mask_t is an opaque type and its internal layout should not
+ * be assumed as it may change in the future.
+ * Instead, always use the functions declared in this header to examine.
+ *
+ * These are the current representations:
+ *
+ * AUDIO_CHANNEL_REPRESENTATION_POSITION
+ * is a channel mask representation for position assignment.
+ * Each low-order bit corresponds to the spatial position of a transducer (output),
+ * or interpretation of channel (input).
+ * The user of a channel mask needs to know the context of whether it is for output or input.
+ * The constants AUDIO_CHANNEL_OUT_* or AUDIO_CHANNEL_IN_* apply to the bits portion.
+ * It is not permitted for no bits to be set.
+ *
+ * AUDIO_CHANNEL_REPRESENTATION_INDEX
+ * is a channel mask representation for index assignment.
+ * Each low-order bit corresponds to a selected channel.
+ * There is no platform interpretation of the various bits.
+ * There is no concept of output or input.
+ * It is not permitted for no bits to be set.
+ *
+ * All other representations are reserved for future use.
+ *
+ * Warning: current representation distinguishes between input and output, but this will not the be
+ * case in future revisions of the platform. Wherever there is an ambiguity between input and output
+ * that is currently resolved by checking the channel mask, the implementer should look for ways to
+ * fix it with additional information outside of the mask.
+ */
+typedef uint32_t audio_channel_mask_t;
+
+/* log(2) of maximum number of representations, not part of public API */
+#define AUDIO_CHANNEL_REPRESENTATION_LOG2 2
+
+/* The return value is undefined if the channel mask is invalid. */
+static inline uint32_t audio_channel_mask_get_bits(audio_channel_mask_t channel)
+{
+ return channel & ((1 << AUDIO_CHANNEL_COUNT_MAX) - 1);
+}
+
+typedef uint32_t audio_channel_representation_t;
+
+/* The return value is undefined if the channel mask is invalid. */
+static inline audio_channel_representation_t audio_channel_mask_get_representation(
+ audio_channel_mask_t channel)
+{
+ // The right shift should be sufficient, but also "and" for safety in case mask is not 32 bits
+ return (audio_channel_representation_t)
+ ((channel >> AUDIO_CHANNEL_COUNT_MAX) & ((1 << AUDIO_CHANNEL_REPRESENTATION_LOG2) - 1));
+}
+
+/* Returns true if the channel mask is valid,
+ * or returns false for AUDIO_CHANNEL_NONE, AUDIO_CHANNEL_INVALID, and other invalid values.
+ * This function is unable to determine whether a channel mask for position assignment
+ * is invalid because an output mask has an invalid output bit set,
+ * or because an input mask has an invalid input bit set.
+ * All other APIs that take a channel mask assume that it is valid.
+ */
+static inline bool audio_channel_mask_is_valid(audio_channel_mask_t channel)
+{
+ uint32_t bits = audio_channel_mask_get_bits(channel);
+ audio_channel_representation_t representation = audio_channel_mask_get_representation(channel);
+ switch (representation) {
+ case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+ case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+ break;
+ default:
+ bits = 0;
+ break;
+ }
+ return bits != 0;
+}
+
+/* Not part of public API */
+static inline audio_channel_mask_t audio_channel_mask_from_representation_and_bits(
+ audio_channel_representation_t representation, uint32_t bits)
+{
+ return (audio_channel_mask_t) ((representation << AUDIO_CHANNEL_COUNT_MAX) | bits);
+}
+
+/**
+ * Expresses the convention when stereo audio samples are stored interleaved
+ * in an array. This should improve readability by allowing code to use
+ * symbolic indices instead of hard-coded [0] and [1].
+ *
+ * For multi-channel beyond stereo, the platform convention is that channels
+ * are interleaved in order from least significant channel mask bit to most
+ * significant channel mask bit, with unused bits skipped. Any exceptions
+ * to this convention will be noted at the appropriate API.
+ */
+enum {
+ AUDIO_INTERLEAVE_LEFT = 0,
+ AUDIO_INTERLEAVE_RIGHT = 1,
+};
+
+/* This enum is deprecated */
+typedef enum {
+ AUDIO_IN_ACOUSTICS_NONE = 0,
+ AUDIO_IN_ACOUSTICS_AGC_ENABLE = 0x0001,
+ AUDIO_IN_ACOUSTICS_AGC_DISABLE = 0,
+ AUDIO_IN_ACOUSTICS_NS_ENABLE = 0x0002,
+ AUDIO_IN_ACOUSTICS_NS_DISABLE = 0,
+ AUDIO_IN_ACOUSTICS_TX_IIR_ENABLE = 0x0004,
+ AUDIO_IN_ACOUSTICS_TX_DISABLE = 0,
+} audio_in_acoustics_t;
+
+typedef uint32_t audio_devices_t;
+/**
+ * Stub audio output device. Used in policy configuration file on platforms without audio outputs.
+ * This alias value to AUDIO_DEVICE_OUT_DEFAULT is only used in the audio policy context.
+ */
+#define AUDIO_DEVICE_OUT_STUB AUDIO_DEVICE_OUT_DEFAULT
+/**
+ * Stub audio input device. Used in policy configuration file on platforms without audio inputs.
+ * This alias value to AUDIO_DEVICE_IN_DEFAULT is only used in the audio policy context.
+ */
+#define AUDIO_DEVICE_IN_STUB AUDIO_DEVICE_IN_DEFAULT
+
+/* Additional information about compressed streams offloaded to
+ * hardware playback
+ * The version and size fields must be initialized by the caller by using
+ * one of the constants defined here.
+ * Must be aligned to transmit as raw memory through Binder.
+ */
+typedef struct {
+ uint16_t version; // version of the info structure
+ uint16_t size; // total size of the structure including version and size
+ uint32_t sample_rate; // sample rate in Hz
+ audio_channel_mask_t channel_mask; // channel mask
+ audio_format_t format; // audio format
+ audio_stream_type_t stream_type; // stream type
+ uint32_t bit_rate; // bit rate in bits per second
+ int64_t duration_us; // duration in microseconds, -1 if unknown
+ bool has_video; // true if stream is tied to a video stream
+ bool is_streaming; // true if streaming, false if local playback
+ uint32_t bit_width;
+ uint32_t offload_buffer_size; // offload fragment size
+ audio_usage_t usage;
+} __attribute__((aligned(8))) audio_offload_info_t;
+
+#define AUDIO_MAKE_OFFLOAD_INFO_VERSION(maj,min) \
+ ((((maj) & 0xff) << 8) | ((min) & 0xff))
+
+#define AUDIO_OFFLOAD_INFO_VERSION_0_1 AUDIO_MAKE_OFFLOAD_INFO_VERSION(0, 1)
+#define AUDIO_OFFLOAD_INFO_VERSION_CURRENT AUDIO_OFFLOAD_INFO_VERSION_0_1
+
+static const audio_offload_info_t AUDIO_INFO_INITIALIZER = {
+ /* .version = */ AUDIO_OFFLOAD_INFO_VERSION_CURRENT,
+ /* .size = */ sizeof(audio_offload_info_t),
+ /* .sample_rate = */ 0,
+ /* .channel_mask = */ 0,
+ /* .format = */ AUDIO_FORMAT_DEFAULT,
+ /* .stream_type = */ AUDIO_STREAM_VOICE_CALL,
+ /* .bit_rate = */ 0,
+ /* .duration_us = */ 0,
+ /* .has_video = */ false,
+ /* .is_streaming = */ false,
+ /* .bit_width = */ 16,
+ /* .offload_buffer_size = */ 0,
+ /* .usage = */ AUDIO_USAGE_UNKNOWN
+};
+
+/* common audio stream configuration parameters
+ * You should memset() the entire structure to zero before use to
+ * ensure forward compatibility
+ * Must be aligned to transmit as raw memory through Binder.
+ */
+struct __attribute__((aligned(8))) audio_config {
+ uint32_t sample_rate;
+ audio_channel_mask_t channel_mask;
+ audio_format_t format;
+ audio_offload_info_t offload_info;
+ uint32_t frame_count;
+};
+typedef struct audio_config audio_config_t;
+
+static const audio_config_t AUDIO_CONFIG_INITIALIZER = {
+ /* .sample_rate = */ 0,
+ /* .channel_mask = */ AUDIO_CHANNEL_NONE,
+ /* .format = */ AUDIO_FORMAT_DEFAULT,
+ /* .offload_info = */ {
+ /* .version = */ AUDIO_OFFLOAD_INFO_VERSION_CURRENT,
+ /* .size = */ sizeof(audio_offload_info_t),
+ /* .sample_rate = */ 0,
+ /* .channel_mask = */ 0,
+ /* .format = */ AUDIO_FORMAT_DEFAULT,
+ /* .stream_type = */ AUDIO_STREAM_VOICE_CALL,
+ /* .bit_rate = */ 0,
+ /* .duration_us = */ 0,
+ /* .has_video = */ false,
+ /* .is_streaming = */ false,
+ /* .bit_width = */ 16,
+ /* .offload_buffer_size = */ 0,
+ /* .usage = */ AUDIO_USAGE_UNKNOWN
+ },
+ /* .frame_count = */ 0,
+};
+
+struct audio_config_base {
+ uint32_t sample_rate;
+ audio_channel_mask_t channel_mask;
+ audio_format_t format;
+};
+
+typedef struct audio_config_base audio_config_base_t;
+
+static const audio_config_base_t AUDIO_CONFIG_BASE_INITIALIZER = {
+ /* .sample_rate = */ 0,
+ /* .channel_mask = */ AUDIO_CHANNEL_NONE,
+ /* .format = */ AUDIO_FORMAT_DEFAULT
+};
+
+/* audio hw module handle functions or structures referencing a module */
+typedef int audio_module_handle_t;
+
+/******************************
+ * Volume control
+ *****************************/
+
+/** 3 dB headroom are allowed on float samples (3db = 10^(3/20) = 1.412538).
+* See: https://developer.android.com/reference/android/media/AudioTrack.html#write(float[], int, int, int)
+*/
+#define FLOAT_NOMINAL_RANGE_HEADROOM 1.412538
+
+/* If the audio hardware supports gain control on some audio paths,
+ * the platform can expose them in the audio_policy.conf file. The audio HAL
+ * will then implement gain control functions that will use the following data
+ * structures. */
+
+typedef uint32_t audio_gain_mode_t;
+
+
+/* An audio_gain struct is a representation of a gain stage.
+ * A gain stage is always attached to an audio port. */
+struct audio_gain {
+ audio_gain_mode_t mode; /* e.g. AUDIO_GAIN_MODE_JOINT */
+ audio_channel_mask_t channel_mask; /* channels which gain an be controlled.
+ N/A if AUDIO_GAIN_MODE_CHANNELS is not supported */
+ int min_value; /* minimum gain value in millibels */
+ int max_value; /* maximum gain value in millibels */
+ int default_value; /* default gain value in millibels */
+ unsigned int step_value; /* gain step in millibels */
+ unsigned int min_ramp_ms; /* minimum ramp duration in ms */
+ unsigned int max_ramp_ms; /* maximum ramp duration in ms */
+};
+
+/* The gain configuration structure is used to get or set the gain values of a
+ * given port */
+struct audio_gain_config {
+ int index; /* index of the corresponding audio_gain in the
+ audio_port gains[] table */
+ audio_gain_mode_t mode; /* mode requested for this command */
+ audio_channel_mask_t channel_mask; /* channels which gain value follows.
+ N/A in joint mode */
+
+ // note this "8" is not FCC_8, so it won't need to be changed for > 8 channels
+ int values[sizeof(audio_channel_mask_t) * 8]; /* gain values in millibels
+ for each channel ordered from LSb to MSb in
+ channel mask. The number of values is 1 in joint
+ mode or popcount(channel_mask) */
+ unsigned int ramp_duration_ms; /* ramp duration in ms */
+};
+
+/******************************
+ * Routing control
+ *****************************/
+
+/* Types defined here are used to describe an audio source or sink at internal
+ * framework interfaces (audio policy, patch panel) or at the audio HAL.
+ * Sink and sources are grouped in a concept of “audio port” representing an
+ * audio end point at the edge of the system managed by the module exposing
+ * the interface. */
+
+/* Each port has a unique ID or handle allocated by policy manager */
+typedef int audio_port_handle_t;
+
+/* the maximum length for the human-readable device name */
+#define AUDIO_PORT_MAX_NAME_LEN 128
+
+/* a union to store port configuration flags. Declared as a type so can be reused
+ in framework code */
+union audio_io_flags {
+ audio_input_flags_t input;
+ audio_output_flags_t output;
+};
+
+/* maximum audio device address length */
+#define AUDIO_DEVICE_MAX_ADDRESS_LEN 32
+
+/* extension for audio port configuration structure when the audio port is a
+ * hardware device */
+struct audio_port_config_device_ext {
+ audio_module_handle_t hw_module; /* module the device is attached to */
+ audio_devices_t type; /* device type (e.g AUDIO_DEVICE_OUT_SPEAKER) */
+ char address[AUDIO_DEVICE_MAX_ADDRESS_LEN]; /* device address. "" if N/A */
+};
+
+/* extension for audio port configuration structure when the audio port is a
+ * sub mix */
+struct audio_port_config_mix_ext {
+ audio_module_handle_t hw_module; /* module the stream is attached to */
+ audio_io_handle_t handle; /* I/O handle of the input/output stream */
+ union {
+ //TODO: change use case for output streams: use strategy and mixer attributes
+ audio_stream_type_t stream;
+ audio_source_t source;
+ } usecase;
+};
+
+/* extension for audio port configuration structure when the audio port is an
+ * audio session */
+struct audio_port_config_session_ext {
+ audio_session_t session; /* audio session */
+};
+
+/* audio port configuration structure used to specify a particular configuration of
+ * an audio port */
+struct audio_port_config {
+ audio_port_handle_t id; /* port unique ID */
+ audio_port_role_t role; /* sink or source */
+ audio_port_type_t type; /* device, mix ... */
+ unsigned int config_mask; /* e.g AUDIO_PORT_CONFIG_ALL */
+ unsigned int sample_rate; /* sampling rate in Hz */
+ audio_channel_mask_t channel_mask; /* channel mask if applicable */
+ audio_format_t format; /* format if applicable */
+ struct audio_gain_config gain; /* gain to apply if applicable */
+#ifndef AUDIO_NO_SYSTEM_DECLARATIONS
+ union audio_io_flags flags; /* framework only: HW_AV_SYNC, DIRECT, ... */
+#endif
+ union {
+ struct audio_port_config_device_ext device; /* device specific info */
+ struct audio_port_config_mix_ext mix; /* mix specific info */
+ struct audio_port_config_session_ext session; /* session specific info */
+ } ext;
+};
+
+
+/* max number of sampling rates in audio port */
+#define AUDIO_PORT_MAX_SAMPLING_RATES 32
+/* max number of channel masks in audio port */
+#define AUDIO_PORT_MAX_CHANNEL_MASKS 32
+/* max number of audio formats in audio port */
+#define AUDIO_PORT_MAX_FORMATS 32
+/* max number of gain controls in audio port */
+#define AUDIO_PORT_MAX_GAINS 16
+
+/* extension for audio port structure when the audio port is a hardware device */
+struct audio_port_device_ext {
+ audio_module_handle_t hw_module; /* module the device is attached to */
+ audio_devices_t type; /* device type (e.g AUDIO_DEVICE_OUT_SPEAKER) */
+ char address[AUDIO_DEVICE_MAX_ADDRESS_LEN];
+};
+
+/* extension for audio port structure when the audio port is a sub mix */
+struct audio_port_mix_ext {
+ audio_module_handle_t hw_module; /* module the stream is attached to */
+ audio_io_handle_t handle; /* I/O handle of the input.output stream */
+ audio_mix_latency_class_t latency_class; /* latency class */
+ // other attributes: routing strategies
+};
+
+/* extension for audio port structure when the audio port is an audio session */
+struct audio_port_session_ext {
+ audio_session_t session; /* audio session */
+};
+
+struct audio_port {
+ audio_port_handle_t id; /* port unique ID */
+ audio_port_role_t role; /* sink or source */
+ audio_port_type_t type; /* device, mix ... */
+ char name[AUDIO_PORT_MAX_NAME_LEN];
+ unsigned int num_sample_rates; /* number of sampling rates in following array */
+ unsigned int sample_rates[AUDIO_PORT_MAX_SAMPLING_RATES];
+ unsigned int num_channel_masks; /* number of channel masks in following array */
+ audio_channel_mask_t channel_masks[AUDIO_PORT_MAX_CHANNEL_MASKS];
+ unsigned int num_formats; /* number of formats in following array */
+ audio_format_t formats[AUDIO_PORT_MAX_FORMATS];
+ unsigned int num_gains; /* number of gains in following array */
+ struct audio_gain gains[AUDIO_PORT_MAX_GAINS];
+ struct audio_port_config active_config; /* current audio port configuration */
+ union {
+ struct audio_port_device_ext device;
+ struct audio_port_mix_ext mix;
+ struct audio_port_session_ext session;
+ } ext;
+};
+
+/* An audio patch represents a connection between one or more source ports and
+ * one or more sink ports. Patches are connected and disconnected by audio policy manager or by
+ * applications via framework APIs.
+ * Each patch is identified by a handle at the interface used to create that patch. For instance,
+ * when a patch is created by the audio HAL, the HAL allocates and returns a handle.
+ * This handle is unique to a given audio HAL hardware module.
+ * But the same patch receives another system wide unique handle allocated by the framework.
+ * This unique handle is used for all transactions inside the framework.
+ */
+typedef int audio_patch_handle_t;
+
+#define AUDIO_PATCH_PORTS_MAX 16
+
+struct audio_patch {
+ audio_patch_handle_t id; /* patch unique ID */
+ unsigned int num_sources; /* number of sources in following array */
+ struct audio_port_config sources[AUDIO_PATCH_PORTS_MAX];
+ unsigned int num_sinks; /* number of sinks in following array */
+ struct audio_port_config sinks[AUDIO_PATCH_PORTS_MAX];
+};
+
+
+
+/* a HW synchronization source returned by the audio HAL */
+typedef uint32_t audio_hw_sync_t;
+
+/* an invalid HW synchronization source indicating an error */
+#define AUDIO_HW_SYNC_INVALID 0
+
+/**
+ * Mmap buffer descriptor returned by audio_stream->create_mmap_buffer().
+ * note\ Used by streams opened in mmap mode.
+ */
+struct audio_mmap_buffer_info {
+ void* shared_memory_address; /**< base address of mmap memory buffer.
+ For use by local process only */
+ int32_t shared_memory_fd; /**< FD for mmap memory buffer */
+ int32_t buffer_size_frames; /**< total buffer size in frames */
+ int32_t burst_size_frames; /**< transfer size granularity in frames */
+};
+
+/**
+ * Mmap buffer read/write position returned by audio_stream->get_mmap_position().
+ * note\ Used by streams opened in mmap mode.
+ */
+struct audio_mmap_position {
+ int64_t time_nanoseconds; /**< timestamp in ns, CLOCK_MONOTONIC */
+ int32_t position_frames; /**< increasing 32 bit frame count reset when stream->stop()
+ is called */
+};
+
+/** Metadata of a record track for an in stream. */
+typedef struct playback_track_metadata {
+ audio_usage_t usage;
+ audio_content_type_t content_type;
+ float gain; // Normalized linear volume. 0=silence, 1=0dbfs...
+} playback_track_metadata_t;
+
+/** Metadata of a playback track for an out stream. */
+typedef struct record_track_metadata {
+ audio_source_t source;
+ float gain; // Normalized linear volume. 0=silence, 1=0dbfs...
+} record_track_metadata_t;
+
+
+/******************************
+ * Helper functions
+ *****************************/
+
+static inline bool audio_is_output_device(audio_devices_t device)
+{
+ if (((device & AUDIO_DEVICE_BIT_IN) == 0) &&
+ (popcount(device) == 1) && ((device & ~AUDIO_DEVICE_OUT_ALL) == 0))
+ return true;
+ else
+ return false;
+}
+
+static inline bool audio_is_input_device(audio_devices_t device)
+{
+ if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+ device &= ~AUDIO_DEVICE_BIT_IN;
+ if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_IN_ALL) == 0))
+ return true;
+ }
+ return false;
+}
+
+static inline bool audio_is_output_devices(audio_devices_t device)
+{
+ return (device & AUDIO_DEVICE_BIT_IN) == 0;
+}
+
+static inline bool audio_is_a2dp_in_device(audio_devices_t device)
+{
+ if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+ device &= ~AUDIO_DEVICE_BIT_IN;
+ if ((popcount(device) == 1) && (device & AUDIO_DEVICE_IN_BLUETOOTH_A2DP))
+ return true;
+ }
+ return false;
+}
+
+static inline bool audio_is_a2dp_out_device(audio_devices_t device)
+{
+ if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_ALL_A2DP))
+ return true;
+ else
+ return false;
+}
+
+// Deprecated - use audio_is_a2dp_out_device() instead
+static inline bool audio_is_a2dp_device(audio_devices_t device)
+{
+ return audio_is_a2dp_out_device(device);
+}
+
+static inline bool audio_is_bluetooth_sco_device(audio_devices_t device)
+{
+ if ((device & AUDIO_DEVICE_BIT_IN) == 0) {
+ if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_OUT_ALL_SCO) == 0))
+ return true;
+ } else {
+ device &= ~AUDIO_DEVICE_BIT_IN;
+ if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) == 0))
+ return true;
+ }
+
+ return false;
+}
+
+static inline bool audio_is_hearing_aid_out_device(audio_devices_t device)
+{
+ return device == AUDIO_DEVICE_OUT_HEARING_AID;
+}
+
+static inline bool audio_is_usb_out_device(audio_devices_t device)
+{
+ return ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_ALL_USB));
+}
+
+static inline bool audio_is_usb_in_device(audio_devices_t device)
+{
+ if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+ device &= ~AUDIO_DEVICE_BIT_IN;
+ if (popcount(device) == 1 && (device & AUDIO_DEVICE_IN_ALL_USB) != 0)
+ return true;
+ }
+ return false;
+}
+
+/* OBSOLETE - use audio_is_usb_out_device() instead. */
+static inline bool audio_is_usb_device(audio_devices_t device)
+{
+ return audio_is_usb_out_device(device);
+}
+
+static inline bool audio_is_remote_submix_device(audio_devices_t device)
+{
+ if ((audio_is_output_devices(device) &&
+ (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX) == AUDIO_DEVICE_OUT_REMOTE_SUBMIX)
+ || (!audio_is_output_devices(device) &&
+ (device & AUDIO_DEVICE_IN_REMOTE_SUBMIX) == AUDIO_DEVICE_IN_REMOTE_SUBMIX))
+ return true;
+ else
+ return false;
+}
+
+/* Returns true if:
+ * representation is valid, and
+ * there is at least one channel bit set which _could_ correspond to an input channel, and
+ * there are no channel bits set which could _not_ correspond to an input channel.
+ * Otherwise returns false.
+ */
+static inline bool audio_is_input_channel(audio_channel_mask_t channel)
+{
+ uint32_t bits = audio_channel_mask_get_bits(channel);
+ switch (audio_channel_mask_get_representation(channel)) {
+ case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+ if (bits & ~AUDIO_CHANNEL_IN_ALL) {
+ bits = 0;
+ }
+ // fall through
+ case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+ return bits != 0;
+ default:
+ return false;
+ }
+}
+
+/* Returns true if:
+ * representation is valid, and
+ * there is at least one channel bit set which _could_ correspond to an output channel, and
+ * there are no channel bits set which could _not_ correspond to an output channel.
+ * Otherwise returns false.
+ */
+static inline bool audio_is_output_channel(audio_channel_mask_t channel)
+{
+ uint32_t bits = audio_channel_mask_get_bits(channel);
+ switch (audio_channel_mask_get_representation(channel)) {
+ case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+ if (bits & ~AUDIO_CHANNEL_OUT_ALL) {
+ bits = 0;
+ }
+ // fall through
+ case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+ return bits != 0;
+ default:
+ return false;
+ }
+}
+
+/* Returns the number of channels from an input channel mask,
+ * used in the context of audio input or recording.
+ * If a channel bit is set which could _not_ correspond to an input channel,
+ * it is excluded from the count.
+ * Returns zero if the representation is invalid.
+ */
+static inline uint32_t audio_channel_count_from_in_mask(audio_channel_mask_t channel)
+{
+ uint32_t bits = audio_channel_mask_get_bits(channel);
+ switch (audio_channel_mask_get_representation(channel)) {
+ case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+ // TODO: We can now merge with from_out_mask and remove anding
+ bits &= AUDIO_CHANNEL_IN_ALL;
+ // fall through
+ case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+ return popcount(bits);
+ default:
+ return 0;
+ }
+}
+
+/* Returns the number of channels from an output channel mask,
+ * used in the context of audio output or playback.
+ * If a channel bit is set which could _not_ correspond to an output channel,
+ * it is excluded from the count.
+ * Returns zero if the representation is invalid.
+ */
+static inline uint32_t audio_channel_count_from_out_mask(audio_channel_mask_t channel)
+{
+ uint32_t bits = audio_channel_mask_get_bits(channel);
+ switch (audio_channel_mask_get_representation(channel)) {
+ case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+ // TODO: We can now merge with from_in_mask and remove anding
+ bits &= AUDIO_CHANNEL_OUT_ALL;
+ // fall through
+ case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+ return popcount(bits);
+ default:
+ return 0;
+ }
+}
+
+/* Derive a channel mask for index assignment from a channel count.
+ * Returns the matching channel mask,
+ * or AUDIO_CHANNEL_NONE if the channel count is zero,
+ * or AUDIO_CHANNEL_INVALID if the channel count exceeds AUDIO_CHANNEL_COUNT_MAX.
+ */
+static inline audio_channel_mask_t audio_channel_mask_for_index_assignment_from_count(
+ uint32_t channel_count)
+{
+ if (channel_count == 0) {
+ return AUDIO_CHANNEL_NONE;
+ }
+ if (channel_count > AUDIO_CHANNEL_COUNT_MAX) {
+ return AUDIO_CHANNEL_INVALID;
+ }
+ uint32_t bits = (1 << channel_count) - 1;
+ return audio_channel_mask_from_representation_and_bits(
+ AUDIO_CHANNEL_REPRESENTATION_INDEX, bits);
+}
+
+/* Derive an output channel mask for position assignment from a channel count.
+ * This is to be used when the content channel mask is unknown. The 1, 2, 4, 5, 6, 7 and 8 channel
+ * cases are mapped to the standard game/home-theater layouts, but note that 4 is mapped to quad,
+ * and not stereo + FC + mono surround. A channel count of 3 is arbitrarily mapped to stereo + FC
+ * for continuity with stereo.
+ * Returns the matching channel mask,
+ * or AUDIO_CHANNEL_NONE if the channel count is zero,
+ * or AUDIO_CHANNEL_INVALID if the channel count exceeds that of the
+ * configurations for which a default output channel mask is defined.
+ */
+static inline audio_channel_mask_t audio_channel_out_mask_from_count(uint32_t channel_count)
+{
+ uint32_t bits;
+ switch (channel_count) {
+ case 0:
+ return AUDIO_CHANNEL_NONE;
+ case 1:
+ bits = AUDIO_CHANNEL_OUT_MONO;
+ break;
+ case 2:
+ bits = AUDIO_CHANNEL_OUT_STEREO;
+ break;
+ case 3:
+ bits = AUDIO_CHANNEL_OUT_STEREO | AUDIO_CHANNEL_OUT_FRONT_CENTER;
+ break;
+ case 4: // 4.0
+ bits = AUDIO_CHANNEL_OUT_QUAD;
+ break;
+ case 5: // 5.0
+ bits = AUDIO_CHANNEL_OUT_QUAD | AUDIO_CHANNEL_OUT_FRONT_CENTER;
+ break;
+ case 6: // 5.1
+ bits = AUDIO_CHANNEL_OUT_5POINT1;
+ break;
+ case 7: // 6.1
+ bits = AUDIO_CHANNEL_OUT_5POINT1 | AUDIO_CHANNEL_OUT_BACK_CENTER;
+ break;
+ case 8:
+ bits = AUDIO_CHANNEL_OUT_7POINT1;
+ break;
+ // FIXME FCC_8
+ default:
+ return AUDIO_CHANNEL_INVALID;
+ }
+ return audio_channel_mask_from_representation_and_bits(
+ AUDIO_CHANNEL_REPRESENTATION_POSITION, bits);
+}
+
+/* Derive a default input channel mask from a channel count.
+ * Assumes a position mask for mono and stereo, or an index mask for channel counts > 2.
+ * Returns the matching channel mask,
+ * or AUDIO_CHANNEL_NONE if the channel count is zero,
+ * or AUDIO_CHANNEL_INVALID if the channel count exceeds that of the
+ * configurations for which a default input channel mask is defined.
+ */
+static inline audio_channel_mask_t audio_channel_in_mask_from_count(uint32_t channel_count)
+{
+ uint32_t bits;
+ switch (channel_count) {
+ case 0:
+ return AUDIO_CHANNEL_NONE;
+ case 1:
+ bits = AUDIO_CHANNEL_IN_MONO;
+ break;
+ case 2:
+ bits = AUDIO_CHANNEL_IN_STEREO;
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ // FIXME FCC_8
+ return audio_channel_mask_for_index_assignment_from_count(channel_count);
+ default:
+ return AUDIO_CHANNEL_INVALID;
+ }
+ return audio_channel_mask_from_representation_and_bits(
+ AUDIO_CHANNEL_REPRESENTATION_POSITION, bits);
+}
+
+static inline audio_channel_mask_t audio_channel_mask_in_to_out(audio_channel_mask_t in)
+{
+ switch (in) {
+ case AUDIO_CHANNEL_IN_MONO:
+ return AUDIO_CHANNEL_OUT_MONO;
+ case AUDIO_CHANNEL_IN_STEREO:
+ return AUDIO_CHANNEL_OUT_STEREO;
+ case AUDIO_CHANNEL_IN_5POINT1:
+ return AUDIO_CHANNEL_OUT_5POINT1;
+ case AUDIO_CHANNEL_IN_3POINT1POINT2:
+ return AUDIO_CHANNEL_OUT_3POINT1POINT2;
+ case AUDIO_CHANNEL_IN_3POINT0POINT2:
+ return AUDIO_CHANNEL_OUT_3POINT0POINT2;
+ case AUDIO_CHANNEL_IN_2POINT1POINT2:
+ return AUDIO_CHANNEL_OUT_2POINT1POINT2;
+ case AUDIO_CHANNEL_IN_2POINT0POINT2:
+ return AUDIO_CHANNEL_OUT_2POINT0POINT2;
+ default:
+ return AUDIO_CHANNEL_INVALID;
+ }
+}
+
+static inline audio_channel_mask_t audio_channel_mask_out_to_in(audio_channel_mask_t out)
+{
+ switch (out) {
+ case AUDIO_CHANNEL_OUT_MONO:
+ return AUDIO_CHANNEL_IN_MONO;
+ case AUDIO_CHANNEL_OUT_STEREO:
+ return AUDIO_CHANNEL_IN_STEREO;
+ case AUDIO_CHANNEL_OUT_5POINT1:
+ return AUDIO_CHANNEL_IN_5POINT1;
+ case AUDIO_CHANNEL_OUT_3POINT1POINT2:
+ return AUDIO_CHANNEL_IN_3POINT1POINT2;
+ case AUDIO_CHANNEL_OUT_3POINT0POINT2:
+ return AUDIO_CHANNEL_IN_3POINT0POINT2;
+ case AUDIO_CHANNEL_OUT_2POINT1POINT2:
+ return AUDIO_CHANNEL_IN_2POINT1POINT2;
+ case AUDIO_CHANNEL_OUT_2POINT0POINT2:
+ return AUDIO_CHANNEL_IN_2POINT0POINT2;
+ default:
+ return AUDIO_CHANNEL_INVALID;
+ }
+}
+
+static inline bool audio_is_valid_format(audio_format_t format)
+{
+ switch (format & AUDIO_FORMAT_MAIN_MASK) {
+ case AUDIO_FORMAT_PCM:
+ switch (format) {
+ case AUDIO_FORMAT_PCM_16_BIT:
+ case AUDIO_FORMAT_PCM_8_BIT:
+ case AUDIO_FORMAT_PCM_32_BIT:
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ case AUDIO_FORMAT_PCM_FLOAT:
+ case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+ return true;
+ default:
+ return false;
+ }
+ /* not reached */
+ case AUDIO_FORMAT_MP3:
+ case AUDIO_FORMAT_AMR_NB:
+ case AUDIO_FORMAT_AMR_WB:
+ case AUDIO_FORMAT_AAC:
+ case AUDIO_FORMAT_AAC_ADTS:
+ case AUDIO_FORMAT_HE_AAC_V1:
+ case AUDIO_FORMAT_HE_AAC_V2:
+ case AUDIO_FORMAT_AAC_ELD:
+ case AUDIO_FORMAT_AAC_XHE:
+ case AUDIO_FORMAT_VORBIS:
+ case AUDIO_FORMAT_OPUS:
+ case AUDIO_FORMAT_AC3:
+ case AUDIO_FORMAT_E_AC3:
+ case AUDIO_FORMAT_DTS:
+ case AUDIO_FORMAT_DTS_HD:
+ case AUDIO_FORMAT_IEC61937:
+ case AUDIO_FORMAT_DOLBY_TRUEHD:
+ case AUDIO_FORMAT_QCELP:
+ case AUDIO_FORMAT_EVRC:
+ case AUDIO_FORMAT_EVRCB:
+ case AUDIO_FORMAT_EVRCWB:
+ case AUDIO_FORMAT_AAC_ADIF:
+ case AUDIO_FORMAT_AMR_WB_PLUS:
+ case AUDIO_FORMAT_MP2:
+ case AUDIO_FORMAT_EVRCNW:
+ case AUDIO_FORMAT_FLAC:
+ case AUDIO_FORMAT_ALAC:
+ case AUDIO_FORMAT_APE:
+ case AUDIO_FORMAT_WMA:
+ case AUDIO_FORMAT_WMA_PRO:
+ case AUDIO_FORMAT_DSD:
+ case AUDIO_FORMAT_AC4:
+ case AUDIO_FORMAT_LDAC:
+ case AUDIO_FORMAT_E_AC3_JOC:
+ case AUDIO_FORMAT_MAT_1_0:
+ case AUDIO_FORMAT_MAT_2_0:
+ case AUDIO_FORMAT_MAT_2_1:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * Extract the primary format, eg. PCM, AC3, etc.
+ */
+static inline audio_format_t audio_get_main_format(audio_format_t format)
+{
+ return (audio_format_t)(format & AUDIO_FORMAT_MAIN_MASK);
+}
+
+/**
+ * Is the data plain PCM samples that can be scaled and mixed?
+ */
+static inline bool audio_is_linear_pcm(audio_format_t format)
+{
+ return (audio_get_main_format(format) == AUDIO_FORMAT_PCM);
+}
+
+/**
+ * For this format, is the number of PCM audio frames directly proportional
+ * to the number of data bytes?
+ *
+ * In other words, is the format transported as PCM audio samples,
+ * but not necessarily scalable or mixable.
+ * This returns true for real PCM, but also for AUDIO_FORMAT_IEC61937,
+ * which is transported as 16 bit PCM audio, but where the encoded data
+ * cannot be mixed or scaled.
+ */
+static inline bool audio_has_proportional_frames(audio_format_t format)
+{
+ audio_format_t mainFormat = audio_get_main_format(format);
+ return (mainFormat == AUDIO_FORMAT_PCM
+ || mainFormat == AUDIO_FORMAT_IEC61937);
+}
+
+static inline size_t audio_bytes_per_sample(audio_format_t format)
+{
+ size_t size = 0;
+
+ switch (format) {
+ case AUDIO_FORMAT_PCM_32_BIT:
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ size = sizeof(int32_t);
+ break;
+ case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+ size = sizeof(uint8_t) * 3;
+ break;
+ case AUDIO_FORMAT_PCM_16_BIT:
+ case AUDIO_FORMAT_IEC61937:
+ size = sizeof(int16_t);
+ break;
+ case AUDIO_FORMAT_PCM_8_BIT:
+ size = sizeof(uint8_t);
+ break;
+ case AUDIO_FORMAT_PCM_FLOAT:
+ size = sizeof(float);
+ break;
+ default:
+ break;
+ }
+ return size;
+}
+
+static inline size_t audio_bytes_per_frame(uint32_t channel_count, audio_format_t format)
+{
+ // cannot overflow for reasonable channel_count
+ return channel_count * audio_bytes_per_sample(format);
+}
+
+/* converts device address to string sent to audio HAL via set_parameters */
+static inline char *audio_device_address_to_parameter(audio_devices_t device, const char *address)
+{
+ const size_t kSize = AUDIO_DEVICE_MAX_ADDRESS_LEN + sizeof("a2dp_sink_address=");
+ char param[kSize];
+
+ if (device & AUDIO_DEVICE_OUT_ALL_A2DP)
+ snprintf(param, kSize, "%s=%s", "a2dp_sink_address", address);
+ else if (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)
+ snprintf(param, kSize, "%s=%s", "mix", address);
+ else
+ snprintf(param, kSize, "%s", address);
+
+ return strdup(param);
+}
+
+static inline bool audio_device_is_digital(audio_devices_t device) {
+ if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+ // input
+ return (~AUDIO_DEVICE_BIT_IN & device & (AUDIO_DEVICE_IN_ALL_USB |
+ AUDIO_DEVICE_IN_HDMI |
+ AUDIO_DEVICE_IN_SPDIF |
+ AUDIO_DEVICE_IN_IP |
+ AUDIO_DEVICE_IN_BUS)) != 0;
+ } else {
+ // output
+ return (device & (AUDIO_DEVICE_OUT_ALL_USB |
+ AUDIO_DEVICE_OUT_HDMI |
+ AUDIO_DEVICE_OUT_HDMI_ARC |
+ AUDIO_DEVICE_OUT_SPDIF |
+ AUDIO_DEVICE_OUT_IP |
+ AUDIO_DEVICE_OUT_BUS)) != 0;
+ }
+}
+
+#ifndef AUDIO_NO_SYSTEM_DECLARATIONS
+
+static inline bool audio_gain_config_are_equal(
+ const struct audio_gain_config *lhs, const struct audio_gain_config *rhs) {
+ if (lhs->mode != rhs->mode) return false;
+ switch (lhs->mode) {
+ case AUDIO_GAIN_MODE_JOINT:
+ if (lhs->values[0] != rhs->values[0]) return false;
+ break;
+ case AUDIO_GAIN_MODE_CHANNELS:
+ case AUDIO_GAIN_MODE_RAMP:
+ if (lhs->channel_mask != rhs->channel_mask) return false;
+ for (int i = 0; i < popcount(lhs->channel_mask); ++i) {
+ if (lhs->values[i] != rhs->values[i]) return false;
+ }
+ break;
+ default: return false;
+ }
+ return lhs->ramp_duration_ms == rhs->ramp_duration_ms;
+}
+
+static inline bool audio_port_config_has_input_direction(const struct audio_port_config *port_cfg) {
+ switch (port_cfg->type) {
+ case AUDIO_PORT_TYPE_DEVICE:
+ switch (port_cfg->role) {
+ case AUDIO_PORT_ROLE_SOURCE: return true;
+ case AUDIO_PORT_ROLE_SINK: return false;
+ default: return false;
+ }
+ case AUDIO_PORT_TYPE_MIX:
+ switch (port_cfg->role) {
+ case AUDIO_PORT_ROLE_SOURCE: return false;
+ case AUDIO_PORT_ROLE_SINK: return true;
+ default: return false;
+ }
+ default: return false;
+ }
+}
+
+static inline bool audio_port_configs_are_equal(
+ const struct audio_port_config *lhs, const struct audio_port_config *rhs) {
+ if (lhs->role != rhs->role || lhs->type != rhs->type) return false;
+ switch (lhs->type) {
+ case AUDIO_PORT_TYPE_NONE: break;
+ case AUDIO_PORT_TYPE_DEVICE:
+ if (lhs->ext.device.hw_module != rhs->ext.device.hw_module ||
+ lhs->ext.device.type != rhs->ext.device.type ||
+ strncmp(lhs->ext.device.address, rhs->ext.device.address,
+ AUDIO_DEVICE_MAX_ADDRESS_LEN) != 0) {
+ return false;
+ }
+ break;
+ case AUDIO_PORT_TYPE_MIX:
+ if (lhs->ext.mix.hw_module != rhs->ext.mix.hw_module ||
+ lhs->ext.mix.handle != rhs->ext.mix.handle) return false;
+ if (lhs->role == AUDIO_PORT_ROLE_SOURCE &&
+ lhs->ext.mix.usecase.stream != rhs->ext.mix.usecase.stream) return false;
+ else if (lhs->role == AUDIO_PORT_ROLE_SINK &&
+ lhs->ext.mix.usecase.source != rhs->ext.mix.usecase.source) return false;
+ break;
+ case AUDIO_PORT_TYPE_SESSION:
+ if (lhs->ext.session.session != rhs->ext.session.session) return false;
+ break;
+ default: return false;
+ }
+ return lhs->config_mask == rhs->config_mask &&
+ ((lhs->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) == 0 ||
+ lhs->sample_rate == rhs->sample_rate) &&
+ ((lhs->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) == 0 ||
+ lhs->channel_mask == rhs->channel_mask) &&
+ ((lhs->config_mask & AUDIO_PORT_CONFIG_FORMAT) == 0 ||
+ lhs->format == rhs->format) &&
+ ((lhs->config_mask & AUDIO_PORT_CONFIG_GAIN) == 0 ||
+ audio_gain_config_are_equal(&lhs->gain, &rhs->gain)) &&
+ ((lhs->config_mask & AUDIO_PORT_CONFIG_FLAGS) == 0 ||
+ (audio_port_config_has_input_direction(lhs) ?
+ lhs->flags.input == rhs->flags.input :
+ lhs->flags.output == rhs->flags.output));
+}
+
+static inline bool audio_port_config_has_hw_av_sync(const struct audio_port_config *port_cfg) {
+ if (!(port_cfg->config_mask & AUDIO_PORT_CONFIG_FLAGS)) {
+ return false;
+ }
+ return audio_port_config_has_input_direction(port_cfg) ?
+ port_cfg->flags.input & AUDIO_INPUT_FLAG_HW_AV_SYNC
+ : port_cfg->flags.output & AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
+}
+
+static inline bool audio_patch_has_hw_av_sync(const struct audio_patch *patch) {
+ for (unsigned int i = 0; i < patch->num_sources; ++i) {
+ if (audio_port_config_has_hw_av_sync(&patch->sources[i])) return true;
+ }
+ for (unsigned int i = 0; i < patch->num_sinks; ++i) {
+ if (audio_port_config_has_hw_av_sync(&patch->sinks[i])) return true;
+ }
+ return false;
+}
+
+static inline bool audio_patch_is_valid(const struct audio_patch *patch) {
+ // Note that patch can have no sinks.
+ return patch->num_sources != 0 && patch->num_sources <= AUDIO_PATCH_PORTS_MAX &&
+ patch->num_sinks <= AUDIO_PATCH_PORTS_MAX;
+}
+
+// Note that when checking for equality the order of ports must match.
+// Patches will not be equivalent if they contain the same ports but they are permuted differently.
+static inline bool audio_patches_are_equal(
+ const struct audio_patch *lhs, const struct audio_patch *rhs) {
+ if (!audio_patch_is_valid(lhs) || !audio_patch_is_valid(rhs)) return false;
+ if (lhs->num_sources != rhs->num_sources || lhs->num_sinks != rhs->num_sinks) return false;
+ for (unsigned int i = 0; i < lhs->num_sources; ++i) {
+ if (!audio_port_configs_are_equal(&lhs->sources[i], &rhs->sources[i])) return false;
+ }
+ for (unsigned int i = 0; i < lhs->num_sinks; ++i) {
+ if (!audio_port_configs_are_equal(&lhs->sinks[i], &rhs->sinks[i])) return false;
+ }
+ return true;
+}
+
+#endif
+
+// Unique effect ID (can be generated from the following site:
+// http://www.itu.int/ITU-T/asn1/uuid.html)
+// This struct is used for effects identification and in soundtrigger.
+typedef struct audio_uuid_s {
+ uint32_t timeLow;
+ uint16_t timeMid;
+ uint16_t timeHiAndVersion;
+ uint16_t clockSeq;
+ uint8_t node[6];
+} audio_uuid_t;
+
+//TODO: audio_microphone_location_t need to move to HAL v4.0
+typedef enum {
+ AUDIO_MICROPHONE_LOCATION_UNKNOWN = 0,
+ AUDIO_MICROPHONE_LOCATION_MAINBODY = 1,
+ AUDIO_MICROPHONE_LOCATION_MAINBODY_MOVABLE = 2,
+ AUDIO_MICROPHONE_LOCATION_PERIPHERAL = 3,
+ AUDIO_MICROPHONE_LOCATION_CNT = 4,
+} audio_microphone_location_t;
+
+//TODO: audio_microphone_directionality_t need to move to HAL v4.0
+typedef enum {
+ AUDIO_MICROPHONE_DIRECTIONALITY_UNKNOWN = 0,
+ AUDIO_MICROPHONE_DIRECTIONALITY_OMNI = 1,
+ AUDIO_MICROPHONE_DIRECTIONALITY_BI_DIRECTIONAL = 2,
+ AUDIO_MICROPHONE_DIRECTIONALITY_CARDIOID = 3,
+ AUDIO_MICROPHONE_DIRECTIONALITY_HYPER_CARDIOID = 4,
+ AUDIO_MICROPHONE_DIRECTIONALITY_SUPER_CARDIOID = 5,
+ AUDIO_MICROPHONE_DIRECTIONALITY_CNT = 6,
+} audio_microphone_directionality_t;
+
+/* A 3D point which could be used to represent geometric location
+ * or orientation of a microphone.
+ */
+struct audio_microphone_coordinate {
+ float x;
+ float y;
+ float z;
+};
+
+/* An number to indicate which group the microphone locate. Main body is
+ * usually group 0. Developer could use this value to group the microphones
+ * that locate on the same peripheral or attachments.
+ */
+typedef int audio_microphone_group_t;
+
+typedef enum {
+ AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED = 0,
+ AUDIO_MICROPHONE_CHANNEL_MAPPING_DIRECT = 1,
+ AUDIO_MICROPHONE_CHANNEL_MAPPING_PROCESSED = 2,
+ AUDIO_MICROPHONE_CHANNEL_MAPPING_CNT = 3,
+} audio_microphone_channel_mapping_t;
+
+/* the maximum length for the microphone id */
+#define AUDIO_MICROPHONE_ID_MAX_LEN 32
+/* max number of frequency responses in a frequency response table */
+#define AUDIO_MICROPHONE_MAX_FREQUENCY_RESPONSES 256
+/* max number of microphone */
+#define AUDIO_MICROPHONE_MAX_COUNT 32
+/* the value of unknown spl */
+#define AUDIO_MICROPHONE_SPL_UNKNOWN -FLT_MAX
+/* the value of unknown sensitivity */
+#define AUDIO_MICROPHONE_SENSITIVITY_UNKNOWN -FLT_MAX
+/* the value of unknown coordinate */
+#define AUDIO_MICROPHONE_COORDINATE_UNKNOWN -FLT_MAX
+/* the value used as address when the address of bottom microphone is empty */
+#define AUDIO_BOTTOM_MICROPHONE_ADDRESS "bottom"
+/* the value used as address when the address of back microphone is empty */
+#define AUDIO_BACK_MICROPHONE_ADDRESS "back"
+
+struct audio_microphone_characteristic_t {
+ char device_id[AUDIO_MICROPHONE_ID_MAX_LEN];
+ audio_port_handle_t id;
+ audio_devices_t device;
+ char address[AUDIO_DEVICE_MAX_ADDRESS_LEN];
+ audio_microphone_channel_mapping_t channel_mapping[AUDIO_CHANNEL_COUNT_MAX];
+ audio_microphone_location_t location;
+ audio_microphone_group_t group;
+ unsigned int index_in_the_group;
+ float sensitivity;
+ float max_spl;
+ float min_spl;
+ audio_microphone_directionality_t directionality;
+ unsigned int num_frequency_responses;
+ float frequency_responses[2][AUDIO_MICROPHONE_MAX_FREQUENCY_RESPONSES];
+ struct audio_microphone_coordinate geometric_location;
+ struct audio_microphone_coordinate orientation;
+};
+
+__END_DECLS
+
+/**
+ * List of known audio HAL modules. This is the base name of the audio HAL
+ * library composed of the "audio." prefix, one of the base names below and
+ * a suffix specific to the device.
+ * e.g: audio.primary.goldfish.so or audio.a2dp.default.so
+ *
+ * The same module names are used in audio policy configuration files.
+ */
+
+#define AUDIO_HARDWARE_MODULE_ID_PRIMARY "primary"
+#define AUDIO_HARDWARE_MODULE_ID_A2DP "a2dp"
+#define AUDIO_HARDWARE_MODULE_ID_USB "usb"
+#define AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX "r_submix"
+#define AUDIO_HARDWARE_MODULE_ID_CODEC_OFFLOAD "codec_offload"
+#define AUDIO_HARDWARE_MODULE_ID_STUB "stub"
+#define AUDIO_HARDWARE_MODULE_ID_HEARING_AID "hearing_aid"
+#define AUDIO_HARDWARE_MODULE_ID_MSD "msd"
+
+/**
+ * Multi-Stream Decoder (MSD) HAL service name. MSD HAL is used to mix
+ * encoded streams together with PCM streams, producing re-encoded
+ * streams or PCM streams.
+ *
+ * The service must register itself using this name, and audioserver
+ * tries to instantiate a device factory using this name as well.
+ * Note that the HIDL implementation library file name *must* have the
+ * suffix "msd" in order to be picked up by HIDL that is:
+ *
+ * android.hardware.audio@x.x-implmsd.so
+ */
+#define AUDIO_HAL_SERVICE_NAME_MSD "msd"
+
+/**
+ * Parameter definitions.
+ * Note that in the framework code it's recommended to use AudioParameter.h
+ * instead of these preprocessor defines, and for sure avoid just copying
+ * the constant values.
+ */
+
+#define AUDIO_PARAMETER_VALUE_ON "on"
+#define AUDIO_PARAMETER_VALUE_OFF "off"
+
+/**
+ * audio device parameters
+ */
+
+/* BT SCO Noise Reduction + Echo Cancellation parameters */
+#define AUDIO_PARAMETER_KEY_BT_NREC "bt_headset_nrec"
+
+/* Get a new HW synchronization source identifier.
+ * Return a valid source (positive integer) or AUDIO_HW_SYNC_INVALID if an error occurs
+ * or no HW sync is available. */
+#define AUDIO_PARAMETER_HW_AV_SYNC "hw_av_sync"
+
+/* Screen state */
+#define AUDIO_PARAMETER_KEY_SCREEN_STATE "screen_state"
+
+/* User's preferred audio language setting (in ISO 639-2/T three-letter string code)
+ * used to select a specific language presentation for next generation audio codecs. */
+#define AUDIO_PARAMETER_KEY_AUDIO_LANGUAGE_PREFERRED "audio_language_preferred"
+
+/**
+ * audio stream parameters
+ */
+
+#define AUDIO_PARAMETER_STREAM_ROUTING "routing" /* audio_devices_t */
+#define AUDIO_PARAMETER_STREAM_FORMAT "format" /* audio_format_t */
+#define AUDIO_PARAMETER_STREAM_CHANNELS "channels" /* audio_channel_mask_t */
+#define AUDIO_PARAMETER_STREAM_FRAME_COUNT "frame_count" /* size_t */
+#define AUDIO_PARAMETER_STREAM_INPUT_SOURCE "input_source" /* audio_source_t */
+#define AUDIO_PARAMETER_STREAM_SAMPLING_RATE "sampling_rate" /* uint32_t */
+
+/* Request the presentation id to be decoded by a next gen audio decoder */
+#define AUDIO_PARAMETER_STREAM_PRESENTATION_ID "presentation_id" /* int32_t */
+
+/* Request the program id to be decoded by a next gen audio decoder */
+#define AUDIO_PARAMETER_STREAM_PROGRAM_ID "program_id" /* int32_t */
+
+#define AUDIO_PARAMETER_DEVICE_CONNECT "connect" /* audio_devices_t */
+#define AUDIO_PARAMETER_DEVICE_DISCONNECT "disconnect" /* audio_devices_t */
+
+/* Enable mono audio playback if 1, else should be 0. */
+#define AUDIO_PARAMETER_MONO_OUTPUT "mono_output"
+
+/* Set the HW synchronization source for an output stream. */
+#define AUDIO_PARAMETER_STREAM_HW_AV_SYNC "hw_av_sync"
+
+/* Query supported formats. The response is a '|' separated list of strings from
+ * audio_format_t enum e.g: "sup_formats=AUDIO_FORMAT_PCM_16_BIT" */
+#define AUDIO_PARAMETER_STREAM_SUP_FORMATS "sup_formats"
+/* Query supported channel masks. The response is a '|' separated list of strings from
+ * audio_channel_mask_t enum e.g: "sup_channels=AUDIO_CHANNEL_OUT_STEREO|AUDIO_CHANNEL_OUT_MONO" */
+#define AUDIO_PARAMETER_STREAM_SUP_CHANNELS "sup_channels"
+/* Query supported sampling rates. The response is a '|' separated list of integer values e.g:
+ * "sup_sampling_rates=44100|48000" */
+#define AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES "sup_sampling_rates"
+
+#define AUDIO_PARAMETER_VALUE_LIST_SEPARATOR "|"
+
+/* Reconfigure offloaded A2DP codec */
+#define AUDIO_PARAMETER_RECONFIG_A2DP "reconfigA2dp"
+/* Query if HwModule supports reconfiguration of offloaded A2DP codec */
+#define AUDIO_PARAMETER_A2DP_RECONFIG_SUPPORTED "isReconfigA2dpSupported"
+
+/**
+ * audio codec parameters
+ */
+
+#define AUDIO_OFFLOAD_CODEC_PARAMS "music_offload_codec_param"
+#define AUDIO_OFFLOAD_CODEC_BIT_PER_SAMPLE "music_offload_bit_per_sample"
+#define AUDIO_OFFLOAD_CODEC_BIT_RATE "music_offload_bit_rate"
+#define AUDIO_OFFLOAD_CODEC_AVG_BIT_RATE "music_offload_avg_bit_rate"
+#define AUDIO_OFFLOAD_CODEC_ID "music_offload_codec_id"
+#define AUDIO_OFFLOAD_CODEC_BLOCK_ALIGN "music_offload_block_align"
+#define AUDIO_OFFLOAD_CODEC_SAMPLE_RATE "music_offload_sample_rate"
+#define AUDIO_OFFLOAD_CODEC_ENCODE_OPTION "music_offload_encode_option"
+#define AUDIO_OFFLOAD_CODEC_NUM_CHANNEL "music_offload_num_channels"
+#define AUDIO_OFFLOAD_CODEC_DOWN_SAMPLING "music_offload_down_sampling"
+#define AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES "delay_samples"
+#define AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES "padding_samples"
+
+#endif // ANDROID_AUDIO_CORE_H
diff --git a/include/system/audio_effect-base.h b/include/system/audio_effect-base.h
new file mode 100644
index 0000000..7a6a593
--- /dev/null
+++ b/include/system/audio_effect-base.h
@@ -0,0 +1,99 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+// Source: android.hardware.audio.effect@4.0
+// Root: android.hardware:hardware/interfaces
+
+#ifndef HIDL_GENERATED_ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_EXPORTED_CONSTANTS_H_
+#define HIDL_GENERATED_ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_EXPORTED_CONSTANTS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+ EFFECT_FLAG_TYPE_SHIFT = 0,
+ EFFECT_FLAG_TYPE_SIZE = 3,
+ EFFECT_FLAG_TYPE_MASK = 7, // (((1 << TYPE_SIZE) - 1) << TYPE_SHIFT)
+ EFFECT_FLAG_TYPE_INSERT = 0, // (0 << TYPE_SHIFT)
+ EFFECT_FLAG_TYPE_AUXILIARY = 1, // (1 << TYPE_SHIFT)
+ EFFECT_FLAG_TYPE_REPLACE = 2, // (2 << TYPE_SHIFT)
+ EFFECT_FLAG_TYPE_PRE_PROC = 3, // (3 << TYPE_SHIFT)
+ EFFECT_FLAG_TYPE_POST_PROC = 4, // (4 << TYPE_SHIFT)
+ EFFECT_FLAG_INSERT_SHIFT = 3, // (TYPE_SHIFT + TYPE_SIZE)
+ EFFECT_FLAG_INSERT_SIZE = 3,
+ EFFECT_FLAG_INSERT_MASK = 56, // (((1 << INSERT_SIZE) - 1) << INSERT_SHIFT)
+ EFFECT_FLAG_INSERT_ANY = 0, // (0 << INSERT_SHIFT)
+ EFFECT_FLAG_INSERT_FIRST = 8, // (1 << INSERT_SHIFT)
+ EFFECT_FLAG_INSERT_LAST = 16, // (2 << INSERT_SHIFT)
+ EFFECT_FLAG_INSERT_EXCLUSIVE = 24, // (3 << INSERT_SHIFT)
+ EFFECT_FLAG_VOLUME_SHIFT = 6, // (INSERT_SHIFT + INSERT_SIZE)
+ EFFECT_FLAG_VOLUME_SIZE = 3,
+ EFFECT_FLAG_VOLUME_MASK = 448, // (((1 << VOLUME_SIZE) - 1) << VOLUME_SHIFT)
+ EFFECT_FLAG_VOLUME_CTRL = 64, // (1 << VOLUME_SHIFT)
+ EFFECT_FLAG_VOLUME_IND = 128, // (2 << VOLUME_SHIFT)
+ EFFECT_FLAG_VOLUME_NONE = 0, // (0 << VOLUME_SHIFT)
+ EFFECT_FLAG_DEVICE_SHIFT = 9, // (VOLUME_SHIFT + VOLUME_SIZE)
+ EFFECT_FLAG_DEVICE_SIZE = 3,
+ EFFECT_FLAG_DEVICE_MASK = 3584, // (((1 << DEVICE_SIZE) - 1) << DEVICE_SHIFT)
+ EFFECT_FLAG_DEVICE_IND = 512, // (1 << DEVICE_SHIFT)
+ EFFECT_FLAG_DEVICE_NONE = 0, // (0 << DEVICE_SHIFT)
+ EFFECT_FLAG_INPUT_SHIFT = 12, // (DEVICE_SHIFT + DEVICE_SIZE)
+ EFFECT_FLAG_INPUT_SIZE = 2,
+ EFFECT_FLAG_INPUT_MASK = 12288, // (((1 << INPUT_SIZE) - 1) << INPUT_SHIFT)
+ EFFECT_FLAG_INPUT_DIRECT = 4096, // (1 << INPUT_SHIFT)
+ EFFECT_FLAG_INPUT_PROVIDER = 8192, // (2 << INPUT_SHIFT)
+ EFFECT_FLAG_INPUT_BOTH = 12288, // (3 << INPUT_SHIFT)
+ EFFECT_FLAG_OUTPUT_SHIFT = 14, // (INPUT_SHIFT + INPUT_SIZE)
+ EFFECT_FLAG_OUTPUT_SIZE = 2,
+ EFFECT_FLAG_OUTPUT_MASK = 49152, // (((1 << OUTPUT_SIZE) - 1) << OUTPUT_SHIFT)
+ EFFECT_FLAG_OUTPUT_DIRECT = 16384, // (1 << OUTPUT_SHIFT)
+ EFFECT_FLAG_OUTPUT_PROVIDER = 32768, // (2 << OUTPUT_SHIFT)
+ EFFECT_FLAG_OUTPUT_BOTH = 49152, // (3 << OUTPUT_SHIFT)
+ EFFECT_FLAG_HW_ACC_SHIFT = 16, // (OUTPUT_SHIFT + OUTPUT_SIZE)
+ EFFECT_FLAG_HW_ACC_SIZE = 2,
+ EFFECT_FLAG_HW_ACC_MASK = 196608, // (((1 << HW_ACC_SIZE) - 1) << HW_ACC_SHIFT)
+ EFFECT_FLAG_HW_ACC_SIMPLE = 65536, // (1 << HW_ACC_SHIFT)
+ EFFECT_FLAG_HW_ACC_TUNNEL = 131072, // (2 << HW_ACC_SHIFT)
+ EFFECT_FLAG_AUDIO_MODE_SHIFT = 18, // (HW_ACC_SHIFT + HW_ACC_SIZE)
+ EFFECT_FLAG_AUDIO_MODE_SIZE = 2,
+ EFFECT_FLAG_AUDIO_MODE_MASK = 786432, // (((1 << AUDIO_MODE_SIZE) - 1) << AUDIO_MODE_SHIFT)
+ EFFECT_FLAG_AUDIO_MODE_IND = 262144, // (1 << AUDIO_MODE_SHIFT)
+ EFFECT_FLAG_AUDIO_MODE_NONE = 0, // (0 << AUDIO_MODE_SHIFT)
+ EFFECT_FLAG_AUDIO_SOURCE_SHIFT = 20, // (AUDIO_MODE_SHIFT + AUDIO_MODE_SIZE)
+ EFFECT_FLAG_AUDIO_SOURCE_SIZE = 2,
+ EFFECT_FLAG_AUDIO_SOURCE_MASK = 3145728, // (((1 << AUDIO_SOURCE_SIZE) - 1) << AUDIO_SOURCE_SHIFT)
+ EFFECT_FLAG_AUDIO_SOURCE_IND = 1048576, // (1 << AUDIO_SOURCE_SHIFT)
+ EFFECT_FLAG_AUDIO_SOURCE_NONE = 0, // (0 << AUDIO_SOURCE_SHIFT)
+ EFFECT_FLAG_OFFLOAD_SHIFT = 22, // (AUDIO_SOURCE_SHIFT + AUDIO_SOURCE_SIZE)
+ EFFECT_FLAG_OFFLOAD_SIZE = 1,
+ EFFECT_FLAG_OFFLOAD_MASK = 4194304, // (((1 << OFFLOAD_SIZE) - 1) << OFFLOAD_SHIFT)
+ EFFECT_FLAG_OFFLOAD_SUPPORTED = 4194304, // (1 << OFFLOAD_SHIFT)
+ EFFECT_FLAG_NO_PROCESS_SHIFT = 23, // (OFFLOAD_SHIFT + OFFLOAD_SIZE)
+ EFFECT_FLAG_NO_PROCESS_SIZE = 1,
+ EFFECT_FLAG_NO_PROCESS_MASK = 8388608, // (((1 << NO_PROCESS_SIZE) - 1) << NO_PROCESS_SHIFT)
+ EFFECT_FLAG_NO_PROCESS = 8388608, // (1 << NO_PROCESS_SHIFT)
+};
+
+typedef enum {
+ EFFECT_BUFFER_ACCESS_WRITE = 0,
+ EFFECT_BUFFER_ACCESS_READ = 1, // (::android::hardware::audio::effect::V4_0::EffectBufferAccess.ACCESS_WRITE implicitly + 1)
+ EFFECT_BUFFER_ACCESS_ACCUMULATE = 2, // (::android::hardware::audio::effect::V4_0::EffectBufferAccess.ACCESS_READ implicitly + 1)
+} effect_buffer_access_e;
+
+enum {
+ EFFECT_CONFIG_BUFFER = 1,
+ EFFECT_CONFIG_SMP_RATE = 2,
+ EFFECT_CONFIG_CHANNELS = 4,
+ EFFECT_CONFIG_FORMAT = 8,
+ EFFECT_CONFIG_ACC_MODE = 16,
+};
+
+typedef enum {
+ EFFECT_FEATURE_AUX_CHANNELS = 0,
+ EFFECT_FEATURE_CNT = 1, // (::android::hardware::audio::effect::V4_0::EffectFeature.AUX_CHANNELS implicitly + 1)
+} effect_feature_e;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // HIDL_GENERATED_ANDROID_HARDWARE_AUDIO_EFFECT_V4_0_EXPORTED_CONSTANTS_H_
diff --git a/include/system/audio_effect.h b/include/system/audio_effect.h
new file mode 100644
index 0000000..4cdc773
--- /dev/null
+++ b/include/system/audio_effect.h
@@ -0,0 +1,536 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef ANDROID_AUDIO_EFFECT_CORE_H
+#define ANDROID_AUDIO_EFFECT_CORE_H
+
+#include "audio.h"
+#include "audio_effect-base.h"
+
+__BEGIN_DECLS
+
+/////////////////////////////////////////////////
+// Common Definitions
+/////////////////////////////////////////////////
+
+//
+//--- Effect descriptor structure effect_descriptor_t
+//
+
+// This format is used for both "type" and "uuid" fields of the effect descriptor structure.
+// - When used for effect type and the engine is implementing and effect corresponding to a standard
+// OpenSL ES interface, this ID must be the one defined in OpenSLES_IID.h for that interface.
+// - When used as uuid, it should be a unique UUID for this particular implementation.
+typedef audio_uuid_t effect_uuid_t;
+
+// Maximum length of character strings in structures defines by this API.
+#define EFFECT_STRING_LEN_MAX 64
+
+// NULL UUID definition (matches SL_IID_NULL_)
+#define EFFECT_UUID_INITIALIZER { 0xec7178ec, 0xe5e1, 0x4432, 0xa3f4, \
+ { 0x46, 0x57, 0xe6, 0x79, 0x52, 0x10 } }
+static const effect_uuid_t EFFECT_UUID_NULL_ = EFFECT_UUID_INITIALIZER;
+static const effect_uuid_t * const EFFECT_UUID_NULL = &EFFECT_UUID_NULL_;
+static const char * const EFFECT_UUID_NULL_STR = "ec7178ec-e5e1-4432-a3f4-4657e6795210";
+
+// The effect descriptor contains necessary information to facilitate the enumeration of the effect
+// engines present in a library.
+typedef struct effect_descriptor_s {
+ effect_uuid_t type; // UUID of to the OpenSL ES interface implemented by this effect
+ effect_uuid_t uuid; // UUID for this particular implementation
+ uint32_t apiVersion; // Version of the effect control API implemented
+ uint32_t flags; // effect engine capabilities/requirements flags (see below)
+ uint16_t cpuLoad; // CPU load indication (see below)
+ uint16_t memoryUsage; // Data Memory usage (see below)
+ char name[EFFECT_STRING_LEN_MAX]; // human readable effect name
+ char implementor[EFFECT_STRING_LEN_MAX]; // human readable effect implementor name
+} effect_descriptor_t;
+
+#define EFFECT_CONFIG_ALL (EFFECT_CONFIG_BUFFER | \
+ EFFECT_CONFIG_SMP_RATE | \
+ EFFECT_CONFIG_CHANNELS | \
+ EFFECT_CONFIG_FORMAT | \
+ EFFECT_CONFIG_ACC_MODE)
+
+/////////////////////////////////////////////////
+// Effect control interface
+/////////////////////////////////////////////////
+
+//
+//--- Standardized command codes for command() function
+//
+enum effect_command_e {
+ EFFECT_CMD_INIT, // initialize effect engine
+ EFFECT_CMD_SET_CONFIG, // configure effect engine (see effect_config_t)
+ EFFECT_CMD_RESET, // reset effect engine
+ EFFECT_CMD_ENABLE, // enable effect process
+ EFFECT_CMD_DISABLE, // disable effect process
+ EFFECT_CMD_SET_PARAM, // set parameter immediately (see effect_param_t)
+ EFFECT_CMD_SET_PARAM_DEFERRED, // set parameter deferred
+ EFFECT_CMD_SET_PARAM_COMMIT, // commit previous set parameter deferred
+ EFFECT_CMD_GET_PARAM, // get parameter
+ EFFECT_CMD_SET_DEVICE, // set audio device (see audio.h, audio_devices_t)
+ EFFECT_CMD_SET_VOLUME, // set volume
+ EFFECT_CMD_SET_AUDIO_MODE, // set the audio mode (normal, ring, ...)
+ EFFECT_CMD_SET_CONFIG_REVERSE, // configure effect engine reverse stream(see effect_config_t)
+ EFFECT_CMD_SET_INPUT_DEVICE, // set capture device (see audio.h, audio_devices_t)
+ EFFECT_CMD_GET_CONFIG, // read effect engine configuration
+ EFFECT_CMD_GET_CONFIG_REVERSE, // read configure effect engine reverse stream configuration
+ EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS,// get all supported configurations for a feature.
+ EFFECT_CMD_GET_FEATURE_CONFIG, // get current feature configuration
+ EFFECT_CMD_SET_FEATURE_CONFIG, // set current feature configuration
+ EFFECT_CMD_SET_AUDIO_SOURCE, // set the audio source (see audio.h, audio_source_t)
+ EFFECT_CMD_OFFLOAD, // set if effect thread is an offload one,
+ // send the ioHandle of the effect thread
+ EFFECT_CMD_FIRST_PROPRIETARY = 0x10000 // first proprietary command code
+};
+
+//==================================================================================================
+// command: EFFECT_CMD_INIT
+//--------------------------------------------------------------------------------------------------
+// description:
+// Initialize effect engine: All configurations return to default
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: 0
+// data: N/A
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(int)
+// data: status
+//==================================================================================================
+// command: EFFECT_CMD_SET_CONFIG
+//--------------------------------------------------------------------------------------------------
+// description:
+// Apply new audio parameters configurations for input and output buffers
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(effect_config_t)
+// data: effect_config_t
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(int)
+// data: status
+//==================================================================================================
+// command: EFFECT_CMD_RESET
+//--------------------------------------------------------------------------------------------------
+// description:
+// Reset the effect engine. Keep configuration but resets state and buffer content
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: 0
+// data: N/A
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: 0
+// data: N/A
+//==================================================================================================
+// command: EFFECT_CMD_ENABLE
+//--------------------------------------------------------------------------------------------------
+// description:
+// Enable the process. Called by the framework before the first call to process()
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: 0
+// data: N/A
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(int)
+// data: status
+//==================================================================================================
+// command: EFFECT_CMD_DISABLE
+//--------------------------------------------------------------------------------------------------
+// description:
+// Disable the process. Called by the framework after the last call to process()
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: 0
+// data: N/A
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(int)
+// data: status
+//==================================================================================================
+// command: EFFECT_CMD_SET_PARAM
+//--------------------------------------------------------------------------------------------------
+// description:
+// Set a parameter and apply it immediately
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(effect_param_t) + size of param and value
+// data: effect_param_t + param + value. See effect_param_t definition below for value offset
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(int)
+// data: status
+//==================================================================================================
+// command: EFFECT_CMD_SET_PARAM_DEFERRED
+//--------------------------------------------------------------------------------------------------
+// description:
+// Set a parameter but apply it only when receiving EFFECT_CMD_SET_PARAM_COMMIT command
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(effect_param_t) + size of param and value
+// data: effect_param_t + param + value. See effect_param_t definition below for value offset
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: 0
+// data: N/A
+//==================================================================================================
+// command: EFFECT_CMD_SET_PARAM_COMMIT
+//--------------------------------------------------------------------------------------------------
+// description:
+// Apply all previously received EFFECT_CMD_SET_PARAM_DEFERRED commands
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: 0
+// data: N/A
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(int)
+// data: status
+//==================================================================================================
+// command: EFFECT_CMD_GET_PARAM
+//--------------------------------------------------------------------------------------------------
+// description:
+// Get a parameter value
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(effect_param_t) + size of param
+// data: effect_param_t + param
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(effect_param_t) + size of param and value
+// data: effect_param_t + param + value. See effect_param_t definition below for value offset
+//==================================================================================================
+// command: EFFECT_CMD_SET_DEVICE
+//--------------------------------------------------------------------------------------------------
+// description:
+// Set the rendering device the audio output path is connected to. See audio.h, audio_devices_t
+// for device values.
+// The effect implementation must set EFFECT_FLAG_DEVICE_IND flag in its descriptor to receive this
+// command when the device changes
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(uint32_t)
+// data: uint32_t
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: 0
+// data: N/A
+//==================================================================================================
+// command: EFFECT_CMD_SET_VOLUME
+//--------------------------------------------------------------------------------------------------
+// description:
+// Set and get volume. Used by audio framework to delegate volume control to effect engine.
+// The effect implementation must set EFFECT_FLAG_VOLUME_IND or EFFECT_FLAG_VOLUME_CTRL flag in
+// its descriptor to receive this command before every call to process() function
+// If EFFECT_FLAG_VOLUME_CTRL flag is set in the effect descriptor, the effect engine must return
+// the volume that should be applied before the effect is processed. The overall volume (the volume
+// actually applied by the effect engine multiplied by the returned value) should match the value
+// indicated in the command.
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: n * sizeof(uint32_t)
+// data: volume for each channel defined in effect_config_t for output buffer expressed in
+// 8.24 fixed point format
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: n * sizeof(uint32_t) / 0
+// data: - if EFFECT_FLAG_VOLUME_CTRL is set in effect descriptor:
+// volume for each channel defined in effect_config_t for output buffer expressed in
+// 8.24 fixed point format
+// - if EFFECT_FLAG_VOLUME_CTRL is not set in effect descriptor:
+// N/A
+// It is legal to receive a null pointer as pReplyData in which case the effect framework has
+// delegated volume control to another effect
+//==================================================================================================
+// command: EFFECT_CMD_SET_AUDIO_MODE
+//--------------------------------------------------------------------------------------------------
+// description:
+// Set the audio mode. The effect implementation must set EFFECT_FLAG_AUDIO_MODE_IND flag in its
+// descriptor to receive this command when the audio mode changes.
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(uint32_t)
+// data: audio_mode_t
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: 0
+// data: N/A
+//==================================================================================================
+// command: EFFECT_CMD_SET_CONFIG_REVERSE
+//--------------------------------------------------------------------------------------------------
+// description:
+// Apply new audio parameters configurations for input and output buffers of reverse stream.
+// An example of reverse stream is the echo reference supplied to an Acoustic Echo Canceler.
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(effect_config_t)
+// data: effect_config_t
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(int)
+// data: status
+//==================================================================================================
+// command: EFFECT_CMD_SET_INPUT_DEVICE
+//--------------------------------------------------------------------------------------------------
+// description:
+// Set the capture device the audio input path is connected to. See audio.h, audio_devices_t
+// for device values.
+// The effect implementation must set EFFECT_FLAG_DEVICE_IND flag in its descriptor to receive this
+// command when the device changes
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(uint32_t)
+// data: uint32_t
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: 0
+// data: N/A
+//==================================================================================================
+// command: EFFECT_CMD_GET_CONFIG
+//--------------------------------------------------------------------------------------------------
+// description:
+// Read audio parameters configurations for input and output buffers
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: 0
+// data: N/A
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(effect_config_t)
+// data: effect_config_t
+//==================================================================================================
+// command: EFFECT_CMD_GET_CONFIG_REVERSE
+//--------------------------------------------------------------------------------------------------
+// description:
+// Read audio parameters configurations for input and output buffers of reverse stream
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: 0
+// data: N/A
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(effect_config_t)
+// data: effect_config_t
+//==================================================================================================
+// command: EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS
+//--------------------------------------------------------------------------------------------------
+// description:
+// Queries for supported configurations for a particular feature (e.g. get the supported
+// combinations of main and auxiliary channels for a noise suppressor).
+// The command parameter is the feature identifier (See effect_feature_e for a list of defined
+// features) followed by the maximum number of configuration descriptor to return.
+// The reply is composed of:
+// - status (uint32_t):
+// - 0 if feature is supported
+// - -ENOSYS if the feature is not supported,
+// - -ENOMEM if the feature is supported but the total number of supported configurations
+// exceeds the maximum number indicated by the caller.
+// - total number of supported configurations (uint32_t)
+// - an array of configuration descriptors.
+// The actual number of descriptors returned must not exceed the maximum number indicated by
+// the caller.
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: 2 x sizeof(uint32_t)
+// data: effect_feature_e + maximum number of configurations to return
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: 2 x sizeof(uint32_t) + n x sizeof (<config descriptor>)
+// data: status + total number of configurations supported + array of n config descriptors
+//==================================================================================================
+// command: EFFECT_CMD_GET_FEATURE_CONFIG
+//--------------------------------------------------------------------------------------------------
+// description:
+// Retrieves current configuration for a given feature.
+// The reply status is:
+// - 0 if feature is supported
+// - -ENOSYS if the feature is not supported,
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(uint32_t)
+// data: effect_feature_e
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(uint32_t) + sizeof (<config descriptor>)
+// data: status + config descriptor
+//==================================================================================================
+// command: EFFECT_CMD_SET_FEATURE_CONFIG
+//--------------------------------------------------------------------------------------------------
+// description:
+// Sets current configuration for a given feature.
+// The reply status is:
+// - 0 if feature is supported
+// - -ENOSYS if the feature is not supported,
+// - -EINVAL if the configuration is invalid
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(uint32_t) + sizeof (<config descriptor>)
+// data: effect_feature_e + config descriptor
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(uint32_t)
+// data: status
+//==================================================================================================
+// command: EFFECT_CMD_SET_AUDIO_SOURCE
+//--------------------------------------------------------------------------------------------------
+// description:
+// Set the audio source the capture path is configured for (Camcorder, voice recognition...).
+// See audio.h, audio_source_t for values.
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(uint32_t)
+// data: uint32_t
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: 0
+// data: N/A
+//==================================================================================================
+// command: EFFECT_CMD_OFFLOAD
+//--------------------------------------------------------------------------------------------------
+// description:
+// 1.indicate if the playback thread the effect is attached to is offloaded or not
+// 2.update the io handle of the playback thread the effect is attached to
+//--------------------------------------------------------------------------------------------------
+// command format:
+// size: sizeof(effect_offload_param_t)
+// data: effect_offload_param_t
+//--------------------------------------------------------------------------------------------------
+// reply format:
+// size: sizeof(uint32_t)
+// data: uint32_t
+//--------------------------------------------------------------------------------------------------
+// command: EFFECT_CMD_FIRST_PROPRIETARY
+//--------------------------------------------------------------------------------------------------
+// description:
+// All proprietary effect commands must use command codes above this value. The size and format of
+// command and response fields is free in this case
+//==================================================================================================
+
+// Audio buffer descriptor used by process(), bufferProvider() functions and buffer_config_t
+// structure. Multi-channel audio is always interleaved. The channel order is from LSB to MSB with
+// regard to the channel mask definition in audio.h, audio_channel_mask_t e.g :
+// Stereo: left, right
+// 5 point 1: front left, front right, front center, low frequency, back left, back right
+// The buffer size is expressed in frame count, a frame being composed of samples for all
+// channels at a given time. Frame size for unspecified format (AUDIO_FORMAT_OTHER) is 8 bit by
+// definition
+typedef struct audio_buffer_s {
+ size_t frameCount; // number of frames in buffer
+ union {
+ void* raw; // raw pointer to start of buffer
+ float* f32; // pointer to float 32 bit data at start of buffer
+ int32_t* s32; // pointer to signed 32 bit data at start of buffer
+ int16_t* s16; // pointer to signed 16 bit data at start of buffer
+ uint8_t* u8; // pointer to unsigned 8 bit data at start of buffer
+ };
+} audio_buffer_t;
+
+// The buffer_provider_s structure contains functions that can be used
+// by the effect engine process() function to query and release input
+// or output audio buffer.
+// The getBuffer() function is called to retrieve a buffer where data
+// should read from or written to by process() function.
+// The releaseBuffer() function MUST be called when the buffer retrieved
+// with getBuffer() is not needed anymore.
+// The process function should use the buffer provider mechanism to retrieve
+// input or output buffer if the inBuffer or outBuffer passed as argument is NULL
+// and the buffer configuration (buffer_config_t) given by the EFFECT_CMD_SET_CONFIG
+// command did not specify an audio buffer.
+
+typedef int32_t (* buffer_function_t)(void *cookie, audio_buffer_t *buffer);
+
+typedef struct buffer_provider_s {
+ buffer_function_t getBuffer; // retrieve next buffer
+ buffer_function_t releaseBuffer; // release used buffer
+ void *cookie; // for use by client of buffer provider functions
+} buffer_provider_t;
+
+// The buffer_config_s structure specifies the input or output audio format
+// to be used by the effect engine.
+typedef struct buffer_config_s {
+ audio_buffer_t buffer; // buffer for use by process() function if not passed explicitly
+ uint32_t samplingRate; // sampling rate
+ uint32_t channels; // channel mask (see audio_channel_mask_t in audio.h)
+ buffer_provider_t bufferProvider; // buffer provider
+ uint8_t format; // Audio format (see audio_format_t in audio.h)
+ uint8_t accessMode; // read/write or accumulate in buffer (effect_buffer_access_e)
+ uint16_t mask; // indicates which of the above fields is valid
+} buffer_config_t;
+
+// EFFECT_FEATURE_AUX_CHANNELS feature configuration descriptor. Describe a combination
+// of main and auxiliary channels supported
+typedef struct channel_config_s {
+ audio_channel_mask_t main_channels; // channel mask for main channels
+ audio_channel_mask_t aux_channels; // channel mask for auxiliary channels
+} channel_config_t;
+
+
+// effect_config_s structure is used to configure audio parameters and buffers for effect engine
+// input and output.
+typedef struct effect_config_s {
+ buffer_config_t inputCfg;
+ buffer_config_t outputCfg;
+} effect_config_t;
+
+
+// effect_param_s structure describes the format of the pCmdData argument of EFFECT_CMD_SET_PARAM
+// command and pCmdData and pReplyData of EFFECT_CMD_GET_PARAM command.
+// psize and vsize represent the actual size of parameter and value.
+//
+// NOTE: the start of value field inside the data field is always on a 32 bit boundary:
+//
+// +-----------+
+// | status | sizeof(int)
+// +-----------+
+// | psize | sizeof(int)
+// +-----------+
+// | vsize | sizeof(int)
+// +-----------+
+// | | | |
+// ~ parameter ~ > psize |
+// | | | > ((psize - 1)/sizeof(int) + 1) * sizeof(int)
+// +-----------+ |
+// | padding | |
+// +-----------+
+// | | |
+// ~ value ~ > vsize
+// | | |
+// +-----------+
+
+typedef struct effect_param_s {
+ int32_t status; // Transaction status (unused for command, used for reply)
+ uint32_t psize; // Parameter size
+ uint32_t vsize; // Value size
+ char data[]; // Start of Parameter + Value data
+} effect_param_t;
+
+// Maximum effect_param_t size
+#define EFFECT_PARAM_SIZE_MAX 65536
+
+// structure used by EFFECT_CMD_OFFLOAD command
+typedef struct effect_offload_param_s {
+ bool isOffload; // true if the playback thread the effect is attached to is offloaded
+ int ioHandle; // io handle of the playback thread the effect is attached to
+} effect_offload_param_t;
+
+
+__END_DECLS
+
+#endif // ANDROID_AUDIO_EFFECT_CORE_H
diff --git a/include/utils/Errors.h b/include/utils/Errors.h
new file mode 100644
index 0000000..16e1fa2
--- /dev/null
+++ b/include/utils/Errors.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_ERRORS_H
+#define ANDROID_ERRORS_H
+
+#include <sys/types.h>
+#include <errno.h>
+
+namespace android {
+
+// use this type to return error codes
+#ifdef _WIN32
+typedef int status_t;
+#else
+typedef int32_t status_t;
+#endif
+
+/* the MS C runtime lacks a few error codes */
+
+/*
+ * Error codes.
+ * All error codes are negative values.
+ */
+
+// Win32 #defines NO_ERROR as well. It has the same value, so there's no
+// real conflict, though it's a bit awkward.
+#ifdef _WIN32
+# undef NO_ERROR
+#endif
+
+enum {
+ OK = 0, // Everything's swell.
+ NO_ERROR = 0, // No errors.
+
+ UNKNOWN_ERROR = (-2147483647-1), // INT32_MIN value
+
+ NO_MEMORY = -ENOMEM,
+ INVALID_OPERATION = -ENOSYS,
+ BAD_VALUE = -EINVAL,
+ BAD_TYPE = (UNKNOWN_ERROR + 1),
+ NAME_NOT_FOUND = -ENOENT,
+ PERMISSION_DENIED = -EPERM,
+ NO_INIT = -ENODEV,
+ ALREADY_EXISTS = -EEXIST,
+ DEAD_OBJECT = -EPIPE,
+ FAILED_TRANSACTION = (UNKNOWN_ERROR + 2),
+#if !defined(_WIN32)
+ BAD_INDEX = -EOVERFLOW,
+ NOT_ENOUGH_DATA = -ENODATA,
+ WOULD_BLOCK = -EWOULDBLOCK,
+ TIMED_OUT = -ETIMEDOUT,
+ UNKNOWN_TRANSACTION = -EBADMSG,
+#else
+ BAD_INDEX = -E2BIG,
+ NOT_ENOUGH_DATA = (UNKNOWN_ERROR + 3),
+ WOULD_BLOCK = (UNKNOWN_ERROR + 4),
+ TIMED_OUT = (UNKNOWN_ERROR + 5),
+ UNKNOWN_TRANSACTION = (UNKNOWN_ERROR + 6),
+#endif
+ FDS_NOT_ALLOWED = (UNKNOWN_ERROR + 7),
+ UNEXPECTED_NULL = (UNKNOWN_ERROR + 8),
+};
+
+// Restore define; enumeration is in "android" namespace, so the value defined
+// there won't work for Win32 code in a different namespace.
+#ifdef _WIN32
+# define NO_ERROR 0L
+#endif
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_ERRORS_H
diff --git a/src/cutils/CMakeLists.txt b/src/cutils/CMakeLists.txt
new file mode 100644
index 0000000..d436aea
--- /dev/null
+++ b/src/cutils/CMakeLists.txt
@@ -0,0 +1,26 @@
+cmake_minimum_required(VERSION 3.8)
+
+#############################################
+# libcutils
+#############################################
+add_library(cutils SHARED
+ hashmap.cpp
+ str_parms.cpp
+ threads.cpp
+ properties.cpp
+)
+
+target_include_directories(cutils PRIVATE
+ ./include)
+
+add_library(cutils_static STATIC
+ strlcpy.c)
+
+target_include_directories(cutils_static PRIVATE
+ ./include)
+
+target_link_libraries(cutils
+ -Wl,--whole-archive cutils_static -Wl,--no-whole-archive)
+
+install(TARGETS cutils
+ LIBRARY DESTINATION "lib")
diff --git a/src/cutils/Makefile b/src/cutils/Makefile
new file mode 100644
index 0000000..3114740
--- /dev/null
+++ b/src/cutils/Makefile
@@ -0,0 +1,74 @@
+################################################################################
+# Device/Makefile
+#
+# This Makefile builds the libs
+#
+################################################################################
+OUT_ROOT ?= dist
+
+CUTILS_DIR = $(AML_COMMON_DIR)/cutils
+
+################################################################################
+# libcutils.so - common src files
+################################################################################
+CUTILS_SRC_DIR = $(CUTILS_DIR)
+cutils_SRCS = \
+ $(CUTILS_SRC_DIR)/hashmap.cpp \
+ $(CUTILS_SRC_DIR)/strlcpy.c \
+ $(CUTILS_SRC_DIR)/str_parms.cpp \
+ $(CUTILS_SRC_DIR)/threads.cpp \
+ $(CUTILS_SRC_DIR)/properties.cpp \
+ $(NULL)
+
+liblog_SRCS += $(wildcard $(CUTILS_SRC_DIR)/liblog/*.c)
+cutils_SRCS += $(liblog_SRCS)
+
+logcat_SRCS = $(CUTILS_SRC_DIR)/logcat.cpp $(liblog_SRCS)
+
+#TODO: Add more include directories here, if necessary.
+INCLUDES += \
+ -I$(CUTILS_DIR)/include \
+ -I$(CUTILS_DIR)/liblog/include
+CFLAGS += -DHAVE_SYS_UIO_H -DHAVE_IOCTL
+
+ALL_SRCS = $(libcutils_SRCS) $(logcat_SRCS)
+
+include $(ROKU_PORT_COMMON_DIR)/build/define_target.mk
+
+comma = ,
+$(eval $(call DEFINE_TARGET,libcutils.so,$(cutils_SRCS),,-lpthread -lstdc++ -fPIC -shared -Wl$(comma)-z$(comma)defs -Wl$(comma)--build-id,lib))
+$(eval $(call DEFINE_TARGET,logcat,$(logcat_SRCS),,-lpthread -lstdc++ -fPIC -Wl$(comma)-z$(comma)defs -Wl$(comma)--build-id,lib))
+
+# ---------------------------------------------------------------------
+# Build rules
+all: $(VENDOR_ALL_TARGETS)
+# Compile .c file.
+# Simultaneously create .d file (see http://make.mad-scientist.net/papers/advanced-auto-dependency-generation).
+$(OUT_ROOT)/%.o: %.c $(OUT_ROOT)/%.d
+ mkdir -p $(dir $@)
+ $(CC) -MT $@ -MMD -MP -MF $(OUT_ROOT)/$*.Td $(CFLAGS) $(INCLUDES) -c -o $@ $<
+ mv -f $(OUT_ROOT)/$*.Td $(OUT_ROOT)/$*.d && touch $@
+# Compile .cpp file.
+# Simultaneously create .d file (see http://make.mad-scientist.net/papers/advanced-auto-dependency-generation).
+$(OUT_ROOT)/%.o: %.cpp $(OUT_ROOT)/%.d
+ @mkdir -p $(dir $@)
+ $(CXX) -MT $@ -MMD -MP -MF $(OUT_ROOT)/$*.Td $(CFLAGS) $(INCLUDES) -c -o $@ $<
+ mv -f $(OUT_ROOT)/$*.Td $(OUT_ROOT)/$*.d && touch $@
+$(OUT_ROOT)/%.d: ;
+.PRECIOUS: $(OUT_ROOT)/%.d
+.PHONY: clean distclean install
+
+include $(wildcard $(patsubst %,$(OUT_ROOT)/%.d,$(basename $(cutils_SRCS))))
+
+clean:
+ -rm -rf $(OUT_ROOT) $(CLEAN_FILES)
+ mkdir -p $(OUT_ROOT)
+
+distclean:
+ -rm $(DESTDIR)/usr/lib/libcutils.so
+ -rm $(DESTDIR)/usr/bin/logcat
+
+install:
+ mkdir -p $(DESTDIR)/usr/lib
+ cp $(OUT_ROOT)/libcutils.so $(DESTDIR)/usr/lib/
+ cp $(OUT_ROOT)/logcat $(DESTDIR)/usr/bin
diff --git a/src/cutils/cutils.mk b/src/cutils/cutils.mk
new file mode 100644
index 0000000..46afb3c
--- /dev/null
+++ b/src/cutils/cutils.mk
@@ -0,0 +1,30 @@
+CUTILS_PROJDIR := $(AML_COMMON_DIR)/cutils
+CUTILS_OSS_LIC := CLOSED
+CUTILS_DEPENDS := #Add dependencies here. E.g. PAL_DEPENDS := platform
+CUTILS_BINARIES := usr/lib/libcutils.so usr/bin/logcat
+CUTILS_ADD_SRC := $(ROKU_OS_INCLUDE_DIRS)
+
+$(eval $(call prep_proj,CUTILS,cutils,$(CUTILS_PROJDIR),$(CUTILS_ADD_SRC)))
+
+LDFLAGS = $(addprefix -L, $(ROKU_3PARTY_LIB_DIRS))
+CUTILS_MAKE_OPTIONS = \
+ CC=$(CC) \
+ CXX=$(CXX) \
+ OUT_ROOT=$(CUTILS_MAKEDIR) \
+ PORTING_KIT_OS=$(PORTING_KIT_OS) \
+ LDFLAGS="$(LDFLAGS)" \
+ PLATFORMDIR=$(PLATFORMDIR) \
+ AML_COMMON_DIR=$(AML_COMMON_DIR) \
+ ROKU_PORT_COMMON_DIR=$(ROKU_PORT_COMMON_DIR)
+
+cutils-configure:
+cutils-build:
+ (PATH=$(CROSSTOOLS_BIN):$(PATH) \
+ $(MAKE) -C $(CUTILS_PROJDIR) $(CUTILS_MAKE_OPTIONS) all)
+
+cutils-install:
+ $(MAKE) -C $(CUTILS_PROJDIR) DESTDIR=$(CUTILS_INSTDIR) $(CUTILS_MAKE_OPTIONS) DESTDIR=$(ROKU_STAGING_DIR)/$(CUTILS_DESTDIR) install
+
+cutils-clean:
+ [ -e $(CUTILS_PROJDIR)/Makefile ] && $(MAKE) -C $(CUTILS_PROJDIR) $(CUTILS_MAKE_OPTIONS) clean || true
+ [ -e $(CUTILS_PROJDIR)/Makefile ] && $(MAKE) -C $(CUTILS_PROJDIR) $(CUTILS_MAKE_OPTIONS) DESTDIR=$(ROKU_STAGING_DIR)/$(CUTILS_DESTDIR) distclean || true
diff --git a/src/cutils/hashmap.cpp b/src/cutils/hashmap.cpp
new file mode 100644
index 0000000..65b6ab1
--- /dev/null
+++ b/src/cutils/hashmap.cpp
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cutils/hashmap.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <cutils/threads.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+typedef struct Entry Entry;
+struct Entry {
+ void* key;
+ int hash;
+ void* value;
+ Entry* next;
+};
+
+struct Hashmap {
+ Entry** buckets;
+ size_t bucketCount;
+ int (*hash)(void* key);
+ bool (*equals)(void* keyA, void* keyB);
+ mutex_t lock;
+ size_t size;
+};
+
+Hashmap* hashmapCreate(size_t initialCapacity,
+ int (*hash)(void* key), bool (*equals)(void* keyA, void* keyB)) {
+ assert(hash != NULL);
+ assert(equals != NULL);
+
+ Hashmap* map = static_cast<Hashmap*>(malloc(sizeof(Hashmap)));
+ if (map == NULL) {
+ return NULL;
+ }
+
+ // 0.75 load factor.
+ size_t minimumBucketCount = initialCapacity * 4 / 3;
+ map->bucketCount = 1;
+ while (map->bucketCount <= minimumBucketCount) {
+ // Bucket count must be power of 2.
+ map->bucketCount <<= 1;
+ }
+
+ map->buckets = static_cast<Entry**>(calloc(map->bucketCount, sizeof(Entry*)));
+ if (map->buckets == NULL) {
+ free(map);
+ return NULL;
+ }
+
+ map->size = 0;
+
+ map->hash = hash;
+ map->equals = equals;
+
+ mutex_init(&map->lock);
+
+ return map;
+}
+
+/**
+ * Hashes the given key.
+ */
+#ifdef __clang__
+__attribute__((no_sanitize("integer")))
+#endif
+static inline int hashKey(Hashmap* map, void* key) {
+ int h = map->hash(key);
+
+ // We apply this secondary hashing discovered by Doug Lea to defend
+ // against bad hashes.
+ h += ~(h << 9);
+ h ^= (((unsigned int) h) >> 14);
+ h += (h << 4);
+ h ^= (((unsigned int) h) >> 10);
+
+ return h;
+}
+
+size_t hashmapSize(Hashmap* map) {
+ return map->size;
+}
+
+static inline size_t calculateIndex(size_t bucketCount, int hash) {
+ return ((size_t) hash) & (bucketCount - 1);
+}
+
+static void expandIfNecessary(Hashmap* map) {
+ // If the load factor exceeds 0.75...
+ if (map->size > (map->bucketCount * 3 / 4)) {
+ // Start off with a 0.33 load factor.
+ size_t newBucketCount = map->bucketCount << 1;
+ Entry** newBuckets = static_cast<Entry**>(calloc(newBucketCount, sizeof(Entry*)));
+ if (newBuckets == NULL) {
+ // Abort expansion.
+ return;
+ }
+
+ // Move over existing entries.
+ size_t i;
+ for (i = 0; i < map->bucketCount; i++) {
+ Entry* entry = map->buckets[i];
+ while (entry != NULL) {
+ Entry* next = entry->next;
+ size_t index = calculateIndex(newBucketCount, entry->hash);
+ entry->next = newBuckets[index];
+ newBuckets[index] = entry;
+ entry = next;
+ }
+ }
+
+ // Copy over internals.
+ free(map->buckets);
+ map->buckets = newBuckets;
+ map->bucketCount = newBucketCount;
+ }
+}
+
+void hashmapLock(Hashmap* map) {
+ mutex_lock(&map->lock);
+}
+
+void hashmapUnlock(Hashmap* map) {
+ mutex_unlock(&map->lock);
+}
+
+void hashmapFree(Hashmap* map) {
+ size_t i;
+ for (i = 0; i < map->bucketCount; i++) {
+ Entry* entry = map->buckets[i];
+ while (entry != NULL) {
+ Entry* next = entry->next;
+ free(entry);
+ entry = next;
+ }
+ }
+ free(map->buckets);
+ mutex_destroy(&map->lock);
+ free(map);
+}
+
+#ifdef __clang__
+__attribute__((no_sanitize("integer")))
+#endif
+/* FIXME: relies on signed integer overflow, which is undefined behavior */
+int hashmapHash(void* key, size_t keySize) {
+ int h = keySize;
+ char* data = (char*) key;
+ size_t i;
+ for (i = 0; i < keySize; i++) {
+ h = h * 31 + *data;
+ data++;
+ }
+ return h;
+}
+
+static Entry* createEntry(void* key, int hash, void* value) {
+ Entry* entry = static_cast<Entry*>(malloc(sizeof(Entry)));
+ if (entry == NULL) {
+ return NULL;
+ }
+ entry->key = key;
+ entry->hash = hash;
+ entry->value = value;
+ entry->next = NULL;
+ return entry;
+}
+
+static inline bool equalKeys(void* keyA, int hashA, void* keyB, int hashB,
+ bool (*equals)(void*, void*)) {
+ if (keyA == keyB) {
+ return true;
+ }
+ if (hashA != hashB) {
+ return false;
+ }
+ return equals(keyA, keyB);
+}
+
+void* hashmapPut(Hashmap* map, void* key, void* value) {
+ int hash = hashKey(map, key);
+ size_t index = calculateIndex(map->bucketCount, hash);
+
+ Entry** p = &(map->buckets[index]);
+ while (true) {
+ Entry* current = *p;
+
+ // Add a new entry.
+ if (current == NULL) {
+ *p = createEntry(key, hash, value);
+ if (*p == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ map->size++;
+ expandIfNecessary(map);
+ return NULL;
+ }
+
+ // Replace existing entry.
+ if (equalKeys(current->key, current->hash, key, hash, map->equals)) {
+ void* oldValue = current->value;
+ current->value = value;
+ return oldValue;
+ }
+
+ // Move to next entry.
+ p = ¤t->next;
+ }
+}
+
+void* hashmapGet(Hashmap* map, void* key) {
+ int hash = hashKey(map, key);
+ size_t index = calculateIndex(map->bucketCount, hash);
+
+ Entry* entry = map->buckets[index];
+ while (entry != NULL) {
+ if (equalKeys(entry->key, entry->hash, key, hash, map->equals)) {
+ return entry->value;
+ }
+ entry = entry->next;
+ }
+
+ return NULL;
+}
+
+bool hashmapContainsKey(Hashmap* map, void* key) {
+ int hash = hashKey(map, key);
+ size_t index = calculateIndex(map->bucketCount, hash);
+
+ Entry* entry = map->buckets[index];
+ while (entry != NULL) {
+ if (equalKeys(entry->key, entry->hash, key, hash, map->equals)) {
+ return true;
+ }
+ entry = entry->next;
+ }
+
+ return false;
+}
+
+void* hashmapMemoize(Hashmap* map, void* key,
+ void* (*initialValue)(void* key, void* context), void* context) {
+ int hash = hashKey(map, key);
+ size_t index = calculateIndex(map->bucketCount, hash);
+
+ Entry** p = &(map->buckets[index]);
+ while (true) {
+ Entry* current = *p;
+
+ // Add a new entry.
+ if (current == NULL) {
+ *p = createEntry(key, hash, NULL);
+ if (*p == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ void* value = initialValue(key, context);
+ (*p)->value = value;
+ map->size++;
+ expandIfNecessary(map);
+ return value;
+ }
+
+ // Return existing value.
+ if (equalKeys(current->key, current->hash, key, hash, map->equals)) {
+ return current->value;
+ }
+
+ // Move to next entry.
+ p = ¤t->next;
+ }
+}
+
+void* hashmapRemove(Hashmap* map, void* key) {
+ int hash = hashKey(map, key);
+ size_t index = calculateIndex(map->bucketCount, hash);
+
+ // Pointer to the current entry.
+ Entry** p = &(map->buckets[index]);
+ Entry* current;
+ while ((current = *p) != NULL) {
+ if (equalKeys(current->key, current->hash, key, hash, map->equals)) {
+ void* value = current->value;
+ *p = current->next;
+ free(current);
+ map->size--;
+ return value;
+ }
+
+ p = ¤t->next;
+ }
+
+ return NULL;
+}
+
+void hashmapForEach(Hashmap* map,
+ bool (*callback)(void* key, void* value, void* context),
+ void* context) {
+ size_t i;
+ for (i = 0; i < map->bucketCount; i++) {
+ Entry* entry = map->buckets[i];
+ while (entry != NULL) {
+ Entry *next = entry->next;
+ if (!callback(entry->key, entry->value, context)) {
+ return;
+ }
+ entry = next;
+ }
+ }
+}
+
+size_t hashmapCurrentCapacity(Hashmap* map) {
+ size_t bucketCount = map->bucketCount;
+ return bucketCount * 3 / 4;
+}
+
+size_t hashmapCountCollisions(Hashmap* map) {
+ size_t collisions = 0;
+ size_t i;
+ for (i = 0; i < map->bucketCount; i++) {
+ Entry* entry = map->buckets[i];
+ while (entry != NULL) {
+ if (entry->next != NULL) {
+ collisions++;
+ }
+ entry = entry->next;
+ }
+ }
+ return collisions;
+}
+
+int hashmapIntHash(void* key) {
+ // Return the key value itself.
+ return *((int*) key);
+}
+
+bool hashmapIntEquals(void* keyA, void* keyB) {
+ int a = *((int*) keyA);
+ int b = *((int*) keyB);
+ return a == b;
+}
diff --git a/src/cutils/logcat.cpp b/src/cutils/logcat.cpp
new file mode 100644
index 0000000..225c15e
--- /dev/null
+++ b/src/cutils/logcat.cpp
@@ -0,0 +1,789 @@
+// Copyright 2006 The Android Open Source Project
+
+#include <cutils/logger.h>
+#include <cutils/logd.h>
+#include <cutils/sockets.h>
+#include <cutils/logprint.h>
+#include <cutils/event_tag_map.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <errno.h>
+#include <assert.h>
+#include <ctype.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <arpa/inet.h>
+
+#define DEFAULT_LOG_ROTATE_SIZE_KBYTES 16
+#define DEFAULT_MAX_ROTATED_LOGS 4
+
+static AndroidLogFormat * g_logformat;
+static bool g_nonblock = false;
+static int g_tail_lines = 0;
+
+/* logd prefixes records with a length field */
+#define RECORD_LENGTH_FIELD_SIZE_BYTES sizeof(uint32_t)
+
+#define LOG_FILE_DIR "/dev/log_"
+
+struct queued_entry_t {
+ union {
+ unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1] __attribute__((aligned(4)));
+ struct logger_entry entry __attribute__((aligned(4)));
+ };
+ queued_entry_t* next;
+
+ queued_entry_t() {
+ next = NULL;
+ }
+};
+
+static int cmp(queued_entry_t* a, queued_entry_t* b) {
+ int n = a->entry.sec - b->entry.sec;
+ if (n != 0) {
+ return n;
+ }
+ return a->entry.nsec - b->entry.nsec;
+}
+
+struct log_device_t {
+ char* device;
+ bool binary;
+ int fd;
+ bool printed;
+ char label;
+
+ queued_entry_t* queue;
+ log_device_t* next;
+
+ log_device_t(char* d, bool b, char l) {
+ device = d;
+ binary = b;
+ label = l;
+ queue = NULL;
+ next = NULL;
+ printed = false;
+ }
+
+ void enqueue(queued_entry_t* entry) {
+ if (this->queue == NULL) {
+ this->queue = entry;
+ } else {
+ queued_entry_t** e = &this->queue;
+ while (*e && cmp(entry, *e) >= 0) {
+ e = &((*e)->next);
+ }
+ entry->next = *e;
+ *e = entry;
+ }
+ }
+};
+
+namespace android {
+
+/* Global Variables */
+
+static const char * g_outputFileName = NULL;
+static int g_logRotateSizeKBytes = 0; // 0 means "no log rotation"
+static int g_maxRotatedLogs = DEFAULT_MAX_ROTATED_LOGS; // 0 means "unbounded"
+static int g_outFD = -1;
+static off_t g_outByteCount = 0;
+static int g_printBinary = 0;
+static int g_devCount = 0;
+
+static EventTagMap* g_eventTagMap = NULL;
+
+static int openLogFile (const char *pathname)
+{
+ return open(g_outputFileName, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
+}
+
+static void rotateLogs()
+{
+ int err;
+
+ // Can't rotate logs if we're not outputting to a file
+ if (g_outputFileName == NULL) {
+ return;
+ }
+
+ close(g_outFD);
+
+ for (int i = g_maxRotatedLogs ; i > 0 ; i--) {
+ char *file0, *file1;
+
+ asprintf(&file1, "%s.%d", g_outputFileName, i);
+
+ if (i - 1 == 0) {
+ asprintf(&file0, "%s", g_outputFileName);
+ } else {
+ asprintf(&file0, "%s.%d", g_outputFileName, i - 1);
+ }
+
+ err = rename (file0, file1);
+
+ if (err < 0 && errno != ENOENT) {
+ perror("while rotating log files");
+ }
+
+ free(file1);
+ free(file0);
+ }
+
+ g_outFD = openLogFile (g_outputFileName);
+
+ if (g_outFD < 0) {
+ perror ("couldn't open output file");
+ exit(-1);
+ }
+
+ g_outByteCount = 0;
+
+}
+
+void printBinary(struct logger_entry *buf)
+{
+ size_t size = sizeof(logger_entry) + buf->len;
+ int ret;
+
+ do {
+ ret = write(g_outFD, buf, size);
+ } while (ret < 0 && errno == EINTR);
+}
+
+static void processBuffer(log_device_t* dev, struct logger_entry *buf)
+{
+ int bytesWritten = 0;
+ int err;
+ AndroidLogEntry entry;
+ char binaryMsgBuf[1024];
+
+ if (dev->binary) {
+ err = android_log_processBinaryLogBuffer(buf, &entry, g_eventTagMap,
+ binaryMsgBuf, sizeof(binaryMsgBuf));
+ //printf(">>> pri=%d len=%d msg='%s'\n",
+ // entry.priority, entry.messageLen, entry.message);
+ } else {
+ err = android_log_processLogBuffer(buf, &entry);
+ }
+ if (err < 0) {
+ goto error;
+ }
+
+ if (android_log_shouldPrintLine(g_logformat, entry.tag, entry.priority)) {
+ if (false && g_devCount > 1) {
+ binaryMsgBuf[0] = dev->label;
+ binaryMsgBuf[1] = ' ';
+ bytesWritten = write(g_outFD, binaryMsgBuf, 2);
+ if (bytesWritten < 0) {
+ perror("output error");
+ exit(-1);
+ }
+ }
+
+ bytesWritten = android_log_printLogLine(g_logformat, g_outFD, &entry);
+
+ if (bytesWritten < 0) {
+ perror("output error");
+ exit(-1);
+ }
+ }
+
+ g_outByteCount += bytesWritten;
+
+ if (g_logRotateSizeKBytes > 0
+ && (g_outByteCount / 1024) >= g_logRotateSizeKBytes
+ ) {
+ rotateLogs();
+ }
+
+error:
+ //fprintf (stderr, "Error processing record\n");
+ return;
+}
+
+static void chooseFirst(log_device_t* dev, log_device_t** firstdev) {
+ for (*firstdev = NULL; dev != NULL; dev = dev->next) {
+ if (dev->queue != NULL && (*firstdev == NULL || cmp(dev->queue, (*firstdev)->queue) < 0)) {
+ *firstdev = dev;
+ }
+ }
+}
+
+static void maybePrintStart(log_device_t* dev) {
+ if (!dev->printed) {
+ dev->printed = true;
+ if (g_devCount > 1 && !g_printBinary) {
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "--------- beginning of %s\n", dev->device);
+ if (write(g_outFD, buf, strlen(buf)) < 0) {
+ perror("output error");
+ exit(-1);
+ }
+ }
+ }
+}
+
+static void skipNextEntry(log_device_t* dev) {
+ maybePrintStart(dev);
+ queued_entry_t* entry = dev->queue;
+ dev->queue = entry->next;
+ delete entry;
+}
+
+static void printNextEntry(log_device_t* dev) {
+ maybePrintStart(dev);
+ if (g_printBinary) {
+ printBinary(&dev->queue->entry);
+ } else {
+ processBuffer(dev, &dev->queue->entry);
+ }
+ skipNextEntry(dev);
+}
+
+static void readLogLines(log_device_t* devices)
+{
+ log_device_t* dev;
+ int max = 0;
+ int ret;
+ int queued_lines = 0;
+ bool sleep = false;
+
+ int result;
+ fd_set readset;
+
+ for (dev=devices; dev; dev = dev->next) {
+ if (dev->fd > max) {
+ max = dev->fd;
+ }
+ }
+
+ while (1) {
+ do {
+ timeval timeout = { 0, 5000 /* 5ms */ }; // If we oversleep it's ok, i.e. ignore EINTR.
+ FD_ZERO(&readset);
+ for (dev=devices; dev; dev = dev->next) {
+ FD_SET(dev->fd, &readset);
+ }
+ result = select(max + 1, &readset, NULL, NULL, sleep ? NULL : &timeout);
+ } while (result == -1 && errno == EINTR);
+
+ if (result >= 0) {
+ for (dev=devices; dev; dev = dev->next) {
+ if (FD_ISSET(dev->fd, &readset)) {
+ queued_entry_t* entry = new queued_entry_t();
+ /* NOTE: driver guarantees we read exactly one full entry */
+ ret = read(dev->fd, entry->buf, LOGGER_ENTRY_MAX_LEN);
+ if (ret < 0) {
+ if (errno == EINTR) {
+ delete entry;
+ goto next;
+ }
+ if (errno == EAGAIN) {
+ delete entry;
+ break;
+ }
+ perror("logcat read");
+ exit(EXIT_FAILURE);
+ }
+ else if (!ret) {
+ fprintf(stderr, "read: Unexpected EOF!\n");
+ exit(EXIT_FAILURE);
+ }
+ else if (entry->entry.len != ret - sizeof(struct logger_entry)) {
+ fprintf(stderr, "read: unexpected length. Expected %d, got %d\n",
+ entry->entry.len, ret - sizeof(struct logger_entry));
+ exit(EXIT_FAILURE);
+ }
+
+ entry->entry.msg[entry->entry.len] = '\0';
+
+ dev->enqueue(entry);
+ ++queued_lines;
+ }
+ }
+
+ if (result == 0) {
+ // we did our short timeout trick and there's nothing new
+ // print everything we have and wait for more data
+ sleep = true;
+ while (true) {
+ chooseFirst(devices, &dev);
+ if (dev == NULL) {
+ break;
+ }
+ if (g_tail_lines == 0 || queued_lines <= g_tail_lines) {
+ printNextEntry(dev);
+ } else {
+ skipNextEntry(dev);
+ }
+ --queued_lines;
+ }
+
+ // the caller requested to just dump the log and exit
+ if (g_nonblock) {
+ return;
+ }
+ } else {
+ // print all that aren't the last in their list
+ sleep = false;
+ while (g_tail_lines == 0 || queued_lines > g_tail_lines) {
+ chooseFirst(devices, &dev);
+ if (dev == NULL || dev->queue->next == NULL) {
+ break;
+ }
+ if (g_tail_lines == 0) {
+ printNextEntry(dev);
+ } else {
+ skipNextEntry(dev);
+ }
+ --queued_lines;
+ }
+ }
+ }
+next:
+ ;
+ }
+}
+
+static int clearLog(int logfd)
+{
+ return ioctl(logfd, LOGGER_FLUSH_LOG);
+}
+
+/* returns the total size of the log's ring buffer */
+static int getLogSize(int logfd)
+{
+ return ioctl(logfd, LOGGER_GET_LOG_BUF_SIZE);
+}
+
+/* returns the readable size of the log's ring buffer (that is, amount of the log consumed) */
+static int getLogReadableSize(int logfd)
+{
+ return ioctl(logfd, LOGGER_GET_LOG_LEN);
+}
+
+static void setupOutput()
+{
+
+ if (g_outputFileName == NULL) {
+ g_outFD = STDOUT_FILENO;
+
+ } else {
+ struct stat statbuf;
+
+ g_outFD = openLogFile (g_outputFileName);
+
+ if (g_outFD < 0) {
+ perror ("couldn't open output file");
+ exit(-1);
+ }
+
+ fstat(g_outFD, &statbuf);
+
+ g_outByteCount = statbuf.st_size;
+ }
+}
+
+static void show_help(const char *cmd)
+{
+ fprintf(stderr,"Usage: %s [options] [filterspecs]\n", cmd);
+
+ fprintf(stderr, "options include:\n"
+ " -s Set default filter to silent.\n"
+ " Like specifying filterspec '*:s'\n"
+ " -f <filename> Log to file. Default to stdout\n"
+ " -r [<kbytes>] Rotate log every kbytes. (16 if unspecified). Requires -f\n"
+ " -n <count> Sets max number of rotated logs to <count>, default 4\n"
+ " -v <format> Sets the log print format, where <format> is one of:\n\n"
+ " brief process tag thread raw time threadtime long\n\n"
+ " -c clear (flush) the entire log and exit\n"
+ " -d dump the log and then exit (don't block)\n"
+ " -t <count> print only the most recent <count> lines (implies -d)\n"
+ " -g get the size of the log's ring buffer and exit\n"
+ " -b <buffer> Request alternate ring buffer, 'main', 'system', 'radio'\n"
+ " or 'events'. Multiple -b parameters are allowed and the\n"
+ " results are interleaved. The default is -b main -b system.\n"
+ " -B output the log in binary");
+
+
+ fprintf(stderr,"\nfilterspecs are a series of \n"
+ " <tag>[:priority]\n\n"
+ "where <tag> is a log component tag (or * for all) and priority is:\n"
+ " V Verbose\n"
+ " D Debug\n"
+ " I Info\n"
+ " W Warn\n"
+ " E Error\n"
+ " F Fatal\n"
+ " S Silent (supress all output)\n"
+ "\n'*' means '*:d' and <tag> by itself means <tag>:v\n"
+ "\nIf not specified on the commandline, filterspec is set from ANDROID_LOG_TAGS.\n"
+ "If no filterspec is found, filter defaults to '*:I'\n"
+ "\nIf not specified with -v, format is set from ANDROID_PRINTF_LOG\n"
+ "or defaults to \"brief\"\n\n");
+
+
+
+}
+
+
+} /* namespace android */
+
+static int setLogFormat(const char * formatString)
+{
+ static AndroidLogPrintFormat format;
+
+ format = android_log_formatFromString(formatString);
+
+ if (format == FORMAT_OFF) {
+ // FORMAT_OFF means invalid string
+ return -1;
+ }
+
+ android_log_setPrintFormat(g_logformat, format);
+
+ return 0;
+}
+
+//extern "C" void logprint_run_tests(void);
+
+int main(int argc, char **argv)
+{
+ int err;
+ int hasSetLogFormat = 0;
+ int clearLog = 0;
+ int getLogSize = 0;
+ int mode = O_RDONLY;
+ const char *forceFilters = NULL;
+ log_device_t* devices = NULL;
+ log_device_t* dev;
+ bool needBinary = false;
+
+ g_logformat = android_log_format_new();
+
+ if (argc == 2 && 0 == strcmp(argv[1], "--test")) {
+ // logprint_run_tests();
+ exit(0);
+ }
+
+ if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
+ android::show_help(argv[0]);
+ exit(0);
+ }
+
+ for (;;) {
+ int ret;
+
+ ret = getopt(argc, argv, "cdt:gsQf:r::n:v:b:B");
+
+ if (ret < 0) {
+ break;
+ }
+
+ switch (ret) {
+ case 's':
+ // default to all silent
+ android_log_addFilterRule(g_logformat, "*:s");
+ break;
+
+ case 'c':
+ clearLog = 1;
+ mode = O_WRONLY;
+ break;
+
+ case 'd':
+ g_nonblock = true;
+ break;
+
+ case 't':
+ g_nonblock = true;
+ g_tail_lines = atoi(optarg);
+ break;
+
+ case 'g':
+ getLogSize = 1;
+ break;
+
+ case 'b': {
+ char* buf = (char*) malloc(strlen(LOG_FILE_DIR) + strlen(optarg) + 1);
+ strcpy(buf, LOG_FILE_DIR);
+ strcat(buf, optarg);
+
+ bool binary = strcmp(optarg, "events") == 0;
+ if (binary) {
+ needBinary = true;
+ }
+
+ if (devices) {
+ dev = devices;
+ while (dev->next) {
+ dev = dev->next;
+ }
+ dev->next = new log_device_t(buf, binary, optarg[0]);
+ } else {
+ devices = new log_device_t(buf, binary, optarg[0]);
+ }
+ android::g_devCount++;
+ }
+ break;
+
+ case 'B':
+ android::g_printBinary = 1;
+ break;
+
+ case 'f':
+ // redirect output to a file
+
+ android::g_outputFileName = optarg;
+
+ break;
+
+ case 'r':
+ if (optarg == NULL) {
+ android::g_logRotateSizeKBytes
+ = DEFAULT_LOG_ROTATE_SIZE_KBYTES;
+ } else {
+ long logRotateSize;
+ char *lastDigit;
+
+ if (!isdigit(optarg[0])) {
+ fprintf(stderr,"Invalid parameter to -r\n");
+ android::show_help(argv[0]);
+ exit(-1);
+ }
+ android::g_logRotateSizeKBytes = atoi(optarg);
+ }
+ break;
+
+ case 'n':
+ if (!isdigit(optarg[0])) {
+ fprintf(stderr,"Invalid parameter to -r\n");
+ android::show_help(argv[0]);
+ exit(-1);
+ }
+
+ android::g_maxRotatedLogs = atoi(optarg);
+ break;
+
+ case 'v':
+ err = setLogFormat (optarg);
+ if (err < 0) {
+ fprintf(stderr,"Invalid parameter to -v\n");
+ android::show_help(argv[0]);
+ exit(-1);
+ }
+
+ hasSetLogFormat = 1;
+ break;
+
+ case 'Q':
+ /* this is a *hidden* option used to start a version of logcat */
+ /* in an emulated device only. it basically looks for androidboot.logcat= */
+ /* on the kernel command line. If something is found, it extracts a log filter */
+ /* and uses it to run the program. If nothing is found, the program should */
+ /* quit immediately */
+#define KERNEL_OPTION "androidboot.logcat="
+#define CONSOLE_OPTION "androidboot.console="
+ {
+ int fd;
+ char* logcat;
+ char* console;
+ int force_exit = 1;
+ static char cmdline[2048];
+
+ fd = open("/proc/cmdline", O_RDONLY);
+ if (fd >= 0) {
+ int n = read(fd, cmdline, sizeof(cmdline)-1 );
+ if (n < 0) n = 0;
+ cmdline[n] = 0;
+ close(fd);
+ } else {
+ cmdline[0] = 0;
+ }
+
+ logcat = strstr( cmdline, KERNEL_OPTION );
+ console = strstr( cmdline, CONSOLE_OPTION );
+ if (logcat != NULL) {
+ char* p = logcat + sizeof(KERNEL_OPTION)-1;;
+ char* q = strpbrk( p, " \t\n\r" );;
+
+ if (q != NULL)
+ *q = 0;
+
+ forceFilters = p;
+ force_exit = 0;
+ }
+ /* if nothing found or invalid filters, exit quietly */
+ if (force_exit)
+ exit(0);
+
+ /* redirect our output to the emulator console */
+ if (console) {
+ char* p = console + sizeof(CONSOLE_OPTION)-1;
+ char* q = strpbrk( p, " \t\n\r" );
+ char devname[64];
+ int len;
+
+ if (q != NULL) {
+ len = q - p;
+ } else
+ len = strlen(p);
+
+ len = snprintf( devname, sizeof(devname), "/dev/%.*s", len, p );
+ fprintf(stderr, "logcat using %s (%d)\n", devname, len);
+ if (len < (int)sizeof(devname)) {
+ fd = open( devname, O_WRONLY );
+ if (fd >= 0) {
+ dup2(fd, 1);
+ dup2(fd, 2);
+ close(fd);
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ fprintf(stderr,"Unrecognized Option\n");
+ android::show_help(argv[0]);
+ exit(-1);
+ break;
+ }
+ }
+
+ if (!devices) {
+ devices = new log_device_t(strdup("/dev/" LOGGER_LOG_MAIN), false, 'm');
+ android::g_devCount = 1;
+ int accessmode =
+ (mode & O_RDONLY) ? R_OK : 0
+ | (mode & O_WRONLY) ? W_OK : 0;
+ // only add this if it's available
+ if (0 == access("/dev/" LOGGER_LOG_SYSTEM, accessmode)) {
+ devices->next = new log_device_t(strdup("/dev/" LOGGER_LOG_SYSTEM), false, 's');
+ android::g_devCount++;
+ }
+ }
+
+ if (android::g_logRotateSizeKBytes != 0
+ && android::g_outputFileName == NULL
+ ) {
+ fprintf(stderr,"-r requires -f as well\n");
+ android::show_help(argv[0]);
+ exit(-1);
+ }
+
+ android::setupOutput();
+
+ if (hasSetLogFormat == 0) {
+ const char* logFormat = getenv("ANDROID_PRINTF_LOG");
+
+ if (logFormat != NULL) {
+ err = setLogFormat(logFormat);
+
+ if (err < 0) {
+ fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n",
+ logFormat);
+ }
+ }
+ }
+
+ if (forceFilters) {
+ err = android_log_addFilterString(g_logformat, forceFilters);
+ if (err < 0) {
+ fprintf (stderr, "Invalid filter expression in -logcat option\n");
+ exit(0);
+ }
+ } else if (argc == optind) {
+ // Add from environment variable
+ char *env_tags_orig = getenv("ANDROID_LOG_TAGS");
+
+ if (env_tags_orig != NULL) {
+ err = android_log_addFilterString(g_logformat, env_tags_orig);
+
+ if (err < 0) {
+ fprintf(stderr, "Invalid filter expression in"
+ " ANDROID_LOG_TAGS\n");
+ android::show_help(argv[0]);
+ exit(-1);
+ }
+ }
+ } else {
+ // Add from commandline
+ for (int i = optind ; i < argc ; i++) {
+ err = android_log_addFilterString(g_logformat, argv[i]);
+
+ if (err < 0) {
+ fprintf (stderr, "Invalid filter expression '%s'\n", argv[i]);
+ android::show_help(argv[0]);
+ exit(-1);
+ }
+ }
+ }
+
+ dev = devices;
+ while (dev) {
+ dev->fd = open(dev->device, mode);
+ if (dev->fd < 0) {
+ fprintf(stderr, "Unable to open log device '%s': %s\n",
+ dev->device, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (clearLog) {
+ int ret;
+ ret = android::clearLog(dev->fd);
+ if (ret) {
+ perror("ioctl");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (getLogSize) {
+ int size, readable;
+
+ size = android::getLogSize(dev->fd);
+ if (size < 0) {
+ perror("ioctl");
+ exit(EXIT_FAILURE);
+ }
+
+ readable = android::getLogReadableSize(dev->fd);
+ if (readable < 0) {
+ perror("ioctl");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("%s: ring buffer is %dKb (%dKb consumed), "
+ "max entry is %db, max payload is %db\n", dev->device,
+ size / 1024, readable / 1024,
+ (int) LOGGER_ENTRY_MAX_LEN, (int) LOGGER_ENTRY_MAX_PAYLOAD);
+ }
+
+ dev = dev->next;
+ }
+
+ if (getLogSize) {
+ exit(0);
+ }
+ if (clearLog) {
+ exit(0);
+ }
+
+ //LOG_EVENT_INT(10, 12345);
+ //LOG_EVENT_LONG(11, 0x1122334455667788LL);
+ //LOG_EVENT_STRING(0, "whassup, doc?");
+
+ if (needBinary)
+ android::g_eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+
+ android::readLogLines(devices);
+
+ return 0;
+}
diff --git a/src/cutils/properties.cpp b/src/cutils/properties.cpp
new file mode 100644
index 0000000..40bcc6e
--- /dev/null
+++ b/src/cutils/properties.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cutils/properties.h>
+
+#define LOG_TAG "properties"
+// #define LOG_NDEBUG 0
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+//#include <cutils/sockets.h>
+#include <cutils/log.h>
+
+int8_t property_get_bool(const char *key, int8_t default_value) {
+ if (!key) {
+ return default_value;
+ }
+
+ int8_t result = default_value;
+ char buf[PROPERTY_VALUE_MAX] = {'\0'};
+
+ int len = property_get(key, buf, "");
+ if (len == 1) {
+ char ch = buf[0];
+ if (ch == '0' || ch == 'n') {
+ result = false;
+ } else if (ch == '1' || ch == 'y') {
+ result = true;
+ }
+ } else if (len > 1) {
+ if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
+ result = false;
+ } else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+// Convert string property to int (default if fails); return default value if out of bounds
+static intmax_t property_get_imax(const char *key, intmax_t lower_bound, intmax_t upper_bound,
+ intmax_t default_value) {
+ if (!key) {
+ return default_value;
+ }
+
+ intmax_t result = default_value;
+ char buf[PROPERTY_VALUE_MAX] = {'\0'};
+ char *end = NULL;
+
+ int len = property_get(key, buf, "");
+ if (len > 0) {
+ int tmp = errno;
+ errno = 0;
+
+ // Infer base automatically
+ result = strtoimax(buf, &end, /*base*/ 0);
+ if ((result == INTMAX_MIN || result == INTMAX_MAX) && errno == ERANGE) {
+ // Over or underflow
+ result = default_value;
+ ALOGV("%s(%s,%" PRIdMAX ") - overflow", __FUNCTION__, key, default_value);
+ } else if (result < lower_bound || result > upper_bound) {
+ // Out of range of requested bounds
+ result = default_value;
+ ALOGV("%s(%s,%" PRIdMAX ") - out of range", __FUNCTION__, key, default_value);
+ } else if (end == buf) {
+ // Numeric conversion failed
+ result = default_value;
+ ALOGV("%s(%s,%" PRIdMAX ") - numeric conversion failed", __FUNCTION__, key,
+ default_value);
+ }
+
+ errno = tmp;
+ }
+
+ return result;
+}
+
+int64_t property_get_int64(const char *key, int64_t default_value) {
+ return (int64_t)property_get_imax(key, INT64_MIN, INT64_MAX, default_value);
+}
+
+int32_t property_get_int32(const char *key, int32_t default_value) {
+ return (int32_t)property_get_imax(key, INT32_MIN, INT32_MAX, default_value);
+}
+
+//#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+//#include <sys/_system_properties.h>
+
+int property_set(const char *key, const char *value) {
+ //return __system_property_set(key, value);
+ return setenv(key, value, 1);
+}
+
+int property_get(const char *key, char *value, const char *default_value) {
+#if 0
+ int len = __system_property_get(key, value);
+ if (len > 0) {
+ return len;
+ }
+#endif
+
+ int i, len;
+ char key_buf[PROPERTY_VALUE_MAX];
+ const char *buf;
+
+ /* convert '.' in property name to '_' */
+ memset(key_buf, 0, sizeof(key_buf));
+ strncpy(key_buf, key, PROPERTY_VALUE_MAX - 1);
+ len = strlen(key_buf);
+ for (i = 0; i < len; i++) {
+ if (key_buf[i] == '.')
+ key_buf[i] = '_';
+ }
+
+ len = 0;
+ buf = getenv(key_buf);
+ if (buf) {
+ len = strlen(strncpy(value, buf, PROPERTY_VALUE_MAX - 1));
+ value[len] = '\0';
+ return len;
+ }
+
+ if (default_value) {
+ len = strnlen(default_value, PROPERTY_VALUE_MAX - 1);
+ memcpy(value, default_value, len);
+ value[len] = '\0';
+ }
+ return len;
+}
+
+#if 0
+struct callback_data {
+ void (*callback)(const char* name, const char* value, void* cookie);
+ void* cookie;
+};
+
+static void trampoline(void* raw_data, const char* name, const char* value, unsigned /*serial*/) {
+ callback_data* data = reinterpret_cast<callback_data*>(raw_data);
+ data->callback(name, value, data->cookie);
+}
+
+static void property_list_callback(const prop_info* pi, void* data) {
+ __system_property_read_callback(pi, trampoline, data);
+}
+
+int property_list(void (*fn)(const char* name, const char* value, void* cookie), void* cookie) {
+ callback_data data = { fn, cookie };
+ return __system_property_foreach(property_list_callback, &data);
+}
+#endif
+
diff --git a/src/cutils/str_parms.cpp b/src/cutils/str_parms.cpp
new file mode 100644
index 0000000..995733e
--- /dev/null
+++ b/src/cutils/str_parms.cpp
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cutils/str_parms.h>
+
+#define LOG_TAG "str_params"
+//#define LOG_NDEBUG 0
+
+#define _GNU_SOURCE 1
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cutils/hashmap.h>
+#include <cutils/memory.h>
+//#include <log/log.h>
+#define ALOGV(...)
+#define ALOGI(...)
+
+/* When an object is allocated but not freed in a function,
+ * because its ownership is released to other object like a hashmap,
+ * call RELEASE_OWNERSHIP to tell the clang analyzer and avoid
+ * false warnings about potential memory leak.
+ * For now, a "temporary" assignment to global variables
+ * is enough to confuse the clang static analyzer.
+ */
+#ifdef __clang_analyzer__
+static void *released_pointer;
+#define RELEASE_OWNERSHIP(x) { released_pointer = x; released_pointer = 0; }
+#else
+#define RELEASE_OWNERSHIP(x)
+#endif
+
+struct str_parms {
+ Hashmap *map;
+};
+
+
+static bool str_eq(void *key_a, void *key_b)
+{
+ return !strcmp((const char *)key_a, (const char *)key_b);
+}
+
+/* use djb hash unless we find it inadequate */
+#ifdef __clang__
+__attribute__((no_sanitize("integer")))
+#endif
+static int str_hash_fn(void *str)
+{
+ uint32_t hash = 5381;
+
+ for (char* p = static_cast<char*>(str); p && *p; p++)
+ hash = ((hash << 5) + hash) + *p;
+ return (int)hash;
+}
+
+struct str_parms *str_parms_create(void)
+{
+ str_parms* s = static_cast<str_parms*>(calloc(1, sizeof(str_parms)));
+ if (!s) return NULL;
+
+ s->map = hashmapCreate(5, str_hash_fn, str_eq);
+ if (!s->map) {
+ free(s);
+ return NULL;
+ }
+
+ return s;
+}
+
+struct remove_ctxt {
+ struct str_parms *str_parms;
+ const char *key;
+};
+
+static bool remove_pair(void *key, void *value, void *context)
+{
+ remove_ctxt* ctxt = static_cast<remove_ctxt*>(context);
+ bool should_continue;
+
+ /*
+ * - if key is not supplied, then we are removing all entries,
+ * so remove key and continue (i.e. return true)
+ * - if key is supplied and matches, then remove it and don't
+ * continue (return false). Otherwise, return true and keep searching
+ * for key.
+ *
+ */
+ if (!ctxt->key) {
+ should_continue = true;
+ goto do_remove;
+ } else if (!strcmp(ctxt->key, static_cast<const char*>(key))) {
+ should_continue = false;
+ goto do_remove;
+ }
+
+ return true;
+
+do_remove:
+ hashmapRemove(ctxt->str_parms->map, key);
+ free(key);
+ free(value);
+ return should_continue;
+}
+
+void str_parms_del(struct str_parms *str_parms, const char *key)
+{
+ struct remove_ctxt ctxt = {
+ .str_parms = str_parms,
+ .key = key,
+ };
+ hashmapForEach(str_parms->map, remove_pair, &ctxt);
+}
+
+void str_parms_destroy(struct str_parms *str_parms)
+{
+ struct remove_ctxt ctxt = {
+ .str_parms = str_parms,
+ };
+
+ hashmapForEach(str_parms->map, remove_pair, &ctxt);
+ hashmapFree(str_parms->map);
+ free(str_parms);
+}
+
+struct str_parms *str_parms_create_str(const char *_string)
+{
+ struct str_parms *str_parms;
+ char *str;
+ char *kvpair;
+ char *tmpstr;
+ int items = 0;
+
+ str_parms = str_parms_create();
+ if (!str_parms)
+ goto err_create_str_parms;
+
+ str = strdup(_string);
+ if (!str)
+ goto err_strdup;
+
+ ALOGV("%s: source string == '%s'\n", __func__, _string);
+
+ kvpair = strtok_r(str, ";", &tmpstr);
+ while (kvpair && *kvpair) {
+ char *eq = strchr(kvpair, '='); /* would love strchrnul */
+ char *value;
+ char *key;
+ void *old_val;
+
+ if (eq == kvpair)
+ goto next_pair;
+
+ if (eq) {
+ key = strndup(kvpair, eq - kvpair);
+ if (*(++eq))
+ value = strdup(eq);
+ else
+ value = strdup("");
+ } else {
+ key = strdup(kvpair);
+ value = strdup("");
+ }
+
+ /* if we replaced a value, free it */
+ old_val = hashmapPut(str_parms->map, key, value);
+ RELEASE_OWNERSHIP(value);
+ if (old_val) {
+ free(old_val);
+ free(key);
+ } else {
+ RELEASE_OWNERSHIP(key);
+ }
+
+ items++;
+next_pair:
+ kvpair = strtok_r(NULL, ";", &tmpstr);
+ }
+
+ if (!items)
+ ALOGV("%s: no items found in string\n", __func__);
+
+ free(str);
+
+ return str_parms;
+
+err_strdup:
+ str_parms_destroy(str_parms);
+err_create_str_parms:
+ return NULL;
+}
+
+int str_parms_add_str(struct str_parms *str_parms, const char *key,
+ const char *value)
+{
+ void *tmp_key = NULL;
+ void *tmp_val = NULL;
+ void *old_val = NULL;
+
+ // strdup and hashmapPut both set errno on failure.
+ // Set errno to 0 so we can recognize whether anything went wrong.
+ int saved_errno = errno;
+ errno = 0;
+
+ tmp_key = strdup(key);
+ if (tmp_key == NULL) {
+ goto clean_up;
+ }
+
+ tmp_val = strdup(value);
+ if (tmp_val == NULL) {
+ goto clean_up;
+ }
+
+ old_val = hashmapPut(str_parms->map, tmp_key, tmp_val);
+ if (old_val == NULL) {
+ // Did hashmapPut fail?
+ if (errno == ENOMEM) {
+ goto clean_up;
+ }
+ // For new keys, hashmap takes ownership of tmp_key and tmp_val.
+ RELEASE_OWNERSHIP(tmp_key);
+ RELEASE_OWNERSHIP(tmp_val);
+ tmp_key = tmp_val = NULL;
+ } else {
+ // For existing keys, hashmap takes ownership of tmp_val.
+ // (It also gives up ownership of old_val.)
+ RELEASE_OWNERSHIP(tmp_val);
+ tmp_val = NULL;
+ }
+
+clean_up:
+ free(tmp_key);
+ free(tmp_val);
+ free(old_val);
+ int result = -errno;
+ errno = saved_errno;
+ return result;
+}
+
+int str_parms_add_int(struct str_parms *str_parms, const char *key, int value)
+{
+ char val_str[12];
+ int ret;
+
+ ret = snprintf(val_str, sizeof(val_str), "%d", value);
+ if (ret < 0)
+ return -EINVAL;
+
+ ret = str_parms_add_str(str_parms, key, val_str);
+ return ret;
+}
+
+int str_parms_add_float(struct str_parms *str_parms, const char *key,
+ float value)
+{
+ char val_str[23];
+ int ret;
+
+ ret = snprintf(val_str, sizeof(val_str), "%.10f", value);
+ if (ret < 0)
+ return -EINVAL;
+
+ ret = str_parms_add_str(str_parms, key, val_str);
+ return ret;
+}
+
+int str_parms_has_key(struct str_parms *str_parms, const char *key) {
+ return hashmapGet(str_parms->map, (void *)key) != NULL;
+}
+
+int str_parms_get_str(struct str_parms *str_parms, const char *key, char *val,
+ int len)
+{
+ // TODO: hashmapGet should take a const* key.
+ char* value = static_cast<char*>(hashmapGet(str_parms->map, (void*)key));
+ if (value)
+ return strlcpy(val, value, len);
+
+ return -ENOENT;
+}
+
+int str_parms_get_int(struct str_parms *str_parms, const char *key, int *val)
+{
+ char *end;
+
+ // TODO: hashmapGet should take a const* key.
+ char* value = static_cast<char*>(hashmapGet(str_parms->map, (void*)key));
+ if (!value)
+ return -ENOENT;
+
+ *val = (int)strtol(value, &end, 0);
+ if (*value != '\0' && *end == '\0')
+ return 0;
+
+ return -EINVAL;
+}
+
+int str_parms_get_float(struct str_parms *str_parms, const char *key,
+ float *val)
+{
+ float out;
+ char *end;
+
+ // TODO: hashmapGet should take a const* key.
+ char* value = static_cast<char*>(hashmapGet(str_parms->map, (void*)(key)));
+ if (!value)
+ return -ENOENT;
+
+ out = strtof(value, &end);
+ if (*value == '\0' || *end != '\0')
+ return -EINVAL;
+
+ *val = out;
+ return 0;
+}
+
+static bool combine_strings(void *key, void *value, void *context)
+{
+ char** old_str = static_cast<char**>(context);
+ char *new_str;
+ int ret;
+
+ ret = asprintf(&new_str, "%s%s%s=%s",
+ *old_str ? *old_str : "",
+ *old_str ? ";" : "",
+ (char *)key,
+ (char *)value);
+ if (*old_str)
+ free(*old_str);
+
+ if (ret >= 0) {
+ *old_str = new_str;
+ return true;
+ }
+
+ *old_str = NULL;
+ return false;
+}
+
+char *str_parms_to_str(struct str_parms *str_parms)
+{
+ char *str = NULL;
+
+ if (hashmapSize(str_parms->map) > 0)
+ hashmapForEach(str_parms->map, combine_strings, &str);
+ else
+ str = strdup("");
+ return str;
+}
+
+static bool dump_entry(void* key, void* value, void* /*context*/) {
+ ALOGI("key: '%s' value: '%s'\n", (char *)key, (char *)value);
+ return true;
+}
+
+void str_parms_dump(struct str_parms *str_parms)
+{
+ hashmapForEach(str_parms->map, dump_entry, str_parms);
+}
diff --git a/src/cutils/strlcpy.c b/src/cutils/strlcpy.c
new file mode 100644
index 0000000..c66246c
--- /dev/null
+++ b/src/cutils/strlcpy.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#if defined(__GLIBC__) || defined(_WIN32)
+
+#include <string.h>
+
+#include <cutils/memory.h>
+
+/* Implementation of strlcpy() for platforms that don't already have it. */
+
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+strlcpy(char *dst, const char *src, size_t siz)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0) {
+ while (--n != 0) {
+ if ((*d++ = *s++) == '\0')
+ break;
+ }
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
+
+#endif
diff --git a/src/cutils/threads.cpp b/src/cutils/threads.cpp
new file mode 100644
index 0000000..a7e6b2d
--- /dev/null
+++ b/src/cutils/threads.cpp
@@ -0,0 +1,111 @@
+/*
+** Copyright (C) 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <cutils/threads.h>
+
+// For gettid.
+#if defined(__APPLE__)
+#include "AvailabilityMacros.h" // For MAC_OS_X_VERSION_MAX_ALLOWED
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <unistd.h>
+#elif defined(__linux__) && !defined(__ANDROID__)
+#include <syscall.h>
+#include <unistd.h>
+#elif defined(_WIN32)
+#include <windows.h>
+#endif
+
+// No definition needed for Android because we'll just pick up bionic's copy.
+#ifndef __ANDROID__
+pid_t gettid() {
+#if defined(__APPLE__)
+ uint64_t tid;
+ pthread_threadid_np(NULL, &tid);
+ return tid;
+#elif defined(__linux__)
+ return syscall(__NR_gettid);
+#elif defined(_WIN32)
+ return GetCurrentThreadId();
+#endif
+}
+#endif // __ANDROID__
+
+#if !defined(_WIN32)
+
+void* thread_store_get( thread_store_t* store )
+{
+ if (!store->has_tls)
+ return NULL;
+
+ return pthread_getspecific( store->tls );
+}
+
+extern void thread_store_set( thread_store_t* store,
+ void* value,
+ thread_store_destruct_t destroy)
+{
+ pthread_mutex_lock( &store->lock );
+ if (!store->has_tls) {
+ if (pthread_key_create( &store->tls, destroy) != 0) {
+ pthread_mutex_unlock(&store->lock);
+ return;
+ }
+ store->has_tls = 1;
+ }
+ pthread_mutex_unlock( &store->lock );
+
+ pthread_setspecific( store->tls, value );
+}
+
+#else /* !defined(_WIN32) */
+void* thread_store_get( thread_store_t* store )
+{
+ if (!store->has_tls)
+ return NULL;
+
+ return (void*) TlsGetValue( store->tls );
+}
+
+void thread_store_set( thread_store_t* store,
+ void* value,
+ thread_store_destruct_t /*destroy*/ )
+{
+ /* XXX: can't use destructor on thread exit */
+ if (!store->lock_init) {
+ store->lock_init = -1;
+ InitializeCriticalSection( &store->lock );
+ store->lock_init = -2;
+ } else while (store->lock_init != -2) {
+ Sleep(10); /* 10ms */
+ }
+
+ EnterCriticalSection( &store->lock );
+ if (!store->has_tls) {
+ store->tls = TlsAlloc();
+ if (store->tls == TLS_OUT_OF_INDEXES) {
+ LeaveCriticalSection( &store->lock );
+ return;
+ }
+ store->has_tls = 1;
+ }
+ LeaveCriticalSection( &store->lock );
+
+ TlsSetValue( store->tls, value );
+}
+#endif /* !defined(_WIN32) */
diff --git a/src/primitives.c b/src/primitives.c
new file mode 100644
index 0000000..8e92fdf
--- /dev/null
+++ b/src/primitives.c
@@ -0,0 +1,610 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string.h>
+#include <cutils/bitops.h> /* for popcount() */
+#include <audio_utils/primitives.h>
+#include "private/private.h"
+
+void ditherAndClamp(int32_t *out, const int32_t *sums, size_t pairs)
+{
+ for (; pairs > 0; --pairs) {
+ const int32_t l = clamp16(*sums++ >> 12);
+ const int32_t r = clamp16(*sums++ >> 12);
+ *out++ = (r << 16) | (l & 0xFFFF);
+ }
+}
+
+void memcpy_to_i16_from_q4_27(int16_t *dst, const int32_t *src, size_t count)
+{
+ for (; count > 0; --count) {
+ *dst++ = clamp16(*src++ >> 12);
+ }
+}
+
+void memcpy_to_i16_from_u8(int16_t *dst, const uint8_t *src, size_t count)
+{
+ dst += count;
+ src += count;
+ for (; count > 0; --count) {
+ *--dst = (int16_t)(*--src - 0x80) << 8;
+ }
+}
+
+void memcpy_to_u8_from_i16(uint8_t *dst, const int16_t *src, size_t count)
+{
+ for (; count > 0; --count) {
+ *dst++ = (*src++ >> 8) + 0x80;
+ }
+}
+
+void memcpy_to_u8_from_float(uint8_t *dst, const float *src, size_t count)
+{
+ for (; count > 0; --count) {
+ *dst++ = clamp8_from_float(*src++);
+ }
+}
+
+void memcpy_to_i16_from_i32(int16_t *dst, const int32_t *src, size_t count)
+{
+ for (; count > 0; --count) {
+ *dst++ = *src++ >> 16;
+ }
+}
+
+void memcpy_to_i16_from_float(int16_t *dst, const float *src, size_t count)
+{
+ for (; count > 0; --count) {
+ *dst++ = clamp16_from_float(*src++);
+ }
+}
+
+void memcpy_to_float_from_q4_27(float *dst, const int32_t *src, size_t count)
+{
+ for (; count > 0; --count) {
+ *dst++ = float_from_q4_27(*src++);
+ }
+}
+
+void memcpy_to_float_from_i16(float *dst, const int16_t *src, size_t count)
+{
+ dst += count;
+ src += count;
+ for (; count > 0; --count) {
+ *--dst = float_from_i16(*--src);
+ }
+}
+
+void memcpy_to_float_from_u8(float *dst, const uint8_t *src, size_t count)
+{
+ dst += count;
+ src += count;
+ for (; count > 0; --count) {
+ *--dst = float_from_u8(*--src);
+ }
+}
+
+void memcpy_to_float_from_p24(float *dst, const uint8_t *src, size_t count)
+{
+ dst += count;
+ src += count * 3;
+ for (; count > 0; --count) {
+ src -= 3;
+ *--dst = float_from_p24(src);
+ }
+}
+
+void memcpy_to_i16_from_p24(int16_t *dst, const uint8_t *src, size_t count)
+{
+ for (; count > 0; --count) {
+#if HAVE_BIG_ENDIAN
+ *dst++ = src[1] | (src[0] << 8);
+#else
+ *dst++ = src[1] | (src[2] << 8);
+#endif
+ src += 3;
+ }
+}
+
+void memcpy_to_i32_from_p24(int32_t *dst, const uint8_t *src, size_t count)
+{
+ dst += count;
+ src += count * 3;
+ for (; count > 0; --count) {
+ src -= 3;
+#if HAVE_BIG_ENDIAN
+ *--dst = (src[2] << 8) | (src[1] << 16) | (src[0] << 24);
+#else
+ *--dst = (src[0] << 8) | (src[1] << 16) | (src[2] << 24);
+#endif
+ }
+}
+
+void memcpy_to_p24_from_i16(uint8_t *dst, const int16_t *src, size_t count)
+{
+ dst += count * 3;
+ src += count;
+ for (; count > 0; --count) {
+ dst -= 3;
+ const int16_t sample = *--src;
+#if HAVE_BIG_ENDIAN
+ dst[0] = sample >> 8;
+ dst[1] = sample;
+ dst[2] = 0;
+#else
+ dst[0] = 0;
+ dst[1] = sample;
+ dst[2] = sample >> 8;
+#endif
+ }
+}
+
+void memcpy_to_p24_from_float(uint8_t *dst, const float *src, size_t count)
+{
+ for (; count > 0; --count) {
+ int32_t ival = clamp24_from_float(*src++);
+
+#if HAVE_BIG_ENDIAN
+ *dst++ = ival >> 16;
+ *dst++ = ival >> 8;
+ *dst++ = ival;
+#else
+ *dst++ = ival;
+ *dst++ = ival >> 8;
+ *dst++ = ival >> 16;
+#endif
+ }
+}
+
+void memcpy_to_p24_from_q8_23(uint8_t *dst, const int32_t *src, size_t count)
+{
+ for (; count > 0; --count) {
+ int32_t ival = clamp24_from_q8_23(*src++);
+
+#if HAVE_BIG_ENDIAN
+ *dst++ = ival >> 16;
+ *dst++ = ival >> 8;
+ *dst++ = ival;
+#else
+ *dst++ = ival;
+ *dst++ = ival >> 8;
+ *dst++ = ival >> 16;
+#endif
+ }
+}
+
+void memcpy_to_p24_from_i32(uint8_t *dst, const int32_t *src, size_t count)
+{
+ for (; count > 0; --count) {
+ int32_t ival = *src++ >> 8;
+
+#if HAVE_BIG_ENDIAN
+ *dst++ = ival >> 16;
+ *dst++ = ival >> 8;
+ *dst++ = ival;
+#else
+ *dst++ = ival;
+ *dst++ = ival >> 8;
+ *dst++ = ival >> 16;
+#endif
+ }
+}
+
+void memcpy_to_q8_23_from_i16(int32_t *dst, const int16_t *src, size_t count)
+{
+ dst += count;
+ src += count;
+ for (; count > 0; --count) {
+ *--dst = (int32_t)*--src << 8;
+ }
+}
+
+void memcpy_to_q8_23_from_float_with_clamp(int32_t *dst, const float *src, size_t count)
+{
+ for (; count > 0; --count) {
+ *dst++ = clamp24_from_float(*src++);
+ }
+}
+
+void memcpy_to_q8_23_from_p24(int32_t *dst, const uint8_t *src, size_t count)
+{
+ dst += count;
+ src += count * 3;
+ for (; count > 0; --count) {
+ src -= 3;
+#if HAVE_BIG_ENDIAN
+ *--dst = (int8_t)src[0] << 16 | src[1] << 8 | src[2];
+#else
+ *--dst = (int8_t)src[2] << 16 | src[1] << 8 | src[0];
+#endif
+ }
+}
+
+void memcpy_to_q4_27_from_float(int32_t *dst, const float *src, size_t count)
+{
+ for (; count > 0; --count) {
+ *dst++ = clampq4_27_from_float(*src++);
+ }
+}
+
+void memcpy_to_i16_from_q8_23(int16_t *dst, const int32_t *src, size_t count)
+{
+ for (; count > 0; --count) {
+ *dst++ = clamp16(*src++ >> 8);
+ }
+}
+
+void memcpy_to_float_from_q8_23(float *dst, const int32_t *src, size_t count)
+{
+ for (; count > 0; --count) {
+ *dst++ = float_from_q8_23(*src++);
+ }
+}
+
+void memcpy_to_i32_from_i16(int32_t *dst, const int16_t *src, size_t count)
+{
+ dst += count;
+ src += count;
+ for (; count > 0; --count) {
+ *--dst = (int32_t)*--src << 16;
+ }
+}
+
+void memcpy_to_i32_from_float(int32_t *dst, const float *src, size_t count)
+{
+ for (; count > 0; --count) {
+ *dst++ = clamp32_from_float(*src++);
+ }
+}
+
+void memcpy_to_float_from_i32(float *dst, const int32_t *src, size_t count)
+{
+ for (; count > 0; --count) {
+ *dst++ = float_from_i32(*src++);
+ }
+}
+
+void memcpy_to_float_from_float_with_clamping(float *dst, const float *src, size_t count,
+ float absMax) {
+ // Note: using NEON intrinsics (vminq_f32, vld1q_f32...) did NOT accelerate
+ // the function when benchmarked. The compiler already vectorize using FMINNM f32x4 & similar.
+ // Note: clamping induce a ~20% overhead compared to memcpy for count in [64, 512]
+ // See primitives_benchmark
+ for (; count > 0; --count) {
+ const float sample = *src++;
+ *dst++ = fmax(-absMax, fmin(absMax, sample));
+ }
+}
+
+void downmix_to_mono_i16_from_stereo_i16(int16_t *dst, const int16_t *src, size_t count)
+{
+ for (; count > 0; --count) {
+ *dst++ = (int16_t)(((int32_t)src[0] + (int32_t)src[1]) >> 1);
+ src += 2;
+ }
+}
+
+void upmix_to_stereo_i16_from_mono_i16(int16_t *dst, const int16_t *src, size_t count)
+{
+ dst += count * 2;
+ src += count;
+ for (; count > 0; --count) {
+ const int32_t temp = *--src;
+ dst -= 2;
+ dst[0] = temp;
+ dst[1] = temp;
+ }
+}
+
+void downmix_to_mono_float_from_stereo_float(float *dst, const float *src, size_t frames)
+{
+ for (; frames > 0; --frames) {
+ *dst++ = (src[0] + src[1]) * 0.5;
+ src += 2;
+ }
+}
+
+void upmix_to_stereo_float_from_mono_float(float *dst, const float *src, size_t frames)
+{
+ dst += frames * 2;
+ src += frames;
+ for (; frames > 0; --frames) {
+ const float temp = *--src;
+ dst -= 2;
+ dst[0] = temp;
+ dst[1] = temp;
+ }
+}
+
+size_t nonZeroMono32(const int32_t *samples, size_t count)
+{
+ size_t nonZero = 0;
+ for (; count > 0; --count) {
+ nonZero += *samples++ != 0;
+ }
+ return nonZero;
+}
+
+size_t nonZeroMono16(const int16_t *samples, size_t count)
+{
+ size_t nonZero = 0;
+ for (; count > 0; --count) {
+ nonZero += *samples++ != 0;
+ }
+ return nonZero;
+}
+
+size_t nonZeroStereo32(const int32_t *frames, size_t count)
+{
+ size_t nonZero = 0;
+ for (; count > 0; --count) {
+ nonZero += frames[0] != 0 || frames[1] != 0;
+ frames += 2;
+ }
+ return nonZero;
+}
+
+size_t nonZeroStereo16(const int16_t *frames, size_t count)
+{
+ size_t nonZero = 0;
+ for (; count > 0; --count) {
+ nonZero += frames[0] != 0 || frames[1] != 0;
+ frames += 2;
+ }
+ return nonZero;
+}
+
+/*
+ * C macro to do channel mask copying independent of dst/src sample type.
+ * Don't pass in any expressions for the macro arguments here.
+ */
+#define copy_frame_by_mask(dst, dmask, src, smask, count, zero) \
+{ \
+ uint32_t bit, ormask; \
+ for (; (count) > 0; --(count)) { \
+ ormask = (dmask) | (smask); \
+ while (ormask) { \
+ bit = ormask & -ormask; /* get lowest bit */ \
+ ormask ^= bit; /* remove lowest bit */ \
+ if ((dmask) & bit) { \
+ *(dst)++ = (smask) & bit ? *(src)++ : (zero); \
+ } else { /* source channel only */ \
+ ++(src); \
+ } \
+ } \
+ } \
+}
+
+void memcpy_by_channel_mask(void *dst, uint32_t dst_mask,
+ const void *src, uint32_t src_mask, size_t sample_size, size_t count)
+{
+#if 0
+ /* alternate way of handling memcpy_by_channel_mask by using the idxary */
+ int8_t idxary[32];
+ uint32_t src_channels = popcount(src_mask);
+ uint32_t dst_channels =
+ memcpy_by_index_array_initialization(idxary, 32, dst_mask, src_mask);
+
+ memcpy_by_idxary(dst, dst_channels, src, src_channels, idxary, sample_size, count);
+#else
+ if (dst_mask == src_mask) {
+ memcpy(dst, src, sample_size * popcount(dst_mask) * count);
+ return;
+ }
+ switch (sample_size) {
+ case 1: {
+ uint8_t *udst = (uint8_t*)dst;
+ const uint8_t *usrc = (const uint8_t*)src;
+
+ copy_frame_by_mask(udst, dst_mask, usrc, src_mask, count, 0);
+ } break;
+ case 2: {
+ uint16_t *udst = (uint16_t*)dst;
+ const uint16_t *usrc = (const uint16_t*)src;
+
+ copy_frame_by_mask(udst, dst_mask, usrc, src_mask, count, 0);
+ } break;
+ case 3: { /* could be slow. use a struct to represent 3 bytes of data. */
+ uint8x3_t *udst = (uint8x3_t*)dst;
+ const uint8x3_t *usrc = (const uint8x3_t*)src;
+ static const uint8x3_t zero; /* tricky - we use this to zero out a sample */
+
+ copy_frame_by_mask(udst, dst_mask, usrc, src_mask, count, zero);
+ } break;
+ case 4: {
+ uint32_t *udst = (uint32_t*)dst;
+ const uint32_t *usrc = (const uint32_t*)src;
+
+ copy_frame_by_mask(udst, dst_mask, usrc, src_mask, count, 0);
+ } break;
+ default:
+ abort(); /* illegal value */
+ break;
+ }
+#endif
+}
+
+/*
+ * C macro to do copying by index array, to rearrange samples
+ * within a frame. This is independent of src/dst sample type.
+ * Don't pass in any expressions for the macro arguments here.
+ */
+#define copy_frame_by_idx(dst, dst_channels, src, src_channels, idxary, count, zero) \
+{ \
+ unsigned i; \
+ int index; \
+ for (; (count) > 0; --(count)) { \
+ for (i = 0; i < (dst_channels); ++i) { \
+ index = (idxary)[i]; \
+ *(dst)++ = index < 0 ? (zero) : (src)[index]; \
+ } \
+ (src) += (src_channels); \
+ } \
+}
+
+void memcpy_by_index_array(void *dst, uint32_t dst_channels,
+ const void *src, uint32_t src_channels,
+ const int8_t *idxary, size_t sample_size, size_t count)
+{
+ switch (sample_size) {
+ case 1: {
+ uint8_t *udst = (uint8_t*)dst;
+ const uint8_t *usrc = (const uint8_t*)src;
+
+ copy_frame_by_idx(udst, dst_channels, usrc, src_channels, idxary, count, 0);
+ } break;
+ case 2: {
+ uint16_t *udst = (uint16_t*)dst;
+ const uint16_t *usrc = (const uint16_t*)src;
+
+ copy_frame_by_idx(udst, dst_channels, usrc, src_channels, idxary, count, 0);
+ } break;
+ case 3: { /* could be slow. use a struct to represent 3 bytes of data. */
+ uint8x3_t *udst = (uint8x3_t*)dst;
+ const uint8x3_t *usrc = (const uint8x3_t*)src;
+ static const uint8x3_t zero;
+
+ copy_frame_by_idx(udst, dst_channels, usrc, src_channels, idxary, count, zero);
+ } break;
+ case 4: {
+ uint32_t *udst = (uint32_t*)dst;
+ const uint32_t *usrc = (const uint32_t*)src;
+
+ copy_frame_by_idx(udst, dst_channels, usrc, src_channels, idxary, count, 0);
+ } break;
+ default:
+ abort(); /* illegal value */
+ break;
+ }
+}
+
+size_t memcpy_by_index_array_initialization(int8_t *idxary, size_t idxcount,
+ uint32_t dst_mask, uint32_t src_mask)
+{
+ size_t n = 0;
+ int srcidx = 0;
+ uint32_t bit, ormask = src_mask | dst_mask;
+
+ while (ormask && n < idxcount) {
+ bit = ormask & -ormask; /* get lowest bit */
+ ormask ^= bit; /* remove lowest bit */
+ if (src_mask & dst_mask & bit) { /* matching channel */
+ idxary[n++] = srcidx++;
+ } else if (src_mask & bit) { /* source channel only */
+ ++srcidx;
+ } else { /* destination channel only */
+ idxary[n++] = -1;
+ }
+ }
+ return n + popcount(ormask & dst_mask);
+}
+
+size_t memcpy_by_index_array_initialization_src_index(int8_t *idxary, size_t idxcount,
+ uint32_t dst_mask, uint32_t src_mask) {
+ size_t dst_count = popcount(dst_mask);
+ if (idxcount == 0) {
+ return dst_count;
+ }
+ if (dst_count > idxcount) {
+ dst_count = idxcount;
+ }
+
+ size_t src_idx, dst_idx;
+ for (src_idx = 0, dst_idx = 0; dst_idx < dst_count; ++dst_idx) {
+ if (src_mask & 1) {
+ idxary[dst_idx] = src_idx++;
+ } else {
+ idxary[dst_idx] = -1;
+ }
+ src_mask >>= 1;
+ }
+ return dst_idx;
+}
+
+size_t memcpy_by_index_array_initialization_dst_index(int8_t *idxary, size_t idxcount,
+ uint32_t dst_mask, uint32_t src_mask) {
+ size_t src_idx, dst_idx;
+ size_t dst_count = __builtin_popcount(dst_mask);
+ size_t src_count = __builtin_popcount(src_mask);
+ if (idxcount == 0) {
+ return dst_count;
+ }
+ if (dst_count > idxcount) {
+ dst_count = idxcount;
+ }
+ for (src_idx = 0, dst_idx = 0; dst_idx < dst_count; ++src_idx) {
+ if (dst_mask & 1) {
+ idxary[dst_idx++] = src_idx < src_count ? (signed)src_idx : -1;
+ }
+ dst_mask >>= 1;
+ }
+ return dst_idx;
+}
+
+void accumulate_i16(int16_t *dst, const int16_t *src, size_t count) {
+ while (count--) {
+ *dst = clamp16((int32_t)*dst + *src++);
+ ++dst;
+ }
+}
+
+void accumulate_u8(uint8_t *dst, const uint8_t *src, size_t count) {
+ int32_t sum;
+ for (; count > 0; --count) {
+ // 8-bit samples are centered around 0x80.
+ sum = *dst + *src++ - 0x80;
+ // Clamp to [0, 0xff].
+ *dst++ = (sum & 0x100) ? (~sum >> 9) : sum;
+ }
+}
+
+void accumulate_p24(uint8_t *dst, const uint8_t *src, size_t count) {
+ for (; count > 0; --count) {
+ // Unpack.
+ int32_t dst_q8_23 = 0;
+ int32_t src_q8_23 = 0;
+ memcpy_to_q8_23_from_p24(&dst_q8_23, dst, 1);
+ memcpy_to_q8_23_from_p24(&src_q8_23, src, 1);
+
+ // Accumulate and overwrite.
+ dst_q8_23 += src_q8_23;
+ memcpy_to_p24_from_q8_23(dst, &dst_q8_23, 1);
+
+ // Move on to next sample.
+ dst += 3;
+ src += 3;
+ }
+}
+
+void accumulate_q8_23(int32_t *dst, const int32_t *src, size_t count) {
+ for (; count > 0; --count) {
+ *dst = clamp24_from_q8_23(*dst + *src++);
+ ++dst;
+ }
+}
+
+void accumulate_i32(int32_t *dst, const int32_t *src, size_t count) {
+ for (; count > 0; --count) {
+ *dst = clamp32((int64_t)*dst + *src++);
+ ++dst;
+ }
+}
+
+void accumulate_float(float *dst, const float *src, size_t count) {
+ for (; count > 0; --count) {
+ *dst++ += *src++;
+ }
+}
diff --git a/src/resampler.c b/src/resampler.c
new file mode 100644
index 0000000..43ba895
--- /dev/null
+++ b/src/resampler.c
@@ -0,0 +1,265 @@
+/*
+** Copyright 2011, The Android Open-Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "resampler"
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <cutils/log.h>
+
+#include <system/audio.h>
+#include <audio_utils/resampler.h>
+#include <speex/speex_resampler.h>
+
+struct resampler {
+ struct resampler_itfe itfe;
+ SpeexResamplerState *speex_resampler; // handle on speex resampler
+ struct resampler_buffer_provider *provider; // buffer provider installed by client
+ uint32_t in_sample_rate; // input sampling rate in Hz
+ uint32_t out_sample_rate; // output sampling rate in Hz
+ uint32_t channel_count; // number of channels (interleaved)
+ int16_t *in_buf; // input buffer
+ size_t in_buf_size; // input buffer size
+ size_t frames_in; // number of frames in input buffer
+ size_t frames_rq; // cached number of output frames
+ size_t frames_needed; // minimum number of input frames to produce
+ // frames_rq output frames
+ int32_t speex_delay_ns; // delay introduced by speex resampler in ns
+};
+
+
+//------------------------------------------------------------------------------
+// speex based resampler
+//------------------------------------------------------------------------------
+
+static void resampler_reset(struct resampler_itfe *resampler)
+{
+ struct resampler *rsmp = (struct resampler *)resampler;
+
+ rsmp->frames_in = 0;
+ rsmp->frames_rq = 0;
+
+ if (rsmp != NULL && rsmp->speex_resampler != NULL) {
+ speex_resampler_reset_mem(rsmp->speex_resampler);
+ }
+}
+
+static int32_t resampler_delay_ns(struct resampler_itfe *resampler)
+{
+ struct resampler *rsmp = (struct resampler *)resampler;
+
+ int32_t delay = (int32_t)((1000000000 * (int64_t)rsmp->frames_in) / rsmp->in_sample_rate);
+ delay += rsmp->speex_delay_ns;
+
+ return delay;
+}
+
+// outputs a number of frames less or equal to *outFrameCount and updates *outFrameCount
+// with the actual number of frames produced.
+int resampler_resample_from_provider(struct resampler_itfe *resampler,
+ int16_t *out,
+ size_t *outFrameCount)
+{
+ struct resampler *rsmp = (struct resampler *)resampler;
+
+ if (rsmp == NULL || out == NULL || outFrameCount == NULL) {
+ return -EINVAL;
+ }
+ if (rsmp->provider == NULL) {
+ *outFrameCount = 0;
+ return -ENOSYS;
+ }
+
+ size_t framesRq = *outFrameCount;
+ // update and cache the number of frames needed at the input sampling rate to produce
+ // the number of frames requested at the output sampling rate
+ if (framesRq != rsmp->frames_rq) {
+ rsmp->frames_needed = (framesRq * rsmp->in_sample_rate) / rsmp->out_sample_rate + 1;
+ rsmp->frames_rq = framesRq;
+ }
+
+ size_t framesWr = 0;
+ spx_uint32_t inFrames = 0;
+ while (framesWr < framesRq) {
+ if (rsmp->frames_in < rsmp->frames_needed) {
+ // make sure that the number of frames present in rsmp->in_buf (rsmp->frames_in) is at
+ // least the number of frames needed to produce the number of frames requested at
+ // the output sampling rate
+ if (rsmp->in_buf_size < rsmp->frames_needed) {
+ rsmp->in_buf_size = rsmp->frames_needed;
+ rsmp->in_buf = (int16_t *)realloc(rsmp->in_buf,
+ rsmp->in_buf_size * rsmp->channel_count * sizeof(int16_t));
+ }
+ struct resampler_buffer buf;
+ buf.frame_count = rsmp->frames_needed - rsmp->frames_in;
+ rsmp->provider->get_next_buffer(rsmp->provider, &buf);
+ if (buf.raw == NULL) {
+ break;
+ }
+ memcpy(rsmp->in_buf + rsmp->frames_in * rsmp->channel_count,
+ buf.raw,
+ buf.frame_count * rsmp->channel_count * sizeof(int16_t));
+ rsmp->frames_in += buf.frame_count;
+ rsmp->provider->release_buffer(rsmp->provider, &buf);
+ }
+
+ spx_uint32_t outFrames = framesRq - framesWr;
+ inFrames = rsmp->frames_in;
+ if (rsmp->channel_count == 1) {
+ speex_resampler_process_int(rsmp->speex_resampler,
+ 0,
+ rsmp->in_buf,
+ &inFrames,
+ out + framesWr,
+ &outFrames);
+ } else {
+ speex_resampler_process_interleaved_int(rsmp->speex_resampler,
+ rsmp->in_buf,
+ &inFrames,
+ out + framesWr * rsmp->channel_count,
+ &outFrames);
+ }
+ framesWr += outFrames;
+ rsmp->frames_in -= inFrames;
+ ALOGW_IF((framesWr != framesRq) && (rsmp->frames_in != 0),
+ "ReSampler::resample() remaining %zu frames in and %zu frames out",
+ rsmp->frames_in, (framesRq - framesWr));
+ }
+ if (rsmp->frames_in) {
+ memmove(rsmp->in_buf,
+ rsmp->in_buf + inFrames * rsmp->channel_count,
+ rsmp->frames_in * rsmp->channel_count * sizeof(int16_t));
+ }
+ *outFrameCount = framesWr;
+
+ return 0;
+}
+
+int resampler_resample_from_input(struct resampler_itfe *resampler,
+ int16_t *in,
+ size_t *inFrameCount,
+ int16_t *out,
+ size_t *outFrameCount)
+{
+ struct resampler *rsmp = (struct resampler *)resampler;
+
+ if (rsmp == NULL || in == NULL || inFrameCount == NULL ||
+ out == NULL || outFrameCount == NULL) {
+ return -EINVAL;
+ }
+ if (rsmp->provider != NULL) {
+ *outFrameCount = 0;
+ return -ENOSYS;
+ }
+
+ if (rsmp->channel_count == 1) {
+ speex_resampler_process_int(rsmp->speex_resampler,
+ 0,
+ in,
+ (spx_uint32_t *)inFrameCount,
+ out,
+ (spx_uint32_t *)outFrameCount);
+ } else {
+ speex_resampler_process_interleaved_int(rsmp->speex_resampler,
+ in,
+ (spx_uint32_t *)inFrameCount,
+ out,
+ (spx_uint32_t *)outFrameCount);
+ }
+
+ ALOGV("resampler_resample_from_input() DONE in %zu out %zu", *inFrameCount, *outFrameCount);
+
+ return 0;
+}
+
+int create_resampler(uint32_t inSampleRate,
+ uint32_t outSampleRate,
+ uint32_t channelCount,
+ uint32_t quality,
+ struct resampler_buffer_provider* provider,
+ struct resampler_itfe **resampler)
+{
+ int error;
+ struct resampler *rsmp;
+
+ ALOGV("create_resampler() In SR %d Out SR %d channels %d",
+ inSampleRate, outSampleRate, channelCount);
+
+ if (resampler == NULL) {
+ return -EINVAL;
+ }
+
+ *resampler = NULL;
+
+ if (quality <= RESAMPLER_QUALITY_MIN || quality >= RESAMPLER_QUALITY_MAX) {
+ return -EINVAL;
+ }
+
+ rsmp = (struct resampler *)calloc(1, sizeof(struct resampler));
+
+ rsmp->speex_resampler = speex_resampler_init(channelCount,
+ inSampleRate,
+ outSampleRate,
+ quality,
+ &error);
+ if (rsmp->speex_resampler == NULL) {
+ ALOGW("ReSampler: Cannot create speex resampler: %s", speex_resampler_strerror(error));
+ free(rsmp);
+ return -ENODEV;
+ }
+
+ rsmp->itfe.reset = resampler_reset;
+ rsmp->itfe.resample_from_provider = resampler_resample_from_provider;
+ rsmp->itfe.resample_from_input = resampler_resample_from_input;
+ rsmp->itfe.delay_ns = resampler_delay_ns;
+
+ rsmp->provider = provider;
+ rsmp->in_sample_rate = inSampleRate;
+ rsmp->out_sample_rate = outSampleRate;
+ rsmp->channel_count = channelCount;
+ rsmp->in_buf = NULL;
+ rsmp->in_buf_size = 0;
+
+ resampler_reset(&rsmp->itfe);
+
+ int frames = speex_resampler_get_input_latency(rsmp->speex_resampler);
+ rsmp->speex_delay_ns = (int32_t)((1000000000 * (int64_t)frames) / rsmp->in_sample_rate);
+ frames = speex_resampler_get_output_latency(rsmp->speex_resampler);
+ rsmp->speex_delay_ns += (int32_t)((1000000000 * (int64_t)frames) / rsmp->out_sample_rate);
+
+ *resampler = &rsmp->itfe;
+ ALOGV("create_resampler() DONE rsmp %p &rsmp->itfe %p speex %p",
+ rsmp, &rsmp->itfe, rsmp->speex_resampler);
+ return 0;
+}
+
+void release_resampler(struct resampler_itfe *resampler)
+{
+ struct resampler *rsmp = (struct resampler *)resampler;
+
+ if (rsmp == NULL) {
+ return;
+ }
+
+ free(rsmp->in_buf);
+
+ if (rsmp->speex_resampler != NULL) {
+ speex_resampler_destroy(rsmp->speex_resampler);
+ }
+ free(rsmp);
+}
diff --git a/src/spdif/AC3FrameScanner.cpp b/src/spdif/AC3FrameScanner.cpp
new file mode 100644
index 0000000..6c92099
--- /dev/null
+++ b/src/spdif/AC3FrameScanner.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioSPDIF"
+
+#include <string.h>
+
+#include <cutils/log.h>
+#include <audio_utils/spdif/FrameScanner.h>
+
+#include "AC3FrameScanner.h"
+
+namespace android {
+
+// These values are from the AC3 spec. Do not change them.
+
+const uint8_t AC3FrameScanner::kSyncBytes[] = { 0x0B, 0x77 };
+
+const uint16_t AC3FrameScanner::kAC3SampleRateTable[AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES]
+ = { 48000, 44100, 32000 };
+
+// Table contains number of 16-bit words in an AC3 frame.
+// From AC3 spec table 5.13
+const uint16_t AC3FrameScanner::kAC3FrameSizeTable[AC3_NUM_FRAME_SIZE_TABLE_ENTRIES]
+ [AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES] = {
+ { 64, 69, 96 },
+ { 64, 70, 96 },
+ { 80, 87, 120 },
+ { 80, 88, 120 },
+ { 96, 104, 144 },
+ { 96, 105, 144 },
+ { 112, 121, 168 },
+ { 112, 122, 168 },
+ { 128, 139, 192 },
+ { 128, 140, 192 },
+ { 160, 174, 240 },
+ { 160, 175, 240 },
+ { 192, 208, 288 },
+ { 192, 209, 288 },
+ { 224, 243, 336 },
+ { 224, 244, 336 },
+ { 256, 278, 384 },
+ { 256, 279, 384 },
+ { 320, 348, 480 },
+ { 320, 349, 480 },
+ { 384, 417, 576 },
+ { 384, 418, 576 },
+ { 448, 487, 672 },
+ { 448, 488, 672 },
+ { 512, 557, 768 },
+ { 512, 558, 768 },
+ { 640, 696, 960 },
+ { 640, 697, 960 },
+ { 768, 835, 1152 },
+ { 768, 836, 1152 },
+ { 896, 975, 1344 },
+ { 896, 976, 1344 },
+ { 1024, 1114, 1536 },
+ { 1024, 1115, 1536 },
+ { 1152, 1253, 1728 },
+ { 1152, 1254, 1728 },
+ { 1280, 1393, 1920 },
+ { 1280, 1394, 1920 }
+};
+
+const uint16_t AC3FrameScanner::kEAC3ReducedSampleRateTable[AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES]
+ = { 24000, 22050, 16000 };
+
+const uint16_t
+ AC3FrameScanner::kEAC3BlocksPerFrameTable[EAC3_NUM_BLOCKS_PER_FRAME_TABLE_ENTRIES]
+ = { 1, 2, 3, 6 };
+
+// Defined in IEC61937-2
+#define SPDIF_DATA_TYPE_AC3 1
+#define SPDIF_DATA_TYPE_E_AC3 21
+#define AC3_STREAM_TYPE_0 0
+#define AC3_STREAM_TYPE_1 1
+#define AC3_STREAM_TYPE_2 2
+// -----------------------------------------------------------------------------
+
+// Scanner for AC3 byte streams.
+AC3FrameScanner::AC3FrameScanner(audio_format_t format)
+ : FrameScanner(SPDIF_DATA_TYPE_AC3,
+ AC3FrameScanner::kSyncBytes,
+ sizeof(AC3FrameScanner::kSyncBytes), 6)
+ , mStreamType(0)
+ , mSubstreamID(0)
+ , mFormat(format)
+{
+ mAudioBlocksPerSyncFrame = 6;
+ memset(mSubstreamBlockCounts, 0, sizeof(mSubstreamBlockCounts));
+}
+
+AC3FrameScanner::~AC3FrameScanner()
+{
+}
+
+int AC3FrameScanner::getSampleFramesPerSyncFrame() const
+{
+ return mRateMultiplier
+ * AC3_MAX_BLOCKS_PER_SYNC_FRAME_BLOCK * AC3_PCM_FRAMES_PER_BLOCK;
+}
+
+void AC3FrameScanner::resetBurst()
+{
+ for (int i = 0; i < EAC3_MAX_SUBSTREAMS; i++) {
+ if (mSubstreamBlockCounts[i] >= AC3_MAX_BLOCKS_PER_SYNC_FRAME_BLOCK) {
+ mSubstreamBlockCounts[i] -= AC3_MAX_BLOCKS_PER_SYNC_FRAME_BLOCK;
+ } else if (mSubstreamBlockCounts[i] > 0) {
+ ALOGW("EAC3 substream[%d] has only %d audio blocks!",
+ i, mSubstreamBlockCounts[i]);
+ mSubstreamBlockCounts[i] = 0;
+ }
+ }
+}
+
+// Per IEC 61973-3:5.3.3, for E-AC3 burst-length shall be in bytes.
+uint16_t AC3FrameScanner::convertBytesToLengthCode(uint16_t numBytes) const
+{
+ return (mDataType == SPDIF_DATA_TYPE_E_AC3) ? numBytes : numBytes * 8;
+}
+
+// per IEC 61973-3 Paragraph 5.3.3
+// We have to send 6 audio blocks on all active substreams.
+// Substream zero must be the first.
+// We don't know if we have all the blocks we need until we see
+// the 7th block of substream#0.
+bool AC3FrameScanner::isFirstInBurst()
+{
+ if (mDataType == SPDIF_DATA_TYPE_E_AC3) {
+ if (((mStreamType == AC3_STREAM_TYPE_0)
+ || (mStreamType == AC3_STREAM_TYPE_2))
+ && (mSubstreamID == 0)
+ // The ">" is intentional. We have to see the beginning
+ // of the block in the next burst before we can send
+ // the current burst.
+ && (mSubstreamBlockCounts[0] > AC3_MAX_BLOCKS_PER_SYNC_FRAME_BLOCK)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AC3FrameScanner::isLastInBurst()
+{
+ // For EAC3 we don't know if we are the end until we see a
+ // frame that must be at the beginning. See isFirstInBurst().
+ return (mDataType != SPDIF_DATA_TYPE_E_AC3); // Just one AC3 frame per burst.
+}
+
+// TODO Use BitFieldParser
+
+// Parse AC3 header.
+// Detect whether the stream is AC3 or EAC3. Extract data depending on type.
+//
+// @return true if valid
+bool AC3FrameScanner::parseHeader()
+{
+ // Interpret bsid based on paragraph E2.3.1.6 of EAC3 spec.
+ uint32_t bsid = mHeaderBuffer[5] >> 3; // bitstream ID
+ // Check BSID to see if this is EAC3 or regular AC3.
+ // These arbitrary BSID numbers do not have any names in the spec.
+ if ((bsid > 10) && (bsid <= 16)) {
+ mDataType = SPDIF_DATA_TYPE_E_AC3;
+ } else if (bsid <= 8) {
+ mDataType = SPDIF_DATA_TYPE_AC3;
+ } else {
+ ALOGW("AC3 bsid = %d not supported", bsid);
+ return false;
+ }
+
+ // bitstream mode, main, commentary, etc.
+ uint32_t bsmod = mHeaderBuffer[5] & 7;
+ mDataTypeInfo = bsmod; // as per IEC61937-3, table 3.
+
+ // The names fscod, frmsiz are from the AC3 spec.
+ uint32_t fscod = mHeaderBuffer[4] >> 6;
+ if (mDataType == SPDIF_DATA_TYPE_E_AC3) {
+ mStreamType = mHeaderBuffer[2] >> 6; // strmtyp in spec
+ mSubstreamID = (mHeaderBuffer[2] >> 3) & 0x07;
+
+ // Frame size is explicit in EAC3. Paragraph E2.3.1.3
+ uint32_t frmsiz = ((mHeaderBuffer[2] & 0x07) << 8) + mHeaderBuffer[3];
+ mFrameSizeBytes = (frmsiz + 1) * sizeof(int16_t);
+
+ uint32_t numblkscod = 3; // 6 blocks default
+ if (fscod == 3) {
+ uint32_t fscod2 = (mHeaderBuffer[4] >> 4) & 0x03;
+ if (fscod2 >= AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES) {
+ ALOGW("Invalid EAC3 fscod2 = %d", fscod2);
+ return false;
+ } else {
+ mSampleRate = kEAC3ReducedSampleRateTable[fscod2];
+ }
+ } else {
+ mSampleRate = kAC3SampleRateTable[fscod];
+ numblkscod = (mHeaderBuffer[4] >> 4) & 0x03;
+ }
+ mRateMultiplier = EAC3_RATE_MULTIPLIER; // per IEC 61973-3 Paragraph 5.3.3
+ // Don't send data burst until we have 6 blocks per substream.
+ mAudioBlocksPerSyncFrame = kEAC3BlocksPerFrameTable[numblkscod];
+ // Keep track of how many audio blocks we have for each substream.
+ // This should be safe because mSubstreamID is ANDed with 0x07 above.
+ // And the array is allocated as [8].
+ if ((mStreamType == AC3_STREAM_TYPE_0)
+ || (mStreamType == AC3_STREAM_TYPE_2)) {
+ mSubstreamBlockCounts[mSubstreamID] += mAudioBlocksPerSyncFrame;
+ }
+
+ // Print enough so we can see all the substreams.
+ ALOGD_IF((mFormatDumpCount < 3*8 ),
+ "EAC3 mStreamType = %d, mSubstreamID = %d",
+ mStreamType, mSubstreamID);
+ } else { // regular AC3
+ // Extract sample rate and frame size from codes.
+ uint32_t frmsizcod = mHeaderBuffer[4] & 0x3F; // frame size code
+
+ if (fscod >= AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES) {
+ ALOGW("Invalid AC3 sampleRateCode = %d", fscod);
+ return false;
+ } else if (frmsizcod >= AC3_NUM_FRAME_SIZE_TABLE_ENTRIES) {
+ ALOGW("Invalid AC3 frameSizeCode = %d", frmsizcod);
+ return false;
+ } else {
+ mSampleRate = kAC3SampleRateTable[fscod];
+ mRateMultiplier = 1;
+ mFrameSizeBytes = sizeof(uint16_t)
+ * kAC3FrameSizeTable[frmsizcod][fscod];
+ }
+ mAudioBlocksPerSyncFrame = 6;
+ if (mFormat == AUDIO_FORMAT_E_AC3) {
+ ALOGV("Its a Ac3 substream in EAC3 stream");
+ mStreamType = 2;
+ mSubstreamID = 0;
+ mSubstreamBlockCounts[0] += mAudioBlocksPerSyncFrame;
+ mDataType = SPDIF_DATA_TYPE_E_AC3;
+ mRateMultiplier = EAC3_RATE_MULTIPLIER;
+ }
+ }
+ ALOGI_IF((mFormatDumpCount == 0),
+ "AC3 frame rate = %d * %d, size = %zu, audioBlocksPerSyncFrame = %d",
+ mSampleRate, mRateMultiplier, mFrameSizeBytes, mAudioBlocksPerSyncFrame);
+ mFormatDumpCount++;
+ return true;
+}
+
+} // namespace android
diff --git a/src/spdif/AC3FrameScanner.h b/src/spdif/AC3FrameScanner.h
new file mode 100644
index 0000000..a73a860
--- /dev/null
+++ b/src/spdif/AC3FrameScanner.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_AC3_FRAME_SCANNER_H
+#define ANDROID_AUDIO_AC3_FRAME_SCANNER_H
+
+#include <stdint.h>
+#include <system/audio.h>
+#include <audio_utils/spdif/FrameScanner.h>
+
+namespace android {
+
+#define AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES 3
+#define AC3_NUM_FRAME_SIZE_TABLE_ENTRIES 38
+#define AC3_PCM_FRAMES_PER_BLOCK 256
+#define AC3_MAX_BLOCKS_PER_SYNC_FRAME_BLOCK 6
+#define EAC3_RATE_MULTIPLIER 4
+#define EAC3_NUM_SAMPLE_RATE_TABLE_ENTRIES 3
+#define EAC3_NUM_BLOCKS_PER_FRAME_TABLE_ENTRIES 38
+#define EAC3_MAX_SUBSTREAMS 8
+
+class AC3FrameScanner : public FrameScanner
+{
+public:
+ explicit AC3FrameScanner(audio_format_t format);
+ virtual ~AC3FrameScanner();
+
+ virtual int getMaxChannels() const { return 5 + 1; } // 5.1 surround
+
+ virtual int getMaxSampleFramesPerSyncFrame() const { return EAC3_RATE_MULTIPLIER
+ * AC3_MAX_BLOCKS_PER_SYNC_FRAME_BLOCK * AC3_PCM_FRAMES_PER_BLOCK; }
+ virtual int getSampleFramesPerSyncFrame() const;
+
+ virtual bool isFirstInBurst();
+ virtual bool isLastInBurst();
+ virtual void resetBurst();
+
+ virtual uint16_t convertBytesToLengthCode(uint16_t numBytes) const;
+
+protected:
+ // Keep track of how many of each substream blocks have been accumulated.
+ // We need all of each substream before sending block data burst.
+ uint8_t mSubstreamBlockCounts[EAC3_MAX_SUBSTREAMS];
+ int mAudioBlocksPerSyncFrame;
+ // The type of EAC3 stream as per EAC3 spec paragraph 2.3.1.1
+ uint32_t mStreamType;
+ // substream index
+ uint32_t mSubstreamID;
+ audio_format_t mFormat;
+
+ // used to recognize the start of an AC3 sync frame
+ static const uint8_t kSyncBytes[];
+ // sample rates from AC3 spec table 5.1
+ static const uint16_t kAC3SampleRateTable[AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES];
+ // frame sizes from AC3 spec table 5.13
+ static const uint16_t kAC3FrameSizeTable[AC3_NUM_FRAME_SIZE_TABLE_ENTRIES]
+ [AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES];
+ // sample rates from EAC3 spec table E2.3
+ static const uint16_t kEAC3ReducedSampleRateTable[AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES];
+ // audio blocks per frame from EAC3 spec table E2.4
+ static const uint16_t kEAC3BlocksPerFrameTable[EAC3_NUM_BLOCKS_PER_FRAME_TABLE_ENTRIES];
+
+ virtual bool parseHeader();
+};
+
+} // namespace android
+
+#endif // ANDROID_AUDIO_AC3_FRAME_SCANNER_H
diff --git a/src/spdif/BitFieldParser.cpp b/src/spdif/BitFieldParser.cpp
new file mode 100644
index 0000000..d513320
--- /dev/null
+++ b/src/spdif/BitFieldParser.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioSPDIF"
+//#define LOG_NDEBUG 0
+
+#include <string.h>
+#include <assert.h>
+
+#include <cutils/log.h>
+#include "BitFieldParser.h"
+
+namespace android {
+
+BitFieldParser::BitFieldParser(uint8_t *data)
+ : mData(data)
+ , mBitCursor(0)
+{
+}
+
+BitFieldParser::~BitFieldParser()
+{
+}
+
+uint32_t BitFieldParser::readBits(uint32_t numBits)
+{
+ ALOG_ASSERT(numBits <= 32);
+
+ // Extract some bits from the current byte.
+ uint32_t byteCursor = mBitCursor >> 3; // 8 bits per byte
+ uint8_t byte = mData[byteCursor];
+
+ uint32_t bitsLeftInByte = 8 - (mBitCursor & 7);
+ uint32_t bitsFromByte = (bitsLeftInByte < numBits) ? bitsLeftInByte : numBits;
+ uint32_t result = byte >> (bitsLeftInByte - bitsFromByte);
+ result &= (1 << bitsFromByte) - 1; // mask
+ mBitCursor += bitsFromByte;
+
+ uint32_t bitsRemaining = numBits - bitsFromByte;
+ if (bitsRemaining == 0) {
+ return result;
+ } else {
+ // Use recursion to get remaining bits.
+ return (result << bitsRemaining) | readBits(bitsRemaining);
+ }
+}
+
+} // namespace android
diff --git a/src/spdif/BitFieldParser.h b/src/spdif/BitFieldParser.h
new file mode 100644
index 0000000..3f6fe59
--- /dev/null
+++ b/src/spdif/BitFieldParser.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_BIT_FIELD_PARSER_H
+#define ANDROID_AUDIO_BIT_FIELD_PARSER_H
+
+#include <stdint.h>
+
+namespace android {
+
+/**
+ * Extract bit fields from a byte array.
+ */
+class BitFieldParser {
+public:
+
+ explicit BitFieldParser(uint8_t *data);
+ virtual ~BitFieldParser();
+
+ /**
+ * Read numBits bits from the data array.
+ * Fields may span byte boundaries but may not exceed 32-bits.
+ * Note that the caller must ensure that there is suffcient data.
+ * Assume data is organized as BigEndian format.
+ */
+ uint32_t readBits(uint32_t numBits);
+
+ /*
+ * When the cursor is zero it points to a position right before
+ * the most significant bit.
+ * When the cursor is seven it points to a position right before
+ * the least significant bit.
+ */
+ uint32_t getBitCursor() const { return mBitCursor; }
+
+private:
+ uint8_t *mData;
+ uint32_t mBitCursor;
+};
+
+
+} // namespace android
+
+#endif // ANDROID_AUDIO_BIT_FIELD_PARSER_H
diff --git a/src/spdif/DTSFrameScanner.cpp b/src/spdif/DTSFrameScanner.cpp
new file mode 100644
index 0000000..941e8b9
--- /dev/null
+++ b/src/spdif/DTSFrameScanner.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioSPDIF"
+//#define LOG_NDEBUG 0
+
+#include <assert.h>
+#include <string.h>
+
+#include <cutils/log.h>
+#include <audio_utils/spdif/FrameScanner.h>
+
+#include "BitFieldParser.h"
+#include "DTSFrameScanner.h"
+
+namespace android {
+
+// TODO Handle termination frames.
+// TODO assert if parse past end of header buffer
+// TODO Handle DTS_HD
+
+const uint8_t DTSFrameScanner::kSyncBytes[] =
+ { 0x7F, 0xFE, 0x80, 0x01 };
+
+const int32_t DTSFrameScanner::kDTSSampleRateTable[DTS_NUM_SAMPLE_RATE_TABLE_ENTRIES]
+ = { -1, 8000, 16000, 32000, -1, -1,
+ 11025, 22050, 44100, -1, -1, 12000, 24000, 48000, -1, -1 };
+
+// Defined in IEC61937-2
+#define IEC61937_DATA_TYPE_DTS_I 11
+#define IEC61937_DATA_TYPE_DTS_II 12
+#define IEC61937_DATA_TYPE_DTS_III 13
+#define IEC61937_DATA_TYPE_DTS_IV 17
+
+#define IEC61937_MAX_SAMPLES_TYPE_I 512
+#define IEC61937_MAX_SAMPLES_TYPE_II 1024
+#define IEC61937_MAX_SAMPLES_TYPE_III 2048
+
+// Limits defined in DTS spec paragraph 5.3.1
+#define DTS_MINIMUM_NBLKS 5
+#define DTS_MINIMUM_FSIZE 95
+
+#define DTS_HEADER_BYTES_NEEDED 12
+
+// Scanner for DTS byte streams.
+DTSFrameScanner::DTSFrameScanner()
+ : FrameScanner(IEC61937_DATA_TYPE_DTS_I,
+ DTSFrameScanner::kSyncBytes,
+ sizeof(DTSFrameScanner::kSyncBytes),
+ DTS_HEADER_BYTES_NEEDED)
+ , mSampleFramesPerSyncFrame(0)
+{
+}
+
+DTSFrameScanner::~DTSFrameScanner()
+{
+}
+
+// Parse DTS header.
+// Detect whether the stream is DTS or DTS_HD. Extract data depending on type.
+// Sets mDataType, mFrameSizeBytes,
+// mSampleRate, mRateMultiplier, mLengthCode.
+//
+// @return true if valid
+bool DTSFrameScanner::parseHeader()
+{
+ BitFieldParser parser(&mHeaderBuffer[mSyncLength]);
+
+ // These variables are named after the fields in the DTS spec 5.3.1
+ // Extract field in order.
+ (void) /* uint32_t ftype = */ parser.readBits(1);
+ (void) /* uint32_t deficit = */ parser.readBits(5); // "short"
+ uint32_t cpf = parser.readBits(1);
+ uint32_t nblks = parser.readBits(7);
+ uint32_t fsize = parser.readBits(14);
+ (void) /* uint32_t amode = */ parser.readBits(6);
+ uint32_t sfreq = parser.readBits(4);
+ // make sure we did not read past collected data
+ ALOG_ASSERT((mSyncLength + ((parser.getBitCursor() + 7) >> 3))
+ <= mHeaderLength);
+
+ // Validate fields.
+ if (cpf != 0) {
+ ALOGE("DTSFrameScanner: ERROR - CPF not zero!");
+ return false;
+ }
+ if (nblks < DTS_MINIMUM_NBLKS) {
+ ALOGE("DTSFrameScanner: ERROR - nblks = %u", nblks);
+ return false;
+ }
+ if (fsize < DTS_MINIMUM_FSIZE) {
+ ALOGE("DTSFrameScanner: ERROR - fsize = %u", fsize);
+ return false;
+ }
+
+ int32_t sampleRate = kDTSSampleRateTable[sfreq];
+ if (sampleRate < 0) {
+ ALOGE("DTSFrameScanner: ERROR - invalid sampleRate[%u] = %d", sfreq, sampleRate);
+ return false;
+ }
+ mSampleRate = (uint32_t) sampleRate;
+
+ mSampleFramesPerSyncFrame = (nblks + 1) * DTS_PCM_FRAMES_PER_BLOCK;
+ if (mSampleFramesPerSyncFrame <= IEC61937_MAX_SAMPLES_TYPE_I) {
+ mDataType = IEC61937_DATA_TYPE_DTS_I;
+ } else if (mSampleFramesPerSyncFrame <= IEC61937_MAX_SAMPLES_TYPE_II) {
+ mDataType = IEC61937_DATA_TYPE_DTS_II;
+ } else if (mSampleFramesPerSyncFrame <= IEC61937_MAX_SAMPLES_TYPE_III) {
+ mDataType = IEC61937_DATA_TYPE_DTS_III;
+ } else {
+ mDataType = IEC61937_DATA_TYPE_DTS_IV;
+ // TODO set bits 8,10
+ }
+
+ mFrameSizeBytes = fsize + 1;
+
+ mRateMultiplier = 1; // TODO what about "frequency extension"?
+ ALOGI_IF((mFormatDumpCount == 0),
+ "DTS frame rate = %d * %d, size = %zu",
+ mSampleRate, mRateMultiplier, mFrameSizeBytes);
+ mFormatDumpCount++;
+ return true;
+}
+
+
+} // namespace android
diff --git a/src/spdif/DTSFrameScanner.h b/src/spdif/DTSFrameScanner.h
new file mode 100644
index 0000000..883ded9
--- /dev/null
+++ b/src/spdif/DTSFrameScanner.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_DTS_FRAME_SCANNER_H
+#define ANDROID_AUDIO_DTS_FRAME_SCANNER_H
+
+#include <stdint.h>
+#include <audio_utils/spdif/FrameScanner.h>
+
+namespace android {
+
+#define DTS_NUM_SAMPLE_RATE_TABLE_ENTRIES 16
+#define DTS_PCM_FRAMES_PER_BLOCK 32
+#define DTS_MAX_BLOCKS_PER_SYNC_FRAME_BLOCK 128
+
+class DTSFrameScanner : public FrameScanner
+{
+public:
+ DTSFrameScanner();
+ virtual ~DTSFrameScanner();
+
+ virtual int getMaxChannels() const { return 5 + 1; }
+
+ virtual int getMaxSampleFramesPerSyncFrame() const {
+ return DTS_MAX_BLOCKS_PER_SYNC_FRAME_BLOCK * DTS_PCM_FRAMES_PER_BLOCK;
+ }
+
+ virtual int getSampleFramesPerSyncFrame() const {
+ return mSampleFramesPerSyncFrame;
+ }
+
+ virtual bool isFirstInBurst() { return true; }
+ virtual bool isLastInBurst() { return true; }
+ virtual void resetBurst() { }
+
+protected:
+
+ int mSampleFramesPerSyncFrame;
+
+ virtual bool parseHeader();
+
+ static const uint8_t kSyncBytes[];
+ static const int32_t kDTSSampleRateTable[];
+
+};
+
+} // namespace android
+#endif // ANDROID_AUDIO_DTS_FRAME_SCANNER_H
diff --git a/src/spdif/FrameScanner.cpp b/src/spdif/FrameScanner.cpp
new file mode 100644
index 0000000..c13d960
--- /dev/null
+++ b/src/spdif/FrameScanner.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioSPDIF"
+
+#include <string.h>
+#include <assert.h>
+
+#include <cutils/log.h>
+#include <audio_utils/spdif/FrameScanner.h>
+
+namespace android {
+
+FrameScanner::FrameScanner(int dataType,
+ const uint8_t *syncBytes,
+ uint32_t syncLength,
+ uint32_t headerLength)
+ : mBytesSkipped(0)
+ , mSyncBytes(syncBytes)
+ , mSyncLength(syncLength)
+ , mHeaderLength(headerLength)
+ , mCursor(0)
+ , mFormatDumpCount(0)
+ , mSampleRate(0)
+ , mRateMultiplier(1)
+ , mFrameSizeBytes(0)
+ , mDataType(dataType)
+ , mDataTypeInfo(0)
+{
+}
+
+FrameScanner::~FrameScanner()
+{
+}
+
+// State machine that scans for headers in a byte stream.
+// @return true if we have detected a complete and valid header.
+bool FrameScanner::scan(uint8_t byte)
+{
+ bool result = false;
+ ALOGV("FrameScanner: byte = 0x%02X, mCursor = %d", byte, mCursor);
+ assert(mCursor < sizeof(mHeaderBuffer));
+ if (mCursor < mSyncLength) {
+ // match sync word
+ if (byte == mSyncBytes[mCursor]) {
+ mHeaderBuffer[mCursor++] = byte;
+ } else {
+ mBytesSkipped += 1; // skip unsynchronized data
+ mCursor = 0;
+ }
+ } else if (mCursor < mHeaderLength) {
+ // gather header for parsing
+ mHeaderBuffer[mCursor++] = byte;
+ if (mCursor >= mHeaderLength) {
+ if (parseHeader()) {
+ result = true;
+ } else {
+ ALOGE("FrameScanner: ERROR - parseHeader() failed.");
+ }
+ mCursor = 0;
+ }
+ }
+ return result;
+}
+
+} // namespace android
diff --git a/src/spdif/SPDIFEncoder.cpp b/src/spdif/SPDIFEncoder.cpp
new file mode 100644
index 0000000..221a072
--- /dev/null
+++ b/src/spdif/SPDIFEncoder.cpp
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#define LOG_TAG "AudioSPDIF"
+#include <cutils/log.h>
+#include <audio_utils/spdif/SPDIFEncoder.h>
+
+#include "AC3FrameScanner.h"
+#include "DTSFrameScanner.h"
+
+namespace android {
+
+// Burst Preamble defined in IEC61937-1
+const uint16_t SPDIFEncoder::kSPDIFSync1 = 0xF872; // Pa
+const uint16_t SPDIFEncoder::kSPDIFSync2 = 0x4E1F; // Pb
+
+static int32_t sEndianDetector = 1;
+#define isLittleEndian() (*((uint8_t *)&sEndianDetector))
+
+SPDIFEncoder::SPDIFEncoder(audio_format_t format)
+ : mFramer(NULL)
+ , mSampleRate(48000)
+ , mBurstBuffer(NULL)
+ , mBurstBufferSizeBytes(0)
+ , mRateMultiplier(1)
+ , mBurstFrames(0)
+ , mByteCursor(0)
+ , mBitstreamNumber(0)
+ , mPayloadBytesPending(0)
+ , mScanning(true)
+{
+ switch(format) {
+ case AUDIO_FORMAT_AC3:
+ case AUDIO_FORMAT_E_AC3:
+ mFramer = new AC3FrameScanner(format);
+ break;
+ case AUDIO_FORMAT_DTS:
+ case AUDIO_FORMAT_DTS_HD:
+ mFramer = new DTSFrameScanner();
+ break;
+ default:
+ break;
+ }
+
+ // This a programmer error. Call isFormatSupported() first.
+ LOG_ALWAYS_FATAL_IF((mFramer == NULL),
+ "SPDIFEncoder: invalid audio format = 0x%08X", format);
+
+ mBurstBufferSizeBytes = sizeof(uint16_t)
+ * SPDIF_ENCODED_CHANNEL_COUNT
+ * mFramer->getMaxSampleFramesPerSyncFrame();
+
+ ALOGI("SPDIFEncoder: mBurstBufferSizeBytes = %zu, littleEndian = %d",
+ mBurstBufferSizeBytes, isLittleEndian());
+ mBurstBuffer = new uint16_t[mBurstBufferSizeBytes >> 1];
+ clearBurstBuffer();
+}
+
+SPDIFEncoder::SPDIFEncoder()
+ : SPDIFEncoder(AUDIO_FORMAT_AC3)
+{
+}
+
+SPDIFEncoder::~SPDIFEncoder()
+{
+ delete[] mBurstBuffer;
+ delete mFramer;
+}
+
+bool SPDIFEncoder::isFormatSupported(audio_format_t format)
+{
+ switch(format) {
+ case AUDIO_FORMAT_AC3:
+ case AUDIO_FORMAT_E_AC3:
+ case AUDIO_FORMAT_DTS:
+ case AUDIO_FORMAT_DTS_HD:
+ return true;
+ default:
+ return false;
+ }
+}
+
+int SPDIFEncoder::getBytesPerOutputFrame()
+{
+ return SPDIF_ENCODED_CHANNEL_COUNT * sizeof(int16_t);
+}
+
+void SPDIFEncoder::writeBurstBufferShorts(const uint16_t *buffer, size_t numShorts)
+{
+ // avoid static analyser warning
+ LOG_ALWAYS_FATAL_IF((mBurstBuffer == NULL), "mBurstBuffer never allocated");
+ mByteCursor = (mByteCursor + 1) & ~1; // round up to even byte
+ size_t bytesToWrite = numShorts * sizeof(uint16_t);
+ if ((mByteCursor + bytesToWrite) > mBurstBufferSizeBytes) {
+ ALOGE("SPDIFEncoder: Burst buffer overflow!");
+ reset();
+ return;
+ }
+ memcpy(&mBurstBuffer[mByteCursor >> 1], buffer, bytesToWrite);
+ mByteCursor += bytesToWrite;
+}
+
+// Pack the bytes into the short buffer in the order:
+// byte[0] -> short[0] MSB
+// byte[1] -> short[0] LSB
+// byte[2] -> short[1] MSB
+// byte[3] -> short[1] LSB
+// etcetera
+// This way they should come out in the correct order for SPDIF on both
+// Big and Little Endian CPUs.
+void SPDIFEncoder::writeBurstBufferBytes(const uint8_t *buffer, size_t numBytes)
+{
+ size_t bytesToWrite = numBytes;
+ if ((mByteCursor + bytesToWrite) > mBurstBufferSizeBytes) {
+ ALOGE("SPDIFEncoder: Burst buffer overflow!");
+ clearBurstBuffer();
+ return;
+ }
+ uint16_t pad = mBurstBuffer[mByteCursor >> 1];
+ for (size_t i = 0; i < bytesToWrite; i++) {
+ if (mByteCursor & 1 ) {
+ pad |= *buffer++; // put second byte in LSB
+ mBurstBuffer[mByteCursor >> 1] = pad;
+ pad = 0;
+ } else {
+ pad |= (*buffer++) << 8; // put first byte in MSB
+ }
+ mByteCursor++;
+ }
+ // Save partially filled short.
+ if (mByteCursor & 1 ){
+ mBurstBuffer[mByteCursor >> 1] = pad;
+ }
+}
+
+void SPDIFEncoder::sendZeroPad()
+{
+ // Pad remainder of burst with zeros.
+ size_t burstSize = mFramer->getSampleFramesPerSyncFrame() * sizeof(uint16_t)
+ * SPDIF_ENCODED_CHANNEL_COUNT;
+ if (mByteCursor > burstSize) {
+ ALOGE("SPDIFEncoder: Burst buffer, contents too large!");
+ clearBurstBuffer();
+ } else {
+ // We don't have to write zeros because buffer already set to zero
+ // by clearBurstBuffer(). Just pretend we wrote zeros by
+ // incrementing cursor.
+ mByteCursor = burstSize;
+ }
+}
+
+void SPDIFEncoder::reset()
+{
+ ALOGV("SPDIFEncoder: reset()");
+ clearBurstBuffer();
+ if (mFramer != NULL) {
+ mFramer->resetBurst();
+ }
+ mPayloadBytesPending = 0;
+ mScanning = true;
+}
+
+void SPDIFEncoder::flushBurstBuffer()
+{
+ const int preambleSize = 4 * sizeof(uint16_t);
+ if (mByteCursor > preambleSize) {
+ // Set lengthCode for valid payload before zeroPad.
+ uint16_t numBytes = (mByteCursor - preambleSize);
+ mBurstBuffer[3] = mFramer->convertBytesToLengthCode(numBytes);
+
+ sendZeroPad();
+ writeOutput(mBurstBuffer, mByteCursor);
+ }
+ reset();
+}
+
+void SPDIFEncoder::clearBurstBuffer()
+{
+ if (mBurstBuffer) {
+ memset(mBurstBuffer, 0, mBurstBufferSizeBytes);
+ }
+ mByteCursor = 0;
+}
+
+void SPDIFEncoder::startDataBurst()
+{
+ // Encode IEC61937-1 Burst Preamble
+ uint16_t preamble[4];
+
+ uint16_t burstInfo = (mBitstreamNumber << 13)
+ | (mFramer->getDataTypeInfo() << 8)
+ | mFramer->getDataType();
+
+ mRateMultiplier = mFramer->getRateMultiplier();
+
+ preamble[0] = kSPDIFSync1;
+ preamble[1] = kSPDIFSync2;
+ preamble[2] = burstInfo;
+ preamble[3] = 0; // lengthCode - This will get set after the buffer is full.
+ writeBurstBufferShorts(preamble, 4);
+}
+
+size_t SPDIFEncoder::startSyncFrame()
+{
+ // Write start of encoded frame that was buffered in frame detector.
+ size_t syncSize = mFramer->getHeaderSizeBytes();
+ writeBurstBufferBytes(mFramer->getHeaderAddress(), syncSize);
+ return mFramer->getFrameSizeBytes() - syncSize;
+}
+
+// Wraps raw encoded data into a data burst.
+ssize_t SPDIFEncoder::write( const void *buffer, size_t numBytes )
+{
+ size_t bytesLeft = numBytes;
+ const uint8_t *data = (const uint8_t *)buffer;
+ ALOGV("SPDIFEncoder: mScanning = %d, write(buffer[0] = 0x%02X, numBytes = %zu)",
+ mScanning, (uint) *data, numBytes);
+ while (bytesLeft > 0) {
+ if (mScanning) {
+ // Look for beginning of next encoded frame.
+ if (mFramer->scan(*data)) {
+ if (mByteCursor == 0) {
+ startDataBurst();
+ } else if (mFramer->isFirstInBurst()) {
+ // Make sure that this frame is at the beginning of the data burst.
+ flushBurstBuffer();
+ startDataBurst();
+ }
+ mPayloadBytesPending = startSyncFrame();
+ mScanning = false;
+ }
+ data++;
+ bytesLeft--;
+ } else {
+ // Write payload until we hit end of frame.
+ size_t bytesToWrite = bytesLeft;
+ // Only write as many as we need to finish the frame.
+ if (bytesToWrite > mPayloadBytesPending) {
+ bytesToWrite = mPayloadBytesPending;
+ }
+ writeBurstBufferBytes(data, bytesToWrite);
+
+ data += bytesToWrite;
+ bytesLeft -= bytesToWrite;
+ mPayloadBytesPending -= bytesToWrite;
+
+ // If we have all the payload then send a data burst.
+ if (mPayloadBytesPending == 0) {
+ if (mFramer->isLastInBurst()) {
+ flushBurstBuffer();
+ }
+ mScanning = true;
+ }
+ }
+ }
+ return numBytes;
+}
+
+} // namespace android
diff --git a/src/speexresample/resample.c b/src/speexresample/resample.c
new file mode 100644
index 0000000..1eeef20
--- /dev/null
+++ b/src/speexresample/resample.c
@@ -0,0 +1,1140 @@
+/* Copyright (C) 2007-2008 Jean-Marc Valin
+ Copyright (C) 2008 Thorvald Natvig
+
+ File: resample.c
+ Arbitrary resampling code
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ The design goals of this code are:
+ - Very fast algorithm
+ - SIMD-friendly algorithm
+ - Low memory requirement
+ - Good *perceptual* quality (and not best SNR)
+
+ Warning: This resampler is relatively new. Although I think I got rid of
+ all the major bugs and I don't expect the API to change anymore, there
+ may be something I've missed. So use with caution.
+
+ This algorithm is based on this original resampling algorithm:
+ Smith, Julius O. Digital Audio Resampling Home Page
+ Center for Computer Research in Music and Acoustics (CCRMA),
+ Stanford University, 2007.
+ Web published at http://www-ccrma.stanford.edu/~jos/resample/.
+
+ There is one main difference, though. This resampler uses cubic
+ interpolation instead of linear interpolation in the above paper. This
+ makes the table much smaller and makes it possible to compute that table
+ on a per-stream basis. In turn, being able to tweak the table for each
+ stream makes it possible to both reduce complexity on simple ratios
+ (e.g. 2/3), and get rid of the rounding operations in the inner loop.
+ The latter both reduces CPU time and makes the algorithm more SIMD-friendly.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef OUTSIDE_SPEEX
+#include <stdlib.h>
+static void *speex_alloc (int size) {return calloc(size,1);}
+static void *speex_realloc (void *ptr, int size) {return realloc(ptr, size);}
+static void speex_free (void *ptr) {free(ptr);}
+#include "speex_resampler.h"
+#include "arch.h"
+#else /* OUTSIDE_SPEEX */
+
+#include "speex/speex_resampler.h"
+#include "arch.h"
+#include "os_support.h"
+#endif /* OUTSIDE_SPEEX */
+
+#include "stack_alloc.h"
+#include <math.h>
+
+#ifndef M_PI
+#define M_PI 3.14159263
+#endif
+
+#ifdef FIXED_POINT
+#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x)))
+#else
+#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x))))
+#endif
+
+#define IMAX(a,b) ((a) > (b) ? (a) : (b))
+#define IMIN(a,b) ((a) < (b) ? (a) : (b))
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifdef _USE_SSE
+#include "resample_sse.h"
+#endif
+
+#ifdef _USE_NEON
+#include "resample_neon.h"
+#endif
+
+/* Numer of elements to allocate on the stack */
+#ifdef VAR_ARRAYS
+#define FIXED_STACK_ALLOC 8192
+#else
+#define FIXED_STACK_ALLOC 1024
+#endif
+
+typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *);
+
+struct SpeexResamplerState_ {
+ spx_uint32_t in_rate;
+ spx_uint32_t out_rate;
+ spx_uint32_t num_rate;
+ spx_uint32_t den_rate;
+
+ int quality;
+ spx_uint32_t nb_channels;
+ spx_uint32_t filt_len;
+ spx_uint32_t mem_alloc_size;
+ spx_uint32_t buffer_size;
+ int int_advance;
+ int frac_advance;
+ float cutoff;
+ spx_uint32_t oversample;
+ int initialised;
+ int started;
+
+ /* These are per-channel */
+ spx_int32_t *last_sample;
+ spx_uint32_t *samp_frac_num;
+ spx_uint32_t *magic_samples;
+
+ spx_word16_t *mem;
+ spx_word16_t *sinc_table;
+ spx_uint32_t sinc_table_length;
+ resampler_basic_func resampler_ptr;
+
+ int in_stride;
+ int out_stride;
+} ;
+
+static double kaiser12_table[68] = {
+ 0.99859849, 1.00000000, 0.99859849, 0.99440475, 0.98745105, 0.97779076,
+ 0.96549770, 0.95066529, 0.93340547, 0.91384741, 0.89213598, 0.86843014,
+ 0.84290116, 0.81573067, 0.78710866, 0.75723148, 0.72629970, 0.69451601,
+ 0.66208321, 0.62920216, 0.59606986, 0.56287762, 0.52980938, 0.49704014,
+ 0.46473455, 0.43304576, 0.40211431, 0.37206735, 0.34301800, 0.31506490,
+ 0.28829195, 0.26276832, 0.23854851, 0.21567274, 0.19416736, 0.17404546,
+ 0.15530766, 0.13794294, 0.12192957, 0.10723616, 0.09382272, 0.08164178,
+ 0.07063950, 0.06075685, 0.05193064, 0.04409466, 0.03718069, 0.03111947,
+ 0.02584161, 0.02127838, 0.01736250, 0.01402878, 0.01121463, 0.00886058,
+ 0.00691064, 0.00531256, 0.00401805, 0.00298291, 0.00216702, 0.00153438,
+ 0.00105297, 0.00069463, 0.00043489, 0.00025272, 0.00013031, 0.0000527734,
+ 0.00001000, 0.00000000};
+/*
+static double kaiser12_table[36] = {
+ 0.99440475, 1.00000000, 0.99440475, 0.97779076, 0.95066529, 0.91384741,
+ 0.86843014, 0.81573067, 0.75723148, 0.69451601, 0.62920216, 0.56287762,
+ 0.49704014, 0.43304576, 0.37206735, 0.31506490, 0.26276832, 0.21567274,
+ 0.17404546, 0.13794294, 0.10723616, 0.08164178, 0.06075685, 0.04409466,
+ 0.03111947, 0.02127838, 0.01402878, 0.00886058, 0.00531256, 0.00298291,
+ 0.00153438, 0.00069463, 0.00025272, 0.0000527734, 0.00000500, 0.00000000};
+*/
+static double kaiser10_table[36] = {
+ 0.99537781, 1.00000000, 0.99537781, 0.98162644, 0.95908712, 0.92831446,
+ 0.89005583, 0.84522401, 0.79486424, 0.74011713, 0.68217934, 0.62226347,
+ 0.56155915, 0.50119680, 0.44221549, 0.38553619, 0.33194107, 0.28205962,
+ 0.23636152, 0.19515633, 0.15859932, 0.12670280, 0.09935205, 0.07632451,
+ 0.05731132, 0.04193980, 0.02979584, 0.02044510, 0.01345224, 0.00839739,
+ 0.00488951, 0.00257636, 0.00115101, 0.00035515, 0.00000000, 0.00000000};
+
+static double kaiser8_table[36] = {
+ 0.99635258, 1.00000000, 0.99635258, 0.98548012, 0.96759014, 0.94302200,
+ 0.91223751, 0.87580811, 0.83439927, 0.78875245, 0.73966538, 0.68797126,
+ 0.63451750, 0.58014482, 0.52566725, 0.47185369, 0.41941150, 0.36897272,
+ 0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758,
+ 0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490,
+ 0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000};
+
+static double kaiser6_table[36] = {
+ 0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003,
+ 0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565,
+ 0.71712752, 0.67172623, 0.62508937, 0.57774224, 0.53019925, 0.48295561,
+ 0.43647969, 0.39120616, 0.34752997, 0.30580127, 0.26632152, 0.22934058,
+ 0.19505503, 0.16360756, 0.13508755, 0.10953262, 0.08693120, 0.06722600,
+ 0.05031820, 0.03607231, 0.02432151, 0.01487334, 0.00752000, 0.00000000};
+
+struct FuncDef {
+ double *table;
+ int oversample;
+};
+
+static struct FuncDef _KAISER12 = {kaiser12_table, 64};
+#define KAISER12 (&_KAISER12)
+/*static struct FuncDef _KAISER12 = {kaiser12_table, 32};
+#define KAISER12 (&_KAISER12)*/
+static struct FuncDef _KAISER10 = {kaiser10_table, 32};
+#define KAISER10 (&_KAISER10)
+static struct FuncDef _KAISER8 = {kaiser8_table, 32};
+#define KAISER8 (&_KAISER8)
+static struct FuncDef _KAISER6 = {kaiser6_table, 32};
+#define KAISER6 (&_KAISER6)
+
+struct QualityMapping {
+ int base_length;
+ int oversample;
+ float downsample_bandwidth;
+ float upsample_bandwidth;
+ struct FuncDef *window_func;
+};
+
+
+/* This table maps conversion quality to internal parameters. There are two
+ reasons that explain why the up-sampling bandwidth is larger than the
+ down-sampling bandwidth:
+ 1) When up-sampling, we can assume that the spectrum is already attenuated
+ close to the Nyquist rate (from an A/D or a previous resampling filter)
+ 2) Any aliasing that occurs very close to the Nyquist rate will be masked
+ by the sinusoids/noise just below the Nyquist rate (guaranteed only for
+ up-sampling).
+*/
+static const struct QualityMapping quality_map[11] = {
+ { 8, 4, 0.830f, 0.860f, KAISER6 }, /* Q0 */
+ { 16, 4, 0.850f, 0.880f, KAISER6 }, /* Q1 */
+ { 32, 4, 0.882f, 0.910f, KAISER6 }, /* Q2 */ /* 82.3% cutoff ( ~60 dB stop) 6 */
+ { 48, 8, 0.895f, 0.917f, KAISER8 }, /* Q3 */ /* 84.9% cutoff ( ~80 dB stop) 8 */
+ { 64, 8, 0.921f, 0.940f, KAISER8 }, /* Q4 */ /* 88.7% cutoff ( ~80 dB stop) 8 */
+ { 80, 16, 0.922f, 0.940f, KAISER10}, /* Q5 */ /* 89.1% cutoff (~100 dB stop) 10 */
+ { 96, 16, 0.940f, 0.945f, KAISER10}, /* Q6 */ /* 91.5% cutoff (~100 dB stop) 10 */
+ {128, 16, 0.950f, 0.950f, KAISER10}, /* Q7 */ /* 93.1% cutoff (~100 dB stop) 10 */
+ {160, 16, 0.960f, 0.960f, KAISER10}, /* Q8 */ /* 94.5% cutoff (~100 dB stop) 10 */
+ {192, 32, 0.968f, 0.968f, KAISER12}, /* Q9 */ /* 95.5% cutoff (~100 dB stop) 10 */
+ {256, 32, 0.975f, 0.975f, KAISER12}, /* Q10 */ /* 96.6% cutoff (~100 dB stop) 10 */
+};
+/*8,24,40,56,80,104,128,160,200,256,320*/
+static double compute_func(float x, struct FuncDef *func)
+{
+ float y, frac;
+ double interp[4];
+ int ind;
+ y = x*func->oversample;
+ ind = (int)floor(y);
+ frac = (y-ind);
+ /* CSE with handle the repeated powers */
+ interp[3] = -0.1666666667*frac + 0.1666666667*(frac*frac*frac);
+ interp[2] = frac + 0.5*(frac*frac) - 0.5*(frac*frac*frac);
+ /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/
+ interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac);
+ /* Just to make sure we don't have rounding problems */
+ interp[1] = 1.f-interp[3]-interp[2]-interp[0];
+
+ /*sum = frac*accum[1] + (1-frac)*accum[2];*/
+ return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3];
+}
+
+#if 0
+#include <stdio.h>
+int main(int argc, char **argv)
+{
+ int i;
+ for (i=0;i<256;i++)
+ {
+ printf ("%f\n", compute_func(i/256., KAISER12));
+ }
+ return 0;
+}
+#endif
+
+#ifdef FIXED_POINT
+/* The slow way of computing a sinc for the table. Should improve that some day */
+static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func)
+{
+ /*fprintf (stderr, "%f ", x);*/
+ float xx = x * cutoff;
+ if (fabs(x)<1e-6f)
+ return WORD2INT(32768.*cutoff);
+ else if (fabs(x) > .5f*N)
+ return 0;
+ /*FIXME: Can it really be any slower than this? */
+ return WORD2INT(32768.*cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func));
+}
+#else
+/* The slow way of computing a sinc for the table. Should improve that some day */
+static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func)
+{
+ /*fprintf (stderr, "%f ", x);*/
+ float xx = x * cutoff;
+ if (fabs(x)<1e-6)
+ return cutoff;
+ else if (fabs(x) > .5*N)
+ return 0;
+ /*FIXME: Can it really be any slower than this? */
+ return cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func);
+}
+#endif
+
+#ifdef FIXED_POINT
+static void cubic_coef(spx_word16_t x, spx_word16_t interp[4])
+{
+ /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation
+ but I know it's MMSE-optimal on a sinc */
+ spx_word16_t x2, x3;
+ x2 = MULT16_16_P15(x, x);
+ x3 = MULT16_16_P15(x, x2);
+ interp[0] = PSHR32(MULT16_16(QCONST16(-0.16667f, 15),x) + MULT16_16(QCONST16(0.16667f, 15),x3),15);
+ interp[1] = EXTRACT16(EXTEND32(x) + SHR32(SUB32(EXTEND32(x2),EXTEND32(x3)),1));
+ interp[3] = PSHR32(MULT16_16(QCONST16(-0.33333f, 15),x) + MULT16_16(QCONST16(.5f,15),x2) - MULT16_16(QCONST16(0.16667f, 15),x3),15);
+ /* Just to make sure we don't have rounding problems */
+ interp[2] = Q15_ONE-interp[0]-interp[1]-interp[3];
+ if (interp[2]<32767)
+ interp[2]+=1;
+}
+#else
+static void cubic_coef(spx_word16_t frac, spx_word16_t interp[4])
+{
+ /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation
+ but I know it's MMSE-optimal on a sinc */
+ interp[0] = -0.16667f*frac + 0.16667f*frac*frac*frac;
+ interp[1] = frac + 0.5f*frac*frac - 0.5f*frac*frac*frac;
+ /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/
+ interp[3] = -0.33333f*frac + 0.5f*frac*frac - 0.16667f*frac*frac*frac;
+ /* Just to make sure we don't have rounding problems */
+ interp[2] = 1.-interp[0]-interp[1]-interp[3];
+}
+#endif
+
+static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
+{
+ const int N = st->filt_len;
+ int out_sample = 0;
+ int last_sample = st->last_sample[channel_index];
+ spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
+ const spx_word16_t *sinc_table = st->sinc_table;
+ const int out_stride = st->out_stride;
+ const int int_advance = st->int_advance;
+ const int frac_advance = st->frac_advance;
+ const spx_uint32_t den_rate = st->den_rate;
+ spx_word32_t sum;
+
+ while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
+ {
+ const spx_word16_t *sinc = & sinc_table[samp_frac_num*N];
+ const spx_word16_t *iptr = & in[last_sample];
+
+#ifndef OVERRIDE_INNER_PRODUCT_SINGLE
+ float accum[4] = {0,0,0,0};
+
+ for(int j=0;j<N;j+=4) {
+ accum[0] += sinc[j]*iptr[j];
+ accum[1] += sinc[j+1]*iptr[j+1];
+ accum[2] += sinc[j+2]*iptr[j+2];
+ accum[3] += sinc[j+3]*iptr[j+3];
+ }
+ sum = accum[0] + accum[1] + accum[2] + accum[3];
+ sum = SATURATE32PSHR(sum, 15, 32767);
+#else
+ sum = inner_product_single(sinc, iptr, N);
+#endif
+
+ out[out_stride * out_sample++] = sum;
+ last_sample += int_advance;
+ samp_frac_num += frac_advance;
+ if (samp_frac_num >= den_rate)
+ {
+ samp_frac_num -= den_rate;
+ last_sample++;
+ }
+ }
+
+ st->last_sample[channel_index] = last_sample;
+ st->samp_frac_num[channel_index] = samp_frac_num;
+ return out_sample;
+}
+
+#ifdef FIXED_POINT
+#else
+/* This is the same as the previous function, except with a double-precision accumulator */
+static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
+{
+ const int N = st->filt_len;
+ int out_sample = 0;
+ int last_sample = st->last_sample[channel_index];
+ spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
+ const spx_word16_t *sinc_table = st->sinc_table;
+ const int out_stride = st->out_stride;
+ const int int_advance = st->int_advance;
+ const int frac_advance = st->frac_advance;
+ const spx_uint32_t den_rate = st->den_rate;
+ double sum;
+ int j;
+
+ while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
+ {
+ const spx_word16_t *sinc = & sinc_table[samp_frac_num*N];
+ const spx_word16_t *iptr = & in[last_sample];
+
+#ifndef OVERRIDE_INNER_PRODUCT_DOUBLE
+ double accum[4] = {0,0,0,0};
+
+ for(j=0;j<N;j+=4) {
+ accum[0] += sinc[j]*iptr[j];
+ accum[1] += sinc[j+1]*iptr[j+1];
+ accum[2] += sinc[j+2]*iptr[j+2];
+ accum[3] += sinc[j+3]*iptr[j+3];
+ }
+ sum = accum[0] + accum[1] + accum[2] + accum[3];
+#else
+ sum = inner_product_double(sinc, iptr, N);
+#endif
+
+ out[out_stride * out_sample++] = PSHR32(sum, 15);
+ last_sample += int_advance;
+ samp_frac_num += frac_advance;
+ if (samp_frac_num >= den_rate)
+ {
+ samp_frac_num -= den_rate;
+ last_sample++;
+ }
+ }
+
+ st->last_sample[channel_index] = last_sample;
+ st->samp_frac_num[channel_index] = samp_frac_num;
+ return out_sample;
+}
+#endif
+
+static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
+{
+ const int N = st->filt_len;
+ int out_sample = 0;
+ int last_sample = st->last_sample[channel_index];
+ spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
+ const int out_stride = st->out_stride;
+ const int int_advance = st->int_advance;
+ const int frac_advance = st->frac_advance;
+ const spx_uint32_t den_rate = st->den_rate;
+ int j;
+ spx_word32_t sum;
+
+ while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
+ {
+ const spx_word16_t *iptr = & in[last_sample];
+
+ const int offset = samp_frac_num*st->oversample/st->den_rate;
+#ifdef FIXED_POINT
+ const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate);
+#else
+ const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate;
+#endif
+ spx_word16_t interp[4];
+
+
+#ifndef OVERRIDE_INTERPOLATE_PRODUCT_SINGLE
+ spx_word32_t accum[4] = {0,0,0,0};
+
+ for(j=0;j<N;j++) {
+ const spx_word16_t curr_in=iptr[j];
+ accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
+ accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
+ accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);
+ accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
+ }
+
+ cubic_coef(frac, interp);
+ sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]);
+ sum = SATURATE32PSHR(sum, 15, 32767);
+#else
+ cubic_coef(frac, interp);
+ sum = interpolate_product_single(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp);
+#endif
+
+ out[out_stride * out_sample++] = sum;
+ last_sample += int_advance;
+ samp_frac_num += frac_advance;
+ if (samp_frac_num >= den_rate)
+ {
+ samp_frac_num -= den_rate;
+ last_sample++;
+ }
+ }
+
+ st->last_sample[channel_index] = last_sample;
+ st->samp_frac_num[channel_index] = samp_frac_num;
+ return out_sample;
+}
+
+#ifdef FIXED_POINT
+#else
+/* This is the same as the previous function, except with a double-precision accumulator */
+static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
+{
+ const int N = st->filt_len;
+ int out_sample = 0;
+ int last_sample = st->last_sample[channel_index];
+ spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
+ const int out_stride = st->out_stride;
+ const int int_advance = st->int_advance;
+ const int frac_advance = st->frac_advance;
+ const spx_uint32_t den_rate = st->den_rate;
+ int j;
+ spx_word32_t sum;
+
+ while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
+ {
+ const spx_word16_t *iptr = & in[last_sample];
+
+ const int offset = samp_frac_num*st->oversample/st->den_rate;
+#ifdef FIXED_POINT
+ const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate);
+#else
+ const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate;
+#endif
+ spx_word16_t interp[4];
+
+
+#ifndef OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE
+ double accum[4] = {0,0,0,0};
+
+ for(j=0;j<N;j++) {
+ const double curr_in=iptr[j];
+ accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
+ accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
+ accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);
+ accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
+ }
+
+ cubic_coef(frac, interp);
+ sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]);
+#else
+ cubic_coef(frac, interp);
+ sum = interpolate_product_double(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp);
+#endif
+
+ out[out_stride * out_sample++] = PSHR32(sum,15);
+ last_sample += int_advance;
+ samp_frac_num += frac_advance;
+ if (samp_frac_num >= den_rate)
+ {
+ samp_frac_num -= den_rate;
+ last_sample++;
+ }
+ }
+
+ st->last_sample[channel_index] = last_sample;
+ st->samp_frac_num[channel_index] = samp_frac_num;
+ return out_sample;
+}
+#endif
+
+static void update_filter(SpeexResamplerState *st)
+{
+ spx_uint32_t old_length;
+
+ old_length = st->filt_len;
+ st->oversample = quality_map[st->quality].oversample;
+ st->filt_len = quality_map[st->quality].base_length;
+
+ if (st->num_rate > st->den_rate)
+ {
+ /* down-sampling */
+ st->cutoff = quality_map[st->quality].downsample_bandwidth * st->den_rate / st->num_rate;
+ /* FIXME: divide the numerator and denominator by a certain amount if they're too large */
+ st->filt_len = st->filt_len*st->num_rate / st->den_rate;
+ /* Round down to make sure we have a multiple of 4 */
+ st->filt_len &= (~0x3);
+ if (2*st->den_rate < st->num_rate)
+ st->oversample >>= 1;
+ if (4*st->den_rate < st->num_rate)
+ st->oversample >>= 1;
+ if (8*st->den_rate < st->num_rate)
+ st->oversample >>= 1;
+ if (16*st->den_rate < st->num_rate)
+ st->oversample >>= 1;
+ if (st->oversample < 1)
+ st->oversample = 1;
+ } else {
+ /* up-sampling */
+ st->cutoff = quality_map[st->quality].upsample_bandwidth;
+ }
+
+ /* Choose the resampling type that requires the least amount of memory */
+#ifdef RESAMPLE_FORCE_FULL_SINC_TABLE
+ if (1)
+#else
+ if (st->den_rate <= st->oversample)
+#endif
+ {
+ spx_uint32_t i;
+ if (!st->sinc_table)
+ st->sinc_table = (spx_word16_t *)speex_alloc(st->filt_len*st->den_rate*sizeof(spx_word16_t));
+ else if (st->sinc_table_length < st->filt_len*st->den_rate)
+ {
+ st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,st->filt_len*st->den_rate*sizeof(spx_word16_t));
+ st->sinc_table_length = st->filt_len*st->den_rate;
+ }
+ for (i=0;i<st->den_rate;i++)
+ {
+ spx_int32_t j;
+ for (j=0;j<st->filt_len;j++)
+ {
+ st->sinc_table[i*st->filt_len+j] = sinc(st->cutoff,((j-(spx_int32_t)st->filt_len/2+1)-((float)i)/st->den_rate), st->filt_len, quality_map[st->quality].window_func);
+ }
+ }
+#ifdef FIXED_POINT
+ st->resampler_ptr = resampler_basic_direct_single;
+#else
+ if (st->quality>8)
+ st->resampler_ptr = resampler_basic_direct_double;
+ else
+ st->resampler_ptr = resampler_basic_direct_single;
+#endif
+ /*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff);*/
+ } else {
+ spx_int32_t i;
+ if (!st->sinc_table)
+ st->sinc_table = (spx_word16_t *)speex_alloc((st->filt_len*st->oversample+8)*sizeof(spx_word16_t));
+ else if (st->sinc_table_length < st->filt_len*st->oversample+8)
+ {
+ st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,(st->filt_len*st->oversample+8)*sizeof(spx_word16_t));
+ st->sinc_table_length = st->filt_len*st->oversample+8;
+ }
+ for (i=-4;i<(spx_int32_t)(st->oversample*st->filt_len+4);i++)
+ st->sinc_table[i+4] = sinc(st->cutoff,(i/(float)st->oversample - st->filt_len/2), st->filt_len, quality_map[st->quality].window_func);
+#ifdef FIXED_POINT
+ st->resampler_ptr = resampler_basic_interpolate_single;
+#else
+ if (st->quality>8)
+ st->resampler_ptr = resampler_basic_interpolate_double;
+ else
+ st->resampler_ptr = resampler_basic_interpolate_single;
+#endif
+ /*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff);*/
+ }
+ st->int_advance = st->num_rate/st->den_rate;
+ st->frac_advance = st->num_rate%st->den_rate;
+
+
+ /* Here's the place where we update the filter memory to take into account
+ the change in filter length. It's probably the messiest part of the code
+ due to handling of lots of corner cases. */
+ if (!st->mem)
+ {
+ spx_uint32_t i;
+ st->mem_alloc_size = st->filt_len-1 + st->buffer_size;
+ st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));
+ for (i=0;i<st->nb_channels*st->mem_alloc_size;i++)
+ st->mem[i] = 0;
+ /*speex_warning("init filter");*/
+ } else if (!st->started)
+ {
+ spx_uint32_t i;
+ st->mem_alloc_size = st->filt_len-1 + st->buffer_size;
+ st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));
+ for (i=0;i<st->nb_channels*st->mem_alloc_size;i++)
+ st->mem[i] = 0;
+ /*speex_warning("reinit filter");*/
+ } else if (st->filt_len > old_length)
+ {
+ spx_int32_t i;
+ /* Increase the filter length */
+ /*speex_warning("increase filter size");*/
+ int old_alloc_size = st->mem_alloc_size;
+ if ((st->filt_len-1 + st->buffer_size) > st->mem_alloc_size)
+ {
+ st->mem_alloc_size = st->filt_len-1 + st->buffer_size;
+ st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));
+ }
+ for (i=st->nb_channels-1;i>=0;i--)
+ {
+ spx_int32_t j;
+ spx_uint32_t olen = old_length;
+ /*if (st->magic_samples[i])*/
+ {
+ /* Try and remove the magic samples as if nothing had happened */
+
+ /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */
+ olen = old_length + 2*st->magic_samples[i];
+ for (j=old_length-2+st->magic_samples[i];j>=0;j--)
+ st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]] = st->mem[i*old_alloc_size+j];
+ for (j=0;j<st->magic_samples[i];j++)
+ st->mem[i*st->mem_alloc_size+j] = 0;
+ st->magic_samples[i] = 0;
+ }
+ if (st->filt_len > olen)
+ {
+ /* If the new filter length is still bigger than the "augmented" length */
+ /* Copy data going backward */
+ for (j=0;j<olen-1;j++)
+ st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = st->mem[i*st->mem_alloc_size+(olen-2-j)];
+ /* Then put zeros for lack of anything better */
+ for (;j<st->filt_len-1;j++)
+ st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = 0;
+ /* Adjust last_sample */
+ st->last_sample[i] += (st->filt_len - olen)/2;
+ } else {
+ /* Put back some of the magic! */
+ st->magic_samples[i] = (olen - st->filt_len)/2;
+ for (j=0;j<st->filt_len-1+st->magic_samples[i];j++)
+ st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]];
+ }
+ }
+ } else if (st->filt_len < old_length)
+ {
+ spx_uint32_t i;
+ /* Reduce filter length, this a bit tricky. We need to store some of the memory as "magic"
+ samples so they can be used directly as input the next time(s) */
+ for (i=0;i<st->nb_channels;i++)
+ {
+ spx_uint32_t j;
+ spx_uint32_t old_magic = st->magic_samples[i];
+ st->magic_samples[i] = (old_length - st->filt_len)/2;
+ /* We must copy some of the memory that's no longer used */
+ /* Copy data going backward */
+ for (j=0;j<st->filt_len-1+st->magic_samples[i]+old_magic;j++)
+ st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]];
+ st->magic_samples[i] += old_magic;
+ }
+ }
+
+}
+
+EXPORT SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err)
+{
+ return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err);
+}
+
+EXPORT SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err)
+{
+ spx_uint32_t i;
+ SpeexResamplerState *st;
+ if (quality > 10 || quality < 0)
+ {
+ if (err)
+ *err = RESAMPLER_ERR_INVALID_ARG;
+ return NULL;
+ }
+ st = (SpeexResamplerState *)speex_alloc(sizeof(SpeexResamplerState));
+ st->initialised = 0;
+ st->started = 0;
+ st->in_rate = 0;
+ st->out_rate = 0;
+ st->num_rate = 0;
+ st->den_rate = 0;
+ st->quality = -1;
+ st->sinc_table_length = 0;
+ st->mem_alloc_size = 0;
+ st->filt_len = 0;
+ st->mem = 0;
+ st->resampler_ptr = 0;
+
+ st->cutoff = 1.f;
+ st->nb_channels = nb_channels;
+ st->in_stride = 1;
+ st->out_stride = 1;
+
+#ifdef FIXED_POINT
+ st->buffer_size = 160;
+#else
+ st->buffer_size = 160;
+#endif
+
+ /* Per channel data */
+ st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int));
+ st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int));
+ st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int));
+ for (i=0;i<nb_channels;i++)
+ {
+ st->last_sample[i] = 0;
+ st->magic_samples[i] = 0;
+ st->samp_frac_num[i] = 0;
+ }
+
+ speex_resampler_set_quality(st, quality);
+ speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate);
+
+
+ update_filter(st);
+
+ st->initialised = 1;
+ if (err)
+ *err = RESAMPLER_ERR_SUCCESS;
+
+ return st;
+}
+
+EXPORT void speex_resampler_destroy(SpeexResamplerState *st)
+{
+ speex_free(st->mem);
+ speex_free(st->sinc_table);
+ speex_free(st->last_sample);
+ speex_free(st->magic_samples);
+ speex_free(st->samp_frac_num);
+ speex_free(st);
+}
+
+static int speex_resampler_process_native(SpeexResamplerState *st, spx_uint32_t channel_index, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
+{
+ int j=0;
+ const int N = st->filt_len;
+ int out_sample = 0;
+ spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size;
+ spx_uint32_t ilen;
+
+ st->started = 1;
+
+ /* Call the right resampler through the function ptr */
+ out_sample = st->resampler_ptr(st, channel_index, mem, in_len, out, out_len);
+
+ if (st->last_sample[channel_index] < (spx_int32_t)*in_len)
+ *in_len = st->last_sample[channel_index];
+ *out_len = out_sample;
+ st->last_sample[channel_index] -= *in_len;
+
+ ilen = *in_len;
+
+ for(j=0;j<N-1;++j)
+ mem[j] = mem[j+ilen];
+
+ return RESAMPLER_ERR_SUCCESS;
+}
+
+static int speex_resampler_magic(SpeexResamplerState *st, spx_uint32_t channel_index, spx_word16_t **out, spx_uint32_t out_len) {
+ spx_uint32_t tmp_in_len = st->magic_samples[channel_index];
+ spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size;
+ const int N = st->filt_len;
+
+ speex_resampler_process_native(st, channel_index, &tmp_in_len, *out, &out_len);
+
+ st->magic_samples[channel_index] -= tmp_in_len;
+
+ /* If we couldn't process all "magic" input samples, save the rest for next time */
+ if (st->magic_samples[channel_index])
+ {
+ spx_uint32_t i;
+ for (i=0;i<st->magic_samples[channel_index];i++)
+ mem[N-1+i]=mem[N-1+i+tmp_in_len];
+ }
+ *out += out_len*st->out_stride;
+ return out_len;
+}
+
+#ifdef FIXED_POINT
+EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
+#else
+EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
+#endif
+{
+ int j;
+ spx_uint32_t ilen = *in_len;
+ spx_uint32_t olen = *out_len;
+ spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size;
+ const int filt_offs = st->filt_len - 1;
+ const spx_uint32_t xlen = st->mem_alloc_size - filt_offs;
+ const int istride = st->in_stride;
+
+ if (st->magic_samples[channel_index])
+ olen -= speex_resampler_magic(st, channel_index, &out, olen);
+ if (! st->magic_samples[channel_index]) {
+ while (ilen && olen) {
+ spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen;
+ spx_uint32_t ochunk = olen;
+
+ if (in) {
+ for(j=0;j<ichunk;++j)
+ x[j+filt_offs]=in[j*istride];
+ } else {
+ for(j=0;j<ichunk;++j)
+ x[j+filt_offs]=0;
+ }
+ speex_resampler_process_native(st, channel_index, &ichunk, out, &ochunk);
+ ilen -= ichunk;
+ olen -= ochunk;
+ out += ochunk * st->out_stride;
+ if (in)
+ in += ichunk * istride;
+ }
+ }
+ *in_len -= ilen;
+ *out_len -= olen;
+ return RESAMPLER_ERR_SUCCESS;
+}
+
+#ifdef FIXED_POINT
+EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
+#else
+EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
+#endif
+{
+ int j;
+ const int istride_save = st->in_stride;
+ const int ostride_save = st->out_stride;
+ spx_uint32_t ilen = *in_len;
+ spx_uint32_t olen = *out_len;
+ spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size;
+ const spx_uint32_t xlen = st->mem_alloc_size - (st->filt_len - 1);
+#ifdef VAR_ARRAYS
+ const unsigned int ylen = (olen < FIXED_STACK_ALLOC) ? olen : FIXED_STACK_ALLOC;
+ VARDECL(spx_word16_t *ystack);
+ ALLOC(ystack, ylen, spx_word16_t);
+#else
+ const unsigned int ylen = FIXED_STACK_ALLOC;
+ spx_word16_t ystack[FIXED_STACK_ALLOC];
+#endif
+
+ st->out_stride = 1;
+
+ while (ilen && olen) {
+ spx_word16_t *y = ystack;
+ spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen;
+ spx_uint32_t ochunk = (olen > ylen) ? ylen : olen;
+ spx_uint32_t omagic = 0;
+
+ if (st->magic_samples[channel_index]) {
+ omagic = speex_resampler_magic(st, channel_index, &y, ochunk);
+ ochunk -= omagic;
+ olen -= omagic;
+ }
+ if (! st->magic_samples[channel_index]) {
+ if (in) {
+ for(j=0;j<ichunk;++j)
+#ifdef FIXED_POINT
+ x[j+st->filt_len-1]=WORD2INT(in[j*istride_save]);
+#else
+ x[j+st->filt_len-1]=in[j*istride_save];
+#endif
+ } else {
+ for(j=0;j<ichunk;++j)
+ x[j+st->filt_len-1]=0;
+ }
+
+ speex_resampler_process_native(st, channel_index, &ichunk, y, &ochunk);
+ } else {
+ ichunk = 0;
+ ochunk = 0;
+ }
+
+ for (j=0;j<ochunk+omagic;++j)
+#ifdef FIXED_POINT
+ out[j*ostride_save] = ystack[j];
+#else
+ out[j*ostride_save] = WORD2INT(ystack[j]);
+#endif
+
+ ilen -= ichunk;
+ olen -= ochunk;
+ out += (ochunk+omagic) * ostride_save;
+ if (in)
+ in += ichunk * istride_save;
+ }
+ st->out_stride = ostride_save;
+ *in_len -= ilen;
+ *out_len -= olen;
+
+ return RESAMPLER_ERR_SUCCESS;
+}
+
+EXPORT int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
+{
+ spx_uint32_t i;
+ int istride_save, ostride_save;
+ spx_uint32_t bak_len = *out_len;
+ istride_save = st->in_stride;
+ ostride_save = st->out_stride;
+ st->in_stride = st->out_stride = st->nb_channels;
+ for (i=0;i<st->nb_channels;i++)
+ {
+ *out_len = bak_len;
+ if (in != NULL)
+ speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len);
+ else
+ speex_resampler_process_float(st, i, NULL, in_len, out+i, out_len);
+ }
+ st->in_stride = istride_save;
+ st->out_stride = ostride_save;
+ return RESAMPLER_ERR_SUCCESS;
+}
+
+EXPORT int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
+{
+ spx_uint32_t i;
+ int istride_save, ostride_save;
+ spx_uint32_t bak_len = *out_len;
+ istride_save = st->in_stride;
+ ostride_save = st->out_stride;
+ st->in_stride = st->out_stride = st->nb_channels;
+ for (i=0;i<st->nb_channels;i++)
+ {
+ *out_len = bak_len;
+ if (in != NULL)
+ speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len);
+ else
+ speex_resampler_process_int(st, i, NULL, in_len, out+i, out_len);
+ }
+ st->in_stride = istride_save;
+ st->out_stride = ostride_save;
+ return RESAMPLER_ERR_SUCCESS;
+}
+
+EXPORT int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate)
+{
+ return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate);
+}
+
+EXPORT void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate)
+{
+ *in_rate = st->in_rate;
+ *out_rate = st->out_rate;
+}
+
+EXPORT int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate)
+{
+ spx_uint32_t fact;
+ spx_uint32_t old_den;
+ spx_uint32_t i;
+ if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den)
+ return RESAMPLER_ERR_SUCCESS;
+
+ old_den = st->den_rate;
+ st->in_rate = in_rate;
+ st->out_rate = out_rate;
+ st->num_rate = ratio_num;
+ st->den_rate = ratio_den;
+ /* FIXME: This is terribly inefficient, but who cares (at least for now)? */
+ for (fact=2;fact<=IMIN(st->num_rate, st->den_rate);fact++)
+ {
+ while ((st->num_rate % fact == 0) && (st->den_rate % fact == 0))
+ {
+ st->num_rate /= fact;
+ st->den_rate /= fact;
+ }
+ }
+
+ if (old_den > 0)
+ {
+ for (i=0;i<st->nb_channels;i++)
+ {
+ st->samp_frac_num[i]=st->samp_frac_num[i]*st->den_rate/old_den;
+ /* Safety net */
+ if (st->samp_frac_num[i] >= st->den_rate)
+ st->samp_frac_num[i] = st->den_rate-1;
+ }
+ }
+
+ if (st->initialised)
+ update_filter(st);
+ return RESAMPLER_ERR_SUCCESS;
+}
+
+EXPORT void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den)
+{
+ *ratio_num = st->num_rate;
+ *ratio_den = st->den_rate;
+}
+
+EXPORT int speex_resampler_set_quality(SpeexResamplerState *st, int quality)
+{
+ if (quality > 10 || quality < 0)
+ return RESAMPLER_ERR_INVALID_ARG;
+ if (st->quality == quality)
+ return RESAMPLER_ERR_SUCCESS;
+ st->quality = quality;
+ if (st->initialised)
+ update_filter(st);
+ return RESAMPLER_ERR_SUCCESS;
+}
+
+EXPORT void speex_resampler_get_quality(SpeexResamplerState *st, int *quality)
+{
+ *quality = st->quality;
+}
+
+EXPORT void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride)
+{
+ st->in_stride = stride;
+}
+
+EXPORT void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride)
+{
+ *stride = st->in_stride;
+}
+
+EXPORT void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride)
+{
+ st->out_stride = stride;
+}
+
+EXPORT void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride)
+{
+ *stride = st->out_stride;
+}
+
+EXPORT int speex_resampler_get_input_latency(SpeexResamplerState *st)
+{
+ return st->filt_len / 2;
+}
+
+EXPORT int speex_resampler_get_output_latency(SpeexResamplerState *st)
+{
+ return ((st->filt_len / 2) * st->den_rate + (st->num_rate >> 1)) / st->num_rate;
+}
+
+EXPORT int speex_resampler_skip_zeros(SpeexResamplerState *st)
+{
+ spx_uint32_t i;
+ for (i=0;i<st->nb_channels;i++)
+ st->last_sample[i] = st->filt_len/2;
+ return RESAMPLER_ERR_SUCCESS;
+}
+
+EXPORT int speex_resampler_reset_mem(SpeexResamplerState *st)
+{
+ spx_uint32_t i;
+ for (i=0;i<st->nb_channels*(st->filt_len-1);i++)
+ st->mem[i] = 0;
+ return RESAMPLER_ERR_SUCCESS;
+}
+
+EXPORT const char *speex_resampler_strerror(int err)
+{
+ switch (err)
+ {
+ case RESAMPLER_ERR_SUCCESS:
+ return "Success.";
+ case RESAMPLER_ERR_ALLOC_FAILED:
+ return "Memory allocation failed.";
+ case RESAMPLER_ERR_BAD_STATE:
+ return "Bad resampler state.";
+ case RESAMPLER_ERR_INVALID_ARG:
+ return "Invalid argument.";
+ case RESAMPLER_ERR_PTR_OVERLAP:
+ return "Input and output buffers overlap.";
+ default:
+ return "Unknown error. Bad error code or strange version mismatch.";
+ }
+}