Merge "Revert "media: Update libchrome APIS to r456626.""
am: 13669840c9
Change-Id: Ic9f40e6c258530ad537f98e01a713b48ba0addf1
diff --git a/alsa_utils/alsa_device_proxy.c b/alsa_utils/alsa_device_proxy.c
index 96b880d..b5d0490 100644
--- a/alsa_utils/alsa_device_proxy.c
+++ b/alsa_utils/alsa_device_proxy.c
@@ -41,9 +41,11 @@
3, /* PCM_FORMAT_S24_3LE */
};
-void proxy_prepare(alsa_device_proxy * proxy, alsa_device_profile* profile,
+int proxy_prepare(alsa_device_proxy * proxy, alsa_device_profile* profile,
struct pcm_config * config)
{
+ int ret = 0;
+
ALOGV("proxy_prepare(c:%d, d:%d)", profile->card, profile->device);
proxy->profile = profile;
@@ -55,17 +57,25 @@
if (config->format != PCM_FORMAT_INVALID && profile_is_format_valid(profile, config->format)) {
proxy->alsa_config.format = config->format;
} else {
+ proxy->alsa_config.format = profile->default_config.format;
ALOGW("Invalid format %d - using default %d.",
config->format, profile->default_config.format);
- proxy->alsa_config.format = profile->default_config.format;
+ // Indicate override when default format was not requested
+ if (config->format != PCM_FORMAT_INVALID) {
+ ret = -EINVAL;
+ }
}
if (config->rate != 0 && profile_is_sample_rate_valid(profile, config->rate)) {
proxy->alsa_config.rate = config->rate;
} else {
+ proxy->alsa_config.rate = profile->default_config.rate;
ALOGW("Invalid sample rate %u - using default %u.",
config->rate, profile->default_config.rate);
- proxy->alsa_config.rate = profile->default_config.rate;
+ // Indicate override when default rate was not requested
+ if (config->rate != 0) {
+ ret = -EINVAL;
+ }
}
if (config->channels != 0 && profile_is_channel_count_valid(profile, config->channels)) {
@@ -74,6 +84,10 @@
proxy->alsa_config.channels = profile_get_closest_channel_count(profile, config->channels);
ALOGW("Invalid channel count %u - using closest %u.",
config->channels, proxy->alsa_config.channels);
+ // Indicate override when default channel count was not requested
+ if (config->channels != 0) {
+ ret = -EINVAL;
+ }
}
proxy->alsa_config.period_count = profile->default_config.period_count;
@@ -94,6 +108,20 @@
} else {
proxy->frame_size = 1;
}
+
+ // let's check to make sure we can ACTUALLY use the maximum rate (with the channel count)
+ // Note that profile->sample_rates is sorted highest to lowest, so the scan will get
+ // us the highest working rate
+ int max_rate_index = proxy_scan_rates(proxy, profile->sample_rates);
+ if (max_rate_index >= 0) {
+ if (proxy->alsa_config.rate > profile->sample_rates[max_rate_index]) {
+ ALOGW("Limiting samplnig rate from %u to %u.",
+ proxy->alsa_config.rate, profile->sample_rates[max_rate_index]);
+ proxy->alsa_config.rate = profile->sample_rates[max_rate_index];
+ ret = -EINVAL;
+ }
+ }
+ return ret;
}
int proxy_open(alsa_device_proxy * proxy)
@@ -113,7 +141,7 @@
}
if (!pcm_is_ready(proxy->pcm)) {
- ALOGE(" proxy_open() pcm_open() failed: %s", pcm_get_error(proxy->pcm));
+ ALOGE(" proxy_open() pcm_is_ready() failed: %s", pcm_get_error(proxy->pcm));
#if defined(LOG_PCM_PARAMS)
log_pcm_config(&proxy->alsa_config, "config");
#endif
@@ -233,3 +261,33 @@
dprintf(fd, " format: %d\n", proxy->alsa_config.format);
}
}
+
+int proxy_scan_rates(alsa_device_proxy * proxy, unsigned sample_rates[]) {
+ alsa_device_profile* profile = proxy->profile;
+ if (profile->card < 0 || profile->device < 0) {
+ return -EINVAL;
+ }
+
+ struct pcm_config alsa_config;
+ memcpy(&alsa_config, &proxy->alsa_config, sizeof(alsa_config));
+
+ struct pcm * alsa_pcm;
+ int rate_index = 0;
+ while (sample_rates[rate_index] != 0) {
+ alsa_config.rate = sample_rates[rate_index];
+ alsa_pcm = pcm_open(profile->card, profile->device,
+ profile->direction | PCM_MONOTONIC, &alsa_config);
+ if (alsa_pcm != NULL) {
+ if (pcm_is_ready(alsa_pcm)) {
+ pcm_close(alsa_pcm);
+ return rate_index;
+ }
+
+ pcm_close(alsa_pcm);
+ }
+
+ rate_index++;
+ }
+
+ return -EINVAL;
+}
diff --git a/alsa_utils/include/alsa_device_profile.h b/alsa_utils/include/alsa_device_profile.h
index e056d70..8307d0a 100644
--- a/alsa_utils/include/alsa_device_profile.h
+++ b/alsa_utils/include/alsa_device_profile.h
@@ -42,6 +42,7 @@
enum pcm_format formats[MAX_PROFILE_FORMATS];
+ /* note that this list is sorted highest rate to lowest */
unsigned sample_rates[MAX_PROFILE_SAMPLE_RATES];
unsigned channel_counts[MAX_PROFILE_CHANNEL_COUNTS];
diff --git a/alsa_utils/include/alsa_device_proxy.h b/alsa_utils/include/alsa_device_proxy.h
index 0bc0731..677bb5e 100644
--- a/alsa_utils/include/alsa_device_proxy.h
+++ b/alsa_utils/include/alsa_device_proxy.h
@@ -34,7 +34,7 @@
/* State */
-void proxy_prepare(alsa_device_proxy * proxy, alsa_device_profile * profile,
+int proxy_prepare(alsa_device_proxy * proxy, alsa_device_profile * profile,
struct pcm_config * config);
int proxy_open(alsa_device_proxy * proxy);
void proxy_close(alsa_device_proxy * proxy);
@@ -48,6 +48,14 @@
unsigned int proxy_get_period_size(const alsa_device_proxy * proxy);
unsigned proxy_get_latency(const alsa_device_proxy * proxy);
+/*
+ * Scans the provided list of sample rates and finds the first one that works.
+ *
+ * returns the index of the first rate for which the ALSA device can be opened.
+ * return negative value if none work or an error occurs.
+ */
+int proxy_scan_rates(alsa_device_proxy * proxy, unsigned sample_rates[]);
+
/* I/O */
int proxy_write(alsa_device_proxy * proxy, const void *data, unsigned int count);
int proxy_read(const alsa_device_proxy * proxy, void *data, unsigned int count);
diff --git a/audio/include/system/audio-base.h b/audio/include/system/audio-base.h
new file mode 100644
index 0000000..441226d
--- /dev/null
+++ b/audio/include/system/audio-base.h
@@ -0,0 +1,397 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+// Source: android.hardware.audio.common@2.0
+// Root: android.hardware:hardware/interfaces
+
+#ifndef HIDL_GENERATED_ANDROID_HARDWARE_AUDIO_COMMON_V2_0_EXPORTED_CONSTANTS_H_
+#define HIDL_GENERATED_ANDROID_HARDWARE_AUDIO_COMMON_V2_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,
+ AUDIO_STREAM_REROUTING = 11,
+ AUDIO_STREAM_PATCH = 12,
+ AUDIO_STREAM_PUBLIC_CNT = 11, // (ACCESSIBILITY + 1)
+ AUDIO_STREAM_FOR_POLICY_CNT = 12, // PATCH
+ AUDIO_STREAM_CNT = 13, // (PATCH + 1)
+} 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_CNT = 10,
+ AUDIO_SOURCE_MAX = 9, // (CNT - 1)
+ AUDIO_SOURCE_FM_TUNER = 1998,
+ AUDIO_SOURCE_HOTWORD = 1999,
+} 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 = 4294967295u, // 0xFFFFFFFFUL
+ AUDIO_FORMAT_DEFAULT = 0u, // 0
+ AUDIO_FORMAT_PCM = 0u, // 0x00000000UL
+ AUDIO_FORMAT_MP3 = 16777216u, // 0x01000000UL
+ AUDIO_FORMAT_AMR_NB = 33554432u, // 0x02000000UL
+ AUDIO_FORMAT_AMR_WB = 50331648u, // 0x03000000UL
+ AUDIO_FORMAT_AAC = 67108864u, // 0x04000000UL
+ AUDIO_FORMAT_HE_AAC_V1 = 83886080u, // 0x05000000UL
+ AUDIO_FORMAT_HE_AAC_V2 = 100663296u, // 0x06000000UL
+ AUDIO_FORMAT_VORBIS = 117440512u, // 0x07000000UL
+ AUDIO_FORMAT_OPUS = 134217728u, // 0x08000000UL
+ AUDIO_FORMAT_AC3 = 150994944u, // 0x09000000UL
+ AUDIO_FORMAT_E_AC3 = 167772160u, // 0x0A000000UL
+ AUDIO_FORMAT_DTS = 184549376u, // 0x0B000000UL
+ AUDIO_FORMAT_DTS_HD = 201326592u, // 0x0C000000UL
+ AUDIO_FORMAT_IEC61937 = 218103808u, // 0x0D000000UL
+ AUDIO_FORMAT_DOLBY_TRUEHD = 234881024u, // 0x0E000000UL
+ AUDIO_FORMAT_EVRC = 268435456u, // 0x10000000UL
+ AUDIO_FORMAT_EVRCB = 285212672u, // 0x11000000UL
+ AUDIO_FORMAT_EVRCWB = 301989888u, // 0x12000000UL
+ AUDIO_FORMAT_EVRCNW = 318767104u, // 0x13000000UL
+ AUDIO_FORMAT_AAC_ADIF = 335544320u, // 0x14000000UL
+ AUDIO_FORMAT_WMA = 352321536u, // 0x15000000UL
+ AUDIO_FORMAT_WMA_PRO = 369098752u, // 0x16000000UL
+ AUDIO_FORMAT_AMR_WB_PLUS = 385875968u, // 0x17000000UL
+ AUDIO_FORMAT_MP2 = 402653184u, // 0x18000000UL
+ AUDIO_FORMAT_QCELP = 419430400u, // 0x19000000UL
+ AUDIO_FORMAT_DSD = 436207616u, // 0x1A000000UL
+ AUDIO_FORMAT_FLAC = 452984832u, // 0x1B000000UL
+ AUDIO_FORMAT_ALAC = 469762048u, // 0x1C000000UL
+ AUDIO_FORMAT_APE = 486539264u, // 0x1D000000UL
+ AUDIO_FORMAT_AAC_ADTS = 503316480u, // 0x1E000000UL
+ AUDIO_FORMAT_SBC = 520093696u, // 0x1F000000UL
+ AUDIO_FORMAT_APTX = 536870912u, // 0x20000000UL
+ AUDIO_FORMAT_APTX_HD = 553648128u, // 0x21000000UL
+ AUDIO_FORMAT_AC4 = 570425344u, // 0x22000000UL
+ AUDIO_FORMAT_LDAC = 587202560u, // 0x23000000UL
+ AUDIO_FORMAT_MAIN_MASK = 4278190080u, // 0xFF000000UL
+ AUDIO_FORMAT_SUB_MASK = 16777215u, // 0x00FFFFFFUL
+ AUDIO_FORMAT_PCM_SUB_16_BIT = 1u, // 0x1
+ AUDIO_FORMAT_PCM_SUB_8_BIT = 2u, // 0x2
+ AUDIO_FORMAT_PCM_SUB_32_BIT = 3u, // 0x3
+ AUDIO_FORMAT_PCM_SUB_8_24_BIT = 4u, // 0x4
+ AUDIO_FORMAT_PCM_SUB_FLOAT = 5u, // 0x5
+ AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED = 6u, // 0x6
+ AUDIO_FORMAT_MP3_SUB_NONE = 0u, // 0x0
+ AUDIO_FORMAT_AMR_SUB_NONE = 0u, // 0x0
+ AUDIO_FORMAT_AAC_SUB_MAIN = 1u, // 0x1
+ AUDIO_FORMAT_AAC_SUB_LC = 2u, // 0x2
+ AUDIO_FORMAT_AAC_SUB_SSR = 4u, // 0x4
+ AUDIO_FORMAT_AAC_SUB_LTP = 8u, // 0x8
+ AUDIO_FORMAT_AAC_SUB_HE_V1 = 16u, // 0x10
+ AUDIO_FORMAT_AAC_SUB_SCALABLE = 32u, // 0x20
+ AUDIO_FORMAT_AAC_SUB_ERLC = 64u, // 0x40
+ AUDIO_FORMAT_AAC_SUB_LD = 128u, // 0x80
+ AUDIO_FORMAT_AAC_SUB_HE_V2 = 256u, // 0x100
+ AUDIO_FORMAT_AAC_SUB_ELD = 512u, // 0x200
+ AUDIO_FORMAT_VORBIS_SUB_NONE = 0u, // 0x0
+ AUDIO_FORMAT_PCM_16_BIT = 1u, // (PCM | PCM_SUB_16_BIT)
+ AUDIO_FORMAT_PCM_8_BIT = 2u, // (PCM | PCM_SUB_8_BIT)
+ AUDIO_FORMAT_PCM_32_BIT = 3u, // (PCM | PCM_SUB_32_BIT)
+ AUDIO_FORMAT_PCM_8_24_BIT = 4u, // (PCM | PCM_SUB_8_24_BIT)
+ AUDIO_FORMAT_PCM_FLOAT = 5u, // (PCM | PCM_SUB_FLOAT)
+ AUDIO_FORMAT_PCM_24_BIT_PACKED = 6u, // (PCM | PCM_SUB_24_BIT_PACKED)
+ AUDIO_FORMAT_AAC_MAIN = 67108865u, // (AAC | AAC_SUB_MAIN)
+ AUDIO_FORMAT_AAC_LC = 67108866u, // (AAC | AAC_SUB_LC)
+ AUDIO_FORMAT_AAC_SSR = 67108868u, // (AAC | AAC_SUB_SSR)
+ AUDIO_FORMAT_AAC_LTP = 67108872u, // (AAC | AAC_SUB_LTP)
+ AUDIO_FORMAT_AAC_HE_V1 = 67108880u, // (AAC | AAC_SUB_HE_V1)
+ AUDIO_FORMAT_AAC_SCALABLE = 67108896u, // (AAC | AAC_SUB_SCALABLE)
+ AUDIO_FORMAT_AAC_ERLC = 67108928u, // (AAC | AAC_SUB_ERLC)
+ AUDIO_FORMAT_AAC_LD = 67108992u, // (AAC | AAC_SUB_LD)
+ AUDIO_FORMAT_AAC_HE_V2 = 67109120u, // (AAC | AAC_SUB_HE_V2)
+ AUDIO_FORMAT_AAC_ELD = 67109376u, // (AAC | AAC_SUB_ELD)
+ AUDIO_FORMAT_AAC_ADTS_MAIN = 503316481u, // (AAC_ADTS | AAC_SUB_MAIN)
+ AUDIO_FORMAT_AAC_ADTS_LC = 503316482u, // (AAC_ADTS | AAC_SUB_LC)
+ AUDIO_FORMAT_AAC_ADTS_SSR = 503316484u, // (AAC_ADTS | AAC_SUB_SSR)
+ AUDIO_FORMAT_AAC_ADTS_LTP = 503316488u, // (AAC_ADTS | AAC_SUB_LTP)
+ AUDIO_FORMAT_AAC_ADTS_HE_V1 = 503316496u, // (AAC_ADTS | AAC_SUB_HE_V1)
+ AUDIO_FORMAT_AAC_ADTS_SCALABLE = 503316512u, // (AAC_ADTS | AAC_SUB_SCALABLE)
+ AUDIO_FORMAT_AAC_ADTS_ERLC = 503316544u, // (AAC_ADTS | AAC_SUB_ERLC)
+ AUDIO_FORMAT_AAC_ADTS_LD = 503316608u, // (AAC_ADTS | AAC_SUB_LD)
+ AUDIO_FORMAT_AAC_ADTS_HE_V2 = 503316736u, // (AAC_ADTS | AAC_SUB_HE_V2)
+ AUDIO_FORMAT_AAC_ADTS_ELD = 503316992u, // (AAC_ADTS | AAC_SUB_ELD)
+} audio_format_t;
+
+enum {
+ FCC_2 = 2,
+ FCC_8 = 8,
+};
+
+enum {
+ AUDIO_CHANNEL_REPRESENTATION_POSITION = 0u, // 0
+ AUDIO_CHANNEL_REPRESENTATION_INDEX = 2u, // 2
+ AUDIO_CHANNEL_NONE = 0u, // 0x0
+ AUDIO_CHANNEL_INVALID = 3221225472u, // 0xC0000000
+ AUDIO_CHANNEL_OUT_FRONT_LEFT = 1u, // 0x1
+ AUDIO_CHANNEL_OUT_FRONT_RIGHT = 2u, // 0x2
+ AUDIO_CHANNEL_OUT_FRONT_CENTER = 4u, // 0x4
+ AUDIO_CHANNEL_OUT_LOW_FREQUENCY = 8u, // 0x8
+ AUDIO_CHANNEL_OUT_BACK_LEFT = 16u, // 0x10
+ AUDIO_CHANNEL_OUT_BACK_RIGHT = 32u, // 0x20
+ AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 64u, // 0x40
+ AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 128u, // 0x80
+ AUDIO_CHANNEL_OUT_BACK_CENTER = 256u, // 0x100
+ AUDIO_CHANNEL_OUT_SIDE_LEFT = 512u, // 0x200
+ AUDIO_CHANNEL_OUT_SIDE_RIGHT = 1024u, // 0x400
+ AUDIO_CHANNEL_OUT_TOP_CENTER = 2048u, // 0x800
+ AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT = 4096u, // 0x1000
+ AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER = 8192u, // 0x2000
+ AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT = 16384u, // 0x4000
+ AUDIO_CHANNEL_OUT_TOP_BACK_LEFT = 32768u, // 0x8000
+ AUDIO_CHANNEL_OUT_TOP_BACK_CENTER = 65536u, // 0x10000
+ AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT = 131072u, // 0x20000
+ AUDIO_CHANNEL_OUT_MONO = 1u, // OUT_FRONT_LEFT
+ AUDIO_CHANNEL_OUT_STEREO = 3u, // (OUT_FRONT_LEFT | OUT_FRONT_RIGHT)
+ AUDIO_CHANNEL_OUT_2POINT1 = 11u, // ((OUT_FRONT_LEFT | OUT_FRONT_RIGHT) | OUT_LOW_FREQUENCY)
+ AUDIO_CHANNEL_OUT_QUAD = 51u, // (((OUT_FRONT_LEFT | OUT_FRONT_RIGHT) | OUT_BACK_LEFT) | OUT_BACK_RIGHT)
+ AUDIO_CHANNEL_OUT_QUAD_BACK = 51u, // OUT_QUAD
+ AUDIO_CHANNEL_OUT_QUAD_SIDE = 1539u, // (((OUT_FRONT_LEFT | OUT_FRONT_RIGHT) | OUT_SIDE_LEFT) | OUT_SIDE_RIGHT)
+ AUDIO_CHANNEL_OUT_SURROUND = 263u, // (((OUT_FRONT_LEFT | OUT_FRONT_RIGHT) | OUT_FRONT_CENTER) | OUT_BACK_CENTER)
+ AUDIO_CHANNEL_OUT_PENTA = 55u, // (OUT_QUAD | OUT_FRONT_CENTER)
+ AUDIO_CHANNEL_OUT_5POINT1 = 63u, // (((((OUT_FRONT_LEFT | OUT_FRONT_RIGHT) | OUT_FRONT_CENTER) | OUT_LOW_FREQUENCY) | OUT_BACK_LEFT) | OUT_BACK_RIGHT)
+ AUDIO_CHANNEL_OUT_5POINT1_BACK = 63u, // OUT_5POINT1
+ AUDIO_CHANNEL_OUT_5POINT1_SIDE = 1551u, // (((((OUT_FRONT_LEFT | OUT_FRONT_RIGHT) | OUT_FRONT_CENTER) | OUT_LOW_FREQUENCY) | OUT_SIDE_LEFT) | OUT_SIDE_RIGHT)
+ AUDIO_CHANNEL_OUT_6POINT1 = 319u, // ((((((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 = 1599u, // (((((((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_ALL = 262143u, // (((((((((((((((((OUT_FRONT_LEFT | OUT_FRONT_RIGHT) | OUT_FRONT_CENTER) | OUT_LOW_FREQUENCY) | OUT_BACK_LEFT) | OUT_BACK_RIGHT) | OUT_FRONT_LEFT_OF_CENTER) | OUT_FRONT_RIGHT_OF_CENTER) | OUT_BACK_CENTER) | OUT_SIDE_LEFT) | OUT_SIDE_RIGHT) | OUT_TOP_CENTER) | OUT_TOP_FRONT_LEFT) | OUT_TOP_FRONT_CENTER) | OUT_TOP_FRONT_RIGHT) | OUT_TOP_BACK_LEFT) | OUT_TOP_BACK_CENTER) | OUT_TOP_BACK_RIGHT)
+ AUDIO_CHANNEL_IN_LEFT = 4u, // 0x4
+ AUDIO_CHANNEL_IN_RIGHT = 8u, // 0x8
+ AUDIO_CHANNEL_IN_FRONT = 16u, // 0x10
+ AUDIO_CHANNEL_IN_BACK = 32u, // 0x20
+ AUDIO_CHANNEL_IN_LEFT_PROCESSED = 64u, // 0x40
+ AUDIO_CHANNEL_IN_RIGHT_PROCESSED = 128u, // 0x80
+ AUDIO_CHANNEL_IN_FRONT_PROCESSED = 256u, // 0x100
+ AUDIO_CHANNEL_IN_BACK_PROCESSED = 512u, // 0x200
+ AUDIO_CHANNEL_IN_PRESSURE = 1024u, // 0x400
+ AUDIO_CHANNEL_IN_X_AXIS = 2048u, // 0x800
+ AUDIO_CHANNEL_IN_Y_AXIS = 4096u, // 0x1000
+ AUDIO_CHANNEL_IN_Z_AXIS = 8192u, // 0x2000
+ AUDIO_CHANNEL_IN_VOICE_UPLINK = 16384u, // 0x4000
+ AUDIO_CHANNEL_IN_VOICE_DNLINK = 32768u, // 0x8000
+ AUDIO_CHANNEL_IN_MONO = 16u, // IN_FRONT
+ AUDIO_CHANNEL_IN_STEREO = 12u, // (IN_LEFT | IN_RIGHT)
+ AUDIO_CHANNEL_IN_FRONT_BACK = 48u, // (IN_FRONT | IN_BACK)
+ AUDIO_CHANNEL_IN_6 = 252u, // (((((IN_LEFT | IN_RIGHT) | IN_FRONT) | IN_BACK) | IN_LEFT_PROCESSED) | IN_RIGHT_PROCESSED)
+ AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO = 16400u, // (IN_VOICE_UPLINK | IN_MONO)
+ AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO = 32784u, // (IN_VOICE_DNLINK | IN_MONO)
+ AUDIO_CHANNEL_IN_VOICE_CALL_MONO = 49168u, // (IN_VOICE_UPLINK_MONO | IN_VOICE_DNLINK_MONO)
+ AUDIO_CHANNEL_IN_ALL = 65532u, // (((((((((((((IN_LEFT | IN_RIGHT) | IN_FRONT) | IN_BACK) | IN_LEFT_PROCESSED) | IN_RIGHT_PROCESSED) | IN_FRONT_PROCESSED) | IN_BACK_PROCESSED) | IN_PRESSURE) | IN_X_AXIS) | IN_Y_AXIS) | IN_Z_AXIS) | IN_VOICE_UPLINK) | IN_VOICE_DNLINK)
+ AUDIO_CHANNEL_COUNT_MAX = 30u, // 30
+ AUDIO_CHANNEL_INDEX_HDR = 2147483648u, // (REPRESENTATION_INDEX << COUNT_MAX)
+ AUDIO_CHANNEL_INDEX_MASK_1 = 2147483649u, // (INDEX_HDR | ((1 << 1) - 1))
+ AUDIO_CHANNEL_INDEX_MASK_2 = 2147483651u, // (INDEX_HDR | ((1 << 2) - 1))
+ AUDIO_CHANNEL_INDEX_MASK_3 = 2147483655u, // (INDEX_HDR | ((1 << 3) - 1))
+ AUDIO_CHANNEL_INDEX_MASK_4 = 2147483663u, // (INDEX_HDR | ((1 << 4) - 1))
+ AUDIO_CHANNEL_INDEX_MASK_5 = 2147483679u, // (INDEX_HDR | ((1 << 5) - 1))
+ AUDIO_CHANNEL_INDEX_MASK_6 = 2147483711u, // (INDEX_HDR | ((1 << 6) - 1))
+ AUDIO_CHANNEL_INDEX_MASK_7 = 2147483775u, // (INDEX_HDR | ((1 << 7) - 1))
+ AUDIO_CHANNEL_INDEX_MASK_8 = 2147483903u, // (INDEX_HDR | ((1 << 8) - 1))
+};
+
+enum {
+ AUDIO_INTERLEAVE_LEFT = 0,
+ AUDIO_INTERLEAVE_RIGHT = 1,
+};
+
+typedef enum {
+ AUDIO_MODE_INVALID = -2, // (-2)
+ AUDIO_MODE_CURRENT = -1, // (-1)
+ AUDIO_MODE_NORMAL = 0,
+ AUDIO_MODE_RINGTONE = 1,
+ AUDIO_MODE_IN_CALL = 2,
+ AUDIO_MODE_IN_COMMUNICATION = 3,
+ AUDIO_MODE_CNT = 4,
+ AUDIO_MODE_MAX = 3, // (CNT - 1)
+} audio_mode_t;
+
+enum {
+ AUDIO_DEVICE_NONE = 0u, // 0x0
+ AUDIO_DEVICE_BIT_IN = 2147483648u, // 0x80000000
+ AUDIO_DEVICE_BIT_DEFAULT = 1073741824u, // 0x40000000
+ AUDIO_DEVICE_OUT_EARPIECE = 1u, // 0x1
+ AUDIO_DEVICE_OUT_SPEAKER = 2u, // 0x2
+ AUDIO_DEVICE_OUT_WIRED_HEADSET = 4u, // 0x4
+ AUDIO_DEVICE_OUT_WIRED_HEADPHONE = 8u, // 0x8
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO = 16u, // 0x10
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 32u, // 0x20
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 64u, // 0x40
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP = 128u, // 0x80
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 256u, // 0x100
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 512u, // 0x200
+ AUDIO_DEVICE_OUT_AUX_DIGITAL = 1024u, // 0x400
+ AUDIO_DEVICE_OUT_HDMI = 1024u, // OUT_AUX_DIGITAL
+ AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET = 2048u, // 0x800
+ AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET = 4096u, // 0x1000
+ AUDIO_DEVICE_OUT_USB_ACCESSORY = 8192u, // 0x2000
+ AUDIO_DEVICE_OUT_USB_DEVICE = 16384u, // 0x4000
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX = 32768u, // 0x8000
+ AUDIO_DEVICE_OUT_TELEPHONY_TX = 65536u, // 0x10000
+ AUDIO_DEVICE_OUT_LINE = 131072u, // 0x20000
+ AUDIO_DEVICE_OUT_HDMI_ARC = 262144u, // 0x40000
+ AUDIO_DEVICE_OUT_SPDIF = 524288u, // 0x80000
+ AUDIO_DEVICE_OUT_FM = 1048576u, // 0x100000
+ AUDIO_DEVICE_OUT_AUX_LINE = 2097152u, // 0x200000
+ AUDIO_DEVICE_OUT_SPEAKER_SAFE = 4194304u, // 0x400000
+ AUDIO_DEVICE_OUT_IP = 8388608u, // 0x800000
+ AUDIO_DEVICE_OUT_BUS = 16777216u, // 0x1000000
+ AUDIO_DEVICE_OUT_PROXY = 33554432u, // 0x2000000
+ AUDIO_DEVICE_OUT_USB_HEADSET = 67108864u, // 0x4000000
+ AUDIO_DEVICE_OUT_DEFAULT = 1073741824u, // BIT_DEFAULT
+ AUDIO_DEVICE_OUT_ALL = 1207959551u, // (((((((((((((((((((((((((((OUT_EARPIECE | OUT_SPEAKER) | OUT_WIRED_HEADSET) | OUT_WIRED_HEADPHONE) | OUT_BLUETOOTH_SCO) | OUT_BLUETOOTH_SCO_HEADSET) | OUT_BLUETOOTH_SCO_CARKIT) | OUT_BLUETOOTH_A2DP) | OUT_BLUETOOTH_A2DP_HEADPHONES) | OUT_BLUETOOTH_A2DP_SPEAKER) | OUT_HDMI) | OUT_ANLG_DOCK_HEADSET) | OUT_DGTL_DOCK_HEADSET) | OUT_USB_ACCESSORY) | OUT_USB_DEVICE) | OUT_REMOTE_SUBMIX) | OUT_TELEPHONY_TX) | OUT_LINE) | OUT_HDMI_ARC) | OUT_SPDIF) | OUT_FM) | OUT_AUX_LINE) | OUT_SPEAKER_SAFE) | OUT_IP) | OUT_BUS) | OUT_PROXY) | OUT_USB_HEADSET) | OUT_DEFAULT)
+ AUDIO_DEVICE_OUT_ALL_A2DP = 896u, // ((OUT_BLUETOOTH_A2DP | OUT_BLUETOOTH_A2DP_HEADPHONES) | OUT_BLUETOOTH_A2DP_SPEAKER)
+ AUDIO_DEVICE_OUT_ALL_SCO = 112u, // ((OUT_BLUETOOTH_SCO | OUT_BLUETOOTH_SCO_HEADSET) | OUT_BLUETOOTH_SCO_CARKIT)
+ AUDIO_DEVICE_OUT_ALL_USB = 67133440u, // ((OUT_USB_ACCESSORY | OUT_USB_DEVICE) | OUT_USB_HEADSET)
+ AUDIO_DEVICE_IN_COMMUNICATION = 2147483649u, // (BIT_IN | 0x1)
+ AUDIO_DEVICE_IN_AMBIENT = 2147483650u, // (BIT_IN | 0x2)
+ AUDIO_DEVICE_IN_BUILTIN_MIC = 2147483652u, // (BIT_IN | 0x4)
+ AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = 2147483656u, // (BIT_IN | 0x8)
+ AUDIO_DEVICE_IN_WIRED_HEADSET = 2147483664u, // (BIT_IN | 0x10)
+ AUDIO_DEVICE_IN_AUX_DIGITAL = 2147483680u, // (BIT_IN | 0x20)
+ AUDIO_DEVICE_IN_HDMI = 2147483680u, // IN_AUX_DIGITAL
+ AUDIO_DEVICE_IN_VOICE_CALL = 2147483712u, // (BIT_IN | 0x40)
+ AUDIO_DEVICE_IN_TELEPHONY_RX = 2147483712u, // IN_VOICE_CALL
+ AUDIO_DEVICE_IN_BACK_MIC = 2147483776u, // (BIT_IN | 0x80)
+ AUDIO_DEVICE_IN_REMOTE_SUBMIX = 2147483904u, // (BIT_IN | 0x100)
+ AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET = 2147484160u, // (BIT_IN | 0x200)
+ AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET = 2147484672u, // (BIT_IN | 0x400)
+ AUDIO_DEVICE_IN_USB_ACCESSORY = 2147485696u, // (BIT_IN | 0x800)
+ AUDIO_DEVICE_IN_USB_DEVICE = 2147487744u, // (BIT_IN | 0x1000)
+ AUDIO_DEVICE_IN_FM_TUNER = 2147491840u, // (BIT_IN | 0x2000)
+ AUDIO_DEVICE_IN_TV_TUNER = 2147500032u, // (BIT_IN | 0x4000)
+ AUDIO_DEVICE_IN_LINE = 2147516416u, // (BIT_IN | 0x8000)
+ AUDIO_DEVICE_IN_SPDIF = 2147549184u, // (BIT_IN | 0x10000)
+ AUDIO_DEVICE_IN_BLUETOOTH_A2DP = 2147614720u, // (BIT_IN | 0x20000)
+ AUDIO_DEVICE_IN_LOOPBACK = 2147745792u, // (BIT_IN | 0x40000)
+ AUDIO_DEVICE_IN_IP = 2148007936u, // (BIT_IN | 0x80000)
+ AUDIO_DEVICE_IN_BUS = 2148532224u, // (BIT_IN | 0x100000)
+ AUDIO_DEVICE_IN_PROXY = 2164260864u, // (BIT_IN | 0x1000000)
+ AUDIO_DEVICE_IN_USB_HEADSET = 2181038080u, // (BIT_IN | 0x2000000)
+ AUDIO_DEVICE_IN_DEFAULT = 3221225472u, // (BIT_IN | BIT_DEFAULT)
+ AUDIO_DEVICE_IN_ALL = 3273654271u, // (((((((((((((((((((((((IN_COMMUNICATION | IN_AMBIENT) | IN_BUILTIN_MIC) | IN_BLUETOOTH_SCO_HEADSET) | IN_WIRED_HEADSET) | IN_HDMI) | IN_TELEPHONY_RX) | IN_BACK_MIC) | IN_REMOTE_SUBMIX) | IN_ANLG_DOCK_HEADSET) | IN_DGTL_DOCK_HEADSET) | IN_USB_ACCESSORY) | IN_USB_DEVICE) | IN_FM_TUNER) | IN_TV_TUNER) | IN_LINE) | IN_SPDIF) | IN_BLUETOOTH_A2DP) | IN_LOOPBACK) | IN_IP) | IN_BUS) | IN_PROXY) | IN_USB_HEADSET) | IN_DEFAULT)
+ AUDIO_DEVICE_IN_ALL_SCO = 2147483656u, // IN_BLUETOOTH_SCO_HEADSET
+ AUDIO_DEVICE_IN_ALL_USB = 2181044224u, // ((IN_USB_ACCESSORY | IN_USB_DEVICE) | IN_USB_HEADSET)
+};
+
+typedef enum {
+ AUDIO_OUTPUT_FLAG_NONE = 0, // 0x0
+ AUDIO_OUTPUT_FLAG_DIRECT = 1, // 0x1
+ AUDIO_OUTPUT_FLAG_PRIMARY = 2, // 0x2
+ AUDIO_OUTPUT_FLAG_FAST = 4, // 0x4
+ AUDIO_OUTPUT_FLAG_DEEP_BUFFER = 8, // 0x8
+ AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD = 16, // 0x10
+ AUDIO_OUTPUT_FLAG_NON_BLOCKING = 32, // 0x20
+ AUDIO_OUTPUT_FLAG_HW_AV_SYNC = 64, // 0x40
+ AUDIO_OUTPUT_FLAG_TTS = 128, // 0x80
+ AUDIO_OUTPUT_FLAG_RAW = 256, // 0x100
+ AUDIO_OUTPUT_FLAG_SYNC = 512, // 0x200
+ AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO = 1024, // 0x400
+ AUDIO_OUTPUT_FLAG_DIRECT_PCM = 8192, // 0x2000
+ AUDIO_OUTPUT_FLAG_MMAP_NOIRQ = 16384, // 0x4000
+ AUDIO_OUTPUT_FLAG_VOIP_RX = 32768, // 0x8000
+} audio_output_flags_t;
+
+typedef enum {
+ AUDIO_INPUT_FLAG_NONE = 0, // 0x0
+ AUDIO_INPUT_FLAG_FAST = 1, // 0x1
+ AUDIO_INPUT_FLAG_HW_HOTWORD = 2, // 0x2
+ AUDIO_INPUT_FLAG_RAW = 4, // 0x4
+ AUDIO_INPUT_FLAG_SYNC = 8, // 0x8
+ AUDIO_INPUT_FLAG_MMAP_NOIRQ = 16, // 0x10
+ AUDIO_INPUT_FLAG_VOIP_TX = 32, // 0x20
+} 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,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9,
+ AUDIO_USAGE_NOTIFICATION_EVENT = 10,
+ 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_CNT = 17,
+ AUDIO_USAGE_MAX = 16, // (CNT - 1)
+} audio_usage_t;
+
+enum {
+ AUDIO_GAIN_MODE_JOINT = 1u, // 0x1
+ AUDIO_GAIN_MODE_CHANNELS = 2u, // 0x2
+ AUDIO_GAIN_MODE_RAMP = 4u, // 0x4
+};
+
+typedef enum {
+ AUDIO_PORT_ROLE_NONE = 0,
+ AUDIO_PORT_ROLE_SOURCE = 1,
+ AUDIO_PORT_ROLE_SINK = 2,
+} audio_port_role_t;
+
+typedef enum {
+ AUDIO_PORT_TYPE_NONE = 0,
+ AUDIO_PORT_TYPE_DEVICE = 1,
+ AUDIO_PORT_TYPE_MIX = 2,
+ AUDIO_PORT_TYPE_SESSION = 3,
+} audio_port_type_t;
+
+enum {
+ AUDIO_PORT_CONFIG_SAMPLE_RATE = 1u, // 0x1
+ AUDIO_PORT_CONFIG_CHANNEL_MASK = 2u, // 0x2
+ AUDIO_PORT_CONFIG_FORMAT = 4u, // 0x4
+ AUDIO_PORT_CONFIG_GAIN = 8u, // 0x8
+ AUDIO_PORT_CONFIG_ALL = 15u, // (((SAMPLE_RATE | CHANNEL_MASK) | FORMAT) | GAIN)
+};
+
+typedef enum {
+ AUDIO_LATENCY_LOW = 0,
+ AUDIO_LATENCY_NORMAL = 1,
+} audio_mix_latency_class_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // HIDL_GENERATED_ANDROID_HARDWARE_AUDIO_COMMON_V2_0_EXPORTED_CONSTANTS_H_
diff --git a/audio/include/system/audio.h b/audio/include/system/audio.h
index d7a90ea..e683d60 100644
--- a/audio/include/system/audio.h
+++ b/audio/include/system/audio.h
@@ -26,61 +26,22 @@
#include <cutils/bitops.h>
+#include "audio-base.h"
+
__BEGIN_DECLS
-/* The macro FCC_2 highlights places where there are 2-channel assumptions.
- * This is typically due to legacy implementation of stereo input or output.
- * Search also for "2", "left", "right", "[0]", "[1]", ">> 16", "<< 16", etc.
- * Do not change this value.
- */
-#define FCC_2 2 // FCC_2 = Fixed Channel Count 2
-
-/* The macro FCC_8 highlights places where there are 8-channel assumptions.
- * This is typically due to audio mixer and resampler limitations.
- * Do not change this value without verifying all locations that use it.
- */
-#define FCC_8 8 // FCC_8 = Fixed Channel Count 8
-
/* 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;
-#define AUDIO_IO_HANDLE_NONE 0
-
-/* Audio stream types */
-typedef enum {
- /* These values must kept in sync with
- * frameworks/base/media/java/android/media/AudioSystem.java
- */
- AUDIO_STREAM_DEFAULT = -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, /* Sounds that cannot be muted by user
- * and must be routed to speaker
- */
- AUDIO_STREAM_DTMF = 8,
- AUDIO_STREAM_TTS = 9, /* Transmitted Through Speaker.
- * Plays over speaker only, silent on other devices.
- */
- AUDIO_STREAM_ACCESSIBILITY = 10, /* For accessibility talk back prompts */
- AUDIO_STREAM_REROUTING = 11, /* For dynamic policy output mixes */
- AUDIO_STREAM_PATCH = 12, /* For internal audio flinger tracks. Fixed volume */
- AUDIO_STREAM_PUBLIC_CNT = AUDIO_STREAM_TTS + 1,
- AUDIO_STREAM_FOR_POLICY_CNT = AUDIO_STREAM_PATCH, /* number of streams considered by
- audio policy for volume and routing */
- AUDIO_STREAM_CNT = AUDIO_STREAM_PATCH + 1,
-} audio_stream_type_t;
/* Do not change these values without updating their counterparts
* in frameworks/base/media/java/android/media/AudioAttributes.java
@@ -96,37 +57,13 @@
AUDIO_CONTENT_TYPE_MAX = AUDIO_CONTENT_TYPE_CNT - 1,
} audio_content_type_t;
-/* Do not change these values without updating their counterparts
- * in frameworks/base/media/java/android/media/AudioAttributes.java
- */
-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,
- AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7,
- AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8,
- AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9,
- AUDIO_USAGE_NOTIFICATION_EVENT = 10,
- 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_CNT,
- AUDIO_USAGE_MAX = AUDIO_USAGE_CNT - 1,
-} audio_usage_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,
@@ -136,39 +73,9 @@
AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY = 0x40,
AUDIO_FLAG_BYPASS_MUTE = 0x80,
AUDIO_FLAG_LOW_LATENCY = 0x100,
+ AUDIO_FLAG_DEEP_BUFFER = 0x200,
};
-/* Do not change these values without updating their counterparts
- * in frameworks/base/media/java/android/media/MediaRecorder.java,
- * frameworks/av/services/audiopolicy/AudioPolicyService.cpp,
- * and system/media/audio_effects/include/audio_effects/audio_effects_conf.h!
- */
-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, /* Source for the mix to be presented remotely. */
- /* An example of remote presentation is Wifi Display */
- /* where a dongle attached to a TV can be used to */
- /* play the mix captured by this audio source. */
- AUDIO_SOURCE_UNPROCESSED = 9, /* Source for unprocessed sound.
- Usage examples include level measurement and raw
- signal analysis. */
- AUDIO_SOURCE_CNT,
- AUDIO_SOURCE_MAX = AUDIO_SOURCE_CNT - 1,
- AUDIO_SOURCE_FM_TUNER = 1998,
- AUDIO_SOURCE_HOTWORD = 1999, /* A low-priority, preemptible audio source for
- for background software hotword detection.
- Same tuning as AUDIO_SOURCE_VOICE_RECOGNITION.
- Used only internally to the framework. Not exposed
- at the audio HAL. */
-} audio_source_t;
-
/* Audio attributes */
#define AUDIO_ATTRIBUTES_TAGS_MAX_SIZE 256
typedef struct {
@@ -179,36 +86,6 @@
char tags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE]; /* UTF8 */
} audio_attributes_t;
-/* special audio session values
- * do not need to have audio_unique_id_get_use(session) == AUDIO_UNIQUE_ID_USE_SESSION
- * (XXX: should this be living in the audio effects land?)
- */
-typedef enum {
- /* session for effects attached to a particular output stream
- * (value must be less than 0)
- */
- AUDIO_SESSION_OUTPUT_STAGE = -1,
-
- /* session for effects applied to output mix. These effects can
- * be moved by audio policy manager to another output stream
- * (value must be 0)
- */
- AUDIO_SESSION_OUTPUT_MIX = 0,
-
- /* application does not specify an explicit session ID to be used,
- * and requests a new session ID to be allocated
- * TODO use unique values for AUDIO_SESSION_OUTPUT_MIX and AUDIO_SESSION_ALLOCATE,
- * after all uses have been updated from 0 to the appropriate symbol, and have been tested.
- * Corresponds to AudioManager.AUDIO_SESSION_ID_GENERATE and AudioSystem.AUDIO_SESSION_ALLOCATE.
- */
- AUDIO_SESSION_ALLOCATE = 0,
-
- /* For use with AudioRecord::start(), this indicates no trigger session.
- * It is also used with output tracks and patch tracks, which never have a session.
- */
- AUDIO_SESSION_NONE = 0,
-} audio_session_t;
-
/* 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
@@ -225,7 +102,7 @@
AUDIO_UNIQUE_ID_USE_PATCH = 4,
AUDIO_UNIQUE_ID_USE_OUTPUT = 5,
AUDIO_UNIQUE_ID_USE_INPUT = 6,
- // 7 is available
+ 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;
@@ -239,253 +116,6 @@
/* Reserved audio_unique_id_t values. FIXME: not a complete list. */
#define AUDIO_UNIQUE_ID_ALLOCATE AUDIO_SESSION_ALLOCATE
-/* Audio sub formats (see enum audio_format). */
-
-/* PCM sub formats */
-typedef enum {
- /* All of these are in native byte order */
- AUDIO_FORMAT_PCM_SUB_16_BIT = 0x1, /* DO NOT CHANGE - PCM signed 16 bits */
- AUDIO_FORMAT_PCM_SUB_8_BIT = 0x2, /* DO NOT CHANGE - PCM unsigned 8 bits */
- AUDIO_FORMAT_PCM_SUB_32_BIT = 0x3, /* PCM signed .31 fixed point */
- AUDIO_FORMAT_PCM_SUB_8_24_BIT = 0x4, /* PCM signed 8.23 fixed point */
- AUDIO_FORMAT_PCM_SUB_FLOAT = 0x5, /* PCM single-precision floating point */
- AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED = 0x6, /* PCM signed .23 fixed point packed in 3 bytes */
-} audio_format_pcm_sub_fmt_t;
-
-/* The audio_format_*_sub_fmt_t declarations are not currently used */
-
-/* MP3 sub format field definition : can use 11 LSBs in the same way as MP3
- * frame header to specify bit rate, stereo mode, version...
- */
-typedef enum {
- AUDIO_FORMAT_MP3_SUB_NONE = 0x0,
-} audio_format_mp3_sub_fmt_t;
-
-/* AMR NB/WB sub format field definition: specify frame block interleaving,
- * bandwidth efficient or octet aligned, encoding mode for recording...
- */
-typedef enum {
- AUDIO_FORMAT_AMR_SUB_NONE = 0x0,
-} audio_format_amr_sub_fmt_t;
-
-/* AAC sub format field definition: specify profile or bitrate for recording... */
-typedef enum {
- AUDIO_FORMAT_AAC_SUB_MAIN = 0x1,
- AUDIO_FORMAT_AAC_SUB_LC = 0x2,
- AUDIO_FORMAT_AAC_SUB_SSR = 0x4,
- AUDIO_FORMAT_AAC_SUB_LTP = 0x8,
- AUDIO_FORMAT_AAC_SUB_HE_V1 = 0x10,
- AUDIO_FORMAT_AAC_SUB_SCALABLE = 0x20,
- AUDIO_FORMAT_AAC_SUB_ERLC = 0x40,
- AUDIO_FORMAT_AAC_SUB_LD = 0x80,
- AUDIO_FORMAT_AAC_SUB_HE_V2 = 0x100,
- AUDIO_FORMAT_AAC_SUB_ELD = 0x200,
-} audio_format_aac_sub_fmt_t;
-
-/* VORBIS sub format field definition: specify quality for recording... */
-typedef enum {
- AUDIO_FORMAT_VORBIS_SUB_NONE = 0x0,
-} audio_format_vorbis_sub_fmt_t;
-
-
-/* Audio format is a 32-bit word that consists of:
- * main format field (upper 8 bits)
- * sub format field (lower 24 bits).
- *
- * The main format indicates the main codec type. The sub format field
- * indicates options and parameters for each format. The sub format is mainly
- * used for record to indicate for instance the requested bitrate or profile.
- * It can also be used for certain formats to give informations not present in
- * the encoded audio stream (e.g. octet alignement for AMR).
- */
-typedef enum {
- AUDIO_FORMAT_INVALID = 0xFFFFFFFFUL,
- AUDIO_FORMAT_DEFAULT = 0,
- AUDIO_FORMAT_PCM = 0x00000000UL, /* DO NOT CHANGE */
- AUDIO_FORMAT_MP3 = 0x01000000UL,
- AUDIO_FORMAT_AMR_NB = 0x02000000UL,
- AUDIO_FORMAT_AMR_WB = 0x03000000UL,
- AUDIO_FORMAT_AAC = 0x04000000UL,
- AUDIO_FORMAT_HE_AAC_V1 = 0x05000000UL, /* Deprecated, Use AUDIO_FORMAT_AAC_HE_V1*/
- AUDIO_FORMAT_HE_AAC_V2 = 0x06000000UL, /* Deprecated, Use AUDIO_FORMAT_AAC_HE_V2*/
- AUDIO_FORMAT_VORBIS = 0x07000000UL,
- AUDIO_FORMAT_OPUS = 0x08000000UL,
- AUDIO_FORMAT_AC3 = 0x09000000UL,
- AUDIO_FORMAT_E_AC3 = 0x0A000000UL,
- AUDIO_FORMAT_DTS = 0x0B000000UL,
- AUDIO_FORMAT_DTS_HD = 0x0C000000UL,
- // IEC61937 is encoded audio wrapped in 16-bit PCM.
- AUDIO_FORMAT_IEC61937 = 0x0D000000UL,
- AUDIO_FORMAT_DOLBY_TRUEHD = 0x0E000000UL,
- AUDIO_FORMAT_MAIN_MASK = 0xFF000000UL, /* Deprecated. Use audio_get_main_format() */
- AUDIO_FORMAT_SUB_MASK = 0x00FFFFFFUL,
-
- /* Aliases */
- /* note != AudioFormat.ENCODING_PCM_16BIT */
- AUDIO_FORMAT_PCM_16_BIT = (AUDIO_FORMAT_PCM |
- AUDIO_FORMAT_PCM_SUB_16_BIT),
- /* note != AudioFormat.ENCODING_PCM_8BIT */
- AUDIO_FORMAT_PCM_8_BIT = (AUDIO_FORMAT_PCM |
- AUDIO_FORMAT_PCM_SUB_8_BIT),
- AUDIO_FORMAT_PCM_32_BIT = (AUDIO_FORMAT_PCM |
- AUDIO_FORMAT_PCM_SUB_32_BIT),
- AUDIO_FORMAT_PCM_8_24_BIT = (AUDIO_FORMAT_PCM |
- AUDIO_FORMAT_PCM_SUB_8_24_BIT),
- AUDIO_FORMAT_PCM_FLOAT = (AUDIO_FORMAT_PCM |
- AUDIO_FORMAT_PCM_SUB_FLOAT),
- AUDIO_FORMAT_PCM_24_BIT_PACKED = (AUDIO_FORMAT_PCM |
- AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED),
- AUDIO_FORMAT_AAC_MAIN = (AUDIO_FORMAT_AAC |
- AUDIO_FORMAT_AAC_SUB_MAIN),
- AUDIO_FORMAT_AAC_LC = (AUDIO_FORMAT_AAC |
- AUDIO_FORMAT_AAC_SUB_LC),
- AUDIO_FORMAT_AAC_SSR = (AUDIO_FORMAT_AAC |
- AUDIO_FORMAT_AAC_SUB_SSR),
- AUDIO_FORMAT_AAC_LTP = (AUDIO_FORMAT_AAC |
- AUDIO_FORMAT_AAC_SUB_LTP),
- AUDIO_FORMAT_AAC_HE_V1 = (AUDIO_FORMAT_AAC |
- AUDIO_FORMAT_AAC_SUB_HE_V1),
- AUDIO_FORMAT_AAC_SCALABLE = (AUDIO_FORMAT_AAC |
- AUDIO_FORMAT_AAC_SUB_SCALABLE),
- AUDIO_FORMAT_AAC_ERLC = (AUDIO_FORMAT_AAC |
- AUDIO_FORMAT_AAC_SUB_ERLC),
- AUDIO_FORMAT_AAC_LD = (AUDIO_FORMAT_AAC |
- AUDIO_FORMAT_AAC_SUB_LD),
- AUDIO_FORMAT_AAC_HE_V2 = (AUDIO_FORMAT_AAC |
- AUDIO_FORMAT_AAC_SUB_HE_V2),
- AUDIO_FORMAT_AAC_ELD = (AUDIO_FORMAT_AAC |
- AUDIO_FORMAT_AAC_SUB_ELD),
-} audio_format_t;
-
-/* For the channel mask for position assignment representation */
-enum {
-
-/* These can be a complete audio_channel_mask_t. */
-
- AUDIO_CHANNEL_NONE = 0x0,
- AUDIO_CHANNEL_INVALID = 0xC0000000,
-
-/* These can be the bits portion of an audio_channel_mask_t
- * with representation AUDIO_CHANNEL_REPRESENTATION_POSITION.
- * Using these bits as a complete audio_channel_mask_t is deprecated.
- */
-
- /* output channels */
- AUDIO_CHANNEL_OUT_FRONT_LEFT = 0x1,
- AUDIO_CHANNEL_OUT_FRONT_RIGHT = 0x2,
- AUDIO_CHANNEL_OUT_FRONT_CENTER = 0x4,
- AUDIO_CHANNEL_OUT_LOW_FREQUENCY = 0x8,
- AUDIO_CHANNEL_OUT_BACK_LEFT = 0x10,
- AUDIO_CHANNEL_OUT_BACK_RIGHT = 0x20,
- AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x40,
- AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x80,
- AUDIO_CHANNEL_OUT_BACK_CENTER = 0x100,
- AUDIO_CHANNEL_OUT_SIDE_LEFT = 0x200,
- AUDIO_CHANNEL_OUT_SIDE_RIGHT = 0x400,
- AUDIO_CHANNEL_OUT_TOP_CENTER = 0x800,
- AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT = 0x1000,
- AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER = 0x2000,
- AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT = 0x4000,
- AUDIO_CHANNEL_OUT_TOP_BACK_LEFT = 0x8000,
- AUDIO_CHANNEL_OUT_TOP_BACK_CENTER = 0x10000,
- AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT = 0x20000,
-
-/* TODO: should these be considered complete channel masks, or only bits? */
-
- AUDIO_CHANNEL_OUT_MONO = AUDIO_CHANNEL_OUT_FRONT_LEFT,
- AUDIO_CHANNEL_OUT_STEREO = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
- AUDIO_CHANNEL_OUT_FRONT_RIGHT),
- AUDIO_CHANNEL_OUT_QUAD = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
- AUDIO_CHANNEL_OUT_FRONT_RIGHT |
- AUDIO_CHANNEL_OUT_BACK_LEFT |
- AUDIO_CHANNEL_OUT_BACK_RIGHT),
- AUDIO_CHANNEL_OUT_QUAD_BACK = AUDIO_CHANNEL_OUT_QUAD,
- /* like AUDIO_CHANNEL_OUT_QUAD_BACK with *_SIDE_* instead of *_BACK_* */
- AUDIO_CHANNEL_OUT_QUAD_SIDE = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
- AUDIO_CHANNEL_OUT_FRONT_RIGHT |
- AUDIO_CHANNEL_OUT_SIDE_LEFT |
- AUDIO_CHANNEL_OUT_SIDE_RIGHT),
- AUDIO_CHANNEL_OUT_5POINT1 = (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_5POINT1_BACK = AUDIO_CHANNEL_OUT_5POINT1,
- /* like AUDIO_CHANNEL_OUT_5POINT1_BACK with *_SIDE_* instead of *_BACK_* */
- AUDIO_CHANNEL_OUT_5POINT1_SIDE = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
- AUDIO_CHANNEL_OUT_FRONT_RIGHT |
- AUDIO_CHANNEL_OUT_FRONT_CENTER |
- AUDIO_CHANNEL_OUT_LOW_FREQUENCY |
- AUDIO_CHANNEL_OUT_SIDE_LEFT |
- AUDIO_CHANNEL_OUT_SIDE_RIGHT),
- // matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND definition for 7.1
- AUDIO_CHANNEL_OUT_7POINT1 = (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_SIDE_LEFT |
- AUDIO_CHANNEL_OUT_SIDE_RIGHT),
- 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),
-
-/* These are bits only, not complete values */
-
- /* input channels */
- AUDIO_CHANNEL_IN_LEFT = 0x4,
- AUDIO_CHANNEL_IN_RIGHT = 0x8,
- AUDIO_CHANNEL_IN_FRONT = 0x10,
- AUDIO_CHANNEL_IN_BACK = 0x20,
- AUDIO_CHANNEL_IN_LEFT_PROCESSED = 0x40,
- AUDIO_CHANNEL_IN_RIGHT_PROCESSED = 0x80,
- AUDIO_CHANNEL_IN_FRONT_PROCESSED = 0x100,
- AUDIO_CHANNEL_IN_BACK_PROCESSED = 0x200,
- AUDIO_CHANNEL_IN_PRESSURE = 0x400,
- AUDIO_CHANNEL_IN_X_AXIS = 0x800,
- AUDIO_CHANNEL_IN_Y_AXIS = 0x1000,
- AUDIO_CHANNEL_IN_Z_AXIS = 0x2000,
- AUDIO_CHANNEL_IN_VOICE_UPLINK = 0x4000,
- AUDIO_CHANNEL_IN_VOICE_DNLINK = 0x8000,
-
-/* TODO: should these be considered complete channel masks, or only bits, or deprecated? */
-
- AUDIO_CHANNEL_IN_MONO = AUDIO_CHANNEL_IN_FRONT,
- AUDIO_CHANNEL_IN_STEREO = (AUDIO_CHANNEL_IN_LEFT | AUDIO_CHANNEL_IN_RIGHT),
- AUDIO_CHANNEL_IN_FRONT_BACK = (AUDIO_CHANNEL_IN_FRONT | AUDIO_CHANNEL_IN_BACK),
- 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),
-};
-
/* 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.
*
@@ -519,42 +149,17 @@
*/
typedef uint32_t audio_channel_mask_t;
-/* Maximum number of channels for all representations */
-#define AUDIO_CHANNEL_COUNT_MAX 30
-
/* log(2) of maximum number of representations, not part of public API */
#define AUDIO_CHANNEL_REPRESENTATION_LOG2 2
-/* Representations */
-typedef enum {
- AUDIO_CHANNEL_REPRESENTATION_POSITION = 0, // must be zero for compatibility
- // 1 is reserved for future use
- AUDIO_CHANNEL_REPRESENTATION_INDEX = 2,
- // 3 is reserved for future use
-} audio_channel_representation_t;
-
-/* The channel index masks defined here are the canonical masks for 1 to 8 channel
- * endpoints and apply to both source and sink.
- */
-enum {
- AUDIO_CHANNEL_INDEX_HDR = AUDIO_CHANNEL_REPRESENTATION_INDEX << AUDIO_CHANNEL_COUNT_MAX,
- AUDIO_CHANNEL_INDEX_MASK_1 = AUDIO_CHANNEL_INDEX_HDR | ((1 << 1) - 1),
- AUDIO_CHANNEL_INDEX_MASK_2 = AUDIO_CHANNEL_INDEX_HDR | ((1 << 2) - 1),
- AUDIO_CHANNEL_INDEX_MASK_3 = AUDIO_CHANNEL_INDEX_HDR | ((1 << 3) - 1),
- AUDIO_CHANNEL_INDEX_MASK_4 = AUDIO_CHANNEL_INDEX_HDR | ((1 << 4) - 1),
- AUDIO_CHANNEL_INDEX_MASK_5 = AUDIO_CHANNEL_INDEX_HDR | ((1 << 5) - 1),
- AUDIO_CHANNEL_INDEX_MASK_6 = AUDIO_CHANNEL_INDEX_HDR | ((1 << 6) - 1),
- AUDIO_CHANNEL_INDEX_MASK_7 = AUDIO_CHANNEL_INDEX_HDR | ((1 << 7) - 1),
- AUDIO_CHANNEL_INDEX_MASK_8 = AUDIO_CHANNEL_INDEX_HDR | ((1 << 8) - 1),
- // FIXME FCC_8
-};
-
/* 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)
@@ -593,32 +198,6 @@
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,
-};
-
-typedef enum {
- AUDIO_MODE_INVALID = -2,
- AUDIO_MODE_CURRENT = -1,
- AUDIO_MODE_NORMAL = 0,
- AUDIO_MODE_RINGTONE = 1,
- AUDIO_MODE_IN_CALL = 2,
- AUDIO_MODE_IN_COMMUNICATION = 3,
-
- AUDIO_MODE_CNT,
- AUDIO_MODE_MAX = AUDIO_MODE_CNT - 1,
-} audio_mode_t;
-
/* This enum is deprecated */
typedef enum {
AUDIO_IN_ACOUSTICS_NONE = 0,
@@ -630,193 +209,17 @@
AUDIO_IN_ACOUSTICS_TX_DISABLE = 0,
} audio_in_acoustics_t;
-enum {
- AUDIO_DEVICE_NONE = 0x0,
- /* reserved bits */
- AUDIO_DEVICE_BIT_IN = 0x80000000,
- AUDIO_DEVICE_BIT_DEFAULT = 0x40000000,
- /* output devices */
- AUDIO_DEVICE_OUT_EARPIECE = 0x1,
- AUDIO_DEVICE_OUT_SPEAKER = 0x2,
- AUDIO_DEVICE_OUT_WIRED_HEADSET = 0x4,
- AUDIO_DEVICE_OUT_WIRED_HEADPHONE = 0x8,
- AUDIO_DEVICE_OUT_BLUETOOTH_SCO = 0x10,
- AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20,
- AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40,
- AUDIO_DEVICE_OUT_BLUETOOTH_A2DP = 0x80,
- AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
- AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200,
- AUDIO_DEVICE_OUT_AUX_DIGITAL = 0x400,
- AUDIO_DEVICE_OUT_HDMI = AUDIO_DEVICE_OUT_AUX_DIGITAL,
- /* uses an analog connection (multiplexed over the USB connector pins for instance) */
- AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800,
- AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000,
- /* USB accessory mode: your Android device is a USB device and the dock is a USB host */
- AUDIO_DEVICE_OUT_USB_ACCESSORY = 0x2000,
- /* USB host mode: your Android device is a USB host and the dock is a USB device */
- AUDIO_DEVICE_OUT_USB_DEVICE = 0x4000,
- AUDIO_DEVICE_OUT_REMOTE_SUBMIX = 0x8000,
- /* Telephony voice TX path */
- AUDIO_DEVICE_OUT_TELEPHONY_TX = 0x10000,
- /* Analog jack with line impedance detected */
- AUDIO_DEVICE_OUT_LINE = 0x20000,
- /* HDMI Audio Return Channel */
- AUDIO_DEVICE_OUT_HDMI_ARC = 0x40000,
- /* S/PDIF out */
- AUDIO_DEVICE_OUT_SPDIF = 0x80000,
- /* FM transmitter out */
- AUDIO_DEVICE_OUT_FM = 0x100000,
- /* Line out for av devices */
- AUDIO_DEVICE_OUT_AUX_LINE = 0x200000,
- /* limited-output speaker device for acoustic safety */
- AUDIO_DEVICE_OUT_SPEAKER_SAFE = 0x400000,
- AUDIO_DEVICE_OUT_IP = 0x800000,
- /* audio bus implemented by the audio system (e.g an MOST stereo channel) */
- AUDIO_DEVICE_OUT_BUS = 0x1000000,
- AUDIO_DEVICE_OUT_DEFAULT = AUDIO_DEVICE_BIT_DEFAULT,
- 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_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),
- /* input devices */
- AUDIO_DEVICE_IN_COMMUNICATION = AUDIO_DEVICE_BIT_IN | 0x1,
- AUDIO_DEVICE_IN_AMBIENT = AUDIO_DEVICE_BIT_IN | 0x2,
- AUDIO_DEVICE_IN_BUILTIN_MIC = AUDIO_DEVICE_BIT_IN | 0x4,
- AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = AUDIO_DEVICE_BIT_IN | 0x8,
- AUDIO_DEVICE_IN_WIRED_HEADSET = AUDIO_DEVICE_BIT_IN | 0x10,
- AUDIO_DEVICE_IN_AUX_DIGITAL = AUDIO_DEVICE_BIT_IN | 0x20,
- AUDIO_DEVICE_IN_HDMI = AUDIO_DEVICE_IN_AUX_DIGITAL,
- /* Telephony voice RX path */
- AUDIO_DEVICE_IN_VOICE_CALL = AUDIO_DEVICE_BIT_IN | 0x40,
- AUDIO_DEVICE_IN_TELEPHONY_RX = AUDIO_DEVICE_IN_VOICE_CALL,
- AUDIO_DEVICE_IN_BACK_MIC = AUDIO_DEVICE_BIT_IN | 0x80,
- AUDIO_DEVICE_IN_REMOTE_SUBMIX = AUDIO_DEVICE_BIT_IN | 0x100,
- AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET = AUDIO_DEVICE_BIT_IN | 0x200,
- AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET = AUDIO_DEVICE_BIT_IN | 0x400,
- AUDIO_DEVICE_IN_USB_ACCESSORY = AUDIO_DEVICE_BIT_IN | 0x800,
- AUDIO_DEVICE_IN_USB_DEVICE = AUDIO_DEVICE_BIT_IN | 0x1000,
- /* FM tuner input */
- AUDIO_DEVICE_IN_FM_TUNER = AUDIO_DEVICE_BIT_IN | 0x2000,
- /* TV tuner input */
- AUDIO_DEVICE_IN_TV_TUNER = AUDIO_DEVICE_BIT_IN | 0x4000,
- /* Analog jack with line impedance detected */
- AUDIO_DEVICE_IN_LINE = AUDIO_DEVICE_BIT_IN | 0x8000,
- /* S/PDIF in */
- AUDIO_DEVICE_IN_SPDIF = AUDIO_DEVICE_BIT_IN | 0x10000,
- AUDIO_DEVICE_IN_BLUETOOTH_A2DP = AUDIO_DEVICE_BIT_IN | 0x20000,
- AUDIO_DEVICE_IN_LOOPBACK = AUDIO_DEVICE_BIT_IN | 0x40000,
- AUDIO_DEVICE_IN_IP = AUDIO_DEVICE_BIT_IN | 0x80000,
- /* audio bus implemented by the audio system (e.g an MOST stereo channel) */
- AUDIO_DEVICE_IN_BUS = AUDIO_DEVICE_BIT_IN | 0x100000,
- AUDIO_DEVICE_IN_DEFAULT = AUDIO_DEVICE_BIT_IN | AUDIO_DEVICE_BIT_DEFAULT,
-
- 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_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),
-};
-
typedef uint32_t audio_devices_t;
-
-/* the audio output flags serve two purposes:
- * - when an AudioTrack is created they indicate a "wish" to be connected to an
- * output stream with attributes corresponding to the specified flags
- * - when present in an output profile descriptor listed for a particular audio
- * hardware module, they indicate that an output stream can be opened that
- * supports the attributes indicated by the flags.
- * the audio policy manager will try to match the flags in the request
- * (when getOuput() is called) to an available output stream.
+/**
+ * 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.
*/
-typedef enum {
- AUDIO_OUTPUT_FLAG_NONE = 0x0, // no attributes
- AUDIO_OUTPUT_FLAG_DIRECT = 0x1, // this output directly connects a track
- // to one output stream: no software mixer
- AUDIO_OUTPUT_FLAG_PRIMARY = 0x2, // this output is the primary output of
- // the device. It is unique and must be
- // present. It is opened by default and
- // receives routing, audio mode and volume
- // controls related to voice calls.
- AUDIO_OUTPUT_FLAG_FAST = 0x4, // output supports "fast tracks",
- // defined elsewhere
- AUDIO_OUTPUT_FLAG_DEEP_BUFFER = 0x8, // use deep audio buffers
- AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD = 0x10, // offload playback of compressed
- // streams to hardware codec
- AUDIO_OUTPUT_FLAG_NON_BLOCKING = 0x20, // use non-blocking write
- AUDIO_OUTPUT_FLAG_HW_AV_SYNC = 0x40, // output uses a hardware A/V synchronization source
- AUDIO_OUTPUT_FLAG_TTS = 0x80, // output for streams transmitted through speaker
- // at a sample rate high enough to accommodate
- // lower-range ultrasonic playback
- AUDIO_OUTPUT_FLAG_RAW = 0x100, // minimize signal processing
- AUDIO_OUTPUT_FLAG_SYNC = 0x200, // synchronize I/O streams
-
- AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO = 0x400, // Audio stream contains compressed audio in
- // SPDIF data bursts, not PCM.
-} audio_output_flags_t;
-
-/* The audio input flags are analogous to audio output flags.
- * Currently they are used only when an AudioRecord is created,
- * to indicate a preference to be connected to an input stream with
- * attributes corresponding to the specified flags.
+#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.
*/
-typedef enum {
- AUDIO_INPUT_FLAG_NONE = 0x0, // no attributes
- AUDIO_INPUT_FLAG_FAST = 0x1, // prefer an input that supports "fast tracks"
- AUDIO_INPUT_FLAG_HW_HOTWORD = 0x2, // prefer an input that captures from hw hotword source
- AUDIO_INPUT_FLAG_RAW = 0x4, // minimize signal processing
- AUDIO_INPUT_FLAG_SYNC = 0x8, // synchronize I/O streams
-
-} audio_input_flags_t;
+#define AUDIO_DEVICE_IN_STUB AUDIO_DEVICE_IN_DEFAULT
/* Additional information about compressed streams offloaded to
* hardware playback
@@ -834,6 +237,9 @@
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;
} audio_offload_info_t;
#define AUDIO_MAKE_OFFLOAD_INFO_VERSION(maj,min) \
@@ -852,7 +258,10 @@
/* .bit_rate = */ 0,
/* .duration_us = */ 0,
/* .has_video = */ false,
- /* .is_streaming = */ false
+ /* .is_streaming = */ false,
+ /* .bit_width = */ 16,
+ /* .offload_buffer_size = */ 0,
+ /* .usage = */ AUDIO_USAGE_UNKNOWN
};
/* common audio stream configuration parameters
@@ -882,7 +291,10 @@
/* .bit_rate = */ 0,
/* .duration_us = */ 0,
/* .has_video = */ false,
- /* .is_streaming = */ false
+ /* .is_streaming = */ false,
+ /* .bit_width = */ 16,
+ /* .offload_buffer_size = */ 0,
+ /* .usage = */ AUDIO_USAGE_UNKNOWN
},
/* .frame_count = */ 0,
};
@@ -902,9 +314,7 @@
};
/* audio hw module handle functions or structures referencing a module */
-typedef enum {
- AUDIO_MODULE_HANDLE_NONE = 0,
-} audio_module_handle_t;
+typedef int audio_module_handle_t;
/******************************
* Volume control
@@ -915,11 +325,6 @@
* will then implement gain control functions that will use the following data
* structures. */
-/* Type of gain control exposed by an audio port */
-#define AUDIO_GAIN_MODE_JOINT 0x1 /* supports joint channel gain control */
-#define AUDIO_GAIN_MODE_CHANNELS 0x2 /* supports separate channel gain control */
-#define AUDIO_GAIN_MODE_RAMP 0x4 /* supports gain ramps */
-
typedef uint32_t audio_gain_mode_t;
@@ -964,26 +369,8 @@
* audio end point at the edge of the system managed by the module exposing
* the interface. */
-/* Audio port role: either source or sink */
-typedef enum {
- AUDIO_PORT_ROLE_NONE,
- AUDIO_PORT_ROLE_SOURCE,
- AUDIO_PORT_ROLE_SINK,
-} audio_port_role_t;
-
-/* Audio port type indicates if it is a session (e.g AudioTrack),
- * a mix (e.g PlaybackThread output) or a physical device
- * (e.g AUDIO_DEVICE_OUT_SPEAKER) */
-typedef enum {
- AUDIO_PORT_TYPE_NONE,
- AUDIO_PORT_TYPE_DEVICE,
- AUDIO_PORT_TYPE_MIX,
- AUDIO_PORT_TYPE_SESSION,
-} audio_port_type_t;
-
/* Each port has a unique ID or handle allocated by policy manager */
typedef int audio_port_handle_t;
-#define AUDIO_PORT_HANDLE_NONE 0
/* the maximum length for the human-readable device name */
#define AUDIO_PORT_MAX_NAME_LEN 128
@@ -1017,16 +404,6 @@
audio_session_t session; /* audio session */
};
-/* Flags indicating which fields are to be considered in struct audio_port_config */
-#define AUDIO_PORT_CONFIG_SAMPLE_RATE 0x1
-#define AUDIO_PORT_CONFIG_CHANNEL_MASK 0x2
-#define AUDIO_PORT_CONFIG_FORMAT 0x4
-#define AUDIO_PORT_CONFIG_GAIN 0x8
-#define AUDIO_PORT_CONFIG_ALL (AUDIO_PORT_CONFIG_SAMPLE_RATE | \
- AUDIO_PORT_CONFIG_CHANNEL_MASK | \
- AUDIO_PORT_CONFIG_FORMAT | \
- AUDIO_PORT_CONFIG_GAIN)
-
/* audio port configuration structure used to specify a particular configuration of
* an audio port */
struct audio_port_config {
@@ -1047,11 +424,11 @@
/* max number of sampling rates in audio port */
-#define AUDIO_PORT_MAX_SAMPLING_RATES 16
+#define AUDIO_PORT_MAX_SAMPLING_RATES 32
/* max number of channel masks in audio port */
-#define AUDIO_PORT_MAX_CHANNEL_MASKS 16
+#define AUDIO_PORT_MAX_CHANNEL_MASKS 32
/* max number of audio formats in audio port */
-#define AUDIO_PORT_MAX_FORMATS 16
+#define AUDIO_PORT_MAX_FORMATS 32
/* max number of gain controls in audio port */
#define AUDIO_PORT_MAX_GAINS 16
@@ -1062,12 +439,6 @@
char address[AUDIO_DEVICE_MAX_ADDRESS_LEN];
};
-/* Latency class of the audio mix */
-typedef enum {
- AUDIO_LATENCY_LOW,
- AUDIO_LATENCY_NORMAL,
-} audio_mix_latency_class_t;
-
/* 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 */
@@ -1111,9 +482,7 @@
* 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 enum {
- AUDIO_PATCH_HANDLE_NONE = 0,
-} audio_patch_handle_t;
+typedef int audio_patch_handle_t;
#define AUDIO_PATCH_PORTS_MAX 16
@@ -1133,6 +502,28 @@
/* 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 */
+};
+
static inline bool audio_is_output_device(audio_devices_t device)
{
if (((device & AUDIO_DEVICE_BIT_IN) == 0) &&
@@ -1434,6 +825,7 @@
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_VORBIS:
@@ -1444,6 +836,22 @@
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:
return true;
default:
return false;
@@ -1546,6 +954,108 @@
}
}
+// 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;
+
__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"
+
+/**
+ * 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"
+
+/**
+ * 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 */
+
+#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 "|"
+
+/**
+ * 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/audio/include/system/audio_effect-base.h b/audio/include/system/audio_effect-base.h
new file mode 100644
index 0000000..572b788
--- /dev/null
+++ b/audio/include/system/audio_effect-base.h
@@ -0,0 +1,100 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+// Source: android.hardware.audio.effect@2.0
+// Root: android.hardware:hardware/interfaces
+
+#ifndef HIDL_GENERATED_ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EXPORTED_CONSTANTS_H_
+#define HIDL_GENERATED_ANDROID_HARDWARE_AUDIO_EFFECT_V2_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,
+ EFFECT_BUFFER_ACCESS_ACCUMULATE = 2,
+} effect_buffer_access_e;
+
+enum {
+ EFFECT_CONFIG_BUFFER = 1, // 0x0001
+ EFFECT_CONFIG_SMP_RATE = 2, // 0x0002
+ EFFECT_CONFIG_CHANNELS = 4, // 0x0004
+ EFFECT_CONFIG_FORMAT = 8, // 0x0008
+ EFFECT_CONFIG_ACC_MODE = 16, // 0x0010
+ EFFECT_CONFIG_ALL = 31, // ((((BUFFER | SMP_RATE) | CHANNELS) | FORMAT) | ACC_MODE)
+};
+
+typedef enum {
+ EFFECT_FEATURE_AUX_CHANNELS = 0,
+ EFFECT_FEATURE_CNT = 1,
+} effect_feature_e;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // HIDL_GENERATED_ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EXPORTED_CONSTANTS_H_
diff --git a/audio/include/system/audio_effect.h b/audio/include/system/audio_effect.h
new file mode 100644
index 0000000..d7bb1a9
--- /dev/null
+++ b/audio/include/system/audio_effect.h
@@ -0,0 +1,529 @@
+/*
+ * 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;
+
+/////////////////////////////////////////////////
+// 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
+ 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/audio_effects/include/audio_effects/audio_effects_conf.h b/audio/include/system/audio_effects/audio_effects_conf.h
old mode 100755
new mode 100644
similarity index 100%
rename from audio_effects/include/audio_effects/audio_effects_conf.h
rename to audio/include/system/audio_effects/audio_effects_conf.h
diff --git a/audio/include/system/audio_effects/effect_aec.h b/audio/include/system/audio_effects/effect_aec.h
new file mode 100644
index 0000000..e87471e
--- /dev/null
+++ b/audio/include/system/audio_effects/effect_aec.h
@@ -0,0 +1,48 @@
+/*
+ * 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_EFFECT_AEC_CORE_H_
+#define ANDROID_EFFECT_AEC_CORE_H_
+
+#include <system/audio_effect.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// The AEC type UUID is not defined by OpenSL ES and has been generated from
+// http://www.itu.int/ITU-T/asn1/uuid.html
+static const effect_uuid_t FX_IID_AEC_ =
+ { 0x7b491460, 0x8d4d, 0x11e0, 0xbd61, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+const effect_uuid_t * const FX_IID_AEC = &FX_IID_AEC_;
+
+typedef enum
+{
+ AEC_PARAM_ECHO_DELAY, // echo delay in microseconds
+ AEC_PARAM_PROPERTIES
+} t_aec_params;
+
+//t_equalizer_settings groups all current aec settings for backup and restore.
+typedef struct s_aec_settings {
+ uint32_t echoDelay;
+} t_aec_settings;
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECT_AEC_CORE_H_*/
diff --git a/audio/include/system/audio_effects/effect_agc.h b/audio/include/system/audio_effects/effect_agc.h
new file mode 100644
index 0000000..b1b9b1d
--- /dev/null
+++ b/audio/include/system/audio_effects/effect_agc.h
@@ -0,0 +1,54 @@
+/*
+ * 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_EFFECT_AGC_CORE_H_
+#define ANDROID_EFFECT_AGC_CORE_H_
+
+#include <system/audio_effect.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// The AGC type UUID is not defined by OpenSL ES and has been generated from
+// http://www.itu.int/ITU-T/asn1/uuid.html
+static const effect_uuid_t FX_IID_AGC_ =
+ { 0x0a8abfe0, 0x654c, 0x11e0, 0xba26, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+const effect_uuid_t * const FX_IID_AGC = &FX_IID_AGC_;
+
+
+typedef enum
+{
+ AGC_PARAM_TARGET_LEVEL, // target output level in millibel
+ AGC_PARAM_COMP_GAIN, // gain in the compression range in millibel
+ AGC_PARAM_LIMITER_ENA, // enable or disable limiter (boolean)
+ AGC_PARAM_PROPERTIES
+} t_agc_params;
+
+
+//t_agc_settings groups all current agc settings for backup and restore.
+typedef struct s_agc_settings {
+ int16_t targetLevel;
+ int16_t compGain;
+ bool limiterEnabled;
+} t_agc_settings;
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECT_AGC_CORE_H_*/
diff --git a/audio/include/system/audio_effects/effect_bassboost.h b/audio/include/system/audio_effects/effect_bassboost.h
new file mode 100644
index 0000000..8776cd7
--- /dev/null
+++ b/audio/include/system/audio_effects/effect_bassboost.h
@@ -0,0 +1,44 @@
+/*
+ * 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_EFFECT_BASSBOOST_CORE_H_
+#define ANDROID_EFFECT_BASSBOOST_CORE_H_
+
+#include <system/audio_effect.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+#ifndef OPENSL_ES_H_
+static const effect_uuid_t SL_IID_BASSBOOST_ = { 0x0634f220, 0xddd4, 0x11db, 0xa0fc,
+ { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+const effect_uuid_t * const SL_IID_BASSBOOST = &SL_IID_BASSBOOST_;
+#endif //OPENSL_ES_H_
+
+/* enumerated parameter settings for BassBoost effect */
+typedef enum
+{
+ BASSBOOST_PARAM_STRENGTH_SUPPORTED,
+ BASSBOOST_PARAM_STRENGTH
+} t_bassboost_params;
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECT_BASSBOOST_CORE_H_*/
diff --git a/audio/include/system/audio_effects/effect_downmix.h b/audio/include/system/audio_effects/effect_downmix.h
new file mode 100644
index 0000000..731229e
--- /dev/null
+++ b/audio/include/system/audio_effects/effect_downmix.h
@@ -0,0 +1,53 @@
+/*
+ * 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_EFFECT_DOWNMIX_CORE_H_
+#define ANDROID_EFFECT_DOWNMIX_CORE_H_
+
+#include <system/audio_effect.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+#define EFFECT_UIID_DOWNMIX__ { 0x381e49cc, 0xa858, 0x4aa2, 0x87f6, \
+ { 0xe8, 0x38, 0x8e, 0x76, 0x01, 0xb2 } }
+static const effect_uuid_t EFFECT_UIID_DOWNMIX_ = EFFECT_UIID_DOWNMIX__;
+const effect_uuid_t * const EFFECT_UIID_DOWNMIX = &EFFECT_UIID_DOWNMIX_;
+
+
+/* enumerated parameter settings for downmix effect */
+typedef enum {
+ DOWNMIX_PARAM_TYPE
+} downmix_params_t;
+
+
+typedef enum {
+ DOWNMIX_TYPE_INVALID = -1,
+ // throw away the extra channels
+ DOWNMIX_TYPE_STRIP = 0,
+ // mix the extra channels with FL/FR
+ DOWNMIX_TYPE_FOLD = 1,
+ DOWNMIX_TYPE_CNT,
+ DOWNMIX_TYPE_LAST = DOWNMIX_TYPE_CNT - 1
+} downmix_type_t;
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECT_DOWNMIX_CORE_H_*/
diff --git a/audio/include/system/audio_effects/effect_environmentalreverb.h b/audio/include/system/audio_effects/effect_environmentalreverb.h
new file mode 100644
index 0000000..2910a1d
--- /dev/null
+++ b/audio/include/system/audio_effects/effect_environmentalreverb.h
@@ -0,0 +1,70 @@
+/*
+ * 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_EFFECT_ENVIRONMENTALREVERB_CORE_H_
+#define ANDROID_EFFECT_ENVIRONMENTALREVERB_CORE_H_
+
+#include <system/audio_effect.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+#ifndef OPENSL_ES_H_
+static const effect_uuid_t SL_IID_ENVIRONMENTALREVERB_ = { 0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac,
+ { 0x4e, 0x23, 0x4d, 0x6, 0x83, 0x9e } };
+const effect_uuid_t * const SL_IID_ENVIRONMENTALREVERB = &SL_IID_ENVIRONMENTALREVERB_;
+#endif //OPENSL_ES_H_
+
+/* enumerated parameter settings for environmental reverb effect */
+typedef enum
+{
+ // Parameters below are as defined in OpenSL ES specification for environmental reverb interface
+ REVERB_PARAM_ROOM_LEVEL, // in millibels, range -6000 to 0
+ REVERB_PARAM_ROOM_HF_LEVEL, // in millibels, range -4000 to 0
+ REVERB_PARAM_DECAY_TIME, // in milliseconds, range 100 to 20000
+ REVERB_PARAM_DECAY_HF_RATIO, // in permilles, range 100 to 1000
+ REVERB_PARAM_REFLECTIONS_LEVEL, // in millibels, range -6000 to 0
+ REVERB_PARAM_REFLECTIONS_DELAY, // in milliseconds, range 0 to 65
+ REVERB_PARAM_REVERB_LEVEL, // in millibels, range -6000 to 0
+ REVERB_PARAM_REVERB_DELAY, // in milliseconds, range 0 to 65
+ REVERB_PARAM_DIFFUSION, // in permilles, range 0 to 1000
+ REVERB_PARAM_DENSITY, // in permilles, range 0 to 1000
+ REVERB_PARAM_PROPERTIES,
+ REVERB_PARAM_BYPASS
+} t_env_reverb_params;
+
+//t_reverb_settings is equal to SLEnvironmentalReverbSettings defined in OpenSL ES specification.
+typedef struct s_reverb_settings {
+ int16_t roomLevel;
+ int16_t roomHFLevel;
+ uint32_t decayTime;
+ int16_t decayHFRatio;
+ int16_t reflectionsLevel;
+ uint32_t reflectionsDelay;
+ int16_t reverbLevel;
+ uint32_t reverbDelay;
+ int16_t diffusion;
+ int16_t density;
+} __attribute__((packed)) t_reverb_settings;
+
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECT_ENVIRONMENTALREVERB_CORE_H_*/
diff --git a/audio/include/system/audio_effects/effect_equalizer.h b/audio/include/system/audio_effects/effect_equalizer.h
new file mode 100644
index 0000000..e0f6848
--- /dev/null
+++ b/audio/include/system/audio_effects/effect_equalizer.h
@@ -0,0 +1,61 @@
+/*
+ * 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_EFFECT_EQUALIZER_CORE_H_
+#define ANDROID_EFFECT_EQUALIZER_CORE_H_
+
+#include <system/audio_effect.h>
+
+#ifndef OPENSL_ES_H_
+static const effect_uuid_t SL_IID_EQUALIZER_ = { 0x0bed4300, 0xddd6, 0x11db, 0x8f34,
+ { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+const effect_uuid_t * const SL_IID_EQUALIZER = &SL_IID_EQUALIZER_;
+#endif //OPENSL_ES_H_
+
+#if __cplusplus
+extern "C" {
+#endif
+
+/* enumerated parameters for Equalizer effect */
+typedef enum
+{
+ EQ_PARAM_NUM_BANDS, // Gets the number of frequency bands that the equalizer
+ // supports.
+ EQ_PARAM_LEVEL_RANGE, // Returns the minimum and maximum band levels supported.
+ EQ_PARAM_BAND_LEVEL, // Gets/Sets the gain set for the given equalizer band.
+ EQ_PARAM_CENTER_FREQ, // Gets the center frequency of the given band.
+ EQ_PARAM_BAND_FREQ_RANGE, // Gets the frequency range of the given frequency band.
+ EQ_PARAM_GET_BAND, // Gets the band that has the most effect on the given
+ // frequency.
+ EQ_PARAM_CUR_PRESET, // Gets/Sets the current preset.
+ EQ_PARAM_GET_NUM_OF_PRESETS, // Gets the total number of presets the equalizer supports.
+ EQ_PARAM_GET_PRESET_NAME, // Gets the preset name based on the index.
+ EQ_PARAM_PROPERTIES // Gets/Sets all parameters at a time.
+} t_equalizer_params;
+
+//t_equalizer_settings groups all current equalizer setting for backup and restore.
+typedef struct s_equalizer_settings {
+ uint16_t curPreset;
+ uint16_t numBands;
+ uint16_t bandLevels[];
+} t_equalizer_settings;
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECT_EQUALIZER_CORE_H_*/
diff --git a/audio/include/system/audio_effects/effect_loudnessenhancer.h b/audio/include/system/audio_effects/effect_loudnessenhancer.h
new file mode 100644
index 0000000..a8a8c9b
--- /dev/null
+++ b/audio/include/system/audio_effects/effect_loudnessenhancer.h
@@ -0,0 +1,45 @@
+/*
+ * 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_EFFECT_LOUDNESS_ENHANCER_CORE_H_
+#define ANDROID_EFFECT_LOUDNESS_ENHANCER_CORE_H_
+
+#include <system/audio_effect.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// this effect is not defined in OpenSL ES as one of the standard effects
+static const effect_uuid_t FX_IID_LOUDNESS_ENHANCER_ =
+ {0xfe3199be, 0xaed0, 0x413f, 0x87bb, {0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}};
+const effect_uuid_t * const FX_IID_LOUDNESS_ENHANCER = &FX_IID_LOUDNESS_ENHANCER_;
+
+#define LOUDNESS_ENHANCER_DEFAULT_TARGET_GAIN_MB 0 // mB
+
+// enumerated parameters for DRC effect
+// to keep in sync with frameworks/base/media/java/android/media/audiofx/LoudnessEnhancer.java
+typedef enum
+{
+ LOUDNESS_ENHANCER_PARAM_TARGET_GAIN_MB = 0,// target gain expressed in mB
+} t_level_monitor_params;
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECT_LOUDNESS_ENHANCER_CORE_H_*/
diff --git a/audio/include/system/audio_effects/effect_ns.h b/audio/include/system/audio_effects/effect_ns.h
new file mode 100644
index 0000000..e0d4330
--- /dev/null
+++ b/audio/include/system/audio_effects/effect_ns.h
@@ -0,0 +1,63 @@
+/*
+ * 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_EFFECT_NS_CORE_H_
+#define ANDROID_EFFECT_NS_CORE_H_
+
+#include <system/audio_effect.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// The NS type UUID is not defined by OpenSL ES and has been generated from
+// http://www.itu.int/ITU-T/asn1/uuid.html
+static const effect_uuid_t FX_IID_NS_ =
+ { 0x58b4b260, 0x8e06, 0x11e0, 0xaa8e, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+const effect_uuid_t * const FX_IID_NS = &FX_IID_NS_;
+
+typedef enum
+{
+ NS_PARAM_LEVEL, // noise suppression level (t_ns_level)
+ NS_PARAM_PROPERTIES,
+ NS_PARAM_TYPE // noise suppression type (t_ns_type)
+} t_ns_params;
+
+// noise suppression level
+typedef enum {
+ NS_LEVEL_LOW,
+ NS_LEVEL_MEDIUM,
+ NS_LEVEL_HIGH
+} t_ns_level;
+
+// noise suppression type
+typedef enum {
+ NS_TYPE_SINGLE_CHANNEL,
+ NS_TYPE_MULTI_CHANNEL
+} t_ns_type;
+
+// s_ns_settings groups all current ns settings for backup and restore.
+typedef struct s_ns_settings {
+ uint32_t level;
+ uint32_t type;
+} t_ns_settings;
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECT_NS_CORE_H_*/
diff --git a/audio/include/system/audio_effects/effect_presetreverb.h b/audio/include/system/audio_effects/effect_presetreverb.h
new file mode 100644
index 0000000..831e117
--- /dev/null
+++ b/audio/include/system/audio_effects/effect_presetreverb.h
@@ -0,0 +1,56 @@
+/*
+ * 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_EFFECT_PRESETREVERB_CORE_H_
+#define ANDROID_EFFECT_PRESETREVERB_CORE_H_
+
+#include <system/audio_effect.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+#ifndef OPENSL_ES_H_
+static const effect_uuid_t SL_IID_PRESETREVERB_ = { 0x47382d60, 0xddd8, 0x11db, 0xbf3a,
+ { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+const effect_uuid_t * const SL_IID_PRESETREVERB = &SL_IID_PRESETREVERB_;
+#endif //OPENSL_ES_H_
+
+/* enumerated parameter settings for preset reverb effect */
+typedef enum
+{
+ REVERB_PARAM_PRESET
+} t_preset_reverb_params;
+
+
+typedef enum
+{
+ REVERB_PRESET_NONE,
+ REVERB_PRESET_SMALLROOM,
+ REVERB_PRESET_MEDIUMROOM,
+ REVERB_PRESET_LARGEROOM,
+ REVERB_PRESET_MEDIUMHALL,
+ REVERB_PRESET_LARGEHALL,
+ REVERB_PRESET_PLATE,
+ REVERB_PRESET_LAST = REVERB_PRESET_PLATE
+} t_reverb_presets;
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECT_PRESETREVERB_CORE_H_*/
diff --git a/audio/include/system/audio_effects/effect_virtualizer.h b/audio/include/system/audio_effects/effect_virtualizer.h
new file mode 100644
index 0000000..05b1544
--- /dev/null
+++ b/audio/include/system/audio_effects/effect_virtualizer.h
@@ -0,0 +1,79 @@
+/*
+ * 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_EFFECT_VIRTUALIZER_CORE_H_
+#define ANDROID_EFFECT_VIRTUALIZER_CORE_H_
+
+#include <system/audio_effect.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+#ifndef OPENSL_ES_H_
+static const effect_uuid_t SL_IID_VIRTUALIZER_ = { 0x37cc2c00, 0xdddd, 0x11db, 0x8577,
+ { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+const effect_uuid_t * const SL_IID_VIRTUALIZER = &SL_IID_VIRTUALIZER_;
+#endif //OPENSL_ES_H_
+
+/* enumerated parameter settings for virtualizer effect */
+/* to keep in sync with frameworks/base/media/java/android/media/audiofx/Virtualizer.java */
+typedef enum
+{
+ VIRTUALIZER_PARAM_STRENGTH_SUPPORTED,
+ VIRTUALIZER_PARAM_STRENGTH,
+ // used with EFFECT_CMD_GET_PARAM
+ // format:
+ // parameters int32_t VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES
+ // audio_channel_mask_t input channel mask
+ // audio_devices_t audio output device
+ // output int32_t* an array of length 3 * the number of channels in the mask
+ // where entries are the succession of the channel mask
+ // of each speaker (i.e. a single bit is selected in the
+ // channel mask) followed by the azimuth and the
+ // elevation angles.
+ // status int -EINVAL if configuration is not supported or invalid or not forcing
+ // 0 if configuration is supported and the mode is forced
+ // notes:
+ // - all angles are expressed in degrees and are relative to the listener,
+ // - for azimuth: 0 is the direction the listener faces, 180 is behind the listener, and
+ // -90 is to her/his left,
+ // - for elevation: 0 is the horizontal plane, +90 is above the listener, -90 is below.
+ VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES,
+ // used with EFFECT_CMD_SET_PARAM
+ // format:
+ // parameters int32_t VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE
+ // audio_devices_t audio output device
+ // status int -EINVAL if the device is not supported or invalid
+ // 0 if the device is supported and the mode is forced, or forcing
+ // was disabled for the AUDIO_DEVICE_NONE audio device.
+ VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE,
+ // used with EFFECT_CMD_GET_PARAM
+ // format:
+ // parameters int32_t VIRTUALIZER_PARAM_VIRTUALIZATION_MODE
+ // output audio_device_t audio device reflecting the current virtualization mode,
+ // AUDIO_DEVICE_NONE when not virtualizing
+ // status int -EINVAL if an error occurred
+ // 0 if the output value is successfully retrieved
+ VIRTUALIZER_PARAM_VIRTUALIZATION_MODE
+} t_virtualizer_params;
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECT_VIRTUALIZER_CORE_H_*/
diff --git a/audio/include/system/audio_effects/effect_visualizer.h b/audio/include/system/audio_effects/effect_visualizer.h
new file mode 100644
index 0000000..b314822
--- /dev/null
+++ b/audio/include/system/audio_effects/effect_visualizer.h
@@ -0,0 +1,74 @@
+/*
+ * 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_EFFECT_VISUALIZER_CORE_H_
+#define ANDROID_EFFECT_VISUALIZER_CORE_H_
+
+#include <system/audio_effect.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+#ifndef OPENSL_ES_H_
+static const effect_uuid_t SL_IID_VISUALIZATION_ =
+ { 0xe46b26a0, 0xdddd, 0x11db, 0x8afd, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+const effect_uuid_t * const SL_IID_VISUALIZATION = &SL_IID_VISUALIZATION_;
+#endif //OPENSL_ES_H_
+
+#define VISUALIZER_CAPTURE_SIZE_MAX 1024 // maximum capture size in samples
+#define VISUALIZER_CAPTURE_SIZE_MIN 128 // minimum capture size in samples
+
+// to keep in sync with frameworks/base/media/java/android/media/audiofx/Visualizer.java
+#define VISUALIZER_SCALING_MODE_NORMALIZED 0
+#define VISUALIZER_SCALING_MODE_AS_PLAYED 1
+
+#define MEASUREMENT_MODE_NONE 0x0
+#define MEASUREMENT_MODE_PEAK_RMS 0x1
+
+#define MEASUREMENT_IDX_PEAK 0
+#define MEASUREMENT_IDX_RMS 1
+#define MEASUREMENT_COUNT 2
+
+/* enumerated parameters for Visualizer effect */
+typedef enum
+{
+ VISUALIZER_PARAM_CAPTURE_SIZE, // Sets the number PCM samples in the capture.
+ VISUALIZER_PARAM_SCALING_MODE, // Sets the way the captured data is scaled
+ VISUALIZER_PARAM_LATENCY, // Informs the visualizer about the downstream latency
+ VISUALIZER_PARAM_MEASUREMENT_MODE, // Sets which measurements are to be made
+} t_visualizer_params;
+
+/* commands */
+typedef enum
+{
+ VISUALIZER_CMD_CAPTURE = EFFECT_CMD_FIRST_PROPRIETARY, // Gets the latest PCM capture.
+ VISUALIZER_CMD_MEASURE, // Gets the current measurements
+}t_visualizer_cmds;
+
+// VISUALIZER_CMD_CAPTURE retrieves the latest PCM snapshot captured by the visualizer engine.
+// It returns the number of samples specified by VISUALIZER_PARAM_CAPTURE_SIZE
+// in 8 bit unsigned format (0 = 0x80)
+
+// VISUALIZER_CMD_MEASURE retrieves the lastest measurements as int32_t saved in the
+// MEASUREMENT_IDX_* array index order.
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECT_VISUALIZER_CORE_H_*/
diff --git a/audio/include/system/sound_trigger.h b/audio/include/system/sound_trigger.h
index 8f80080..c5156d9 100644
--- a/audio/include/system/sound_trigger.h
+++ b/audio/include/system/sound_trigger.h
@@ -50,13 +50,7 @@
SOUND_MODEL_TYPE_GENERIC = 1 /* use for all models other than keyphrase */
} sound_trigger_sound_model_type_t;
-typedef struct sound_trigger_uuid_s {
- unsigned int timeLow;
- unsigned short timeMid;
- unsigned short timeHiAndVersion;
- unsigned short clockSeq;
- unsigned char node[6];
-} sound_trigger_uuid_t;
+typedef audio_uuid_t sound_trigger_uuid_t;
/*
* sound trigger implementation descriptor read by the framework via get_properties().
diff --git a/audio_effects/include/audio_effects/effect_aec.h b/audio_effects/include/audio_effects/effect_aec.h
index a0e1ca0..f48749a 100644
--- a/audio_effects/include/audio_effects/effect_aec.h
+++ b/audio_effects/include/audio_effects/effect_aec.h
@@ -14,35 +14,20 @@
* limitations under the License.
*/
+/*
+ * USAGE NOTE: Only include this header when _implementing_ a particular
+ * effect. When access to UUID and properties is enough, include the
+ * corresponding header from system/audio_effects/, which doesn't include
+ * hardware/audio_effect.h.
+ *
+ * Only code that immediately calls into HAL or implements an effect
+ * can import hardware/audio_effect.h.
+ */
+
#ifndef ANDROID_EFFECT_AEC_H_
#define ANDROID_EFFECT_AEC_H_
#include <hardware/audio_effect.h>
-
-#if __cplusplus
-extern "C" {
-#endif
-
-// The AEC type UUID is not defined by OpenSL ES and has been generated from
-// http://www.itu.int/ITU-T/asn1/uuid.html
-static const effect_uuid_t FX_IID_AEC_ =
- { 0x7b491460, 0x8d4d, 0x11e0, 0xbd61, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
-const effect_uuid_t * const FX_IID_AEC = &FX_IID_AEC_;
-
-typedef enum
-{
- AEC_PARAM_ECHO_DELAY, // echo delay in microseconds
- AEC_PARAM_PROPERTIES
-} t_aec_params;
-
-//t_equalizer_settings groups all current aec settings for backup and restore.
-typedef struct s_aec_settings {
- uint32_t echoDelay;
-} t_aec_settings;
-
-#if __cplusplus
-} // extern "C"
-#endif
-
+#include <system/audio_effects/effect_aec.h>
#endif /*ANDROID_EFFECT_AEC_H_*/
diff --git a/audio_effects/include/audio_effects/effect_agc.h b/audio_effects/include/audio_effects/effect_agc.h
index eddac67..466ea96 100644
--- a/audio_effects/include/audio_effects/effect_agc.h
+++ b/audio_effects/include/audio_effects/effect_agc.h
@@ -14,41 +14,20 @@
* limitations under the License.
*/
+/*
+ * USAGE NOTE: Only include this header when _implementing_ a particular
+ * effect. When access to UUID and properties is enough, include the
+ * corresponding header from system/audio_effects/, which doesn't include
+ * hardware/audio_effect.h.
+ *
+ * Only code that immediately calls into HAL or implements an effect
+ * can import hardware/audio_effect.h.
+ */
+
#ifndef ANDROID_EFFECT_AGC_H_
#define ANDROID_EFFECT_AGC_H_
#include <hardware/audio_effect.h>
-
-#if __cplusplus
-extern "C" {
-#endif
-
-// The AGC type UUID is not defined by OpenSL ES and has been generated from
-// http://www.itu.int/ITU-T/asn1/uuid.html
-static const effect_uuid_t FX_IID_AGC_ =
- { 0x0a8abfe0, 0x654c, 0x11e0, 0xba26, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
-const effect_uuid_t * const FX_IID_AGC = &FX_IID_AGC_;
-
-
-typedef enum
-{
- AGC_PARAM_TARGET_LEVEL, // target output level in millibel
- AGC_PARAM_COMP_GAIN, // gain in the compression range in millibel
- AGC_PARAM_LIMITER_ENA, // enable or disable limiter (boolean)
- AGC_PARAM_PROPERTIES
-} t_agc_params;
-
-
-//t_agc_settings groups all current agc settings for backup and restore.
-typedef struct s_agc_settings {
- int16_t targetLevel;
- int16_t compGain;
- bool limiterEnabled;
-} t_agc_settings;
-
-#if __cplusplus
-} // extern "C"
-#endif
-
+#include <system/audio_effects/effect_agc.h>
#endif /*ANDROID_EFFECT_AGC_H_*/
diff --git a/audio_effects/include/audio_effects/effect_bassboost.h b/audio_effects/include/audio_effects/effect_bassboost.h
index 3735904..157452e 100644
--- a/audio_effects/include/audio_effects/effect_bassboost.h
+++ b/audio_effects/include/audio_effects/effect_bassboost.h
@@ -14,31 +14,20 @@
* limitations under the License.
*/
+/*
+ * USAGE NOTE: Only include this header when _implementing_ a particular
+ * effect. When access to UUID and properties is enough, include the
+ * corresponding header from system/audio_effects/, which doesn't include
+ * hardware/audio_effect.h.
+ *
+ * Only code that immediately calls into HAL or implements an effect
+ * can import hardware/audio_effect.h.
+ */
+
#ifndef ANDROID_EFFECT_BASSBOOST_H_
#define ANDROID_EFFECT_BASSBOOST_H_
#include <hardware/audio_effect.h>
-
-#if __cplusplus
-extern "C" {
-#endif
-
-#ifndef OPENSL_ES_H_
-static const effect_uuid_t SL_IID_BASSBOOST_ = { 0x0634f220, 0xddd4, 0x11db, 0xa0fc,
- { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
-const effect_uuid_t * const SL_IID_BASSBOOST = &SL_IID_BASSBOOST_;
-#endif //OPENSL_ES_H_
-
-/* enumerated parameter settings for BassBoost effect */
-typedef enum
-{
- BASSBOOST_PARAM_STRENGTH_SUPPORTED,
- BASSBOOST_PARAM_STRENGTH
-} t_bassboost_params;
-
-#if __cplusplus
-} // extern "C"
-#endif
-
+#include <system/audio_effects/effect_bassboost.h>
#endif /*ANDROID_EFFECT_BASSBOOST_H_*/
diff --git a/audio_effects/include/audio_effects/effect_downmix.h b/audio_effects/include/audio_effects/effect_downmix.h
index 0f6b073..26b849b 100644
--- a/audio_effects/include/audio_effects/effect_downmix.h
+++ b/audio_effects/include/audio_effects/effect_downmix.h
@@ -14,40 +14,20 @@
* limitations under the License.
*/
+/*
+ * USAGE NOTE: Only include this header when _implementing_ a particular
+ * effect. When access to UUID and properties is enough, include the
+ * corresponding header from system/audio_effects/, which doesn't include
+ * hardware/audio_effect.h.
+ *
+ * Only code that immediately calls into HAL or implements an effect
+ * can import hardware/audio_effect.h.
+ */
+
#ifndef ANDROID_EFFECT_DOWNMIX_H_
#define ANDROID_EFFECT_DOWNMIX_H_
#include <hardware/audio_effect.h>
-
-#if __cplusplus
-extern "C" {
-#endif
-
-#define EFFECT_UIID_DOWNMIX__ { 0x381e49cc, 0xa858, 0x4aa2, 0x87f6, \
- { 0xe8, 0x38, 0x8e, 0x76, 0x01, 0xb2 } }
-static const effect_uuid_t EFFECT_UIID_DOWNMIX_ = EFFECT_UIID_DOWNMIX__;
-const effect_uuid_t * const EFFECT_UIID_DOWNMIX = &EFFECT_UIID_DOWNMIX_;
-
-
-/* enumerated parameter settings for downmix effect */
-typedef enum {
- DOWNMIX_PARAM_TYPE
-} downmix_params_t;
-
-
-typedef enum {
- DOWNMIX_TYPE_INVALID = -1,
- // throw away the extra channels
- DOWNMIX_TYPE_STRIP = 0,
- // mix the extra channels with FL/FR
- DOWNMIX_TYPE_FOLD = 1,
- DOWNMIX_TYPE_CNT,
- DOWNMIX_TYPE_LAST = DOWNMIX_TYPE_CNT - 1
-} downmix_type_t;
-
-#if __cplusplus
-} // extern "C"
-#endif
-
+#include <system/audio_effects/effect_downmix.h>
#endif /*ANDROID_EFFECT_DOWNMIX_H_*/
diff --git a/audio_effects/include/audio_effects/effect_environmentalreverb.h b/audio_effects/include/audio_effects/effect_environmentalreverb.h
index 3acbd5c..dd474c2 100644
--- a/audio_effects/include/audio_effects/effect_environmentalreverb.h
+++ b/audio_effects/include/audio_effects/effect_environmentalreverb.h
@@ -14,57 +14,20 @@
* limitations under the License.
*/
+/*
+ * USAGE NOTE: Only include this header when _implementing_ a particular
+ * effect. When access to UUID and properties is enough, include the
+ * corresponding header from system/audio_effects/, which doesn't include
+ * hardware/audio_effect.h.
+ *
+ * Only code that immediately calls into HAL or implements an effect
+ * can import hardware/audio_effect.h.
+ */
+
#ifndef ANDROID_EFFECT_ENVIRONMENTALREVERB_H_
#define ANDROID_EFFECT_ENVIRONMENTALREVERB_H_
#include <hardware/audio_effect.h>
-
-#if __cplusplus
-extern "C" {
-#endif
-
-#ifndef OPENSL_ES_H_
-static const effect_uuid_t SL_IID_ENVIRONMENTALREVERB_ = { 0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac,
- { 0x4e, 0x23, 0x4d, 0x6, 0x83, 0x9e } };
-const effect_uuid_t * const SL_IID_ENVIRONMENTALREVERB = &SL_IID_ENVIRONMENTALREVERB_;
-#endif //OPENSL_ES_H_
-
-/* enumerated parameter settings for environmental reverb effect */
-typedef enum
-{
- // Parameters below are as defined in OpenSL ES specification for environmental reverb interface
- REVERB_PARAM_ROOM_LEVEL, // in millibels, range -6000 to 0
- REVERB_PARAM_ROOM_HF_LEVEL, // in millibels, range -4000 to 0
- REVERB_PARAM_DECAY_TIME, // in milliseconds, range 100 to 20000
- REVERB_PARAM_DECAY_HF_RATIO, // in permilles, range 100 to 1000
- REVERB_PARAM_REFLECTIONS_LEVEL, // in millibels, range -6000 to 0
- REVERB_PARAM_REFLECTIONS_DELAY, // in milliseconds, range 0 to 65
- REVERB_PARAM_REVERB_LEVEL, // in millibels, range -6000 to 0
- REVERB_PARAM_REVERB_DELAY, // in milliseconds, range 0 to 65
- REVERB_PARAM_DIFFUSION, // in permilles, range 0 to 1000
- REVERB_PARAM_DENSITY, // in permilles, range 0 to 1000
- REVERB_PARAM_PROPERTIES,
- REVERB_PARAM_BYPASS
-} t_env_reverb_params;
-
-//t_reverb_settings is equal to SLEnvironmentalReverbSettings defined in OpenSL ES specification.
-typedef struct s_reverb_settings {
- int16_t roomLevel;
- int16_t roomHFLevel;
- uint32_t decayTime;
- int16_t decayHFRatio;
- int16_t reflectionsLevel;
- uint32_t reflectionsDelay;
- int16_t reverbLevel;
- uint32_t reverbDelay;
- int16_t diffusion;
- int16_t density;
-} __attribute__((packed)) t_reverb_settings;
-
-
-#if __cplusplus
-} // extern "C"
-#endif
-
+#include <system/audio_effects/effect_environmentalreverb.h>
#endif /*ANDROID_EFFECT_ENVIRONMENTALREVERB_H_*/
diff --git a/audio_effects/include/audio_effects/effect_equalizer.h b/audio_effects/include/audio_effects/effect_equalizer.h
index 17ee74f..3059ec2 100644
--- a/audio_effects/include/audio_effects/effect_equalizer.h
+++ b/audio_effects/include/audio_effects/effect_equalizer.h
@@ -14,48 +14,20 @@
* limitations under the License.
*/
+/*
+ * USAGE NOTE: Only include this header when _implementing_ a particular
+ * effect. When access to UUID and properties is enough, include the
+ * corresponding header from system/audio_effects/, which doesn't include
+ * hardware/audio_effect.h.
+ *
+ * Only code that immediately calls into HAL or implements an effect
+ * can import hardware/audio_effect.h.
+ */
+
#ifndef ANDROID_EFFECT_EQUALIZER_H_
#define ANDROID_EFFECT_EQUALIZER_H_
#include <hardware/audio_effect.h>
-
-#ifndef OPENSL_ES_H_
-static const effect_uuid_t SL_IID_EQUALIZER_ = { 0x0bed4300, 0xddd6, 0x11db, 0x8f34,
- { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
-const effect_uuid_t * const SL_IID_EQUALIZER = &SL_IID_EQUALIZER_;
-#endif //OPENSL_ES_H_
-
-#if __cplusplus
-extern "C" {
-#endif
-
-/* enumerated parameters for Equalizer effect */
-typedef enum
-{
- EQ_PARAM_NUM_BANDS, // Gets the number of frequency bands that the equalizer
- // supports.
- EQ_PARAM_LEVEL_RANGE, // Returns the minimum and maximum band levels supported.
- EQ_PARAM_BAND_LEVEL, // Gets/Sets the gain set for the given equalizer band.
- EQ_PARAM_CENTER_FREQ, // Gets the center frequency of the given band.
- EQ_PARAM_BAND_FREQ_RANGE, // Gets the frequency range of the given frequency band.
- EQ_PARAM_GET_BAND, // Gets the band that has the most effect on the given
- // frequency.
- EQ_PARAM_CUR_PRESET, // Gets/Sets the current preset.
- EQ_PARAM_GET_NUM_OF_PRESETS, // Gets the total number of presets the equalizer supports.
- EQ_PARAM_GET_PRESET_NAME, // Gets the preset name based on the index.
- EQ_PARAM_PROPERTIES // Gets/Sets all parameters at a time.
-} t_equalizer_params;
-
-//t_equalizer_settings groups all current equalizer setting for backup and restore.
-typedef struct s_equalizer_settings {
- uint16_t curPreset;
- uint16_t numBands;
- uint16_t bandLevels[];
-} t_equalizer_settings;
-
-#if __cplusplus
-} // extern "C"
-#endif
-
+#include <system/audio_effects/effect_equalizer.h>
#endif /*ANDROID_EFFECT_EQUALIZER_H_*/
diff --git a/audio_effects/include/audio_effects/effect_loudnessenhancer.h b/audio_effects/include/audio_effects/effect_loudnessenhancer.h
index c5bcaee..f37ba45 100644
--- a/audio_effects/include/audio_effects/effect_loudnessenhancer.h
+++ b/audio_effects/include/audio_effects/effect_loudnessenhancer.h
@@ -14,32 +14,20 @@
* limitations under the License.
*/
+/*
+ * USAGE NOTE: Only include this header when _implementing_ a particular
+ * effect. When access to UUID and properties is enough, include the
+ * corresponding header from system/audio_effects/, which doesn't include
+ * hardware/audio_effect.h.
+ *
+ * Only code that immediately calls into HAL or implements an effect
+ * can import hardware/audio_effect.h.
+ */
+
#ifndef ANDROID_EFFECT_LOUDNESS_ENHANCER_H_
#define ANDROID_EFFECT_LOUDNESS_ENHANCER_H_
#include <hardware/audio_effect.h>
-
-#if __cplusplus
-extern "C" {
-#endif
-
-// this effect is not defined in OpenSL ES as one of the standard effects
-static const effect_uuid_t FX_IID_LOUDNESS_ENHANCER_ =
- {0xfe3199be, 0xaed0, 0x413f, 0x87bb, {0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}};
-const effect_uuid_t * const FX_IID_LOUDNESS_ENHANCER = &FX_IID_LOUDNESS_ENHANCER_;
-
-#define LOUDNESS_ENHANCER_DEFAULT_TARGET_GAIN_MB 0 // mB
-
-// enumerated parameters for DRC effect
-// to keep in sync with frameworks/base/media/java/android/media/audiofx/LoudnessEnhancer.java
-typedef enum
-{
- LOUDNESS_ENHANCER_PARAM_TARGET_GAIN_MB = 0,// target gain expressed in mB
-} t_level_monitor_params;
-
-#if __cplusplus
-} // extern "C"
-#endif
-
+#include <system/audio_effects/effect_loudnessenhancer.h>
#endif /*ANDROID_EFFECT_LOUDNESS_ENHANCER_H_*/
diff --git a/audio_effects/include/audio_effects/effect_ns.h b/audio_effects/include/audio_effects/effect_ns.h
index 8cda094..3bd8a41 100644
--- a/audio_effects/include/audio_effects/effect_ns.h
+++ b/audio_effects/include/audio_effects/effect_ns.h
@@ -14,50 +14,20 @@
* limitations under the License.
*/
+/*
+ * USAGE NOTE: Only include this header when _implementing_ a particular
+ * effect. When access to UUID and properties is enough, include the
+ * corresponding header from system/audio_effects/, which doesn't include
+ * hardware/audio_effect.h.
+ *
+ * Only code that immediately calls into HAL or implements an effect
+ * can import hardware/audio_effect.h.
+ */
+
#ifndef ANDROID_EFFECT_NS_H_
#define ANDROID_EFFECT_NS_H_
#include <hardware/audio_effect.h>
-
-#if __cplusplus
-extern "C" {
-#endif
-
-// The NS type UUID is not defined by OpenSL ES and has been generated from
-// http://www.itu.int/ITU-T/asn1/uuid.html
-static const effect_uuid_t FX_IID_NS_ =
- { 0x58b4b260, 0x8e06, 0x11e0, 0xaa8e, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
-const effect_uuid_t * const FX_IID_NS = &FX_IID_NS_;
-
-typedef enum
-{
- NS_PARAM_LEVEL, // noise suppression level (t_ns_level)
- NS_PARAM_PROPERTIES,
- NS_PARAM_TYPE // noise suppression type (t_ns_type)
-} t_ns_params;
-
-// noise suppression level
-typedef enum {
- NS_LEVEL_LOW,
- NS_LEVEL_MEDIUM,
- NS_LEVEL_HIGH
-} t_ns_level;
-
-// noise suppression type
-typedef enum {
- NS_TYPE_SINGLE_CHANNEL,
- NS_TYPE_MULTI_CHANNEL
-} t_ns_type;
-
-// s_ns_settings groups all current ns settings for backup and restore.
-typedef struct s_ns_settings {
- uint32_t level;
- uint32_t type;
-} t_ns_settings;
-
-#if __cplusplus
-} // extern "C"
-#endif
-
+#include <system/audio_effects/effect_ns.h>
#endif /*ANDROID_EFFECT_NS_H_*/
diff --git a/audio_effects/include/audio_effects/effect_presetreverb.h b/audio_effects/include/audio_effects/effect_presetreverb.h
index ba1beae..eac1f5f 100644
--- a/audio_effects/include/audio_effects/effect_presetreverb.h
+++ b/audio_effects/include/audio_effects/effect_presetreverb.h
@@ -14,43 +14,20 @@
* limitations under the License.
*/
+/*
+ * USAGE NOTE: Only include this header when _implementing_ a particular
+ * effect. When access to UUID and properties is enough, include the
+ * corresponding header from system/audio_effects/, which doesn't include
+ * hardware/audio_effect.h.
+ *
+ * Only code that immediately calls into HAL or implements an effect
+ * can import hardware/audio_effect.h.
+ */
+
#ifndef ANDROID_EFFECT_PRESETREVERB_H_
#define ANDROID_EFFECT_PRESETREVERB_H_
#include <hardware/audio_effect.h>
-
-#if __cplusplus
-extern "C" {
-#endif
-
-#ifndef OPENSL_ES_H_
-static const effect_uuid_t SL_IID_PRESETREVERB_ = { 0x47382d60, 0xddd8, 0x11db, 0xbf3a,
- { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
-const effect_uuid_t * const SL_IID_PRESETREVERB = &SL_IID_PRESETREVERB_;
-#endif //OPENSL_ES_H_
-
-/* enumerated parameter settings for preset reverb effect */
-typedef enum
-{
- REVERB_PARAM_PRESET
-} t_preset_reverb_params;
-
-
-typedef enum
-{
- REVERB_PRESET_NONE,
- REVERB_PRESET_SMALLROOM,
- REVERB_PRESET_MEDIUMROOM,
- REVERB_PRESET_LARGEROOM,
- REVERB_PRESET_MEDIUMHALL,
- REVERB_PRESET_LARGEHALL,
- REVERB_PRESET_PLATE,
- REVERB_PRESET_LAST = REVERB_PRESET_PLATE
-} t_reverb_presets;
-
-#if __cplusplus
-} // extern "C"
-#endif
-
+#include <system/audio_effects/effect_presetreverb.h>
#endif /*ANDROID_EFFECT_PRESETREVERB_H_*/
diff --git a/audio_effects/include/audio_effects/effect_virtualizer.h b/audio_effects/include/audio_effects/effect_virtualizer.h
index 3374a35..aeecfa5 100644
--- a/audio_effects/include/audio_effects/effect_virtualizer.h
+++ b/audio_effects/include/audio_effects/effect_virtualizer.h
@@ -14,66 +14,20 @@
* limitations under the License.
*/
+/*
+ * USAGE NOTE: Only include this header when _implementing_ a particular
+ * effect. When access to UUID and properties is enough, include the
+ * corresponding header from system/audio_effects/, which doesn't include
+ * hardware/audio_effect.h.
+ *
+ * Only code that immediately calls into HAL or implements an effect
+ * can import hardware/audio_effect.h.
+ */
+
#ifndef ANDROID_EFFECT_VIRTUALIZER_H_
#define ANDROID_EFFECT_VIRTUALIZER_H_
#include <hardware/audio_effect.h>
-
-#if __cplusplus
-extern "C" {
-#endif
-
-#ifndef OPENSL_ES_H_
-static const effect_uuid_t SL_IID_VIRTUALIZER_ = { 0x37cc2c00, 0xdddd, 0x11db, 0x8577,
- { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
-const effect_uuid_t * const SL_IID_VIRTUALIZER = &SL_IID_VIRTUALIZER_;
-#endif //OPENSL_ES_H_
-
-/* enumerated parameter settings for virtualizer effect */
-/* to keep in sync with frameworks/base/media/java/android/media/audiofx/Virtualizer.java */
-typedef enum
-{
- VIRTUALIZER_PARAM_STRENGTH_SUPPORTED,
- VIRTUALIZER_PARAM_STRENGTH,
- // used with EFFECT_CMD_GET_PARAM
- // format:
- // parameters int32_t VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES
- // audio_channel_mask_t input channel mask
- // audio_devices_t audio output device
- // output int32_t* an array of length 3 * the number of channels in the mask
- // where entries are the succession of the channel mask
- // of each speaker (i.e. a single bit is selected in the
- // channel mask) followed by the azimuth and the
- // elevation angles.
- // status int -EINVAL if configuration is not supported or invalid or not forcing
- // 0 if configuration is supported and the mode is forced
- // notes:
- // - all angles are expressed in degrees and are relative to the listener,
- // - for azimuth: 0 is the direction the listener faces, 180 is behind the listener, and
- // -90 is to her/his left,
- // - for elevation: 0 is the horizontal plane, +90 is above the listener, -90 is below.
- VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES,
- // used with EFFECT_CMD_SET_PARAM
- // format:
- // parameters int32_t VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE
- // audio_devices_t audio output device
- // status int -EINVAL if the device is not supported or invalid
- // 0 if the device is supported and the mode is forced, or forcing
- // was disabled for the AUDIO_DEVICE_NONE audio device.
- VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE,
- // used with EFFECT_CMD_GET_PARAM
- // format:
- // parameters int32_t VIRTUALIZER_PARAM_VIRTUALIZATION_MODE
- // output audio_device_t audio device reflecting the current virtualization mode,
- // AUDIO_DEVICE_NONE when not virtualizing
- // status int -EINVAL if an error occurred
- // 0 if the output value is successfully retrieved
- VIRTUALIZER_PARAM_VIRTUALIZATION_MODE
-} t_virtualizer_params;
-
-#if __cplusplus
-} // extern "C"
-#endif
-
+#include <system/audio_effects/effect_virtualizer.h>
#endif /*ANDROID_EFFECT_VIRTUALIZER_H_*/
diff --git a/audio_effects/include/audio_effects/effect_visualizer.h b/audio_effects/include/audio_effects/effect_visualizer.h
index fe46d7f..47217e7 100644
--- a/audio_effects/include/audio_effects/effect_visualizer.h
+++ b/audio_effects/include/audio_effects/effect_visualizer.h
@@ -14,61 +14,20 @@
* limitations under the License.
*/
+/*
+ * USAGE NOTE: Only include this header when _implementing_ a particular
+ * effect. When access to UUID and properties is enough, include the
+ * corresponding header from system/audio_effects/, which doesn't include
+ * hardware/audio_effect.h.
+ *
+ * Only code that immediately calls into HAL or implements an effect
+ * can import hardware/audio_effect.h.
+ */
+
#ifndef ANDROID_EFFECT_VISUALIZER_H_
#define ANDROID_EFFECT_VISUALIZER_H_
#include <hardware/audio_effect.h>
-
-#if __cplusplus
-extern "C" {
-#endif
-
-#ifndef OPENSL_ES_H_
-static const effect_uuid_t SL_IID_VISUALIZATION_ =
- { 0xe46b26a0, 0xdddd, 0x11db, 0x8afd, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
-const effect_uuid_t * const SL_IID_VISUALIZATION = &SL_IID_VISUALIZATION_;
-#endif //OPENSL_ES_H_
-
-#define VISUALIZER_CAPTURE_SIZE_MAX 1024 // maximum capture size in samples
-#define VISUALIZER_CAPTURE_SIZE_MIN 128 // minimum capture size in samples
-
-// to keep in sync with frameworks/base/media/java/android/media/audiofx/Visualizer.java
-#define VISUALIZER_SCALING_MODE_NORMALIZED 0
-#define VISUALIZER_SCALING_MODE_AS_PLAYED 1
-
-#define MEASUREMENT_MODE_NONE 0x0
-#define MEASUREMENT_MODE_PEAK_RMS 0x1
-
-#define MEASUREMENT_IDX_PEAK 0
-#define MEASUREMENT_IDX_RMS 1
-#define MEASUREMENT_COUNT 2
-
-/* enumerated parameters for Visualizer effect */
-typedef enum
-{
- VISUALIZER_PARAM_CAPTURE_SIZE, // Sets the number PCM samples in the capture.
- VISUALIZER_PARAM_SCALING_MODE, // Sets the way the captured data is scaled
- VISUALIZER_PARAM_LATENCY, // Informs the visualizer about the downstream latency
- VISUALIZER_PARAM_MEASUREMENT_MODE, // Sets which measurements are to be made
-} t_visualizer_params;
-
-/* commands */
-typedef enum
-{
- VISUALIZER_CMD_CAPTURE = EFFECT_CMD_FIRST_PROPRIETARY, // Gets the latest PCM capture.
- VISUALIZER_CMD_MEASURE, // Gets the current measurements
-}t_visualizer_cmds;
-
-// VISUALIZER_CMD_CAPTURE retrieves the latest PCM snapshot captured by the visualizer engine.
-// It returns the number of samples specified by VISUALIZER_PARAM_CAPTURE_SIZE
-// in 8 bit unsigned format (0 = 0x80)
-
-// VISUALIZER_CMD_MEASURE retrieves the lastest measurements as int32_t saved in the
-// MEASUREMENT_IDX_* array index order.
-
-#if __cplusplus
-} // extern "C"
-#endif
-
+#include <system/audio_effects/effect_visualizer.h>
#endif /*ANDROID_EFFECT_VISUALIZER_H_*/
diff --git a/audio_route/audio_route.c b/audio_route/audio_route.c
index 3796958..89b076b 100644
--- a/audio_route/audio_route.c
+++ b/audio_route/audio_route.c
@@ -153,17 +153,16 @@
unsigned int i;
for (i = 0; i < ar->num_mixer_paths; i++) {
- if (ar->mixer_path[i].name)
- free(ar->mixer_path[i].name);
+ free(ar->mixer_path[i].name);
if (ar->mixer_path[i].setting) {
- if (ar->mixer_path[i].setting->value.ptr)
- free(ar->mixer_path[i].setting->value.ptr);
+ free(ar->mixer_path[i].setting->value.ptr);
free(ar->mixer_path[i].setting);
}
}
free(ar->mixer_path);
ar->mixer_path = NULL;
ar->mixer_path_size = 0;
+ ar->num_mixer_paths = 0;
}
static struct mixer_path *path_get_by_name(struct audio_route *ar,
@@ -478,7 +477,11 @@
} else {
/* nested path */
struct mixer_path *sub_path = path_get_by_name(ar, attr_name);
- path_add_path(ar, state->path, sub_path);
+ if (!sub_path) {
+ ALOGE("unable to find sub path '%s'", attr_name);
+ } else {
+ path_add_path(ar, state->path, sub_path);
+ }
}
}
}
@@ -878,7 +881,7 @@
file = fopen(xml_path, "r");
if (!file) {
- ALOGE("Failed to open %s", xml_path);
+ ALOGE("Failed to open %s: %s", xml_path, strerror(errno));
goto err_fopen;
}
diff --git a/audio_utils/Android.bp b/audio_utils/Android.bp
index 36023f5..f6129cb 100644
--- a/audio_utils/Android.bp
+++ b/audio_utils/Android.bp
@@ -20,10 +20,14 @@
srcs: [
"channels.c",
- "fifo.c",
+ "ErrorLog.cpp",
+ "fifo.cpp",
+ "fifo_index.cpp",
"format.c",
"limiter.c",
"minifloat.c",
+ "power.cpp",
+ "PowerLog.cpp",
"primitives.c",
"roundup.c",
],
@@ -87,7 +91,8 @@
name: "libfifo",
defaults: ["audio_utils_defaults"],
srcs: [
- "fifo.c",
+ "fifo.cpp",
+ "fifo_index.cpp",
"primitives.c",
"roundup.c",
],
diff --git a/audio_utils/ErrorLog.cpp b/audio_utils/ErrorLog.cpp
new file mode 100644
index 0000000..54742e9
--- /dev/null
+++ b/audio_utils/ErrorLog.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017 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 "audio_utils_ErrorLog"
+#include <log/log.h>
+
+#include <audio_utils/ErrorLog.h>
+
+using namespace android;
+
+error_log_t *error_log_create(size_t entries, int64_t aggregate_ns)
+{
+ return reinterpret_cast<error_log_t *>
+ (new(std::nothrow) ErrorLog<int32_t>(entries, aggregate_ns));
+}
+
+void error_log_log(error_log_t *error_log, int32_t code, int64_t now_ns)
+{
+ if (error_log == nullptr) {
+ return;
+ }
+ reinterpret_cast<ErrorLog<int32_t> *>(error_log)->log(code, now_ns);
+}
+
+int error_log_dump(
+ error_log_t *error_log, int fd, const char *prefix, size_t lines, int64_t limit_ns)
+{
+ if (error_log == nullptr) {
+ return BAD_VALUE;
+ }
+ return reinterpret_cast<ErrorLog<int32_t> *>(error_log)->dump(fd, prefix, lines, limit_ns);
+}
+
+void error_log_destroy(error_log_t *error_log)
+{
+ delete reinterpret_cast<ErrorLog<int32_t> *>(error_log);
+}
diff --git a/audio_utils/PowerLog.cpp b/audio_utils/PowerLog.cpp
new file mode 100644
index 0000000..ab0dcaa
--- /dev/null
+++ b/audio_utils/PowerLog.cpp
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2017 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 "audio_utils_PowerLog"
+#include <log/log.h>
+
+#include <algorithm>
+#include <iomanip>
+#include <math.h>
+#include <sstream>
+#include <stdint.h>
+
+#include <audio_utils/clock.h>
+#include <audio_utils/power.h>
+#include <audio_utils/PowerLog.h>
+
+namespace android {
+
+// TODO move to separate file
+template <typename T, size_t N>
+constexpr size_t array_size(const T(&)[N])
+{
+ return N;
+}
+
+PowerLog::PowerLog(uint32_t sampleRate,
+ uint32_t channelCount,
+ audio_format_t format,
+ size_t entries,
+ size_t framesPerEntry)
+ : mCurrentTime(0)
+ , mCurrentEnergy(0)
+ , mCurrentFrames(0)
+ , mIdx(0)
+ , mConsecutiveZeroes(0)
+ , mSampleRate(sampleRate)
+ , mChannelCount(channelCount)
+ , mFormat(format)
+ , mFramesPerEntry(framesPerEntry)
+ , mEntries(entries)
+{
+ (void)mSampleRate; // currently unused, for future use
+ LOG_ALWAYS_FATAL_IF(!audio_utils_is_compute_power_format_supported(format),
+ "unsupported format: %#x", format);
+}
+
+void PowerLog::log(const void *buffer, size_t frames, int64_t nowNs)
+{
+ std::lock_guard<std::mutex> guard(mLock);
+
+ const size_t bytes_per_sample = audio_bytes_per_sample(mFormat);
+ while (frames > 0) {
+ // check partial computation
+ size_t required = mFramesPerEntry - mCurrentFrames;
+ size_t process = std::min(required, frames);
+
+ if (mCurrentTime == 0) {
+ mCurrentTime = nowNs;
+ }
+ mCurrentEnergy +=
+ audio_utils_compute_energy_mono(buffer, mFormat, process * mChannelCount);
+ mCurrentFrames += process;
+
+ ALOGV("nowNs:%lld, required:%zu, process:%zu, mCurrentEnergy:%f, mCurrentFrames:%zu",
+ (long long)nowNs, required, process, mCurrentEnergy, mCurrentFrames);
+ if (process < required) {
+ return;
+ }
+
+ // We store the data as normalized energy per sample. The energy sequence is
+ // zero terminated. Consecutive zeroes are ignored.
+ if (mCurrentEnergy == 0.f) {
+ if (mConsecutiveZeroes++ == 0) {
+ mEntries[mIdx++] = std::make_pair(nowNs, 0.f);
+ // zero terminate the signal sequence.
+ }
+ } else {
+ mConsecutiveZeroes = 0;
+ mEntries[mIdx++] = std::make_pair(mCurrentTime, mCurrentEnergy);
+ ALOGV("writing %lld %f", (long long)mCurrentTime, mCurrentEnergy);
+ }
+ if (mIdx >= mEntries.size()) {
+ mIdx -= mEntries.size();
+ }
+ mCurrentTime = 0;
+ mCurrentEnergy = 0;
+ mCurrentFrames = 0;
+ frames -= process;
+ buffer = (const uint8_t *)buffer + mCurrentFrames * mChannelCount * bytes_per_sample;
+ }
+}
+
+std::string PowerLog::dumpToString(const char *prefix, size_t lines, int64_t limitNs) const
+{
+ std::lock_guard<std::mutex> guard(mLock);
+
+ const size_t maxColumns = 10;
+ const size_t numberOfEntries = mEntries.size();
+ if (lines == 0) lines = SIZE_MAX;
+
+ // compute where to start logging
+ enum {
+ AT_END,
+ IN_SIGNAL,
+ } state = IN_SIGNAL;
+ size_t count = 1;
+ size_t column = 0;
+ size_t nonzeros = 0;
+ ssize_t offset; // TODO doesn't dump if # entries exceeds SSIZE_MAX
+ for (offset = 0; offset < (ssize_t)numberOfEntries && count < lines; ++offset) {
+ const size_t idx = (mIdx + numberOfEntries - offset - 1) % numberOfEntries; // reverse direction
+ const int64_t time = mEntries[idx].first;
+ const float energy = mEntries[idx].second;
+
+ if (state == AT_END) {
+ if (energy == 0.f) {
+ ALOGV("two zeroes detected");
+ break; // normally single zero terminated - two zeroes means no more data.
+ }
+ state = IN_SIGNAL;
+ } else { // IN_SIGNAL
+ if (energy == 0.f) {
+ if (column != 0) {
+ column = 0;
+ ++count;
+ }
+ state = AT_END;
+ continue;
+ }
+ }
+ if (column == 0 && time < limitNs) {
+ break;
+ }
+ ++nonzeros;
+ if (++column == maxColumns) {
+ column = 0;
+ // TODO ideally we would peek the previous entry to see if it is 0
+ // to ensure we properly put in a starting signal bracket.
+ // We don't do that because it would complicate the logic here.
+ ++count;
+ }
+ }
+ if (offset > 0) {
+ --offset;
+ }
+ // We accumulate the log info into a string, and write to the fd once.
+ std::stringstream ss;
+ ss << std::fixed << std::setprecision(1);
+ // ss << std::scientific;
+ if (nonzeros == 0) {
+ ss << prefix << "Signal power history: (none)\n";
+ } else {
+ ss << prefix << "Signal power history:\n";
+
+ size_t column = 0;
+ bool first = true;
+ bool start = false;
+ float cumulative = 0.f;
+ for (; offset >= 0; --offset) {
+ const size_t idx = (mIdx + numberOfEntries - offset - 1) % numberOfEntries;
+ const int64_t time = mEntries[idx].first;
+ const float energy = mEntries[idx].second;
+
+ if (energy == 0.f) {
+ if (!first) {
+ ss << " ] sum(" << audio_utils_power_from_energy(cumulative) << ")";
+ }
+ cumulative = 0.f;
+ column = 0;
+ start = true;
+ continue;
+ }
+ if (column == 0) {
+ // print time if at start of column
+ if (!first) {
+ ss << "\n";
+ }
+ ss << prefix << " " << audio_utils_time_string_from_ns(time).time
+ << (start ? ": [ ": ": ");
+ first = false;
+ start = false;
+ } else {
+ ss << " ";
+ }
+ if (++column >= maxColumns) {
+ column = 0;
+ }
+
+ cumulative += energy;
+ // convert energy to power and print
+ const float power =
+ audio_utils_power_from_energy(energy / (mChannelCount * mFramesPerEntry));
+ ss << std::setw(6) << power;
+ ALOGV("state: %d %lld %f", state, (long long)time, power);
+ }
+ ss << "\n";
+ }
+ return ss.str();
+}
+
+status_t PowerLog::dump(int fd, const char *prefix, size_t lines, int64_t limitNs) const
+{
+ // Since dumpToString and write are thread safe, this function
+ // is conceptually thread-safe but simultaneous calls to dump
+ // by different threads to the same file descriptor may not write
+ // the two logs in time order.
+ const std::string s = dumpToString(prefix, lines, limitNs);
+ if (s.size() > 0 && write(fd, s.c_str(), s.size()) < 0) {
+ return -errno;
+ }
+ return NO_ERROR;
+}
+
+} // namespace android
+
+using namespace android;
+
+power_log_t *power_log_create(uint32_t sample_rate,
+ uint32_t channel_count, audio_format_t format, size_t entries, size_t frames_per_entry)
+{
+ if (!audio_utils_is_compute_power_format_supported(format)) {
+ return nullptr;
+ }
+ return reinterpret_cast<power_log_t *>
+ (new(std::nothrow)
+ PowerLog(sample_rate, channel_count, format, entries, frames_per_entry));
+}
+
+void power_log_log(power_log_t *power_log,
+ const void *buffer, size_t frames, int64_t now_ns)
+{
+ if (power_log == nullptr) {
+ return;
+ }
+ reinterpret_cast<PowerLog *>(power_log)->log(buffer, frames, now_ns);
+}
+
+int power_log_dump(
+ power_log_t *power_log, int fd, const char *prefix, size_t lines, int64_t limit_ns)
+{
+ if (power_log == nullptr) {
+ return BAD_VALUE;
+ }
+ return reinterpret_cast<PowerLog *>(power_log)->dump(fd, prefix, lines, limit_ns);
+}
+
+void power_log_destroy(power_log_t *power_log)
+{
+ delete reinterpret_cast<PowerLog *>(power_log);
+}
diff --git a/audio_utils/README.md b/audio_utils/README.md
new file mode 100644
index 0000000..df78972
--- /dev/null
+++ b/audio_utils/README.md
@@ -0,0 +1,8 @@
+# How to build and view documentation
+
+* doxygen Doxyfile
+* cd html
+* python -m SimpleHTTPServer
+* open in web browser
+ http://localhost:8000/classaudio__utils__fifo.html
+* when done: rm -rf html
diff --git a/audio_utils/channels.c b/audio_utils/channels.c
index 1e22e8b..91d18fd 100644
--- a/audio_utils/channels.c
+++ b/audio_utils/channels.c
@@ -33,7 +33,7 @@
* Converts a uint8x3_t into an int32_t
*/
static inline int32_t uint8x3_to_int32(uint8x3_t val) {
-#ifdef HAVE_BIG_ENDIAN
+#if HAVE_BIG_ENDIAN
int32_t temp = (val.c[0] << 24 | val.c[1] << 16 | val.c[2] << 8) >> 8;
#else
int32_t temp = (val.c[2] << 24 | val.c[1] << 16 | val.c[0] << 8) >> 8;
@@ -46,7 +46,7 @@
*/
static inline uint8x3_t int32_to_uint8x3(int32_t in) {
uint8x3_t out;
-#ifdef HAVE_BIG_ENDIAN
+#if HAVE_BIG_ENDIAN
out.c[2] = in;
out.c[1] = in >> 8;
out.c[0] = in >> 16;
diff --git a/audio_utils/fifo.c b/audio_utils/fifo.c
deleted file mode 100644
index c818a50..0000000
--- a/audio_utils/fifo.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 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_NDEBUG 0
-#define LOG_TAG "audio_utils_fifo"
-
-#include <stdlib.h>
-#include <string.h>
-#include <audio_utils/fifo.h>
-#include <audio_utils/roundup.h>
-#include <cutils/atomic.h>
-#include <cutils/log.h>
-
-void audio_utils_fifo_init(struct audio_utils_fifo *fifo, size_t frameCount, size_t frameSize,
- void *buffer)
-{
- // We would need a 64-bit roundup to support larger frameCount.
- ALOG_ASSERT(fifo != NULL && frameCount > 0 && frameSize > 0 && buffer != NULL);
- fifo->mFrameCount = frameCount;
- fifo->mFrameCountP2 = roundup(frameCount);
- fifo->mFudgeFactor = fifo->mFrameCountP2 - fifo->mFrameCount;
- fifo->mFrameSize = frameSize;
- fifo->mBuffer = buffer;
- fifo->mFront = 0;
- fifo->mRear = 0;
-}
-
-void audio_utils_fifo_deinit(struct audio_utils_fifo *fifo __unused)
-{
-}
-
-// Return a new index as the sum of an old index (either mFront or mRear) and a specified increment.
-static inline int32_t audio_utils_fifo_sum(struct audio_utils_fifo *fifo, int32_t index,
- uint32_t increment)
-{
- if (fifo->mFudgeFactor) {
- uint32_t mask = fifo->mFrameCountP2 - 1;
- ALOG_ASSERT((index & mask) < fifo->mFrameCount);
- ALOG_ASSERT(/*0 <= increment &&*/ increment <= fifo->mFrameCountP2);
- if ((index & mask) + increment >= fifo->mFrameCount) {
- increment += fifo->mFudgeFactor;
- }
- index += increment;
- ALOG_ASSERT((index & mask) < fifo->mFrameCount);
- return index;
- } else {
- return index + increment;
- }
-}
-
-// Return the difference between two indices: rear - front, where 0 <= difference <= mFrameCount.
-static inline size_t audio_utils_fifo_diff(struct audio_utils_fifo *fifo, int32_t rear,
- int32_t front)
-{
- int32_t diff = rear - front;
- if (fifo->mFudgeFactor) {
- uint32_t mask = ~(fifo->mFrameCountP2 - 1);
- int32_t genDiff = (rear & mask) - (front & mask);
- if (genDiff != 0) {
- ALOG_ASSERT(genDiff == (int32_t) fifo->mFrameCountP2);
- diff -= fifo->mFudgeFactor;
- }
- }
- // FIFO should not be overfull
- ALOG_ASSERT(0 <= diff && diff <= (int32_t) fifo->mFrameCount);
- return (size_t) diff;
-}
-
-ssize_t audio_utils_fifo_write(struct audio_utils_fifo *fifo, const void *buffer, size_t count)
-{
- int32_t front = android_atomic_acquire_load(&fifo->mFront);
- int32_t rear = fifo->mRear;
- size_t availToWrite = fifo->mFrameCount - audio_utils_fifo_diff(fifo, rear, front);
- if (availToWrite > count) {
- availToWrite = count;
- }
- rear &= fifo->mFrameCountP2 - 1;
- size_t part1 = fifo->mFrameCount - rear;
- if (part1 > availToWrite) {
- part1 = availToWrite;
- }
- if (part1 > 0) {
- memcpy((char *) fifo->mBuffer + (rear * fifo->mFrameSize), buffer,
- part1 * fifo->mFrameSize);
- size_t part2 = availToWrite - part1;
- if (part2 > 0) {
- memcpy(fifo->mBuffer, (char *) buffer + (part1 * fifo->mFrameSize),
- part2 * fifo->mFrameSize);
- }
- android_atomic_release_store(audio_utils_fifo_sum(fifo, fifo->mRear, availToWrite),
- &fifo->mRear);
- }
- return availToWrite;
-}
-
-ssize_t audio_utils_fifo_read(struct audio_utils_fifo *fifo, void *buffer, size_t count)
-{
- int32_t rear = android_atomic_acquire_load(&fifo->mRear);
- int32_t front = fifo->mFront;
- size_t availToRead = audio_utils_fifo_diff(fifo, rear, front);
- if (availToRead > count) {
- availToRead = count;
- }
- front &= fifo->mFrameCountP2 - 1;
- size_t part1 = fifo->mFrameCount - front;
- if (part1 > availToRead) {
- part1 = availToRead;
- }
- if (part1 > 0) {
- memcpy(buffer, (char *) fifo->mBuffer + (front * fifo->mFrameSize),
- part1 * fifo->mFrameSize);
- size_t part2 = availToRead - part1;
- if (part2 > 0) {
- memcpy((char *) buffer + (part1 * fifo->mFrameSize), fifo->mBuffer,
- part2 * fifo->mFrameSize);
- }
- android_atomic_release_store(audio_utils_fifo_sum(fifo, fifo->mFront, availToRead),
- &fifo->mFront);
- }
- return availToRead;
-}
diff --git a/audio_utils/fifo.cpp b/audio_utils/fifo.cpp
new file mode 100644
index 0000000..883a9c0
--- /dev/null
+++ b/audio_utils/fifo.cpp
@@ -0,0 +1,660 @@
+/*
+ * Copyright (C) 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_NDEBUG 0
+#define LOG_TAG "audio_utils_fifo"
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <audio_utils/clock_nanosleep.h>
+#include <audio_utils/fifo.h>
+#include <audio_utils/futex.h>
+#include <audio_utils/roundup.h>
+#include <cutils/log.h>
+#include <utils/Errors.h>
+
+audio_utils_fifo_base::audio_utils_fifo_base(uint32_t frameCount,
+ audio_utils_fifo_index& writerRear, audio_utils_fifo_index *throttleFront)
+ __attribute__((no_sanitize("integer"))) :
+ mFrameCount(frameCount), mFrameCountP2(roundup(frameCount)),
+ mFudgeFactor(mFrameCountP2 - mFrameCount),
+ // FIXME need an API to configure the sync types
+ mWriterRear(writerRear), mWriterRearSync(AUDIO_UTILS_FIFO_SYNC_SHARED),
+ mThrottleFront(throttleFront), mThrottleFrontSync(AUDIO_UTILS_FIFO_SYNC_SHARED),
+ mIsShutdown(false)
+{
+ // actual upper bound on frameCount will depend on the frame size
+ LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameCount > ((uint32_t) INT32_MAX));
+}
+
+audio_utils_fifo_base::~audio_utils_fifo_base()
+{
+}
+
+uint32_t audio_utils_fifo_base::sum(uint32_t index, uint32_t increment) const
+ __attribute__((no_sanitize("integer")))
+{
+ if (mFudgeFactor > 0) {
+ uint32_t mask = mFrameCountP2 - 1;
+ ALOG_ASSERT((index & mask) < mFrameCount);
+ ALOG_ASSERT(increment <= mFrameCountP2);
+ if ((index & mask) + increment >= mFrameCount) {
+ increment += mFudgeFactor;
+ }
+ index += increment;
+ ALOG_ASSERT((index & mask) < mFrameCount);
+ return index;
+ } else {
+ return index + increment;
+ }
+}
+
+int32_t audio_utils_fifo_base::diff(uint32_t rear, uint32_t front, size_t *lost, bool flush) const
+ __attribute__((no_sanitize("integer")))
+{
+ // TODO replace multiple returns by a single return point so this isn't needed
+ if (lost != NULL) {
+ *lost = 0;
+ }
+ if (mIsShutdown) {
+ return -EIO;
+ }
+ uint32_t diff = rear - front;
+ if (mFudgeFactor > 0) {
+ uint32_t mask = mFrameCountP2 - 1;
+ uint32_t rearOffset = rear & mask;
+ uint32_t frontOffset = front & mask;
+ if (rearOffset >= mFrameCount || frontOffset >= mFrameCount) {
+ ALOGE("%s frontOffset=%u rearOffset=%u mFrameCount=%u",
+ __func__, frontOffset, rearOffset, mFrameCount);
+ shutdown();
+ return -EIO;
+ }
+ // genDiff is the difference between the generation count fields of rear and front,
+ // and is always a multiple of mFrameCountP2.
+ uint32_t genDiff = (rear & ~mask) - (front & ~mask);
+ // It's OK for writer to be one generation beyond reader,
+ // but reader has lost frames if writer is further than one generation beyond.
+ if (genDiff > mFrameCountP2) {
+ if (lost != NULL) {
+ // Calculate the number of lost frames as the raw difference,
+ // less the mFrameCount frames that are still valid and can be read on retry,
+ // less the wasted indices that don't count as true lost frames.
+ *lost = diff - (flush ? 0 : mFrameCount) - mFudgeFactor * (genDiff/mFrameCountP2);
+ }
+ return -EOVERFLOW;
+ }
+ // If writer is one generation beyond reader, skip over the wasted indices.
+ if (genDiff > 0) {
+ diff -= mFudgeFactor;
+ // Note is still possible for diff > mFrameCount. BCD 16 - BCD 1 shows the problem.
+ // genDiff is 16, fudge is 6, decimal diff is 15 = (22 - 1 - 6).
+ // So we need to check diff for overflow one more time. See "if" a few lines below.
+ }
+ }
+ // FIFO should not be overfull
+ if (diff > mFrameCount) {
+ if (lost != NULL) {
+ *lost = diff - (flush ? 0 : mFrameCount);
+ }
+ return -EOVERFLOW;
+ }
+ return (int32_t) diff;
+}
+
+void audio_utils_fifo_base::shutdown() const
+{
+ ALOGE("%s", __func__);
+ mIsShutdown = true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer,
+ audio_utils_fifo_index& writerRear, audio_utils_fifo_index *throttleFront)
+ __attribute__((no_sanitize("integer"))) :
+ audio_utils_fifo_base(frameCount, writerRear, throttleFront),
+ mFrameSize(frameSize), mBuffer(buffer)
+{
+ // maximum value of frameCount * frameSize is INT32_MAX (2^31 - 1), not 2^31, because we need to
+ // be able to distinguish successful and error return values from read and write.
+ LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameSize == 0 || buffer == NULL ||
+ frameCount > ((uint32_t) INT32_MAX) / frameSize);
+}
+
+audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer,
+ bool throttlesWriter) :
+ audio_utils_fifo(frameCount, frameSize, buffer, mSingleProcessSharedRear,
+ throttlesWriter ? &mSingleProcessSharedFront : NULL)
+{
+}
+
+audio_utils_fifo::~audio_utils_fifo()
+{
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+audio_utils_fifo_provider::audio_utils_fifo_provider(audio_utils_fifo& fifo) :
+ mFifo(fifo), mObtained(0), mTotalReleased(0)
+{
+}
+
+audio_utils_fifo_provider::~audio_utils_fifo_provider()
+{
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+audio_utils_fifo_writer::audio_utils_fifo_writer(audio_utils_fifo& fifo) :
+ audio_utils_fifo_provider(fifo), mLocalRear(0),
+ mArmLevel(fifo.mFrameCount), mTriggerLevel(0),
+ mIsArmed(true), // because initial fill level of zero is < mArmLevel
+ mEffectiveFrames(fifo.mFrameCount)
+{
+}
+
+audio_utils_fifo_writer::~audio_utils_fifo_writer()
+{
+}
+
+ssize_t audio_utils_fifo_writer::write(const void *buffer, size_t count,
+ const struct timespec *timeout)
+ __attribute__((no_sanitize("integer")))
+{
+ audio_utils_iovec iovec[2];
+ ssize_t availToWrite = obtain(iovec, count, timeout);
+ if (availToWrite > 0) {
+ memcpy((char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize, buffer,
+ iovec[0].mLength * mFifo.mFrameSize);
+ if (iovec[1].mLength > 0) {
+ memcpy((char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
+ (char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
+ iovec[1].mLength * mFifo.mFrameSize);
+ }
+ release(availToWrite);
+ }
+ return availToWrite;
+}
+
+// iovec == NULL is not part of the public API, but internally it means don't set mObtained
+ssize_t audio_utils_fifo_writer::obtain(audio_utils_iovec iovec[2], size_t count,
+ const struct timespec *timeout)
+ __attribute__((no_sanitize("integer")))
+{
+ int err = 0;
+ size_t availToWrite;
+ if (mFifo.mThrottleFront != NULL) {
+ int retries = kRetries;
+ uint32_t front;
+ for (;;) {
+ front = mFifo.mThrottleFront->loadAcquire();
+ // returns -EIO if mIsShutdown
+ int32_t filled = mFifo.diff(mLocalRear, front);
+ if (filled < 0) {
+ // on error, return an empty slice
+ err = filled;
+ availToWrite = 0;
+ break;
+ }
+ availToWrite = mEffectiveFrames > (uint32_t) filled ?
+ mEffectiveFrames - (uint32_t) filled : 0;
+ // TODO pull out "count == 0"
+ if (count == 0 || availToWrite > 0 || timeout == NULL ||
+ (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
+ break;
+ }
+ // TODO add comments
+ // TODO abstract out switch and replace by general sync object
+ // the high level code (synchronization, sleep, futex, iovec) should be completely
+ // separate from the low level code (indexes, available, masking).
+ int op = FUTEX_WAIT;
+ switch (mFifo.mThrottleFrontSync) {
+ case AUDIO_UTILS_FIFO_SYNC_SLEEP:
+ err = audio_utils_clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout,
+ NULL /*remain*/);
+ if (err < 0) {
+ LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno);
+ err = -errno;
+ } else {
+ err = -ETIMEDOUT;
+ }
+ break;
+ case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
+ op = FUTEX_WAIT_PRIVATE;
+ // fall through
+ case AUDIO_UTILS_FIFO_SYNC_SHARED:
+ if (timeout->tv_sec == LONG_MAX) {
+ timeout = NULL;
+ }
+ err = mFifo.mThrottleFront->wait(op, front, timeout);
+ if (err < 0) {
+ switch (errno) {
+ case EWOULDBLOCK:
+ // Benign race condition with partner: mFifo.mThrottleFront->mIndex
+ // changed value between the earlier atomic_load_explicit() and sys_futex().
+ // Try to load index again, but give up if we are unable to converge.
+ if (retries-- > 0) {
+ // bypass the "timeout = NULL;" below
+ continue;
+ }
+ // fall through
+ case EINTR:
+ case ETIMEDOUT:
+ err = -errno;
+ break;
+ default:
+ LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
+ break;
+ }
+ }
+ break;
+ default:
+ LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync);
+ break;
+ }
+ timeout = NULL;
+ }
+ } else {
+ if (mFifo.mIsShutdown) {
+ err = -EIO;
+ availToWrite = 0;
+ } else {
+ availToWrite = mEffectiveFrames;
+ }
+ }
+ if (availToWrite > count) {
+ availToWrite = count;
+ }
+ uint32_t rearOffset = mLocalRear & (mFifo.mFrameCountP2 - 1);
+ size_t part1 = mFifo.mFrameCount - rearOffset;
+ if (part1 > availToWrite) {
+ part1 = availToWrite;
+ }
+ size_t part2 = part1 > 0 ? availToWrite - part1 : 0;
+ // return slice
+ if (iovec != NULL) {
+ iovec[0].mOffset = rearOffset;
+ iovec[0].mLength = part1;
+ iovec[1].mOffset = 0;
+ iovec[1].mLength = part2;
+ mObtained = availToWrite;
+ }
+ return availToWrite > 0 ? availToWrite : err;
+}
+
+void audio_utils_fifo_writer::release(size_t count)
+ __attribute__((no_sanitize("integer")))
+{
+ // no need to do an early check for mIsShutdown, because the extra code executed is harmless
+ if (count > 0) {
+ if (count > mObtained) {
+ ALOGE("%s(count=%zu) > mObtained=%u", __func__, count, mObtained);
+ mFifo.shutdown();
+ return;
+ }
+ if (mFifo.mThrottleFront != NULL) {
+ uint32_t front = mFifo.mThrottleFront->loadAcquire();
+ // returns -EIO if mIsShutdown
+ int32_t filled = mFifo.diff(mLocalRear, front);
+ mLocalRear = mFifo.sum(mLocalRear, count);
+ mFifo.mWriterRear.storeRelease(mLocalRear);
+ // TODO add comments
+ int op = FUTEX_WAKE;
+ switch (mFifo.mWriterRearSync) {
+ case AUDIO_UTILS_FIFO_SYNC_SLEEP:
+ break;
+ case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
+ op = FUTEX_WAKE_PRIVATE;
+ // fall through
+ case AUDIO_UTILS_FIFO_SYNC_SHARED:
+ if (filled >= 0) {
+ if ((uint32_t) filled < mArmLevel) {
+ mIsArmed = true;
+ }
+ if (mIsArmed && filled + count > mTriggerLevel) {
+ int err = mFifo.mWriterRear.wake(op, INT32_MAX /*waiters*/);
+ // err is number of processes woken up
+ if (err < 0) {
+ LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d",
+ __func__, err, errno);
+ }
+ mIsArmed = false;
+ }
+ }
+ break;
+ default:
+ LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync);
+ break;
+ }
+ } else {
+ mLocalRear = mFifo.sum(mLocalRear, count);
+ mFifo.mWriterRear.storeRelease(mLocalRear);
+ }
+ mObtained -= count;
+ mTotalReleased += count;
+ }
+}
+
+ssize_t audio_utils_fifo_writer::available()
+{
+ // iovec == NULL is not part of the public API, but internally it means don't set mObtained
+ return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/);
+}
+
+void audio_utils_fifo_writer::resize(uint32_t frameCount)
+{
+ // cap to range [0, mFifo.mFrameCount]
+ if (frameCount > mFifo.mFrameCount) {
+ frameCount = mFifo.mFrameCount;
+ }
+ // if we reduce the effective frame count, update hysteresis points to be within the new range
+ if (frameCount < mEffectiveFrames) {
+ if (mArmLevel > frameCount) {
+ mArmLevel = frameCount;
+ }
+ if (mTriggerLevel > frameCount) {
+ mTriggerLevel = frameCount;
+ }
+ }
+ mEffectiveFrames = frameCount;
+}
+
+uint32_t audio_utils_fifo_writer::size() const
+{
+ return mEffectiveFrames;
+}
+
+void audio_utils_fifo_writer::setHysteresis(uint32_t lowLevelArm, uint32_t highLevelTrigger)
+{
+ // cap to range [0, mEffectiveFrames]
+ if (lowLevelArm > mEffectiveFrames) {
+ lowLevelArm = mEffectiveFrames;
+ }
+ if (highLevelTrigger > mEffectiveFrames) {
+ highLevelTrigger = mEffectiveFrames;
+ }
+ // TODO this is overly conservative; it would be better to arm based on actual fill level
+ if (lowLevelArm > mArmLevel) {
+ mIsArmed = true;
+ }
+ mArmLevel = lowLevelArm;
+ mTriggerLevel = highLevelTrigger;
+}
+
+void audio_utils_fifo_writer::getHysteresis(uint32_t *armLevel, uint32_t *triggerLevel) const
+{
+ *armLevel = mArmLevel;
+ *triggerLevel = mTriggerLevel;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+audio_utils_fifo_reader::audio_utils_fifo_reader(audio_utils_fifo& fifo, bool throttlesWriter,
+ bool flush) :
+ audio_utils_fifo_provider(fifo),
+
+ // If we throttle the writer, then initialize our front index to zero so that we see all data
+ // currently in the buffer.
+ // Otherwise, ignore everything currently in the buffer by initializing our front index to the
+ // current value of writer's rear. This avoids an immediate -EOVERFLOW (overrun) in the case
+ // where reader starts out more than one buffer behind writer. The initial catch-up does not
+ // contribute towards the totalLost, totalFlushed, or totalReleased counters.
+ mLocalFront(throttlesWriter ? 0 : mFifo.mWriterRear.loadConsume()),
+
+ mThrottleFront(throttlesWriter ? mFifo.mThrottleFront : NULL),
+ mFlush(flush),
+ mArmLevel(-1), mTriggerLevel(mFifo.mFrameCount),
+ mIsArmed(true), // because initial fill level of zero is > mArmLevel
+ mTotalLost(0), mTotalFlushed(0)
+{
+}
+
+audio_utils_fifo_reader::~audio_utils_fifo_reader()
+{
+ // TODO Need a way to pass throttle capability to the another reader, should one reader exit.
+}
+
+ssize_t audio_utils_fifo_reader::read(void *buffer, size_t count, const struct timespec *timeout,
+ size_t *lost)
+ __attribute__((no_sanitize("integer")))
+{
+ audio_utils_iovec iovec[2];
+ ssize_t availToRead = obtain(iovec, count, timeout, lost);
+ if (availToRead > 0) {
+ memcpy(buffer, (char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize,
+ iovec[0].mLength * mFifo.mFrameSize);
+ if (iovec[1].mLength > 0) {
+ memcpy((char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
+ (char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
+ iovec[1].mLength * mFifo.mFrameSize);
+ }
+ release(availToRead);
+ }
+ return availToRead;
+}
+
+ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
+ const struct timespec *timeout)
+ __attribute__((no_sanitize("integer")))
+{
+ return obtain(iovec, count, timeout, NULL /*lost*/);
+}
+
+void audio_utils_fifo_reader::release(size_t count)
+ __attribute__((no_sanitize("integer")))
+{
+ // no need to do an early check for mIsShutdown, because the extra code executed is harmless
+ if (count > 0) {
+ if (count > mObtained) {
+ ALOGE("%s(count=%zu) > mObtained=%u", __func__, count, mObtained);
+ mFifo.shutdown();
+ return;
+ }
+ if (mThrottleFront != NULL) {
+ uint32_t rear = mFifo.mWriterRear.loadAcquire();
+ // returns -EIO if mIsShutdown
+ int32_t filled = mFifo.diff(rear, mLocalFront);
+ mLocalFront = mFifo.sum(mLocalFront, count);
+ mThrottleFront->storeRelease(mLocalFront);
+ // TODO add comments
+ int op = FUTEX_WAKE;
+ switch (mFifo.mThrottleFrontSync) {
+ case AUDIO_UTILS_FIFO_SYNC_SLEEP:
+ break;
+ case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
+ op = FUTEX_WAKE_PRIVATE;
+ // fall through
+ case AUDIO_UTILS_FIFO_SYNC_SHARED:
+ if (filled >= 0) {
+ if (filled > mArmLevel) {
+ mIsArmed = true;
+ }
+ if (mIsArmed && filled - count < mTriggerLevel) {
+ int err = mThrottleFront->wake(op, 1 /*waiters*/);
+ // err is number of processes woken up
+ if (err < 0 || err > 1) {
+ LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d",
+ __func__, err, errno);
+ }
+ mIsArmed = false;
+ }
+ }
+ break;
+ default:
+ LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync);
+ break;
+ }
+ } else {
+ mLocalFront = mFifo.sum(mLocalFront, count);
+ }
+ mObtained -= count;
+ mTotalReleased += count;
+ }
+}
+
+// iovec == NULL is not part of the public API, but internally it means don't set mObtained
+ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
+ const struct timespec *timeout, size_t *lost)
+ __attribute__((no_sanitize("integer")))
+{
+ int err = 0;
+ int retries = kRetries;
+ uint32_t rear;
+ for (;;) {
+ rear = mFifo.mWriterRear.loadAcquire();
+ // TODO pull out "count == 0"
+ if (count == 0 || rear != mLocalFront || timeout == NULL ||
+ (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
+ break;
+ }
+ // TODO add comments
+ int op = FUTEX_WAIT;
+ switch (mFifo.mWriterRearSync) {
+ case AUDIO_UTILS_FIFO_SYNC_SLEEP:
+ err = audio_utils_clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout,
+ NULL /*remain*/);
+ if (err < 0) {
+ LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno);
+ err = -errno;
+ } else {
+ err = -ETIMEDOUT;
+ }
+ break;
+ case AUDIO_UTILS_FIFO_SYNC_PRIVATE:
+ op = FUTEX_WAIT_PRIVATE;
+ // fall through
+ case AUDIO_UTILS_FIFO_SYNC_SHARED:
+ if (timeout->tv_sec == LONG_MAX) {
+ timeout = NULL;
+ }
+ err = mFifo.mWriterRear.wait(op, rear, timeout);
+ if (err < 0) {
+ switch (errno) {
+ case EWOULDBLOCK:
+ // Benign race condition with partner: mFifo.mWriterRear->mIndex
+ // changed value between the earlier atomic_load_explicit() and sys_futex().
+ // Try to load index again, but give up if we are unable to converge.
+ if (retries-- > 0) {
+ // bypass the "timeout = NULL;" below
+ continue;
+ }
+ // fall through
+ case EINTR:
+ case ETIMEDOUT:
+ err = -errno;
+ break;
+ default:
+ LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
+ break;
+ }
+ }
+ break;
+ default:
+ LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync);
+ break;
+ }
+ timeout = NULL;
+ }
+ size_t ourLost;
+ if (lost == NULL) {
+ lost = &ourLost;
+ }
+ // returns -EIO if mIsShutdown
+ int32_t filled = mFifo.diff(rear, mLocalFront, lost, mFlush);
+ mTotalLost += *lost;
+ mTotalReleased += *lost;
+ if (filled < 0) {
+ if (filled == -EOVERFLOW) {
+ // catch up with writer, but preserve the still valid frames in buffer
+ mLocalFront = rear - (mFlush ? 0 : mFifo.mFrameCountP2 /*sic*/);
+ }
+ // on error, return an empty slice
+ err = filled;
+ filled = 0;
+ }
+ size_t availToRead = (size_t) filled;
+ if (availToRead > count) {
+ availToRead = count;
+ }
+ uint32_t frontOffset = mLocalFront & (mFifo.mFrameCountP2 - 1);
+ size_t part1 = mFifo.mFrameCount - frontOffset;
+ if (part1 > availToRead) {
+ part1 = availToRead;
+ }
+ size_t part2 = part1 > 0 ? availToRead - part1 : 0;
+ // return slice
+ if (iovec != NULL) {
+ iovec[0].mOffset = frontOffset;
+ iovec[0].mLength = part1;
+ iovec[1].mOffset = 0;
+ iovec[1].mLength = part2;
+ mObtained = availToRead;
+ }
+ return availToRead > 0 ? availToRead : err;
+}
+
+ssize_t audio_utils_fifo_reader::available()
+{
+ return available(NULL /*lost*/);
+}
+
+ssize_t audio_utils_fifo_reader::available(size_t *lost)
+{
+ // iovec == NULL is not part of the public API, but internally it means don't set mObtained
+ return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/, lost);
+}
+
+ssize_t audio_utils_fifo_reader::flush(size_t *lost)
+{
+ audio_utils_iovec iovec[2];
+ ssize_t ret = obtain(iovec, SIZE_MAX /*count*/, NULL /*timeout*/, lost);
+ if (ret > 0) {
+ size_t flushed = (size_t) ret;
+ release(flushed);
+ mTotalFlushed += flushed;
+ ret = flushed;
+ }
+ return ret;
+}
+
+void audio_utils_fifo_reader::setHysteresis(int32_t armLevel, uint32_t triggerLevel)
+{
+ // cap to range [0, mFifo.mFrameCount]
+ if (armLevel < 0) {
+ armLevel = -1;
+ } else if ((uint32_t) armLevel > mFifo.mFrameCount) {
+ armLevel = mFifo.mFrameCount;
+ }
+ if (triggerLevel > mFifo.mFrameCount) {
+ triggerLevel = mFifo.mFrameCount;
+ }
+ // TODO this is overly conservative; it would be better to arm based on actual fill level
+ if (armLevel < mArmLevel) {
+ mIsArmed = true;
+ }
+ mArmLevel = armLevel;
+ mTriggerLevel = triggerLevel;
+}
+
+void audio_utils_fifo_reader::getHysteresis(int32_t *armLevel, uint32_t *triggerLevel) const
+{
+ *armLevel = mArmLevel;
+ *triggerLevel = mTriggerLevel;
+}
diff --git a/audio_utils/fifo_index.cpp b/audio_utils/fifo_index.cpp
new file mode 100644
index 0000000..d9a200a
--- /dev/null
+++ b/audio_utils/fifo_index.cpp
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <audio_utils/fifo_index.h>
+#include <audio_utils/futex.h>
+
+// These are not implemented within <audio_utils/fifo_index.h>
+// so that we don't expose futex.
+
+uint32_t audio_utils_fifo_index::loadAcquire()
+{
+ return atomic_load_explicit(&mIndex, std::memory_order_acquire);
+}
+
+void audio_utils_fifo_index::storeRelease(uint32_t value)
+{
+ atomic_store_explicit(&mIndex, value, std::memory_order_release);
+}
+
+int audio_utils_fifo_index::wait(int op, uint32_t expected, const struct timespec *timeout)
+{
+ return sys_futex(&mIndex, op, expected, timeout, NULL, 0);
+}
+
+int audio_utils_fifo_index::wake(int op, int waiters)
+{
+ return sys_futex(&mIndex, op, waiters, NULL, NULL, 0);
+}
+
+uint32_t audio_utils_fifo_index::loadConsume()
+{
+ return atomic_load_explicit(&mIndex, std::memory_order_consume);
+}
+
+////
+
+RefIndexDeferredStoreReleaseDeferredWake::RefIndexDeferredStoreReleaseDeferredWake(
+ audio_utils_fifo_index& index)
+ : mIndex(index), mValue(0), mWriteback(false), mWaiters(0), mWakeOp(FUTEX_WAIT_PRIVATE)
+{
+}
+
+RefIndexDeferredStoreReleaseDeferredWake::~RefIndexDeferredStoreReleaseDeferredWake()
+{
+ writeback();
+ wakeNowIfNeeded();
+}
+
+void RefIndexDeferredStoreReleaseDeferredWake::set(uint32_t value) {
+ mValue = value;
+ mWriteback = true;
+}
+
+void RefIndexDeferredStoreReleaseDeferredWake::writeback()
+{
+ if (mWriteback) {
+ // TODO When part of a collection, should use relaxed for all but the last writeback
+ mIndex.storeRelease(mValue);
+ mWriteback = false;
+ }
+}
+
+void RefIndexDeferredStoreReleaseDeferredWake::writethrough(uint32_t value) {
+ set(value);
+ writeback();
+}
+
+void RefIndexDeferredStoreReleaseDeferredWake::wakeDeferred(int op, int waiters)
+{
+ if (waiters <= 0) {
+ return;
+ }
+ // default is FUTEX_WAKE_PRIVATE
+ if (op == FUTEX_WAKE) {
+ mWakeOp = FUTEX_WAKE;
+ }
+ if (waiters < INT_MAX - mWaiters) {
+ mWaiters += waiters;
+ } else {
+ mWaiters = INT_MAX;
+ }
+}
+
+void RefIndexDeferredStoreReleaseDeferredWake::wakeNowIfNeeded()
+{
+ if (mWaiters > 0) {
+ mIndex.wake(mWakeOp, mWaiters);
+ mWaiters = 0;
+ mWakeOp = FUTEX_WAKE_PRIVATE;
+ }
+}
+
+void RefIndexDeferredStoreReleaseDeferredWake::wakeNow(int op, int waiters)
+{
+ wakeDeferred(op, waiters);
+ wakeNowIfNeeded();
+}
+
+////
+
+RefIndexCachedLoadAcquireDeferredWait::RefIndexCachedLoadAcquireDeferredWait(
+ audio_utils_fifo_index& index)
+ : mIndex(index), mValue(0), mLoaded(false)
+{
+}
+
+RefIndexCachedLoadAcquireDeferredWait::~RefIndexCachedLoadAcquireDeferredWait()
+{
+}
+
+uint32_t RefIndexCachedLoadAcquireDeferredWait::get()
+{
+ prefetch();
+ return mValue;
+}
+
+void RefIndexCachedLoadAcquireDeferredWait::prefetch()
+{
+ if (!mLoaded) {
+ // TODO When part of a collection, should use relaxed for all but the last load
+ mValue = mIndex.loadAcquire();
+ mLoaded = true;
+ }
+}
+
+void RefIndexCachedLoadAcquireDeferredWait::invalidate()
+{
+ mLoaded = false;
+}
+
+#if 0
+uint32_t RefIndexCachedLoadAcquireDeferredWait::readthrough()
+{
+ invalidate();
+ return get();
+}
+#endif
+
+int RefIndexCachedLoadAcquireDeferredWait::wait(int op, const struct timespec *timeout)
+{
+ if (!mLoaded) {
+ return -EINVAL;
+ }
+ int err = mIndex.wait(op, mValue /*expected*/, timeout);
+ invalidate();
+ return err;
+}
diff --git a/audio_utils/include/audio_utils/ErrorLog.h b/audio_utils/include/audio_utils/ErrorLog.h
new file mode 100644
index 0000000..88448b1
--- /dev/null
+++ b/audio_utils/include/audio_utils/ErrorLog.h
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2017 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_ERROR_LOG_H
+#define ANDROID_AUDIO_ERROR_LOG_H
+
+#ifdef __cplusplus
+
+#include <iomanip>
+#include <mutex>
+#include <sstream>
+#include <unistd.h>
+#include <vector>
+
+#include <audio_utils/clock.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+/**
+ * ErrorLog captures audio errors codes, combining consecutive identical error codes
+ * (within a specified time) into a single entry (to reduce log spamming).
+ *
+ * The entry thus contains the number of consecutive error codes,
+ * together with the first time the error code occurs and the last time the error code occurs.
+ *
+ * The type T represents the error code type and is an int32_t for the C API.
+ */
+template <typename T>
+class ErrorLog {
+public:
+ /**
+ * \brief Creates an ErrorLog object
+ *
+ * \param entries the length of error history.
+ * \param aggregateNs the maximum time in nanoseconds between identical error codes
+ * to be aggregated into a single entry.
+ */
+ explicit ErrorLog(size_t entries, int64_t aggregateNs = 1000000000 /* one second */)
+ : mErrors(0)
+ , mIdx(0)
+ , mAggregateNs(aggregateNs)
+ , mEntries(entries)
+ {
+ }
+
+ /**
+ * \brief Adds new error code to the error log.
+ *
+ * Consecutive errors with the same code will be aggregated
+ * if they occur within aggregateNs.
+ *
+ * \param code error code of type T.
+ * \param nowNs current time in nanoseconds.
+ */
+ void log(const T &code, int64_t nowNs)
+ {
+ std::lock_guard<std::mutex> guard(mLock);
+
+ ++mErrors;
+
+ // Within mAggregateNs (1 second by default), aggregate error codes together.
+ if (code == mEntries[mIdx].mCode
+ && nowNs - mEntries[mIdx].mLastTime < mAggregateNs) {
+ mEntries[mIdx].mCount++;
+ mEntries[mIdx].mLastTime = nowNs;
+ return;
+ }
+
+ // Add new error entry.
+ if (++mIdx >= mEntries.size()) {
+ mIdx = 0;
+ }
+ mEntries[mIdx].setFirstError(code, nowNs);
+ }
+
+ /**
+ * \brief Dumps the log to a std::string.
+ * \param prefix the prefix to use for each line
+ * (generally a null terminated string of spaces).
+ * \param lines maximum number of lines to output (0 disables).
+ * \param limitNs limit dump to data more recent than limitNs (0 disables).
+ * \return std::string of the dump.
+ */
+ std::string dumpToString(const char *prefix = "", size_t lines = 0, int64_t limitNs = 0) const
+ {
+ std::lock_guard<std::mutex> guard(mLock);
+
+ std::stringstream ss;
+ const size_t numberOfEntries = mEntries.size();
+ const size_t headerLines = 2;
+
+ if (lines == 0) {
+ lines = SIZE_MAX;
+ }
+ ss << prefix << "Errors: " << mErrors << "\n";
+
+ if (mErrors == 0 || lines <= headerLines) {
+ return ss.str();
+ }
+
+ lines = std::min(lines - headerLines, numberOfEntries);
+ // compute where to start dump log
+ ssize_t offset;
+ for (offset = 0; offset < (ssize_t)lines; ++offset) {
+ const auto &entry =
+ mEntries[(mIdx + numberOfEntries - offset) % numberOfEntries];
+ if (entry.mCount == 0 || entry.mLastTime < limitNs) {
+ break;
+ }
+ }
+ if (offset > 0) {
+ offset--;
+ ss << prefix << " Code Freq First time Last time\n";
+ for (; offset >= 0; --offset) {
+ const auto &entry =
+ mEntries[(mIdx + numberOfEntries - offset) % numberOfEntries];
+
+ ss << prefix << std::setw(5) << entry.mCode
+ << " " << std::setw(5) << entry.mCount
+ << " " << audio_utils_time_string_from_ns(entry.mFirstTime).time
+ << " " << audio_utils_time_string_from_ns(entry.mLastTime).time << "\n";
+ }
+ }
+ return ss.str();
+ }
+
+ /**
+ * \brief Dumps the log to a raw file descriptor.
+ * \param fd file descriptor to use.
+ * \param prefix the prefix to use for each line
+ * (generally a null terminated string of spaces).
+ * \param lines maximum number of lines to output (0 disables).
+ * \param limitNs limit dump to data more recent than limitNs (0 disables).
+ * \return
+ * NO_ERROR on success or a negative number (-errno) on failure of write().
+ */
+ status_t dump(int fd, const char *prefix = "", size_t lines = 0, int64_t limitNs = 0) const
+ {
+ // thread safe but not necessarily serial with respect to concurrent dumps to the same fd.
+ const std::string s = dumpToString(prefix, lines, limitNs);
+ if (s.size() > 0 && write(fd, s.c_str(), s.size()) < 0) {
+ return -errno;
+ }
+ return NO_ERROR;
+ }
+
+ struct Entry {
+ Entry()
+ : mCode(0)
+ , mCount(0)
+ , mFirstTime(0)
+ , mLastTime(0)
+ {
+ }
+
+ // Initialize entry with code as the first error at the given time.
+ void setFirstError(T code, int64_t time) {
+ mCode = code;
+ mCount = 1;
+ mFirstTime = time;
+ mLastTime = time;
+ }
+
+ T mCode; // error code
+ uint32_t mCount; // number of consecutive errors of the same code.
+ int64_t mFirstTime; // first time of the error code.
+ int64_t mLastTime; // last time of the error code.
+ };
+
+private:
+ mutable std::mutex mLock; // monitor mutex
+ int64_t mErrors; // total number of errors registered
+ size_t mIdx; // current index into mEntries (active)
+ const int64_t mAggregateNs; // number of nanoseconds to aggregate consecutive error codes.
+ std::vector<Entry> mEntries; // circular buffer of error entries.
+};
+
+} // namespace android
+
+#endif // __cplusplus
+
+// C API (see C++ API above for details)
+
+/** \cond */
+__BEGIN_DECLS
+/** \endcond */
+
+typedef struct error_log_t error_log_t;
+
+/**
+ * \brief Creates an error log object
+ *
+ * \param entries the length of error history.
+ * \param aggregate_ns the maximum time in nanoseconds between identical error codes
+ * to be aggregated into a single entry.
+ * \return the error log object or NULL on failure.
+ */
+error_log_t *error_log_create(size_t entries, int64_t aggregate_ns);
+
+/**
+ * \brief Adds new error code to the error log.
+ *
+ * Consecutive errors with the same code will be aggregated if
+ * they occur within aggregate_ns.
+ *
+ * \param error_log object returned by create, if NULL nothing happens.
+ * \param code error code of type T.
+ * \param now_ns current time in nanoseconds.
+ */
+void error_log_log(error_log_t *error_log, int32_t code, int64_t now_ns);
+
+/**
+ * \brief Dumps the log to a raw file descriptor.
+ * \param error_log object returned by create, if NULL nothing happens.
+ * \param prefix the prefix to use for each line
+ * (generally a null terminated string of spaces).
+ * \param fd file descriptor to use.
+ * \param lines maximum number of lines to output (0 disables).
+ * \param limit_ns limit dump to data more recent than limit_ns (0 disables).
+ * \return
+ * NO_ERROR on success or a negative number (-errno) on failure of write().
+ * if power_log is NULL, BAD_VALUE is returned.
+ */
+int error_log_dump(
+ error_log_t *error_log, int fd, const char *prefix, size_t lines, int64_t limit_ns);
+
+/**
+ * \brief Destroys the error log object.
+ *
+ * \param error_log object returned by create, if NULL nothing happens.
+ */
+void error_log_destroy(error_log_t *error_log);
+
+/** \cond */
+__END_DECLS
+/** \endcond */
+
+#endif // !ANDROID_AUDIO_ERROR_LOG_H
diff --git a/audio_utils/include/audio_utils/PowerLog.h b/audio_utils/include/audio_utils/PowerLog.h
new file mode 100644
index 0000000..1f5a8b7
--- /dev/null
+++ b/audio_utils/include/audio_utils/PowerLog.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2017 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_POWER_LOG_H
+#define ANDROID_AUDIO_POWER_LOG_H
+
+#ifdef __cplusplus
+
+#include <mutex>
+#include <vector>
+#include <system/audio.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+/**
+ * PowerLog captures the audio data power (measured in dBFS) over time.
+ *
+ * For the purposes of power evaluation, the audio data is divided into "bins",
+ * and grouped by signals consisting of consecutive non-zero energy bins.
+ * The sum energy in dB of each signal is computed for comparison purposes.
+ *
+ * No distinction is made between channels in an audio frame; they are all
+ * summed together for energy purposes.
+ *
+ * The public methods are internally protected by a mutex to be thread-safe.
+ */
+class PowerLog {
+public:
+ /**
+ * \brief Creates a PowerLog object.
+ *
+ * \param sampleRate sample rate of the audio data.
+ * \param channelCount channel count of the audio data.
+ * \param format format of the audio data. It must be allowed by
+ * audio_utils_is_compute_power_format_supported()
+ * else the constructor will abort.
+ * \param entries total number of energy entries "bins" to use.
+ * \param framesPerEntry total number of audio frames used in each entry.
+ */
+ PowerLog(uint32_t sampleRate,
+ uint32_t channelCount,
+ audio_format_t format,
+ size_t entries,
+ size_t framesPerEntry);
+
+ /**
+ * \brief Adds new audio data to the power log.
+ *
+ * \param buffer pointer to the audio data buffer.
+ * \param frames buffer size in audio frames.
+ * \param nowNs current time in nanoseconds.
+ */
+ void log(const void *buffer, size_t frames, int64_t nowNs);
+
+ /**
+ * \brief Dumps the log to a std::string.
+ *
+ * \param lines maximum number of lines to output (0 disables).
+ * \param limitNs limit dump to data more recent than limitNs (0 disables).
+ * \return the std::string for the log.
+ */
+ std::string dumpToString(
+ const char *prefix = "", size_t lines = 0, int64_t limitNs = 0) const;
+
+ /**
+ * \brief Dumps the log to a raw file descriptor.
+ *
+ * \param fd file descriptor to use.
+ * \param lines maximum number of lines to output (0 disables).
+ * \param limitNs limit dump to data more recent than limitNs (0 disables).
+ * \return
+ * NO_ERROR on success or a negative number (-errno) on failure of write().
+ */
+ status_t dump(int fd, const char *prefix = "", size_t lines = 0, int64_t limitNs = 0) const;
+
+private:
+ mutable std::mutex mLock; // monitor mutex
+ int64_t mCurrentTime; // time of first frame in buffer
+ float mCurrentEnergy; // local energy accumulation
+ size_t mCurrentFrames; // number of frames in the energy
+ size_t mIdx; // next usable index in mEntries
+ size_t mConsecutiveZeroes; // current run of consecutive zero entries
+ const uint32_t mSampleRate; // audio data sample rate
+ const uint32_t mChannelCount; // audio data channel count
+ const audio_format_t mFormat; // audio data format
+ const size_t mFramesPerEntry; // number of audio frames per entry
+ std::vector<std::pair<int64_t /* real time ns */, float /* energy */>> mEntries;
+};
+
+} // namespace android
+
+#endif // __cplusplus
+
+/** \cond */
+__BEGIN_DECLS
+/** \endcond */
+
+// C API (see C++ api above for details)
+
+typedef struct power_log_t power_log_t;
+
+/**
+ * \brief Creates a power log object.
+ *
+ * \param sample_rate sample rate of the audio data.
+ * \param channel_count channel count of the audio data.
+ * \param format format of the audio data. It must be allowed by
+ * audio_utils_is_compute_power_format_supported().
+ * \param entries total number of energy entries "bins" to use.
+ * \param frames_per_entry total number of audio frames used in each entry.
+ *
+ * \return power log object or NULL on failure.
+ */
+power_log_t *power_log_create(uint32_t sample_rate,
+ uint32_t channel_count, audio_format_t format, size_t entries, size_t frames_per_entry);
+
+/**
+ * \brief Adds new audio data to the power log.
+ *
+ * \param power_log object returned by create, if NULL nothing happens.
+ * \param buffer pointer to the audio data buffer.
+ * \param frames buffer size in audio frames.
+ * \param now_ns current time in nanoseconds.
+ */
+void power_log_log(power_log_t *power_log, const void *buffer, size_t frames, int64_t now_ns);
+
+/**
+ * \brief Dumps the log to a raw file descriptor.
+ *
+ * \param power_log object returned by create, if NULL nothing happens.
+ * \param fd file descriptor to use.
+ * \param lines maximum number of lines to output (0 disables).
+ * \param limit_ns limit dump to data more recent than limit_ns (0 disables).
+ * \return
+ * NO_ERROR on success or a negative number (-errno) on failure of write().
+ * if power_log is NULL, BAD_VALUE is returned.
+ */
+int power_log_dump(
+ power_log_t *power_log, int fd, const char *prefix, size_t lines, int64_t limit_ns);
+
+/**
+ * \brief Destroys the power log object.
+ *
+ * \param power_log object returned by create, if NULL nothing happens.
+ */
+void power_log_destroy(power_log_t *power_log);
+
+/** \cond */
+__END_DECLS
+/** \endcond */
+
+#endif // !ANDROID_AUDIO_POWER_LOG_H
diff --git a/audio_utils/include/audio_utils/SimpleLog.h b/audio_utils/include/audio_utils/SimpleLog.h
new file mode 100644
index 0000000..d5fd021
--- /dev/null
+++ b/audio_utils/include/audio_utils/SimpleLog.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2017 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_SIMPLE_LOG_H
+#define ANDROID_AUDIO_SIMPLE_LOG_H
+
+#include <deque>
+#include <mutex>
+#include <sstream>
+#include <stdint.h>
+#include <string>
+#include <unistd.h>
+#include <utils/Errors.h>
+
+#include <audio_utils/clock.h>
+
+namespace android {
+
+/**
+ * SimpleLog provides a private logcat-style logging to avoid cluttering
+ * the device logcat.
+ *
+ * The public methods are internally protected by a mutex to be thread-safe.
+ * Do not call from a sched_fifo thread as it can use a system time call
+ * and obtains a local mutex.
+ *
+ * Formatted logs by log() and logv() will be truncated at kMaxStringLength - 1
+ * due to null termination. logs() does not have a string length limitation.
+ */
+
+class SimpleLog {
+public:
+ /**
+ * \brief Creates a SimpleLog object.
+ *
+ * \param maxLogLines the maximum number of log lines.
+ */
+ explicit SimpleLog(size_t maxLogLines = kDefaultMaxLogLines)
+ : mMaxLogLines(maxLogLines)
+ {
+ }
+
+ /**
+ * \brief Adds a formatted string into the log.
+ *
+ * Time is automatically associated with the string by audio_utils_get_real_time_ns().
+ *
+ * \param format the format string, similar to printf().
+ *
+ * and optional arguments.
+ */
+ // using C++11 unified attribute syntax; index is offset by 1 for implicit "this".
+ [[gnu::format(printf, 2 /* string-index */, 3 /* first-to-check */)]]
+ void log(const char *format, ...)
+ {
+ va_list args;
+ va_start(args, format);
+ // use -1 to trigger the clock fetch within the mutex lock.
+ logv(-1 /* nowNs */, format, args);
+ va_end(args);
+ }
+
+ /**
+ * \brief Adds a formatted string into the log with time.
+ *
+ * \param nowNs the time to use for logging. Assumed to be monotonically
+ * increasing for sequential calls. If -1, then
+ * audio_utils_get_real_time_ns() is called.
+ * \param format the format string, similar to printf().
+ *
+ * and optional arguments.
+ */
+ // using C++11 unified attribute syntax; index is offset by 1 for implicit "this".
+ [[gnu::format(printf, 3 /* string-index */, 4 /* first-to-check */)]]
+ void log(int64_t nowNs, const char *format, ...)
+ {
+ va_list args;
+ va_start(args, format);
+ logv(nowNs, format, args);
+ va_end(args);
+ }
+
+ /**
+ * \brief Adds a formatted string by va_list with time. Not intended for typical use.
+ *
+ * \param nowNs the time to use for logging. Assumed to be monotonically
+ * increasing for sequential calls. If -1, then
+ * audio_utils_get_real_time_ns() is called.
+ * \param format the format string, similar to printf().
+ * \param args va_list args.
+ */
+ void logv(int64_t nowNs, const char *format, va_list args)
+ {
+ // format to buffer
+ char buffer[kMaxStringLength];
+ int length = vsnprintf(buffer, sizeof(buffer), format, args);
+ if (length < 0) { // encoding error
+ logs(nowNs, "invalid format");
+ return;
+ } else if (length >= (signed)sizeof(buffer)) {
+ length = sizeof(buffer) - 1;
+ }
+
+ // strip out trailing newlines
+ while (length > 0 && buffer[length - 1] == '\n') {
+ buffer[--length] = '\0';
+ }
+ logs(nowNs, buffer);
+ }
+
+ /**
+ * \brief Logs a string to the buffer with time.
+ * \param nowNs the time to use for logging. Assumed to be monotonically
+ * increasing for sequential calls. If -1, then
+ * audio_utils_get_real_time_ns() is called.
+ * \param buffer contains a null terminated string, which may have
+ * special characters such as % and \ that are
+ * not interpreted.
+ */
+ void logs(int64_t nowNs, const char *buffer)
+ {
+ // store in circular array
+ std::lock_guard<std::mutex> guard(mLock);
+ if (nowNs == -1) {
+ nowNs = audio_utils_get_real_time_ns();
+ }
+ mLog.emplace_back(nowNs, std::string(buffer));
+ if (mLog.size() > mMaxLogLines) {
+ mLog.pop_front();
+ }
+ }
+
+ /**
+ * \brief Dumps the log to a string.
+ *
+ * \param prefix the prefix to use for each line
+ * (generally a null terminated string of spaces).
+ * \param lines maximum number of lines to output (0 disables).
+ * \param limitNs limit dump to data more recent than limitNs (0 disables).
+ * \return a string object for the log.
+ */
+ std::string dumpToString(const char *prefix = "", size_t lines = 0, int64_t limitNs = 0) const
+ {
+ if (lines == 0) {
+ lines = mLog.size();
+ }
+
+ std::stringstream ss;
+ std::lock_guard<std::mutex> guard(mLock);
+ auto it = mLog.begin();
+
+ // Note: this restricts the lines before checking the time constraint.
+ if (mLog.size() > lines) {
+ it += (mLog.size() - lines);
+ }
+ for (; it != mLog.end(); ++it) {
+ const int64_t time = it->first;
+ if (time < limitNs) continue; // too old
+ ss << prefix << audio_utils_time_string_from_ns(time).time
+ << " " << it->second.c_str() << "\n";
+ }
+ return ss.str();
+ }
+
+ /**
+ * \brief Dumps the log to a raw file descriptor.
+ *
+ * \param fd file descriptor to use.
+ * \param prefix the prefix to use for each line
+ * (generally a null terminated string of spaces).
+ * \param lines maximum number of lines to output (0 disables).
+ * \param limitNs limit dump to data more recent than limitNs (0 disables).
+ * \return
+ * NO_ERROR on success or a negative number (-errno) on failure of write().
+ */
+ status_t dump(int fd, const char *prefix = "", size_t lines = 0, int64_t limitNs = 0) const
+ {
+ // dumpToString() and write() are individually thread-safe, but concurrent threads
+ // using dump() to the same file descriptor may write out of order.
+ const std::string s = dumpToString(prefix, lines, limitNs);
+ if (s.size() > 0 && write(fd, s.c_str(), s.size()) < 0) {
+ return -errno;
+ }
+ return NO_ERROR;
+ }
+
+private:
+ mutable std::mutex mLock;
+ static const size_t kMaxStringLength = 1024; // maximum formatted string length
+ static const size_t kDefaultMaxLogLines = 80; // default maximum log history
+
+ const size_t mMaxLogLines; // maximum log history
+ std::deque<std::pair<int64_t, std::string>> mLog; // circular buffer is backed by deque.
+};
+
+} // namespace android
+
+#endif // !ANDROID_AUDIO_SIMPLE_LOG_H
diff --git a/audio_utils/include/audio_utils/clock.h b/audio_utils/include/audio_utils/clock.h
new file mode 100644
index 0000000..31bf1f6
--- /dev/null
+++ b/audio_utils/include/audio_utils/clock.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2017 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_CLOCK_H
+#define ANDROID_AUDIO_CLOCK_H
+
+// This file can be included for either C or C++ source.
+
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <time.h>
+
+/**
+ * \brief Converts time in ns to a time string, with format similar to logcat.
+ * \param ns input time in nanoseconds to convert.
+ * \param buffer caller allocated string buffer, buffer_length must be >= 19 chars
+ * in order to fully fit in time. The string is always returned
+ * null terminated if buffer_size is greater than zero.
+ * \param buffer_size size of buffer.
+ */
+static inline void audio_utils_ns_to_string(int64_t ns, char *buffer, size_t buffer_size)
+{
+ if (buffer_size == 0) return;
+
+ const int one_second = 1000000000;
+ const time_t sec = ns / one_second;
+ struct tm tm;
+
+ // Supported on bionic, glibc, and macOS, but not mingw.
+ if (localtime_r(&sec, &tm) == NULL) {
+ buffer[0] = '\0';
+ return;
+ }
+
+ if (snprintf(buffer, buffer_size, "%02d-%02d %02d:%02d:%02d.%03d",
+ tm.tm_mon + 1, // localtime_r uses months in 0 - 11 range
+ tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
+ (int)(ns % one_second / 1000000)) < 0) {
+ buffer[0] = '\0'; // null terminate on format error, which should not happen
+ }
+}
+
+/**
+ * An object that contains the formatted time string.
+ *
+ * The time string is 19 characters (including null termination).
+ * Example: "03-27 16:47:06.187"
+ * MM DD HH MM SS MS
+ */
+typedef struct audio_utils_time_string {
+ char time[19]; /* minimum size buffer */
+} audio_utils_time_string_t;
+
+/**
+ * \brief Converts time in ns to a time string object, with format similar to logcat.
+ * \param ns input time in nanoseconds to convert.
+ */
+static inline audio_utils_time_string_t audio_utils_time_string_from_ns(int64_t ns)
+{
+ audio_utils_time_string_t ts;
+
+ audio_utils_ns_to_string(ns, ts.time, sizeof(ts.time));
+ return ts;
+}
+
+/**
+ * \brief Converts a timespec to nanoseconds.
+ * \param ts input timespec to convert.
+ * \return timespec converted to nanoseconds.
+ */
+static inline int64_t audio_utils_ns_from_timespec(const struct timespec *ts)
+{
+ return ts->tv_sec * 1000000000LL + ts->tv_nsec;
+}
+
+/**
+ * \brief Gets the real time clock in nanoseconds.
+ * \return the real time clock in nanoseconds, or 0 on error.
+ */
+static inline int64_t audio_utils_get_real_time_ns() {
+
+#if defined(__linux__)
+
+ struct timespec now_ts;
+ if (clock_gettime(CLOCK_REALTIME, &now_ts) == 0) {
+ return audio_utils_ns_from_timespec(&now_ts);
+ }
+ return 0; // should not happen.
+
+#else
+
+ // Mac OS X compatible
+ struct timeval now_tv;
+ if (gettimeofday(&now_tv, NULL /* struct timezone * */) == 0) {
+ return now_tv.tv_sec * 1000000000LL + now_tv.tv_usec * 1000LL;
+ }
+ return 0; // should not happen.
+
+#endif
+
+}
+
+#endif // !ANDROID_AUDIO_CLOCK_H
diff --git a/audio_utils/include/audio_utils/clock_nanosleep.h b/audio_utils/include/audio_utils/clock_nanosleep.h
new file mode 100644
index 0000000..e39c0ab
--- /dev/null
+++ b/audio_utils/include/audio_utils/clock_nanosleep.h
@@ -0,0 +1,61 @@
+/*
+ * 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_CLOCK_NANOSLEEP_H
+#define ANDROID_AUDIO_CLOCK_NANOSLEEP_H
+
+#include <time.h>
+#include <unistd.h>
+
+#ifdef __linux__
+
+#include <sys/syscall.h>
+#ifdef __ANDROID__
+// bionic for Android provides clock_nanosleep
+#define audio_utils_clock_nanosleep clock_nanosleep
+#else
+// bionic for desktop Linux omits clock_nanosleep
+static inline
+int audio_utils_clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request,
+ struct timespec *remain)
+{
+ return syscall(SYS_clock_nanosleep, clock_id, flags, request, remain);
+}
+#endif // __ANDROID__
+
+#else // __linux__
+
+// macOS <10.12 doesn't have clockid_t / CLOCK_MONOTONIC
+#ifndef CLOCK_MONOTONIC
+typedef int clockid_t;
+#define CLOCK_MONOTONIC 0
+#endif
+// macOS doesn't have clock_nanosleep
+static inline
+int audio_utils_clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request,
+ struct timespec *remain)
+{
+ (void) clock_id;
+ (void) flags;
+ (void) request;
+ (void) remain;
+ errno = ENOSYS;
+ return -1;
+}
+
+#endif // __linux__
+
+#endif // !ANDROID_AUDIO_CLOCK_NANOSLEEP_H
diff --git a/audio_utils/include/audio_utils/fifo.h b/audio_utils/include/audio_utils/fifo.h
index f882368..14b50da 100644
--- a/audio_utils/include/audio_utils/fifo.h
+++ b/audio_utils/include/audio_utils/fifo.h
@@ -17,83 +17,606 @@
#ifndef ANDROID_AUDIO_FIFO_H
#define ANDROID_AUDIO_FIFO_H
+#include <atomic>
#include <stdlib.h>
+#include <audio_utils/fifo_index.h>
-// FIXME use atomic_int_least32_t and new atomic operations instead of legacy Android ones
-// #include <stdatomic.h>
-
-#ifdef __cplusplus
-extern "C" {
+#ifndef __cplusplus
+#error C API is no longer supported
#endif
-// Single writer, single reader non-blocking FIFO.
-// Writer and reader must be in same process.
-
-// No user-serviceable parts within.
-struct audio_utils_fifo {
- // These fields are const after initialization
- size_t mFrameCount; // max number of significant frames to be stored in the FIFO > 0
- size_t mFrameCountP2; // roundup(mFrameCount)
- size_t mFudgeFactor; // mFrameCountP2 - mFrameCount, the number of "wasted" frames after
- // the end of mBuffer. Only the indices are wasted, not any memory.
- size_t mFrameSize; // size of each frame in bytes
- void *mBuffer; // pointer to caller-allocated buffer of size mFrameCount frames
-
- volatile int32_t mFront; // frame index of first frame slot available to read, or read index
- volatile int32_t mRear; // frame index of next frame slot available to write, or write index
+/** Indicates whether an index is also used for synchronization. */
+enum audio_utils_fifo_sync {
+ /** Index is not also used for synchronization; timeouts are done via clock_nanosleep(). */
+ AUDIO_UTILS_FIFO_SYNC_SLEEP,
+ /** Index is also used for synchronization as futex, and is mapped by one process. */
+ AUDIO_UTILS_FIFO_SYNC_PRIVATE,
+ /** Index is also used for synchronization as futex, and is mapped by one or more processes. */
+ AUDIO_UTILS_FIFO_SYNC_SHARED,
};
/**
- * Initialize a FIFO object.
- *
- * \param fifo Pointer to the FIFO object.
- * \param frameCount Max number of significant frames to be stored in the FIFO > 0.
- * If writes and reads always use the same count, and that count is a divisor of
- * frameCount, then the writes and reads will never do a partial transfer.
- * \param frameSize Size of each frame in bytes.
- * \param buffer Pointer to a caller-allocated buffer of frameCount frames.
+ * Base class for single-writer, single-reader or multi-reader, optionally blocking FIFO.
+ * The base class manipulates frame indices only, and has no knowledge of frame sizes or the buffer.
+ * At most one reader, called the "throttling reader", can block the writer.
+ * The "fill level", or unread frame count, is defined with respect to the throttling reader.
*/
-void audio_utils_fifo_init(struct audio_utils_fifo *fifo, size_t frameCount, size_t frameSize,
- void *buffer);
+class audio_utils_fifo_base {
+
+public:
+
+ /**
+ * Return the capacity, or statically configured maximum frame count.
+ *
+ * \return The capacity in frames.
+ */
+ uint32_t capacity() const
+ { return mFrameCount; }
+
+protected:
+
+ /**
+ * Construct FIFO base class
+ *
+ * \param frameCount Maximum usable frames to be stored in the FIFO > 0 && <= INT32_MAX,
+ * aka "capacity".
+ * If release()s always use the same count, and the count is a divisor of
+ * (effective) \p frameCount, then the obtain()s won't ever be fragmented.
+ * \param writerRear Writer's rear index. Passed by reference because it must be non-NULL.
+ * \param throttleFront Pointer to the front index of at most one reader that throttles the
+ * writer, or NULL for no throttling.
+ */
+ audio_utils_fifo_base(uint32_t frameCount, audio_utils_fifo_index& writerRear,
+ audio_utils_fifo_index *throttleFront = NULL);
+ /*virtual*/ ~audio_utils_fifo_base();
+
+ /** Return a new index as the sum of a validated index and a specified increment.
+ *
+ * \param index Caller should supply a validated mFront or mRear.
+ * \param increment Value to be added to the index <= mFrameCount.
+ *
+ * \return The sum of index plus increment.
+ */
+ uint32_t sum(uint32_t index, uint32_t increment) const;
+
+ /** Return the difference between two indices: rear - front.
+ *
+ * \param rear Caller should supply an unvalidated mRear.
+ * \param front Caller should supply an unvalidated mFront.
+ * \param lost If non-NULL, set to the approximate number of frames lost before
+ * re-synchronization when -EOVERFLOW occurs, or set to zero when no frames lost.
+ * \param flush Whether to flush the entire buffer on -EOVERFLOW.
+ *
+ * \return The zero or positive difference <= mFrameCount, or a negative error code.
+ * \retval -EIO corrupted indices, no recovery is possible
+ * \retval -EOVERFLOW reader doesn't throttle writer, and frames were lost because reader
+ * isn't keeping up with writer; see \p lost
+ */
+ int32_t diff(uint32_t rear, uint32_t front, size_t *lost = NULL, bool flush = false) const;
+
+ /**
+ * Mark the FIFO as shutdown (permanently unusable), usually due to an -EIO status from an API.
+ * Thereafter, all APIs that return a status will return -EIO, and other APIs will be no-ops.
+ */
+ void shutdown() const;
+
+ // These fields are const after initialization
+
+ /** Maximum usable frames to be stored in the FIFO > 0 && <= INT32_MAX, aka "capacity". */
+ const uint32_t mFrameCount;
+ /** Equal to roundup(mFrameCount). */
+ const uint32_t mFrameCountP2;
+
+ /**
+ * Equal to mFrameCountP2 - mFrameCount, the number of "wasted" frames after the end of mBuffer.
+ * Only the indices are wasted, not any memory.
+ */
+ const uint32_t mFudgeFactor;
+
+ /** Reference to writer's rear index. */
+ audio_utils_fifo_index& mWriterRear;
+ /** Indicates how synchronization is done for mWriterRear. */
+ const audio_utils_fifo_sync mWriterRearSync;
+
+ /**
+ * Pointer to the front index of at most one reader that throttles the writer,
+ * or NULL for no throttling.
+ */
+ audio_utils_fifo_index* const mThrottleFront;
+ /** Indicates how synchronization is done for mThrottleFront. */
+ const audio_utils_fifo_sync mThrottleFrontSync;
+
+ /** Whether FIFO is marked as shutdown due to detection of an "impossible" error condition. */
+ mutable bool mIsShutdown;
+};
+
+////////////////////////////////////////////////////////////////////////////////
/**
- * De-initialize a FIFO object.
- *
- * \param fifo Pointer to the FIFO object.
+ * Same as audio_utils_fifo_base, but understands frame sizes and knows about the buffer but does
+ * not own it.
*/
-void audio_utils_fifo_deinit(struct audio_utils_fifo *fifo);
+class audio_utils_fifo : public audio_utils_fifo_base {
+
+ friend class audio_utils_fifo_reader;
+ friend class audio_utils_fifo_writer;
+
+public:
+
+ /**
+ * Construct a FIFO object: multi-process.
+ *
+ * \param frameCount Maximum usable frames to be stored in the FIFO > 0 && <= INT32_MAX,
+ * aka "capacity".
+ * If writes and reads always use the same count, and the count is a divisor
+ * of \p frameCount, then the writes and reads won't do a partial transfer.
+ * \param frameSize Size of each frame in bytes > 0,
+ * \p frameSize * \p frameCount <= INT32_MAX.
+ * \param buffer Pointer to a non-NULL caller-allocated buffer of \p frameCount frames.
+ * \param writerRear Writer's rear index. Passed by reference because it must be non-NULL.
+ * \param throttleFront Pointer to the front index of at most one reader that throttles the
+ * writer, or NULL for no throttling.
+ */
+ audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer,
+ audio_utils_fifo_index& writerRear, audio_utils_fifo_index *throttleFront = NULL);
+
+ /**
+ * Construct a FIFO object: single-process.
+ * \param frameCount Maximum usable frames to be stored in the FIFO > 0 && <= INT32_MAX,
+ * aka "capacity".
+ * If writes and reads always use the same count, and the count is a divisor
+ * of \p frameCount, then the writes and reads won't do a partial transfer.
+ * \param frameSize Size of each frame in bytes > 0,
+ * \p frameSize * \p frameCount <= INT32_MAX.
+ * \param buffer Pointer to a non-NULL caller-allocated buffer of \p frameCount frames.
+ * \param throttlesWriter Whether there is one reader that throttles the writer.
+ */
+ audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer,
+ bool throttlesWriter = true);
+
+ /*virtual*/ ~audio_utils_fifo();
+
+ /**
+ * Return the frame size in bytes.
+ *
+ * \return frame size in bytes, always > 0.
+ */
+ uint32_t frameSize() const
+ { return mFrameSize; }
+
+ /**
+ * Return a pointer to the caller-allocated buffer.
+ *
+ * \return non-NULL pointer to buffer.
+ */
+ void *buffer() const
+ { return mBuffer; }
+
+private:
+ // These fields are const after initialization
+ const uint32_t mFrameSize; // size of each frame in bytes
+ void * const mBuffer; // non-NULL pointer to caller-allocated buffer
+ // of size mFrameCount frames
+
+ // only used for single-process constructor
+ audio_utils_fifo_index mSingleProcessSharedRear;
+
+ // only used for single-process constructor when throttlesWriter == true
+ audio_utils_fifo_index mSingleProcessSharedFront;
+};
/**
- * Write to FIFO.
- *
- * \param fifo Pointer to the FIFO object.
- * \param buffer Pointer to source buffer containing 'count' frames of data.
- * \param count Desired number of frames to write.
- *
- * \return actual number of frames written <= count.
- *
- * The actual transfer count may be zero if the FIFO is full,
- * or partial if the FIFO was almost full.
- * A negative return value indicates an error. Currently there are no errors defined.
+ * Describes one virtually contiguous fragment of a logically contiguous slice.
+ * Compare to struct iovec for readv(2) and writev(2).
*/
-ssize_t audio_utils_fifo_write(struct audio_utils_fifo *fifo, const void *buffer, size_t count);
+struct audio_utils_iovec {
+ /** Offset of fragment in frames, relative to mBuffer, undefined if mLength == 0 */
+ uint32_t mOffset;
+ /** Length of fragment in frames, 0 means fragment is empty */
+ uint32_t mLength;
+};
-/** Read from FIFO.
- *
- * \param fifo Pointer to the FIFO object.
- * \param buffer Pointer to destination buffer to be filled with up to 'count' frames of data.
- * \param count Desired number of frames to read.
- *
- * \return actual number of frames read <= count.
- *
- * The actual transfer count may be zero if the FIFO is empty,
- * or partial if the FIFO was almost empty.
- * A negative return value indicates an error. Currently there are no errors defined.
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Based on frameworks/av/include/media/AudioBufferProvider.h
*/
-ssize_t audio_utils_fifo_read(struct audio_utils_fifo *fifo, void *buffer, size_t count);
+class audio_utils_fifo_provider {
+public:
+ audio_utils_fifo_provider(audio_utils_fifo& fifo);
+ virtual ~audio_utils_fifo_provider();
-#ifdef __cplusplus
-}
-#endif
+ /**
+ * Obtain access to a logically contiguous slice of a stream, represented by \p iovec.
+ * For the reader(s), the slice is initialized and has read-only access.
+ * For the writer, the slice is uninitialized and has read/write access.
+ * It is permitted to call obtain() multiple times without an intervening release().
+ * Each call resets the notion of most recently obtained slice.
+ *
+ * \param iovec Non-NULL pointer to a pair of fragment descriptors.
+ * On entry, the descriptors may be uninitialized.
+ * On exit, the descriptors are initialized and refer to each of the two fragments.
+ * iovec[0] describes the initial fragment of the slice, and
+ * iovec[1] describes the remaining non-virtually-contiguous fragment.
+ * Empty iovec[0] implies that iovec[1] is also empty.
+ * iovec[0].mOffset and iovec[1].mOffset are always < capacity.
+ * Typically iovec[1].mOffset is zero, but don't assume that.
+ * \param count The maximum number of frames to obtain.
+ * See setHysteresis() for something which is close to, but not the same as,
+ * a minimum.
+ * \param timeout Indicates the maximum time to block for at least one frame.
+ * NULL and {0, 0} both mean non-blocking.
+ * Time is expressed as relative CLOCK_MONOTONIC.
+ * As an optimization, if \p timeout->tv_sec is the maximum positive value for
+ * time_t (LONG_MAX), then the implementation treats it as infinite timeout.
+ * See fifo_index.h for explanation of why representation is struct timespec.
+ *
+ * \return Actual number of frames available, if greater than or equal to zero.
+ * Guaranteed to be <= \p count and == iovec[0].mLength + iovec[1].mLength.
+ *
+ * \retval -EIO corrupted indices, no recovery is possible
+ * \retval -EOVERFLOW reader doesn't throttle writer, and frames were lost because reader
+ * isn't keeping up with writer; see \p lost
+ * \retval -ETIMEDOUT count is greater than zero, timeout is non-NULL and not {0, 0},
+ * timeout expired, and no frames were available after the timeout.
+ * \retval -EINTR count is greater than zero, timeout is non-NULL and not {0, 0}, timeout
+ * was interrupted by a signal, and no frames were available after signal.
+ * \retval -EWOULDBLOCK count is greater than zero, timeout is non-NULL and not {0, 0},
+ * futex wait failed due to benign race, and unable to converge after
+ * retrying. Should usually handle like -EINTR.
+ *
+ * Applications should treat all of these as equivalent to zero available frames,
+ * except they convey extra information as to the cause.
+ * After any error, both iovec[0] and iovec[1] will be empty.
+ */
+ virtual ssize_t obtain(audio_utils_iovec iovec[2], size_t count,
+ const struct timespec *timeout = NULL) = 0;
+
+ /**
+ * Release access to a portion of the most recently obtained slice.
+ * It is permitted to call release() multiple times without an intervening obtain().
+ *
+ * \param count Number of frames to release. The cumulative number of frames released must not
+ * exceed the number of frames most recently obtained.
+ * If it ever happens, then the FIFO will be marked unusable with shutdown().
+ */
+ virtual void release(size_t count) = 0;
+
+ /**
+ * Determine the number of frames that could be obtained or read/written without blocking.
+ * There's an inherent race condition: the value may soon be obsolete so shouldn't be trusted.
+ * available() may be called after obtain(), but doesn't affect the number of releasable frames.
+ *
+ * \return Number of available frames, if greater than or equal to zero.
+ * \retval -EIO corrupted indices, no recovery is possible
+ * \retval -EOVERFLOW reader doesn't throttle writer, and frames were lost because reader
+ * isn't keeping up with writer
+ */
+ virtual ssize_t available() = 0;
+
+ /**
+ * Return the capacity, or statically configured maximum frame count.
+ *
+ * \return The capacity in frames.
+ */
+ uint32_t capacity() const
+ { return mFifo.capacity(); }
+
+ /**
+ * Return the total number of frames released since construction.
+ * For a reader, this includes lost and flushed frames.
+ *
+ * \return Total frames released.
+ */
+ uint64_t totalReleased() const
+ { return mTotalReleased; }
+
+protected:
+ audio_utils_fifo& mFifo;
+
+ /** Number of frames obtained at most recent obtain(), less total number of frames released. */
+ uint32_t mObtained;
+
+ /** Number of times to retry a futex wait that fails with EWOULDBLOCK. */
+ static const int kRetries = 2;
+
+ /**
+ * Total number of frames released since construction.
+ * For a reader, this includes lost and flushed frames.
+ */
+ uint64_t mTotalReleased;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Used to write to a FIFO. There should be exactly one writer per FIFO.
+ * The writer is multi-thread safe with respect to reader(s),
+ * but not with respect to multiple threads calling the writer API.
+ */
+class audio_utils_fifo_writer : public audio_utils_fifo_provider {
+
+public:
+ /**
+ * Single-process and multi-process use same constructor here,
+ * but different FIFO constructors.
+ *
+ * \param fifo Associated FIFO. Passed by reference because it must be non-NULL.
+ */
+ explicit audio_utils_fifo_writer(audio_utils_fifo& fifo);
+ virtual ~audio_utils_fifo_writer();
+
+ /**
+ * Write to FIFO. Resets the number of releasable frames to zero.
+ *
+ * \param buffer Pointer to source buffer containing \p count frames of data.
+ * Pointer must be non-NULL if \p count is greater than zero.
+ * \param count Desired number of frames to write.
+ * \param timeout Indicates the maximum time to block for at least one frame.
+ * NULL and {0, 0} both mean non-blocking.
+ * Time is expressed as relative CLOCK_MONOTONIC.
+ * As an optimization, if \p timeout->tv_sec is the maximum positive value for
+ * time_t (LONG_MAX), then the implementation treats it as infinite timeout.
+ * See fifo_index.h for explanation of why representation is struct timespec.
+ *
+ * \return Actual number of frames written, if greater than or equal to zero.
+ * Guaranteed to be <= \p count.
+ * The actual transfer count may be zero if the FIFO is full,
+ * or partial if the FIFO was almost full.
+ * \retval -EIO corrupted indices, no recovery is possible
+ * \retval -ETIMEDOUT count is greater than zero, timeout is non-NULL and not {0, 0},
+ * timeout expired, and no frames were available after the timeout.
+ * \retval -EINTR count is greater than zero, timeout is non-NULL and not {0, 0}, timeout
+ * was interrupted by a signal, and no frames were available after signal.
+ * \retval -EWOULDBLOCK count is greater than zero, timeout is non-NULL and not {0, 0},
+ * futex wait failed due to benign race, and unable to converge after
+ * retrying. Should usually handle like -EINTR.
+ */
+ ssize_t write(const void *buffer, size_t count, const struct timespec *timeout = NULL);
+
+ // Implement audio_utils_fifo_provider
+ virtual ssize_t obtain(audio_utils_iovec iovec[2], size_t count,
+ const struct timespec *timeout = NULL);
+ virtual void release(size_t count);
+ virtual ssize_t available();
+
+ /**
+ * Set the current effective buffer size.
+ * Any filled frames already written or released to the buffer are unaltered, and pending
+ * releasable frames from obtain() may be release()ed. However subsequent write() and obtain()
+ * will be limited such that the total filled frame count is <= the effective buffer size.
+ * The default effective buffer size is mFifo.mFrameCount.
+ * Reducing the effective buffer size may update the hysteresis levels; see getHysteresis().
+ *
+ * \param frameCount effective buffer size in frames. Capped to range [0, mFifo.mFrameCount].
+ */
+ void resize(uint32_t frameCount);
+
+ /**
+ * Get the current effective buffer size.
+ * This value is not exposed to reader(s), and so must be conveyed via an out-of-band channel.
+ *
+ * \return effective buffer size in frames
+ */
+ uint32_t size() const;
+
+ /**
+ * Set the hysteresis levels for the writer to wake blocked readers.
+ * Hysteresis can decrease the number of context switches between writer and a blocking reader.
+ * A non-empty write() or release() will wake readers
+ * only if the fill level was < \p armLevel before the write() or release(),
+ * and then the fill level became > \p triggerLevel afterwards.
+ * The default value for \p armLevel is mFifo.mFrameCount, which means always armed.
+ * The default value for \p triggerLevel is zero,
+ * which means every write() or release() will wake the readers.
+ * For hysteresis, \p armLevel must be <= \p triggerLevel + 1.
+ * Increasing \p armLevel will arm for wakeup, regardless of the current fill level.
+ *
+ * \param armLevel Arm for wakeup when fill level < this value.
+ * Capped to range [0, effective buffer size].
+ * \param triggerLevel Trigger wakeup when armed and fill level > this value.
+ * Capped to range [0, effective buffer size].
+ */
+ void setHysteresis(uint32_t armLevel, uint32_t triggerLevel);
+
+ /**
+ * Get the hysteresis levels for waking readers.
+ *
+ * \param armLevel Set to the current arm level in frames.
+ * \param triggerLevel Set to the current trigger level in frames.
+ */
+ void getHysteresis(uint32_t *armLevel, uint32_t *triggerLevel) const;
+
+private:
+ // Accessed by writer only using ordinary operations
+ uint32_t mLocalRear; // frame index of next frame slot available to write, or write index
+
+ // TODO make a separate class and associate with the synchronization object
+ uint32_t mArmLevel; // arm if filled < arm level before release()
+ uint32_t mTriggerLevel; // trigger if armed and filled > trigger level after release()
+ bool mIsArmed; // whether currently armed
+
+ uint32_t mEffectiveFrames; // current effective buffer size, <= mFifo.mFrameCount
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Used to read from a FIFO. There can be one or more readers per FIFO,
+ * and at most one of those readers can throttle the writer.
+ * All other readers must keep up with the writer or they will lose frames.
+ * Each reader is multi-thread safe with respect to the writer and any other readers,
+ * but not with respect to multiple threads calling the reader API.
+ */
+class audio_utils_fifo_reader : public audio_utils_fifo_provider {
+
+public:
+ /**
+ * Single-process and multi-process use same constructor here,
+ * but different FIFO constructors.
+ *
+ * \param fifo Associated FIFO. Passed by reference because it must be non-NULL.
+ * \param throttlesWriter Whether this reader throttles the writer.
+ * At most one reader can specify throttlesWriter == true.
+ * A non-throttling reader does not see any data written
+ * prior to construction of the reader.
+ * \param flush Whether to flush (discard) the entire buffer on -EOVERFLOW.
+ * The advantage of flushing is that it increases the chance that next
+ * read will be successful. The disadvantage is that it loses more data.
+ */
+ explicit audio_utils_fifo_reader(audio_utils_fifo& fifo, bool throttlesWriter = true,
+ bool flush = false);
+ virtual ~audio_utils_fifo_reader();
+
+ /**
+ * Read from FIFO. Resets the number of releasable frames to zero.
+ *
+ * \param buffer Pointer to destination buffer to be filled with up to \p count frames of data.
+ * Pointer must be non-NULL if \p count is greater than zero.
+ * \param count Desired number of frames to read.
+ * \param timeout Indicates the maximum time to block for at least one frame.
+ * NULL and {0, 0} both mean non-blocking.
+ * Time is expressed as relative CLOCK_MONOTONIC.
+ * As an optimization, if \p timeout->tv_sec is the maximum positive value for
+ * time_t (LONG_MAX), then the implementation treats it as infinite timeout.
+ * See fifo_index.h for explanation of why representation is struct timespec.
+ * \param lost If non-NULL, set to the approximate number of frames lost before
+ * re-synchronization when -EOVERFLOW occurs, or set to zero when no frames lost.
+ *
+ * \return Actual number of frames read, if greater than or equal to zero.
+ * Guaranteed to be <= \p count.
+ * The actual transfer count may be zero if the FIFO is empty,
+ * or partial if the FIFO was almost empty.
+ * \retval -EIO corrupted indices, no recovery is possible
+ * \retval -EOVERFLOW reader doesn't throttle writer, and frames were lost because reader
+ * isn't keeping up with writer; see \p lost
+ * \retval -ETIMEDOUT count is greater than zero, timeout is non-NULL and not {0, 0},
+ * timeout expired, and no frames were available after the timeout.
+ * \retval -EINTR count is greater than zero, timeout is non-NULL and not {0, 0}, timeout
+ * was interrupted by a signal, and no frames were available after signal.
+ * \retval -EWOULDBLOCK count is greater than zero, timeout is non-NULL and not {0, 0},
+ * futex wait failed due to benign race, and unable to converge after
+ * retrying. Should usually handle like -EINTR.
+ */
+ ssize_t read(void *buffer, size_t count, const struct timespec *timeout = NULL,
+ size_t *lost = NULL);
+
+ // Implement audio_utils_fifo_provider
+ virtual ssize_t obtain(audio_utils_iovec iovec[2], size_t count,
+ const struct timespec *timeout = NULL);
+ virtual void release(size_t count);
+ virtual ssize_t available();
+
+ /**
+ * Same as audio_utils_fifo_provider::obtain, except has an additional parameter \p lost.
+ *
+ * \param iovec See audio_utils_fifo_provider::obtain.
+ * \param count See audio_utils_fifo_provider::obtain.
+ * \param timeout See audio_utils_fifo_provider::obtain.
+ * \param lost If non-NULL, set to the approximate number of frames lost before
+ * re-synchronization when -EOVERFLOW occurs, or set to zero when no frames lost.
+ * \return See audio_utils_fifo_provider::obtain for 'Returns' and 'Return values'.
+ */
+ ssize_t obtain(audio_utils_iovec iovec[2], size_t count, const struct timespec *timeout,
+ size_t *lost);
+
+ /**
+ * Determine the number of frames that could be obtained or read without blocking.
+ * There's an inherent race condition: the value may soon be obsolete so shouldn't be trusted.
+ * available() may be called after obtain(), but doesn't affect the number of releasable frames.
+ *
+ * \param lost If non-NULL, set to the approximate number of frames lost before
+ * re-synchronization when -EOVERFLOW occurs, or set to zero when no frames lost.
+ *
+ * \return Number of available frames, if greater than or equal to zero.
+ * \retval -EIO corrupted indices, no recovery is possible
+ * \retval -EOVERFLOW reader doesn't throttle writer, and frames were lost because reader
+ * isn't keeping up with writer; see \p lost
+ */
+ ssize_t available(size_t *lost);
+
+ /**
+ * Flush (discard) all frames that could be obtained or read without blocking.
+ * Note that flush is a method on a reader, so if the writer wants to flush
+ * then it must communicate the request to the reader(s) via an out-of-band channel.
+ *
+ * \param lost If non-NULL, set to the approximate number of frames lost before
+ * re-synchronization when -EOVERFLOW occurs, or set to zero when no frames lost.
+ *
+ * \return Number of flushed frames, if greater than or equal to zero.
+ * This number does not include any lost frames.
+ * \retval -EIO corrupted indices, no recovery is possible
+ * \retval -EOVERFLOW reader doesn't throttle writer, and frames were lost because reader
+ * isn't keeping up with writer; see \p lost
+ */
+ ssize_t flush(size_t *lost = NULL);
+
+ /**
+ * Set the hysteresis levels for a throttling reader to wake a blocked writer.
+ * Hysteresis can decrease the number of context switches between reader and a blocking writer.
+ * A non-empty read() or release() by a throttling reader will wake the writer
+ * only if the fill level was > \p armLevel before the read() or release(),
+ * and then the fill level became < \p triggerLevel afterwards.
+ * The default value for \p armLevel is -1, which means always armed.
+ * The default value for \p triggerLevel is mFifo.mFrameCount,
+ * which means every read() or release() will wake the writer.
+ * For hysteresis, \p armLevel must be >= \p triggerLevel - 1.
+ * Decreasing \p armLevel will arm for wakeup, regardless of the current fill level.
+ * Note that the throttling reader is not directly aware of the writer's effective buffer size,
+ * so any change in effective buffer size must be communicated indirectly.
+ *
+ * \param armLevel Arm for wakeup when fill level > this value.
+ * Capped to range [-1, mFifo.mFrameCount].
+ * \param triggerLevel Trigger wakeup when armed and fill level < this value.
+ * Capped to range [0, mFifo.mFrameCount].
+ */
+ void setHysteresis(int32_t armLevel, uint32_t triggerLevel);
+
+ /**
+ * Get the hysteresis levels for waking readers.
+ *
+ * \param armLevel Set to the current arm level in frames.
+ * \param triggerLevel Set to the current trigger level in frames.
+ */
+ void getHysteresis(int32_t *armLevel, uint32_t *triggerLevel) const;
+
+ /**
+ * Return the total number of lost frames since construction, due to reader not keeping up with
+ * writer. Does not include flushed frames.
+ * It is necessary to call read(), obtain(), or flush() prior to calling this method,
+ * in order to observe an increase in the total,
+ * but it is not necessary for the 'lost' parameter of those prior calls to be non-NULL.
+ *
+ * \return Total lost frames.
+ */
+ uint64_t totalLost() const
+ { return mTotalLost; }
+
+ /**
+ * Return the total number of flushed frames since construction.
+ * Does not include lost frames.
+ *
+ * \return Total flushed frames.
+ */
+ uint64_t totalFlushed() const
+ { return mTotalFlushed; }
+
+private:
+ // Accessed by reader only using ordinary operations
+ uint32_t mLocalFront; // frame index of first frame slot available to read, or read index
+
+ // Points to shared front index if this reader throttles writer, or NULL if we don't throttle
+ // FIXME consider making it a boolean
+ audio_utils_fifo_index* mThrottleFront;
+
+ bool mFlush; // whether to flush the entire buffer on -EOVERFLOW
+
+ int32_t mArmLevel; // arm if filled > arm level before release()
+ uint32_t mTriggerLevel; // trigger if armed and filled < trigger level after release()
+ bool mIsArmed; // whether currently armed
+
+ uint64_t mTotalLost; // total lost frames, does not include flushed frames
+ uint64_t mTotalFlushed; // total flushed frames, does not include lost frames
+};
#endif // !ANDROID_AUDIO_FIFO_H
diff --git a/audio_utils/include/audio_utils/fifo_index.h b/audio_utils/include/audio_utils/fifo_index.h
new file mode 100644
index 0000000..1b8401f
--- /dev/null
+++ b/audio_utils/include/audio_utils/fifo_index.h
@@ -0,0 +1,191 @@
+/*
+ * 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_FIFO_INDEX_H
+#define ANDROID_AUDIO_FIFO_INDEX_H
+
+#include <atomic>
+#include <stdint.h>
+#include <time.h>
+
+/**
+ * An index that may optionally be placed in shared memory.
+ * Must be Plain Old Data (POD), so no virtual methods are allowed.
+ * If in shared memory, exactly one process must explicitly call the constructor via placement new.
+ * \see #audio_utils_fifo_sync
+ */
+class audio_utils_fifo_index {
+
+public:
+ audio_utils_fifo_index() : mIndex(0) { }
+ ~audio_utils_fifo_index() { }
+
+ /**
+ * Load value of index now with memory order 'acquire'.
+ *
+ * \return Index value
+ */
+ uint32_t loadAcquire();
+
+ /**
+ * Store new value into index now with memory order 'release'.
+ *
+ * \param value New value to store into index
+ */
+ void storeRelease(uint32_t value);
+
+ // TODO op should be set in the constructor.
+ /**
+ * Wait for value of index to change from the specified expected value.
+ *
+ * \param op Either FUTEX_WAIT or FUTEX_WAIT_PRIVATE.
+ * \param timeout Indicates the maximum time to block while waiting for value to change.
+ * NULL means to block forever.
+ * Time is expressed as relative CLOCK_MONOTONIC.
+ * We use the Linux kernel representation of time for the very lowest levels,
+ * and save other representations for the APIs that are built on top of this.
+ * This permits APIs to choose the int64_t representation if desired, or the
+ * Linux representation without a double conversion.
+ *
+ * \return Zero for success, or a negative error code as specified at "man 2 futex".
+ */
+ int wait(int op, uint32_t expected, const struct timespec *timeout);
+
+ // TODO op should be set in the constructor.
+ /**
+ * Wake up any threads waiting for the value of index to change.
+ *
+ * \param op Either FUTEX_WAIT or FUTEX_WAIT_PRIVATE.
+ * \param waiters Maximum number of waiting threads to wake up.
+ *
+ * \return Actual number of threads woken up.
+ */
+ int wake(int op, int waiters = 1);
+
+ // specialized use only, prefer loadAcquire in most cases
+ uint32_t loadConsume();
+
+private:
+ // Linux futex is 32 bits regardless of platform.
+ // It would make more sense to declare this as atomic_uint32_t, but there is no such type name.
+ // TODO Support 64-bit index with 32-bit futex in low-order bits.
+ std::atomic_uint_least32_t mIndex; // accessed by both sides using atomic operations
+ static_assert(sizeof(mIndex) == sizeof(uint32_t), "mIndex must be 32 bits");
+};
+
+static_assert(sizeof(audio_utils_fifo_index) == sizeof(uint32_t),
+ "audio_utils_fifo_index must be 32 bits");
+
+// TODO
+// From a design POV, these next two classes should be related.
+// Extract a base class (that shares their property of being a reference to a fifo index)
+// This should be good in the case if there is a need for generic manipulations on these references.
+// Or can we perhaps define a template and make two specializations of it.
+// This is in the case when compile-time polymorphism is sufficient.
+
+/**
+ * A reference to an audio_utils_fifo_index with deferred store-release and deferred wake.
+ *
+ * TODO Currently the index and futex share the same 32-bit cell.
+ * In the future, the index may optionally be increased to 64-bits,
+ * and the futex will either be the low-order 32 bits of the index,
+ * or an unrelated 32-bit cell used as a set of event flags.
+ * Both of these will require a change to the API.
+ */
+class RefIndexDeferredStoreReleaseDeferredWake
+{
+public:
+ RefIndexDeferredStoreReleaseDeferredWake(audio_utils_fifo_index& index);
+ ~RefIndexDeferredStoreReleaseDeferredWake();
+
+ // Place 'value' into the cache but do not store it to memory yet.
+ void set(uint32_t value);
+
+ // If there is a new value in the cache, store it now with memory order 'release'.
+ void writeback();
+
+ // Place 'value' into the cache and then store it with memory order 'release'.
+ void writethrough(uint32_t value);
+
+ // op is FUTEX_WAKE or FUTEX_WAKE_PRIVATE
+ // TODO op should be set in the constructor, and should be abstracted.
+ // waiters is number of waiting threads to wake up
+ void wakeDeferred(int op, int waiters = 1);
+ void wakeNowIfNeeded();
+ // TODO op should be set in the constructor.
+ void wakeNow(int op, int waiters = 1);
+
+private:
+ audio_utils_fifo_index& mIndex; // reference to associated index
+ uint32_t mValue; // cached value to be stored
+ bool mWriteback; // whether the cached value needs to be stored
+ int mWaiters; // number of waiters to wake
+ int mWakeOp; // which kind of wake operation to use
+};
+
+/**
+ * A reference to an audio_utils_fifo_index with cached load-acquire, and deferred wait.
+ *
+ * TODO Same as RefIndexDeferredStoreReleaseDeferredWake.
+ */
+class RefIndexCachedLoadAcquireDeferredWait
+{
+public:
+ RefIndexCachedLoadAcquireDeferredWait(audio_utils_fifo_index& index);
+ ~RefIndexCachedLoadAcquireDeferredWait();
+
+ // If value is already cached, return the cached value.
+ // Otherwise load now with memory order 'acquire', cache for later, and return the value.
+ uint32_t get();
+
+ // If value is already cached, this is a no-op.
+ // Otherwise load now with memory order 'acquire' and cache the value for later use.
+ void prefetch();
+
+ // Discard any value in the cache.
+ void invalidate();
+
+#if 0
+ /**
+ * Load a fresh value for index, ignoring any previously cached information.
+ */
+ uint32_t readthrough();
+#endif
+
+ // TODO This is an immediate wait, but we needed deferred wait
+ /**
+ * Wait for value of index to change from when it was most recently read with get().
+ * To avoid a race condition, the caller must have already read the index with get(),
+ * and then made the decision to call wait() based on that value.
+ *
+ * \param op Either FUTEX_WAIT or FUTEX_WAIT_PRIVATE.
+ * \param timeout Indicates the maximum time to block while waiting for value to change.
+ * NULL means to block forever.
+ * Time is expressed as relative CLOCK_MONOTONIC.
+ * See above for explanation of why representation is struct timespec.
+ *
+ * \return Zero for success, or a negative error code as specified at "man 2 futex".
+ * \retval -EINVAL caller did not call get() prior to wait()
+ */
+ int wait(int op, const struct timespec *timeout);
+
+private:
+ audio_utils_fifo_index& mIndex; // reference to associated index
+ uint32_t mValue; // most recently cached value
+ bool mLoaded; // whether mValue is valid
+};
+
+#endif // !ANDROID_AUDIO_FIFO_INDEX_H
diff --git a/audio_utils/include/audio_utils/futex.h b/audio_utils/include/audio_utils/futex.h
new file mode 100644
index 0000000..77e6fa8
--- /dev/null
+++ b/audio_utils/include/audio_utils/futex.h
@@ -0,0 +1,53 @@
+/*
+ * 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_FUTEX_H
+#define ANDROID_AUDIO_FUTEX_H
+
+// FIXME futex portion is not supported on macOS, should use the macOS alternative
+
+#ifdef __linux__
+#include <unistd.h>
+#include <linux/futex.h>
+#include <sys/syscall.h>
+#else
+#include <errno.h>
+#define FUTEX_WAIT 0
+#define FUTEX_WAIT_PRIVATE 0
+#define FUTEX_WAKE 0
+#define FUTEX_WAKE_PRIVATE 0
+#endif
+
+static inline
+int sys_futex(void *addr1, int op, int val1, const struct timespec *timeout, void *addr2,
+ int val3)
+{
+#ifdef __linux__
+ return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3);
+#else // __linux__
+ // macOS doesn't have futex
+ (void) addr1;
+ (void) op;
+ (void) val1;
+ (void) timeout;
+ (void) addr2;
+ (void) val3;
+ errno = ENOSYS;
+ return -1;
+#endif // __linux__
+}
+
+#endif // !ANDROID_AUDIO_FUTEX_H
diff --git a/audio_utils/include/audio_utils/power.h b/audio_utils/include/audio_utils/power.h
new file mode 100644
index 0000000..385b6a7
--- /dev/null
+++ b/audio_utils/include/audio_utils/power.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2017 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_POWER_H
+#define ANDROID_AUDIO_POWER_H
+
+#include <math.h>
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <system/audio.h>
+
+/** \cond */
+__BEGIN_DECLS
+/** \endcond */
+
+/**
+ * \brief Compute signal power on a scale of 0 dBFS.
+ *
+ * \param buffer buffer of samples.
+ * \param format one of AUDIO_FORMAT_PCM_8_BIT, AUDIO_FORMAT_PCM_16_BIT,
+ * AUDIO_FORMAT_PCM_24_BIT_PACKED, AUDIO_FORMAT_PCM_8_24_BIT,
+ * AUDIO_FORMAT_PCM_32_BIT, AUDIO_FORMAT_PCM_FLOAT.
+ * \param samples number of samples in buffer. This is not audio frames;
+ * usually the number of samples is the number of audio frames
+ * multiplied by channel count.
+ *
+ * \return
+ * signal power of the samples in the buffer. It is possible to return negative infinity
+ * if the power is zero.
+ */
+
+float audio_utils_compute_power_mono(const void *buffer, audio_format_t format, size_t samples);
+
+/**
+ * \brief Compute signal energy (sum of squared amplitudes).
+ *
+ * \param buffer buffer of samples.
+ * \param format one of AUDIO_FORMAT_PCM_8_BIT, AUDIO_FORMAT_PCM_16_BIT,
+ * AUDIO_FORMAT_PCM_24_BIT_PACKED, AUDIO_FORMAT_PCM_8_24_BIT,
+ * AUDIO_FORMAT_PCM_32_BIT, AUDIO_FORMAT_PCM_FLOAT.
+ * \param samples number of samples in buffer. This is not audio frames;
+ * usually the number of samples is the number of audio frames
+ * multiplied by channel count.
+ *
+ * \return
+ * signal energy of the samples in the buffer (sum of squares) where each sample is
+ * normalized to peak to peak range of 1.f.
+ */
+
+float audio_utils_compute_energy_mono(const void *buffer, audio_format_t format, size_t samples);
+
+/**
+ * \brief Returns true if the format is supported for compute_energy_for_mono()
+ * and compute_power_for_mono().
+ * \param format format under consideration.
+ * \return true if supported.
+ */
+bool audio_utils_is_compute_power_format_supported(audio_format_t format);
+
+/**
+ * \brief Returns the signal power from amplitude.
+ * \param amplitude the signal amplitude. A negative amplitude is treated
+ * the same as a positive amplitude.
+ * \return signal power in dB. It is possible to return negative infinity
+ * if the input is zero.
+ */
+static inline float audio_utils_power_from_amplitude(float amplitude)
+{
+ return 20.f * log10f(fabsf(amplitude));
+}
+
+/**
+ * \brief Returns the signal power from energy.
+ * \param energy the signal energy. This should be non-negative.
+ * \return signal power in dB. It is possible to return NaN if the input is
+ * negative, or negative infinity if the input is zero.
+ */
+static inline float audio_utils_power_from_energy(float energy)
+{
+ return 10.f * log10f(energy);
+}
+
+/** \cond */
+__END_DECLS
+/** \endcond */
+
+#endif // !ANDROID_AUDIO_POWER_H
diff --git a/audio_utils/include/audio_utils/sndfile.h b/audio_utils/include/audio_utils/sndfile.h
index 958b414..6346295 100644
--- a/audio_utils/include/audio_utils/sndfile.h
+++ b/audio_utils/include/audio_utils/sndfile.h
@@ -67,7 +67,7 @@
* Read interleaved frames
* \return actual number of frames read
*/
-sf_count_t sf_readf_short(SNDFILE *handle, short *ptr, sf_count_t desired);
+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);
@@ -75,7 +75,7 @@
* Write interleaved frames
* \return actual number of frames written
*/
-sf_count_t sf_writef_short(SNDFILE *handle, const short *ptr, sf_count_t desired);
+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);
diff --git a/audio_utils/include/audio_utils/spdif/SPDIFEncoder.h b/audio_utils/include/audio_utils/spdif/SPDIFEncoder.h
index b356149..3c84d73 100644
--- a/audio_utils/include/audio_utils/spdif/SPDIFEncoder.h
+++ b/audio_utils/include/audio_utils/spdif/SPDIFEncoder.h
@@ -18,7 +18,7 @@
#define ANDROID_AUDIO_SPDIF_ENCODER_H
#include <stdint.h>
-#include <hardware/audio.h>
+#include <system/audio.h>
#include <audio_utils/spdif/FrameScanner.h>
namespace android {
@@ -105,8 +105,8 @@
// state variable, true if scanning for start of frame
bool mScanning;
- static const unsigned short kSPDIFSync1; // Pa
- static const unsigned short kSPDIFSync2; // Pb
+ static const uint16_t kSPDIFSync1; // Pa
+ static const uint16_t kSPDIFSync2; // Pb
};
} // namespace android
diff --git a/audio_utils/power.cpp b/audio_utils/power.cpp
new file mode 100644
index 0000000..e801da0
--- /dev/null
+++ b/audio_utils/power.cpp
@@ -0,0 +1,306 @@
+/*
+ * Copyright 2017 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 "audio_utils_power"
+#include <log/log.h>
+
+#include <math.h>
+
+#include <audio_utils/power.h>
+#include <audio_utils/primitives.h>
+
+#if defined(__aarch64__) || defined(__ARM_NEON__)
+#include <arm_neon.h>
+#define USE_NEON
+#endif
+
+namespace {
+
+constexpr inline bool isFormatSupported(audio_format_t format) {
+ switch (format) {
+ case AUDIO_FORMAT_PCM_8_BIT:
+ case AUDIO_FORMAT_PCM_16_BIT:
+ case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ case AUDIO_FORMAT_PCM_32_BIT:
+ case AUDIO_FORMAT_PCM_FLOAT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+template <typename T>
+inline T getPtrPtrValueAndIncrement(const void **data)
+{
+ return *(*reinterpret_cast<const T **>(data))++;
+}
+
+template <audio_format_t FORMAT>
+inline float convertToFloatAndIncrement(const void **data)
+{
+ switch (FORMAT) {
+ case AUDIO_FORMAT_PCM_8_BIT:
+ return float_from_u8(getPtrPtrValueAndIncrement<uint8_t>(data));
+
+ case AUDIO_FORMAT_PCM_16_BIT:
+ return float_from_i16(getPtrPtrValueAndIncrement<int16_t>(data));
+
+ case AUDIO_FORMAT_PCM_24_BIT_PACKED: {
+ const uint8_t *uptr = reinterpret_cast<const uint8_t *>(*data);
+ *data = uptr + 3;
+ return float_from_p24(uptr);
+ }
+
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ return float_from_q8_23(getPtrPtrValueAndIncrement<int32_t>(data));
+
+ case AUDIO_FORMAT_PCM_32_BIT:
+ return float_from_i32(getPtrPtrValueAndIncrement<int32_t>(data));
+
+ case AUDIO_FORMAT_PCM_FLOAT:
+ return getPtrPtrValueAndIncrement<float>(data);
+
+ default:
+ // static_assert cannot use false because the compiler may interpret it
+ // even though this code path may never be taken.
+ static_assert(isFormatSupported(FORMAT), "unsupported format");
+ }
+}
+
+// used to normalize integer fixed point value to the floating point equivalent.
+template <audio_format_t FORMAT>
+constexpr inline float normalizeAmplitude()
+{
+ switch (FORMAT) {
+ case AUDIO_FORMAT_PCM_8_BIT:
+ return 1.f / (1 << 7);
+
+ case AUDIO_FORMAT_PCM_16_BIT:
+ return 1.f / (1 << 15);
+
+ case AUDIO_FORMAT_PCM_24_BIT_PACKED: // fall through
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ return 1.f / (1 << 23);
+
+ case AUDIO_FORMAT_PCM_32_BIT:
+ return 1.f / (1U << 31);
+
+ case AUDIO_FORMAT_PCM_FLOAT:
+ return 1.f;
+
+ default:
+ // static_assert cannot use false because the compiler may interpret it
+ // even though this code path may never be taken.
+ static_assert(isFormatSupported(FORMAT), "unsupported format");
+ }
+}
+
+template <audio_format_t FORMAT>
+constexpr inline float normalizeEnergy()
+{
+ const float val = normalizeAmplitude<FORMAT>();
+ return val * val;
+}
+
+template <audio_format_t FORMAT>
+inline float energyMonoRef(const void *amplitudes, size_t size)
+{
+ float accum(0.f);
+ for (size_t i = 0; i < size; ++i) {
+ const float amplitude = convertToFloatAndIncrement<FORMAT>(&litudes);
+ accum += amplitude * amplitude;
+ }
+ return accum;
+}
+
+template <audio_format_t FORMAT>
+inline float energyMono(const void *amplitudes, size_t size)
+{
+ return energyMonoRef<FORMAT>(amplitudes, size);
+}
+
+// fast float power computation for ARM processors that support NEON.
+#ifdef USE_NEON
+
+template <>
+inline float energyMono<AUDIO_FORMAT_PCM_FLOAT>(const void *amplitudes, size_t size)
+{
+ float32x4_t *famplitudes = (float32x4_t *)amplitudes;
+
+ // clear accumulator
+ float32x4_t accum = vdupq_n_f32(0);
+
+ // iterate over array getting sum of squares in 4 lanes.
+ size_t i;
+ for (i = 0; i < (size & ~3); i += 4) {
+ accum = vmlaq_f32(accum, *famplitudes, *famplitudes);
+ ++famplitudes;
+ }
+
+ // narrow 4 lanes of floats
+ float32x2_t accum2 = vadd_f32(vget_low_f32(accum), vget_high_f32(accum)); // get stereo volume
+ accum2 = vpadd_f32(accum2, accum2); // combine to mono
+
+ // accumulate remainder
+ float value = vget_lane_f32(accum2, 0);
+ for (; i < size; ++i) {
+ const float amplitude = ((float *)amplitudes)[i];
+ value += amplitude * amplitude;
+ }
+
+ return value;
+}
+
+template <>
+inline float energyMono<AUDIO_FORMAT_PCM_16_BIT>(const void *amplitudes, size_t size)
+{
+ int16x4_t *samplitudes = (int16x4_t *)amplitudes;
+
+ // clear accumulator
+ float32x4_t accum = vdupq_n_f32(0);
+
+ // iterate over array getting sum of squares in 4 lanes.
+ size_t i;
+ for (i = 0; i < (size & ~3); i += 4) {
+ // expand s16 to s32
+ int32x4_t amplitude = vmovl_s16(*samplitudes);
+ ++samplitudes;
+ // convert s32 to f32
+ float32x4_t famplitude = vcvtq_f32_s32(amplitude);
+ accum = vmlaq_f32(accum, famplitude, famplitude);
+ }
+
+ // narrow 4 lanes of floats
+ float32x2_t accum2 = vadd_f32(vget_low_f32(accum), vget_high_f32(accum)); // get stereo volume
+ accum2 = vpadd_f32(accum2, accum2); // combine to mono
+
+ // accumulate remainder
+ float value = vget_lane_f32(accum2, 0);
+ for (; i < size; ++i) {
+ const float amplitude = (float)((int16_t *)amplitudes)[i];
+ value += amplitude * amplitude;
+ }
+
+ return value * normalizeEnergy<AUDIO_FORMAT_PCM_16_BIT>();
+}
+
+// fast int32_t power computation for PCM_32
+template <>
+inline float energyMono<AUDIO_FORMAT_PCM_32_BIT>(const void *amplitudes, size_t size)
+{
+ int32x4_t *samplitudes = (int32x4_t *)amplitudes;
+
+ // clear accumulator
+ float32x4_t accum = vdupq_n_f32(0);
+
+ // iterate over array getting sum of squares in 4 lanes.
+ size_t i;
+ for (i = 0; i < (size & ~3); i += 4) {
+ // convert s32 to f32
+ float32x4_t famplitude = vcvtq_f32_s32(*samplitudes);
+ ++samplitudes;
+ accum = vmlaq_f32(accum, famplitude, famplitude);
+ }
+
+ // narrow 4 lanes of floats
+ float32x2_t accum2 = vadd_f32(vget_low_f32(accum), vget_high_f32(accum)); // get stereo volume
+ accum2 = vpadd_f32(accum2, accum2); // combine to mono
+
+ // accumulate remainder
+ float value = vget_lane_f32(accum2, 0);
+ for (; i < size; ++i) {
+ const float amplitude = (float)((int32_t *)amplitudes)[i];
+ value += amplitude * amplitude;
+ }
+
+ return value * normalizeEnergy<AUDIO_FORMAT_PCM_32_BIT>();
+}
+
+// fast int32_t power computation for PCM_8_24 (essentially identical to PCM_32 above)
+template <>
+inline float energyMono<AUDIO_FORMAT_PCM_8_24_BIT>(const void *amplitudes, size_t size)
+{
+ int32x4_t *samplitudes = (int32x4_t *)amplitudes;
+
+ // clear accumulator
+ float32x4_t accum = vdupq_n_f32(0);
+
+ // iterate over array getting sum of squares in 4 lanes.
+ size_t i;
+ for (i = 0; i < (size & ~3); i += 4) {
+ // convert s32 to f32
+ float32x4_t famplitude = vcvtq_f32_s32(*samplitudes);
+ ++samplitudes;
+ accum = vmlaq_f32(accum, famplitude, famplitude);
+ }
+
+ // narrow 4 lanes of floats
+ float32x2_t accum2 = vadd_f32(vget_low_f32(accum), vget_high_f32(accum)); // get stereo volume
+ accum2 = vpadd_f32(accum2, accum2); // combine to mono
+
+ // accumulate remainder
+ float value = vget_lane_f32(accum2, 0);
+ for (; i < size; ++i) {
+ const float amplitude = (float)((int32_t *)amplitudes)[i];
+ value += amplitude * amplitude;
+ }
+
+ return value * normalizeEnergy<AUDIO_FORMAT_PCM_8_24_BIT>();
+}
+
+#endif // USE_NEON
+
+} // namespace
+
+float audio_utils_compute_energy_mono(const void *buffer, audio_format_t format, size_t samples)
+{
+ switch (format) {
+ case AUDIO_FORMAT_PCM_8_BIT:
+ return energyMono<AUDIO_FORMAT_PCM_8_BIT>(buffer, samples);
+
+ case AUDIO_FORMAT_PCM_16_BIT:
+ return energyMono<AUDIO_FORMAT_PCM_16_BIT>(buffer, samples);
+
+ case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+ return energyMono<AUDIO_FORMAT_PCM_24_BIT_PACKED>(buffer, samples);
+
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ return energyMono<AUDIO_FORMAT_PCM_8_24_BIT>(buffer, samples);
+
+ case AUDIO_FORMAT_PCM_32_BIT:
+ return energyMono<AUDIO_FORMAT_PCM_32_BIT>(buffer, samples);
+
+ case AUDIO_FORMAT_PCM_FLOAT:
+ return energyMono<AUDIO_FORMAT_PCM_FLOAT>(buffer, samples);
+
+ default:
+ LOG_ALWAYS_FATAL("invalid format: %#x", format);
+ }
+}
+
+float audio_utils_compute_power_mono(const void *buffer, audio_format_t format, size_t samples)
+{
+ return audio_utils_power_from_energy(
+ audio_utils_compute_energy_mono(buffer, format, samples) / samples);
+}
+
+bool audio_utils_is_compute_power_format_supported(audio_format_t format)
+{
+ return isFormatSupported(format);
+}
+
diff --git a/audio_utils/primitives.c b/audio_utils/primitives.c
index d44c29e..f4bd645 100644
--- a/audio_utils/primitives.c
+++ b/audio_utils/primitives.c
@@ -101,7 +101,7 @@
void memcpy_to_i16_from_p24(int16_t *dst, const uint8_t *src, size_t count)
{
while (count--) {
-#ifdef HAVE_BIG_ENDIAN
+#if HAVE_BIG_ENDIAN
*dst++ = src[1] | (src[0] << 8);
#else
*dst++ = src[1] | (src[2] << 8);
@@ -113,7 +113,7 @@
void memcpy_to_i32_from_p24(int32_t *dst, const uint8_t *src, size_t count)
{
while (count--) {
-#ifdef HAVE_BIG_ENDIAN
+#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);
@@ -125,7 +125,7 @@
void memcpy_to_p24_from_i16(uint8_t *dst, const int16_t *src, size_t count)
{
while (count--) {
-#ifdef HAVE_BIG_ENDIAN
+#if HAVE_BIG_ENDIAN
*dst++ = *src >> 8;
*dst++ = *src++;
*dst++ = 0;
@@ -142,7 +142,7 @@
while (count--) {
int32_t ival = clamp24_from_float(*src++);
-#ifdef HAVE_BIG_ENDIAN
+#if HAVE_BIG_ENDIAN
*dst++ = ival >> 16;
*dst++ = ival >> 8;
*dst++ = ival;
@@ -159,7 +159,7 @@
while (count--) {
int32_t ival = clamp24_from_q8_23(*src++);
-#ifdef HAVE_BIG_ENDIAN
+#if HAVE_BIG_ENDIAN
*dst++ = ival >> 16;
*dst++ = ival >> 8;
*dst++ = ival;
@@ -176,7 +176,7 @@
while (count--) {
int32_t ival = *src++ >> 8;
-#ifdef HAVE_BIG_ENDIAN
+#if HAVE_BIG_ENDIAN
*dst++ = ival >> 16;
*dst++ = ival >> 8;
*dst++ = ival;
@@ -205,7 +205,7 @@
void memcpy_to_q8_23_from_p24(int32_t *dst, const uint8_t *src, size_t count)
{
while (count--) {
-#ifdef HAVE_BIG_ENDIAN
+#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];
diff --git a/audio_utils/spdif/AC3FrameScanner.h b/audio_utils/spdif/AC3FrameScanner.h
index 9f3ea57..a73a860 100644
--- a/audio_utils/spdif/AC3FrameScanner.h
+++ b/audio_utils/spdif/AC3FrameScanner.h
@@ -18,7 +18,7 @@
#define ANDROID_AUDIO_AC3_FRAME_SCANNER_H
#include <stdint.h>
-#include <hardware/audio.h>
+#include <system/audio.h>
#include <audio_utils/spdif/FrameScanner.h>
namespace android {
diff --git a/audio_utils/spdif/SPDIFEncoder.cpp b/audio_utils/spdif/SPDIFEncoder.cpp
index efcd556..5c62299 100644
--- a/audio_utils/spdif/SPDIFEncoder.cpp
+++ b/audio_utils/spdif/SPDIFEncoder.cpp
@@ -27,8 +27,8 @@
namespace android {
// Burst Preamble defined in IEC61937-1
-const unsigned short SPDIFEncoder::kSPDIFSync1 = 0xF872; // Pa
-const unsigned short SPDIFEncoder::kSPDIFSync2 = 0x4E1F; // Pb
+const uint16_t SPDIFEncoder::kSPDIFSync1 = 0xF872; // Pa
+const uint16_t SPDIFEncoder::kSPDIFSync2 = 0x4E1F; // Pb
static int32_t sEndianDetector = 1;
#define isLittleEndian() (*((uint8_t *)&sEndianDetector))
diff --git a/audio_utils/tests/Android.bp b/audio_utils/tests/Android.bp
index 2d5f1a4..0f13a1e 100644
--- a/audio_utils/tests/Android.bp
+++ b/audio_utils/tests/Android.bp
@@ -35,6 +35,35 @@
],
}
+cc_binary {
+ name: "fifo_multiprocess",
+ host_supported: false,
+ srcs: ["fifo_multiprocess.cpp"],
+ shared_libs: ["libaudioutils", "libcutils"],
+ static_libs: ["libsndfile"],
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+}
+
+cc_binary_host {
+ name: "fifo_threads",
+ // TODO move getch.c and .h to a utility library
+ srcs: [
+ "fifo_threads.cpp",
+ "getch.c",
+ ],
+ static_libs: [
+ "libaudioutils",
+ "liblog",
+ ],
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+}
+
cc_binary_host {
name: "limiter_tests",
srcs: ["limiter_tests.c"],
@@ -42,5 +71,102 @@
cflags: [
"-Werror",
"-Wall",
+ "-UNDEBUG",
],
}
+
+cc_test {
+ name: "power_tests",
+ host_supported: true,
+
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ ],
+ srcs: ["power_tests.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ target: {
+ android: {
+ shared_libs: ["libaudioutils"],
+ },
+ host: {
+ static_libs: ["libaudioutils"],
+ },
+ }
+}
+
+cc_test {
+ name: "errorlog_tests",
+ host_supported: false,
+
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ ],
+ srcs: ["errorlog_tests.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ target: {
+ android: {
+ shared_libs: ["libaudioutils"],
+ },
+ host: {
+ static_libs: ["libaudioutils"],
+ },
+ }
+}
+
+cc_test {
+ name: "powerlog_tests",
+ host_supported: false,
+
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ ],
+ srcs: ["powerlog_tests.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ target: {
+ android: {
+ shared_libs: ["libaudioutils"],
+ },
+ host: {
+ static_libs: ["libaudioutils"],
+ },
+ }
+}
+
+cc_test {
+ name: "simplelog_tests",
+ host_supported: false,
+
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ ],
+ srcs: ["simplelog_tests.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ target: {
+ android: {
+ shared_libs: ["libaudioutils"],
+ },
+ host: {
+ static_libs: ["libaudioutils"],
+ },
+ }
+}
diff --git a/audio_utils/tests/README.md b/audio_utils/tests/README.md
index 021818a..456350c 100644
--- a/audio_utils/tests/README.md
+++ b/audio_utils/tests/README.md
@@ -1,3 +1,5 @@
primitive\_tests uses gtest framework
fifo\_tests does not run under gtest
+
+FIXME: getch.[ch] are copied from ../../../../frameworks/wilhelm/tests/sandbox/
diff --git a/audio_utils/tests/errorlog_tests.cpp b/audio_utils/tests/errorlog_tests.cpp
new file mode 100644
index 0000000..491d43b
--- /dev/null
+++ b/audio_utils/tests/errorlog_tests.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2017 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 "audio_utils_errorlog_tests"
+
+#include <audio_utils/ErrorLog.h>
+#include <gtest/gtest.h>
+#include <iostream>
+#include <log/log.h>
+
+using namespace android;
+
+static size_t countNewLines(const std::string &s) {
+ return std::count(s.begin(), s.end(), '\n');
+}
+
+TEST(audio_utils_errorlog, basic) {
+ auto elog = std::make_unique<ErrorLog<int32_t>>(100 /* lines */);
+ const int64_t oneSecond = 1000000000;
+
+ EXPECT_EQ((size_t)1, countNewLines(elog->dumpToString()));
+
+ elog->log(1 /* code */, 0 /* nowNs */);
+ elog->log(2 /* code */, 1 /* nowNs */);
+
+ // two separate errors (4 lines including 2 header lines)
+ EXPECT_EQ((size_t)4, countNewLines(elog->dumpToString()));
+
+ // aggregation at (oneSecond - 1)
+ elog->log(2 /* code */, oneSecond /* nowNs */);
+ EXPECT_EQ((size_t)4, countNewLines(elog->dumpToString()));
+
+ // no aggregation if spaced exactly one second apart
+ elog->log(2 /* code */, oneSecond * 2 /* nowNs */);
+ EXPECT_EQ((size_t)5, countNewLines(elog->dumpToString()));
+
+ // Check log:
+ // truncate on lines
+ EXPECT_EQ((size_t)3, countNewLines(elog->dumpToString("" /* prefix */, 3 /* lines */)));
+
+ // truncate on time
+ EXPECT_EQ((size_t)4, countNewLines(
+ elog->dumpToString("" /* prefix */, 0 /* lines */, oneSecond - 1 /* limitNs */)));
+
+ // truncate on time
+ EXPECT_EQ((size_t)4, countNewLines(
+ elog->dumpToString("" /* prefix */, 0 /* lines */, oneSecond /* limitNs */)));
+
+ // truncate on time (more)
+ EXPECT_EQ((size_t)3, countNewLines(
+ elog->dumpToString("" /* prefix */, 0 /* lines */, oneSecond + 1 /* limitNs */)));
+
+ // truncate on time
+ EXPECT_EQ((size_t)3, countNewLines(
+ elog->dumpToString("" /* prefix */, 0 /* lines */, oneSecond * 2 /* limitNs */)));
+
+ // truncate on time (to first header line)
+ EXPECT_EQ((size_t)1, countNewLines(
+ elog->dumpToString("" /* prefix */, 0 /* lines */, oneSecond * 2 + 1/* limitNs */)));
+
+ elog->dump(0 /* fd (stdout) */);
+
+ // The output below depends on the local time zone.
+ // The indentation below is exact, check alignment.
+ /*
+Errors: 4
+ Code Freq First time Last time
+ 1 1 12-31 16:00:00.000 12-31 16:00:00.000
+ 2 2 12-31 16:00:00.000 12-31 16:00:01.000
+ 2 1 12-31 16:00:02.000 12-31 16:00:02.000
+ */
+}
+
+TEST(audio_utils_errorlog, c) {
+ error_log_t *error_log =
+ error_log_create(100 /* lines */, 1000000000 /* one second aggregation */);
+
+ // just a sanity test
+ error_log_log(error_log, 2 /* code */, 1 /* now_ns */);
+ error_log_dump(error_log, 0 /* fd */, " " /* prefix */, 0 /* lines */, 0 /* limit_ns */);
+ error_log_destroy(error_log);
+
+ // This has a 2 character prefix offset from the previous test when dumping.
+ // The indentation below is exact, check alignment.
+ /*
+ Errors: 1
+ Code Freq First time Last time
+ 2 1 12-31 16:00:00.000 12-31 16:00:00.000
+ */
+}
diff --git a/audio_utils/tests/fifo_multiprocess.cpp b/audio_utils/tests/fifo_multiprocess.cpp
new file mode 100644
index 0000000..f9c72e2
--- /dev/null
+++ b/audio_utils/tests/fifo_multiprocess.cpp
@@ -0,0 +1,224 @@
+/*
+ * 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.
+ */
+
+#include <new>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <audio_utils/fifo.h>
+#include <cutils/ashmem.h>
+
+#define FRAME_COUNT 2048
+#define FRAME_SIZE sizeof(int16_t)
+#define BUFFER_SIZE (FRAME_COUNT * FRAME_SIZE)
+
+int main(int argc __unused, char **argv __unused)
+{
+ // TODO Add error checking for ashmem_create_region and mmap
+
+ const int frontFd = ashmem_create_region("front", sizeof(audio_utils_fifo_index));
+ printf("frontFd=%d\n", frontFd);
+
+ const int rearFd = ashmem_create_region("rear", sizeof(audio_utils_fifo_index));
+ printf("rearFd=%d\n", rearFd);
+
+ const int dataFd = ashmem_create_region("buffer", BUFFER_SIZE);
+ printf("dataFd=%d\n", dataFd);
+
+ // next two index constructors must execute exactly once, so we do it in the parent
+
+ audio_utils_fifo_index *frontIndex = (audio_utils_fifo_index *) mmap(NULL,
+ sizeof(audio_utils_fifo_index), PROT_READ | PROT_WRITE, MAP_SHARED, frontFd, (off_t) 0);
+ printf("parent frontIndex=%p\n", frontIndex);
+ (void) new(frontIndex) audio_utils_fifo_index();
+
+ audio_utils_fifo_index *rearIndex = (audio_utils_fifo_index *) mmap(NULL,
+ sizeof(audio_utils_fifo_index), PROT_READ | PROT_WRITE, MAP_SHARED, rearFd, (off_t) 0);
+ printf("parent rearIndex=%p\n", rearIndex);
+ (void) new(rearIndex) audio_utils_fifo_index();
+
+ int16_t *data = (int16_t *) mmap(NULL, sizeof(audio_utils_fifo_index), PROT_READ | PROT_WRITE,
+ MAP_SHARED, dataFd, (off_t) 0);
+ printf("parent data=%p\n", data);
+ memset(data, 0, BUFFER_SIZE);
+
+ const int pageSize = getpagesize();
+ printf("page size=%d\n", pageSize);
+
+ // create writer
+
+ printf("fork writer:\n");
+ const pid_t pidWriter = fork();
+ // TODO check if pidWriter < 0
+ if (!pidWriter) {
+
+ // Child inherits the parent's read/write mapping of front index.
+ // To confirm that there are no attempts to write to the front index,
+ // unmap it and then re-map it as read-only.
+ int ok = munmap(frontIndex, sizeof(audio_utils_fifo_index));
+ printf("writer unmap front ok=%d\n", ok);
+ ok = ashmem_set_prot_region(frontFd, PROT_READ);
+ printf("writer prot read front ok=%d\n", ok);
+ // The pagesize * 4 offset confirms that we don't assume identical mapping in both processes
+ frontIndex = (audio_utils_fifo_index *) mmap((char *) frontIndex + pageSize * 4,
+ sizeof(audio_utils_fifo_index), PROT_READ, MAP_SHARED | MAP_FIXED, frontFd,
+ (off_t) 0);
+ printf("writer frontIndex=%p\n", frontIndex);
+
+ // Retain our read/write mapping of rear index and data
+ audio_utils_fifo fifo(FRAME_COUNT, FRAME_SIZE, data, *rearIndex, frontIndex);
+ audio_utils_fifo_writer writer(fifo);
+
+ sleep(2);
+
+ for (int16_t value = 1; value <= 20; value++) {
+ printf("writing %d\n", value);
+ const ssize_t actual = writer.write(&value, 1);
+ if (actual != 1) {
+ printf("wrote unexpected actual = %zd\n", actual);
+ break;
+ }
+ // TODO needs a lot of work
+ switch (value) {
+ case 10:
+ sleep(2);
+ break;
+ case 14:
+ sleep(4);
+ break;
+ default:
+ usleep(500000);
+ break;
+ }
+ }
+
+ (void) close(frontFd);
+ (void) close(rearFd);
+ (void) close(dataFd);
+
+ return EXIT_SUCCESS;
+ }
+
+ // The sleep(2) above and sleep(1) here ensure that the order is:
+ // a. writer initializes
+ // b. reader initializes
+ // c. reader starts the read loop
+ // d. writer starts the write loop
+ // Actually, as long as (a) precedes (d) and (b) precedes (c), the order does not matter.
+ // TODO test all valid sequences.
+ sleep(1);
+
+ // create reader
+
+ printf("fork reader:\n");
+ const pid_t pidReader = fork();
+ // TODO check if pidReader < 0
+ if (!pidReader) {
+
+ // Child inherits the parent's read/write mapping of rear index.
+ // To confirm that there are no attempts to write to the rear index,
+ // unmap it and then re-map it as read-only.
+ int ok = munmap(rearIndex, sizeof(audio_utils_fifo_index));
+ printf("reader unmap rear ok=%d\n", ok);
+ ok = ashmem_set_prot_region(rearFd, PROT_READ);
+ printf("reader prot read rear ok=%d\n", ok);
+ // The pagesize * 4 offset confirms that we don't assume identical mapping in both processes
+ rearIndex = (audio_utils_fifo_index *) mmap((char *) rearIndex + pageSize * 4,
+ sizeof(audio_utils_fifo_index), PROT_READ, MAP_SHARED | MAP_FIXED, rearFd,
+ (off_t) 0);
+ printf("reader rearIndex=%p\n", rearIndex);
+
+ // Similarly for the data
+ ok = munmap(data, BUFFER_SIZE);
+ printf("reader unmap data ok=%d\n", ok);
+ ok = ashmem_set_prot_region(dataFd, PROT_READ);
+ printf("reader prot read data ok=%d\n", ok);
+ // The pagesize * 8 offset confirms that we don't assume identical mapping in both processes
+ data = (int16_t *) mmap((char *) data + pageSize * 8, BUFFER_SIZE, PROT_READ,
+ MAP_SHARED | MAP_FIXED, dataFd, (off_t) 0);
+ printf("reader data=%p\n", data);
+
+ // Retain our read/write mapping of front index
+ audio_utils_fifo fifo(FRAME_COUNT, FRAME_SIZE, data, *rearIndex, frontIndex);
+ audio_utils_fifo_reader reader(fifo);
+
+ for (;;) {
+ int16_t value;
+ struct timespec timeout = {
+ .tv_sec = 1,
+ .tv_nsec = 0
+ };
+ const ssize_t actual = reader.read(&value, 1, &timeout);
+ switch (actual) {
+ case 0:
+ break;
+ case 1:
+ printf("read %d\n", value);
+ if (value == 20) {
+ goto out;
+ }
+ break;
+ case -ETIMEDOUT:
+ printf("read timed out\n");
+ break;
+ default:
+ printf("read unexpected actual = %zd\n", actual);
+ goto out;
+ }
+ }
+out:
+
+ (void) close(frontFd);
+ (void) close(rearFd);
+ (void) close(dataFd);
+
+ return EXIT_SUCCESS;
+ }
+
+ int status;
+ pid_t pid = waitpid(pidWriter, &status, 0);
+ if (pid == pidWriter) {
+ printf("writer exited with status %d\n", status);
+ } else {
+ printf("waitpid on writer = %d\n", pid);
+ }
+ pid = waitpid(pidReader, &status, 0);
+ if (pid == pidReader) {
+ printf("reader exited with status %d\n", status);
+ } else {
+ printf("waitpid on reader = %d\n", pid);
+ }
+
+ // next two index destructors must execute exactly once, so we do it in the parent
+ frontIndex->~audio_utils_fifo_index();
+ rearIndex->~audio_utils_fifo_index();
+
+ int ok = munmap(frontIndex, sizeof(audio_utils_fifo_index));
+ printf("parent unmap front ok=%d\n", ok);
+ ok = munmap(rearIndex, sizeof(audio_utils_fifo_index));
+ printf("parent unmap rear ok=%d\n", ok);
+ ok = munmap(data, BUFFER_SIZE);
+ printf("parent unmap data ok=%d\n", ok);
+
+ (void) close(frontFd);
+ (void) close(rearFd);
+ (void) close(dataFd);
+
+ return EXIT_SUCCESS;
+}
diff --git a/audio_utils/tests/fifo_tests.cpp b/audio_utils/tests/fifo_tests.cpp
index 99e73c9..b015810 100644
--- a/audio_utils/tests/fifo_tests.cpp
+++ b/audio_utils/tests/fifo_tests.cpp
@@ -17,29 +17,42 @@
// Test program for audio_utils FIFO library.
// This only tests the single-threaded aspects, not the barriers.
+#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <audio_utils/fifo.h>
#include <audio_utils/sndfile.h>
+#ifndef min
+#define min(x, y) (((x) < (y)) ? (x) : (y))
+#endif
+
int main(int argc, char **argv)
{
- size_t frameCount = 256;
- size_t maxFramesPerRead = 1;
- size_t maxFramesPerWrite = 1;
+ size_t frameCount = 0;
+ size_t maxFramesPerRead = 0;
+ size_t maxFramesPerWrite = 0;
+ bool readerThrottlesWriter = true;
+ bool verbose = false;
int i;
for (i = 1; i < argc; i++) {
char *arg = argv[i];
if (arg[0] != '-')
break;
switch (arg[1]) {
- case 'c': // FIFO frame count
+ case 'f': // FIFO frame count
frameCount = atoi(&arg[2]);
break;
case 'r': // maximum frame count per read from FIFO
maxFramesPerRead = atoi(&arg[2]);
break;
+ case 't': // disable throttling of writer by reader
+ readerThrottlesWriter = false;
+ break;
+ case 'v': // enable verbose logging
+ verbose = true;
+ break;
case 'w': // maximum frame count per write to FIFO
maxFramesPerWrite = atoi(&arg[2]);
break;
@@ -48,10 +61,19 @@
goto usage;
}
}
+ if (frameCount == 0) {
+ frameCount = 256;
+ }
+ if (maxFramesPerRead == 0) {
+ maxFramesPerRead = frameCount;
+ }
+ if (maxFramesPerWrite == 0) {
+ maxFramesPerWrite = frameCount;
+ }
if (argc - i != 2) {
usage:
- fprintf(stderr, "usage: %s [-c#] in.wav out.wav\n", argv[0]);
+ fprintf(stderr, "usage: %s [-f#] [-r#] [-t] [-v] [-w#] in.wav out.wav\n", argv[0]);
return EXIT_FAILURE;
}
char *inputFile = argv[i];
@@ -64,18 +86,17 @@
perror(inputFile);
return EXIT_FAILURE;
}
- // sf_readf_short() does conversion, so not strictly necessary to check the file format.
- // But I want to do "cmp" on input and output files afterwards,
- // and it is easier if they are all the same format.
- // Enforcing that everything is 16-bit is convenient for this.
- if ((sfinfoin.format & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK)) !=
- (SF_FORMAT_WAV | SF_FORMAT_PCM_16)) {
+ switch (sfinfoin.format & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK)) {
+ case SF_FORMAT_WAV | SF_FORMAT_PCM_16:
+ case SF_FORMAT_WAV | SF_FORMAT_PCM_U8:
+ break;
+ default:
fprintf(stderr, "%s: unsupported format\n", inputFile);
sf_close(sfin);
return EXIT_FAILURE;
}
- size_t frameSize = sizeof(short) * sfinfoin.channels;
- short *inputBuffer = new short[sfinfoin.frames * sfinfoin.channels];
+ size_t frameSize = sizeof(int16_t) * sfinfoin.channels;
+ int16_t *inputBuffer = new int16_t[sfinfoin.frames * sfinfoin.channels];
sf_count_t actualRead = sf_readf_short(sfin, inputBuffer, sfinfoin.frames);
if (actualRead != sfinfoin.frames) {
fprintf(stderr, "%s: unexpected EOF or error\n", inputFile);
@@ -84,18 +105,19 @@
}
sf_close(sfin);
- short *outputBuffer = new short[sfinfoin.frames * sfinfoin.channels];
+ int16_t *outputBuffer = new int16_t[sfinfoin.frames * sfinfoin.channels];
size_t framesWritten = 0;
size_t framesRead = 0;
- struct audio_utils_fifo fifo;
- short *fifoBuffer = new short[frameCount * sfinfoin.channels];
- audio_utils_fifo_init(&fifo, frameCount, frameSize, fifoBuffer);
+ int16_t *fifoBuffer = new int16_t[frameCount * sfinfoin.channels];
+ audio_utils_fifo fifo(frameCount, frameSize, fifoBuffer, readerThrottlesWriter);
+ audio_utils_fifo_writer fifoWriter(fifo);
+ audio_utils_fifo_reader fifoReader(fifo, readerThrottlesWriter);
int fifoWriteCount = 0, fifoReadCount = 0;
int fifoFillLevel = 0, minFillLevel = INT_MAX, maxFillLevel = INT_MIN;
for (;;) {
size_t framesToWrite = sfinfoin.frames - framesWritten;
size_t framesToRead = sfinfoin.frames - framesRead;
- if (framesToWrite == 0 && framesToRead == 0) {
+ if (framesToWrite == 0 && (framesToRead == 0 || !readerThrottlesWriter)) {
break;
}
@@ -103,49 +125,100 @@
framesToWrite = maxFramesPerWrite;
}
framesToWrite = rand() % (framesToWrite + 1);
- ssize_t actualWritten = audio_utils_fifo_write(&fifo,
+ ssize_t actualWritten = fifoWriter.write(
&inputBuffer[framesWritten * sfinfoin.channels], framesToWrite);
+ if (verbose) {
+ printf("wrote %d out of %d\n", (int) actualWritten, (int) framesToWrite);
+ }
if (actualWritten < 0 || (size_t) actualWritten > framesToWrite) {
fprintf(stderr, "write to FIFO failed\n");
break;
}
+ if (actualWritten < min((int) frameCount - fifoFillLevel, (int) framesToWrite)) {
+ fprintf(stderr, "only wrote %d when should have written min(%d, %d)\n",
+ (int) actualWritten, (int) frameCount - fifoFillLevel, (int) framesToWrite);
+ }
framesWritten += actualWritten;
if (actualWritten > 0) {
fifoWriteCount++;
}
fifoFillLevel += actualWritten;
+ if (verbose) {
+ printf("fill level after write %d\n", fifoFillLevel);
+ }
if (fifoFillLevel > maxFillLevel) {
maxFillLevel = fifoFillLevel;
- if (maxFillLevel > (int) frameCount)
- abort();
+ if (maxFillLevel > (int) frameCount) {
+ if (readerThrottlesWriter) {
+ printf("maxFillLevel=%d > frameCount=%d\n", maxFillLevel, (int) frameCount);
+ abort();
+ }
+ }
}
if (framesToRead > maxFramesPerRead) {
framesToRead = maxFramesPerRead;
}
framesToRead = rand() % (framesToRead + 1);
- ssize_t actualRead = audio_utils_fifo_read(&fifo,
+ ssize_t actualRead = fifoReader.read(
&outputBuffer[framesRead * sfinfoin.channels], framesToRead);
+ if (verbose) {
+ printf("read %d out of %d\n", (int) actualRead, (int) framesToRead);
+ }
if (actualRead < 0 || (size_t) actualRead > framesToRead) {
- fprintf(stderr, "read from FIFO failed\n");
- break;
+ switch (actualRead) {
+ case -EIO:
+ fprintf(stderr, "read from FIFO failed: corrupted indices\n");
+ abort();
+ break;
+ case -EOVERFLOW:
+ if (readerThrottlesWriter) {
+ fprintf(stderr, "read from FIFO failed: unexpected overflow\n");
+ abort();
+ }
+ printf("warning: reader lost frames\n");
+ actualRead = 0;
+ break;
+ default:
+ if (actualRead < 0) {
+ fprintf(stderr, "read from FIFO failed: unexpected error code %d\n",
+ (int) actualRead);
+ } else {
+ fprintf(stderr, "read from FIFO failed: actualRead=%d > framesToRead=%d\n",
+ (int) actualRead, (int) framesToRead);
+ }
+ abort();
+ }
+ }
+ if (actualRead < min(fifoFillLevel, (int) framesToRead)) {
+ //fprintf(stderr, "only read %d when should have read min(%d, %d)\n",
+ // (int) actualRead, fifoFillLevel, (int) framesToRead);
}
framesRead += actualRead;
if (actualRead > 0) {
fifoReadCount++;
}
fifoFillLevel -= actualRead;
+ if (verbose) {
+ printf("fill level after read %d\n", fifoFillLevel);
+ }
if (fifoFillLevel < minFillLevel) {
minFillLevel = fifoFillLevel;
- if (minFillLevel < 0)
+ if (minFillLevel < 0) {
+ printf("minFillLevel=%d < 0\n", minFillLevel);
abort();
+ }
}
}
+ delete[] inputBuffer;
+ inputBuffer = NULL;
+ delete[] fifoBuffer;
+ fifoBuffer = NULL;
+
printf("FIFO non-empty writes: %d, non-empty reads: %d\n", fifoWriteCount, fifoReadCount);
printf("fill=%d, min=%d, max=%d\n", fifoFillLevel, minFillLevel, maxFillLevel);
- audio_utils_fifo_deinit(&fifo);
- delete[] fifoBuffer;
+ printf("writing output\n");
SF_INFO sfinfoout;
memset(&sfinfoout, 0, sizeof(sfinfoout));
sfinfoout.samplerate = sfinfoin.samplerate;
@@ -157,14 +230,16 @@
return EXIT_FAILURE;
}
sf_count_t actualWritten = sf_writef_short(sfout, outputBuffer, framesRead);
- delete[] inputBuffer;
delete[] outputBuffer;
- delete[] fifoBuffer;
+ outputBuffer = NULL;
+
if (actualWritten != (sf_count_t) framesRead) {
fprintf(stderr, "%s: unexpected error\n", outputFile);
sf_close(sfout);
return EXIT_FAILURE;
}
sf_close(sfout);
+ printf("done\n");
+
return EXIT_SUCCESS;
}
diff --git a/audio_utils/tests/fifo_threads.cpp b/audio_utils/tests/fifo_threads.cpp
new file mode 100644
index 0000000..83a0cdf
--- /dev/null
+++ b/audio_utils/tests/fifo_threads.cpp
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <audio_utils/fifo.h>
+extern "C" {
+#include "getch.h"
+}
+
+struct Context {
+ audio_utils_fifo_writer *mInputWriter;
+ audio_utils_fifo_reader *mInputReader;
+ audio_utils_fifo_writer *mTransferWriter;
+ audio_utils_fifo_reader *mTransferReader;
+ audio_utils_fifo_writer *mOutputWriter;
+ audio_utils_fifo_reader *mOutputReader;
+};
+
+void *input_routine(void *arg)
+{
+ Context *context = (Context *) arg;
+ for (;;) {
+ struct timespec timeout;
+ timeout.tv_sec = 30;
+ timeout.tv_nsec = 0;
+ char buffer[4];
+ ssize_t actual = context->mInputReader->read(buffer, sizeof(buffer), &timeout);
+ // TODO this test is unreadable
+ if (actual > 0) {
+ if ((size_t) actual > sizeof(buffer)) {
+ printf("input.read actual = %d\n", (int) actual);
+ abort();
+ }
+ ssize_t actual2 = context->mTransferWriter->write(buffer, actual, &timeout);
+ if (actual2 != actual) {
+ printf("transfer.write(%d) = %d\n", (int) actual, (int) actual2);
+ }
+ //sleep(10);
+ } else if (actual == -ETIMEDOUT) {
+ (void) write(1, "t", 1);
+ } else {
+ printf("input.read actual = %d\n", (int) actual);
+ }
+ }
+ return NULL;
+}
+
+volatile bool outputPaused = false;
+
+void *output_routine(void *arg)
+{
+ Context *context = (Context *) arg;
+ for (;;) {
+ if (outputPaused) {
+ sleep(1);
+ continue;
+ }
+ struct timespec timeout;
+ timeout.tv_sec = 60;
+ timeout.tv_nsec = 0;
+ char buffer[4];
+ ssize_t actual = context->mTransferReader->read(buffer, sizeof(buffer), &timeout);
+ if (actual > 0) {
+ if ((size_t) actual > sizeof(buffer)) {
+ printf("transfer.read actual = %d\n", (int) actual);
+ abort();
+ }
+ ssize_t actual2 = context->mOutputWriter->write(buffer, actual, NULL /*timeout*/);
+ if (actual2 != actual) {
+ printf("output.write(%d) = %d\n", (int) actual, (int) actual2);
+ }
+ } else if (actual == -ETIMEDOUT) {
+ (void) write(1, "T", 1);
+ } else {
+ printf("transfer.read actual = %d\n", (int) actual);
+ }
+ }
+ return NULL;
+}
+
+int main(int argc, char **argv)
+{
+ set_conio_terminal_mode();
+ argc = argc + 0;
+ argv = &argv[0];
+
+ char inputBuffer[16];
+ audio_utils_fifo inputFifo(sizeof(inputBuffer) /*frameCount*/, 1 /*frameSize*/, inputBuffer,
+ true /*throttlesWriter*/);
+ audio_utils_fifo_writer inputWriter(inputFifo);
+ audio_utils_fifo_reader inputReader(inputFifo, true /*throttlesWriter*/);
+ //inputWriter.setHysteresis(sizeof(inputBuffer) * 1/4, sizeof(inputBuffer) * 3/4);
+
+ char transferBuffer[64];
+ audio_utils_fifo transferFifo(sizeof(transferBuffer) /*frameCount*/, 1 /*frameSize*/,
+ transferBuffer, true /*throttlesWriter*/);
+ audio_utils_fifo_writer transferWriter(transferFifo);
+ audio_utils_fifo_reader transferReader(transferFifo, true /*throttlesWriter*/);
+ transferReader.setHysteresis(sizeof(transferBuffer) * 3/4, sizeof(transferBuffer) * 1/4);
+ //transferWriter.setEffective(8);
+
+ char outputBuffer[64];
+ audio_utils_fifo outputFifo(sizeof(outputBuffer) /*frameCount*/, 1 /*frameSize*/, outputBuffer,
+ true /*throttlesWriter*/);
+ audio_utils_fifo_writer outputWriter(outputFifo);
+ audio_utils_fifo_reader outputReader(outputFifo, true /*readerThrottlesWriter*/);
+
+ Context context;
+ context.mInputWriter = &inputWriter;
+ context.mInputReader = &inputReader;
+ context.mTransferWriter = &transferWriter;
+ context.mTransferReader = &transferReader;
+ context.mOutputWriter = &outputWriter;
+ context.mOutputReader = &outputReader;
+
+ pthread_t input_thread;
+ int ok = pthread_create(&input_thread, (const pthread_attr_t *) NULL, input_routine,
+ (void *) &context);
+ pthread_t output_thread;
+ ok = pthread_create(&output_thread, (const pthread_attr_t *) NULL, output_routine,
+ (void *) &context);
+ ok = ok + 0;
+
+ for (;;) {
+ char buffer[4];
+ ssize_t actual = outputReader.read(buffer, sizeof(buffer), NULL /*timeout*/);
+ if (actual > 0) {
+ printf("%.*s", (int) actual, buffer);
+ fflush(stdout);
+ } else if (actual != 0) {
+ printf("outputReader.read actual = %d\n", (int) actual);
+ }
+ if (kbhit()) {
+ int ch = getch();
+ if (ch <= 0 || ch == '\003' /*control-C*/) {
+ break;
+ }
+ if (ch == 'p')
+ outputPaused = true;
+ else if (ch == 'p')
+ outputPaused = false;
+ buffer[0] = ch;
+ actual = inputWriter.write(buffer, 1, NULL /*timeout*/);
+ if (actual != 1) {
+ printf("inputWriter.write actual = %d\n", (int) actual);
+ }
+ }
+ }
+ reset_terminal_mode();
+}
diff --git a/audio_utils/tests/getch.c b/audio_utils/tests/getch.c
new file mode 100644
index 0000000..446770a
--- /dev/null
+++ b/audio_utils/tests/getch.c
@@ -0,0 +1,65 @@
+/*
+C non-blocking keyboard input
+http://stackoverflow.com/questions/448944/c-non-blocking-keyboard-input
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/select.h>
+#include <termios.h>
+#include <unistd.h>
+#include "getch.h"
+
+struct termios orig_termios;
+
+void reset_terminal_mode()
+{
+ tcsetattr(0, TCSANOW, &orig_termios);
+}
+
+void set_conio_terminal_mode()
+{
+ struct termios new_termios;
+
+ /* take two copies - one for now, one for later */
+ tcgetattr(0, &orig_termios);
+ memcpy(&new_termios, &orig_termios, sizeof(new_termios));
+
+ /* register cleanup handler, and set the new terminal mode */
+ atexit(reset_terminal_mode);
+ cfmakeraw(&new_termios);
+ new_termios.c_oflag |= OPOST;
+ tcsetattr(0, TCSANOW, &new_termios);
+}
+
+int kbhit()
+{
+ struct timeval tv = { 0L, 0L };
+ fd_set fds;
+ FD_ZERO(&fds); // not in original posting to stackoverflow
+ FD_SET(0, &fds);
+ return select(1, &fds, NULL, NULL, &tv);
+}
+
+int getch()
+{
+ int r;
+ unsigned char c;
+ if ((r = read(0, &c, sizeof(c))) < 0) {
+ return r;
+ } else {
+ return c;
+ }
+}
+
+#if 0
+int main(int argc, char *argv[])
+{
+ set_conio_terminal_mode();
+
+ while (!kbhit()) {
+ /* do some work */
+ }
+ (void)getch(); /* consume the character */
+}
+#endif
diff --git a/audio_utils/tests/getch.h b/audio_utils/tests/getch.h
new file mode 100644
index 0000000..41b050d
--- /dev/null
+++ b/audio_utils/tests/getch.h
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+extern int kbhit();
+extern int getch(void);
+extern void set_conio_terminal_mode(void);
+extern void reset_terminal_mode(void);
diff --git a/audio_utils/tests/power_tests.cpp b/audio_utils/tests/power_tests.cpp
new file mode 100644
index 0000000..b86dac3
--- /dev/null
+++ b/audio_utils/tests/power_tests.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2017 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 "audio_utils_power_tests"
+
+#include <cmath>
+#include <math.h>
+
+#include <audio_utils/power.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+
+typedef struct { uint8_t c[3]; } __attribute__((__packed__)) uint8x3_t;
+
+void testFloatValue(float f_value, size_t length) {
+ const float power = audio_utils_power_from_amplitude(f_value);
+ float f_ary[length];
+ uint8_t u8_ary[length];
+ int16_t i16_ary[length];
+ int32_t i32_ary[length];
+ int32_t q8_23_ary[length];
+ uint8x3_t p24_ary[length];
+
+ // magic formulas to convert floating point to fixed point representations.
+ // we negate the floating point value to ensure full integer range for 1.f.
+ const uint8_t u8_value((1.f - f_value) * 128);
+ const int16_t i16_value(f_value * INT16_MIN);
+ const int32_t i32_value (f_value * INT32_MIN);
+ const int32_t q8_23_value(f_value * -(1 << 23));
+
+ // PCM_24_BIT_PACKED is native endian.
+#if HAVE_BIG_ENDIAN
+ const uint8x3_t p24_value{{
+ uint8_t(q8_23_value >> 16),
+ uint8_t(q8_23_value >> 8),
+ uint8_t(q8_23_value),
+ }};
+#else
+ const uint8x3_t p24_value{{
+ uint8_t(q8_23_value),
+ uint8_t(q8_23_value >> 8),
+ uint8_t(q8_23_value >> 16),
+ }};
+#endif
+
+ for (size_t i = 0; i < length; ++i) {
+ f_ary[i] = f_value;
+ u8_ary[i] = u8_value;
+ i16_ary[i] = i16_value;
+ i32_ary[i] = i32_value;
+ q8_23_ary[i] = q8_23_value;
+ p24_ary[i] = p24_value;
+ }
+
+ EXPECT_EQ(power,
+ audio_utils_compute_power_mono(f_ary, AUDIO_FORMAT_PCM_FLOAT, length));
+ EXPECT_EQ(power,
+ audio_utils_compute_power_mono(u8_ary, AUDIO_FORMAT_PCM_8_BIT, length));
+ EXPECT_EQ(power,
+ audio_utils_compute_power_mono(i16_ary, AUDIO_FORMAT_PCM_16_BIT, length));
+ EXPECT_EQ(power,
+ audio_utils_compute_power_mono(i32_ary, AUDIO_FORMAT_PCM_32_BIT, length));
+ EXPECT_EQ(power,
+ audio_utils_compute_power_mono(q8_23_ary, AUDIO_FORMAT_PCM_8_24_BIT, length));
+ EXPECT_EQ(power,
+ audio_utils_compute_power_mono(p24_ary, AUDIO_FORMAT_PCM_24_BIT_PACKED, length));
+}
+
+void testFloatRamp(size_t length) {
+ float f_ary[length];
+ uint8_t u8_ary[length];
+ int16_t i16_ary[length];
+ int32_t i32_ary[length];
+ int32_t q8_23_ary[length];
+ uint8x3_t p24_ary[length];
+
+ for (size_t i = 0; i < length; ++i) {
+ // must be expressed cleanly in uint8_t
+ const float f_value = (int(length & 0xff) - 128) / 128.f;
+
+ // magic formulas to convert floating point to fixed point representations.
+ // we negate the floating point value to ensure full integer range for 1.f.
+ const uint8_t u8_value((1.f - f_value) * 128);
+ const int16_t i16_value(f_value * INT16_MIN);
+ const int32_t i32_value (f_value * INT32_MIN);
+ const int32_t q8_23_value(f_value * -(1 << 23));
+
+ // PCM_24_BIT_PACKED is native endian.
+ #if HAVE_BIG_ENDIAN
+ const uint8x3_t p24_value{{
+ uint8_t(q8_23_value >> 16),
+ uint8_t(q8_23_value >> 8),
+ uint8_t(q8_23_value),
+ }};
+ #else
+ const uint8x3_t p24_value{{
+ uint8_t(q8_23_value),
+ uint8_t(q8_23_value >> 8),
+ uint8_t(q8_23_value >> 16),
+ }};
+ #endif
+
+ f_ary[i] = f_value;
+ u8_ary[i] = u8_value;
+ i16_ary[i] = i16_value;
+ i32_ary[i] = i32_value;
+ q8_23_ary[i] = q8_23_value;
+ p24_ary[i] = p24_value;
+ }
+
+ const float power8 = audio_utils_compute_power_mono(u8_ary, AUDIO_FORMAT_PCM_8_BIT, length);
+
+ EXPECT_EQ(power8,
+ audio_utils_compute_power_mono(f_ary, AUDIO_FORMAT_PCM_FLOAT, length));
+ EXPECT_EQ(power8,
+ audio_utils_compute_power_mono(i16_ary, AUDIO_FORMAT_PCM_16_BIT, length));
+ EXPECT_EQ(power8,
+ audio_utils_compute_power_mono(i32_ary, AUDIO_FORMAT_PCM_32_BIT, length));
+ EXPECT_EQ(power8,
+ audio_utils_compute_power_mono(q8_23_ary, AUDIO_FORMAT_PCM_8_24_BIT, length));
+ EXPECT_EQ(power8,
+ audio_utils_compute_power_mono(p24_ary, AUDIO_FORMAT_PCM_24_BIT_PACKED, length));
+}
+
+// power_mono implicitly tests energy_mono
+TEST(audio_utils_power, power_mono) {
+ // f_values should have limited mantissa
+ for (float f_value : { 0.f, 0.25f, 0.5f, 0.75f, 1.f }) {
+ const float power = audio_utils_power_from_amplitude(f_value);
+ printf("power_mono: amplitude: %f power: %f\n", f_value, power);
+
+ for (size_t length : { 1, 3, 5, 7, 16, 21, 32, 37 }) {
+ testFloatValue(f_value, length);
+ }
+ }
+}
+
+// power_mono implicitly tests energy_mono
+TEST(audio_utils_power, power_mono_ramp) {
+ for (size_t length : { 1, 3, 5, 7, 16, 21, 32, 37, 297 }) {
+ testFloatRamp(length);
+ }
+}
+
+TEST(audio_utils_power, power_from) {
+ EXPECT_EQ(0.f, audio_utils_power_from_amplitude(1.f));
+ EXPECT_EQ(-INFINITY, audio_utils_power_from_amplitude(0.f));
+ EXPECT_EQ(0.f, audio_utils_power_from_amplitude(-1.f));
+
+ EXPECT_EQ(0.f, audio_utils_power_from_energy(1.f));
+ EXPECT_EQ(-INFINITY, audio_utils_power_from_energy(0.f));
+ EXPECT_TRUE(std::isnan(audio_utils_power_from_energy(-1.f)));
+}
diff --git a/audio_utils/tests/powerlog_tests.cpp b/audio_utils/tests/powerlog_tests.cpp
new file mode 100644
index 0000000..2a7988d
--- /dev/null
+++ b/audio_utils/tests/powerlog_tests.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2017 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 "audio_utils_powerlog_tests"
+
+#include <audio_utils/PowerLog.h>
+#include <gtest/gtest.h>
+#include <iostream>
+#include <log/log.h>
+
+using namespace android;
+
+static size_t countNewLines(const std::string &s) {
+ return std::count(s.begin(), s.end(), '\n');
+}
+
+TEST(audio_utils_powerlog, basic) {
+ auto plog = std::make_unique<PowerLog>(
+ 48000 /* sampleRate */,
+ 1 /* channelCount */,
+ AUDIO_FORMAT_PCM_16_BIT,
+ 100 /* entries */,
+ 1 /* framesPerEntry */);
+
+ // header
+ EXPECT_EQ((size_t)1, countNewLines(plog->dumpToString()));
+
+ const int16_t zero = 0;
+ const int16_t half = 0x4000;
+
+ plog->log(&half, 1 /* frame */, 0 /* nowNs */);
+ plog->log(&half, 1 /* frame */, 1 /* nowNs */);
+ plog->log(&half, 1 /* frame */, 2 /* nowNs */);
+
+ // one line / signal
+ EXPECT_EQ((size_t)2, countNewLines(plog->dumpToString()));
+
+ plog->log(&zero, 1 /* frame */, 3 /* nowNs */);
+ // zero termination doesn't change this.
+ EXPECT_EQ((size_t)2, countNewLines(plog->dumpToString()));
+
+ // but adding next line does.
+ plog->log(&half, 1 /* frame */, 4 /* nowNs */);
+ EXPECT_EQ((size_t)3, countNewLines(plog->dumpToString()));
+
+ // truncating on lines
+ EXPECT_EQ((size_t)2, countNewLines(plog->dumpToString(
+ "" /* prefix */, 2 /* lines */)));
+
+ // truncating on time
+ EXPECT_EQ((size_t)3, countNewLines(plog->dumpToString(
+ "" /* prefix */, 0 /* lines */, 2 /* limitNs */)));
+ EXPECT_EQ((size_t)2, countNewLines(plog->dumpToString(
+ "" /* prefix */, 0 /* lines */, 3 /* limitNs */)));
+ plog->dump(0 /* fd (stdout) */);
+
+ // The output below depends on the local time zone.
+ // The indentation below is exact, check alignment.
+ /*
+Signal power history:
+ 12-31 16:00:00.000: [ -6.0 -6.0 -6.0 ] sum(-1.2)
+ 12-31 16:00:00.000: [ -6.0
+ */
+}
+
+TEST(audio_utils_powerlog, c) {
+ power_log_t *power_log = power_log_create(
+ 48000 /* sample_rate */,
+ 1 /* channel_count */,
+ AUDIO_FORMAT_PCM_16_BIT,
+ 100 /* entries */,
+ 1 /* frames_per_entry */);
+
+ // sanity test
+ const int16_t zero = 0;
+ const int16_t quarter = 0x2000;
+
+ power_log_log(power_log, &quarter, 1 /* frame */, 0 /* now_ns */);
+ power_log_log(power_log, &zero, 1 /* frame */, 1 /* now_ns */);
+ power_log_dump(power_log, 0 /* fd */, " " /* prefix */, 0 /* lines */, 0 /* limit_ns */);
+ power_log_destroy(power_log);
+
+ // This has a 2 character prefix offset from the previous test when dumping.
+ // The indentation below is exact, check alignment.
+ /*
+ Signal power history:
+ 12-31 16:00:00.000: [ -12.0 ] sum(-12.0)
+ */
+}
diff --git a/audio_utils/tests/simplelog_tests.cpp b/audio_utils/tests/simplelog_tests.cpp
new file mode 100644
index 0000000..1ef8a83
--- /dev/null
+++ b/audio_utils/tests/simplelog_tests.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2017 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 "audio_utils_errorlog_tests"
+
+#include <audio_utils/SimpleLog.h>
+#include <gtest/gtest.h>
+#include <iostream>
+#include <log/log.h>
+
+using namespace android;
+
+static size_t countNewLines(const std::string &s) {
+ return std::count(s.begin(), s.end(), '\n');
+}
+
+TEST(audio_utils_simplelog, basic) {
+ auto slog = std::make_unique<SimpleLog>();
+ const int64_t oneSecond = 1000000000;
+
+ EXPECT_EQ((size_t)0, countNewLines(slog->dumpToString()));
+
+ const int nine = 9;
+ slog->log("Hello %d", nine);
+ slog->log("World");
+
+ // two lines (no header)
+ EXPECT_EQ((size_t)2, countNewLines(slog->dumpToString()));
+
+ // another two lines (this is out of time order, but the log doesn't care)
+ slog->log(oneSecond /* nowNs */, "Hello World %d", 10);
+ slog->log(oneSecond * 2 /* nowNs */, "%s", "Goodbye");
+
+ EXPECT_EQ((size_t)4, countNewLines(slog->dumpToString()));
+
+ // truncate on lines
+ EXPECT_EQ((size_t)1, countNewLines(slog->dumpToString("" /* prefix */, 1 /* lines */)));
+
+ // truncate on time
+ EXPECT_EQ((size_t)4, countNewLines(
+ slog->dumpToString("" /* prefix */, 0 /* lines */, oneSecond /* limitNs */)));
+
+ // truncate on time (more)
+ EXPECT_EQ((size_t)3, countNewLines(
+ slog->dumpToString("" /* prefix */, 0 /* lines */, oneSecond * 2 /* limitNs */)));
+
+ // truncate on time (more)
+ EXPECT_EQ((size_t)2, countNewLines(
+ slog->dumpToString("" /* prefix */, 0 /* lines */, oneSecond * 2 + 1 /* limitNs */)));
+
+ std::cout << slog->dumpToString() << std::flush;
+
+ slog->dump(0 /* fd (stdout) */, " "); // add a prefix
+
+ // The output below depends on the local time zone and current time.
+ // The indentation below is exact, check alignment.
+ /*
+03-27 14:47:43.567 Hello 9
+03-27 14:47:43.567 World
+12-31 16:00:01.000 Hello World 10
+12-31 16:00:02.000 Goodbye
+ 03-27 14:47:43.567 Hello 9
+ 03-27 14:47:43.567 World
+ 12-31 16:00:01.000 Hello World 10
+ 12-31 16:00:02.000 Goodbye
+ */
+}
diff --git a/brillo/audio/audioservice/Android.mk b/brillo/audio/audioservice/Android.mk
index 16fdb88..ada9fe2 100644
--- a/brillo/audio/audioservice/Android.mk
+++ b/brillo/audio/audioservice/Android.mk
@@ -63,7 +63,7 @@
$(audio_client_sources)
LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl
LOCAL_SHARED_LIBRARIES := $(audio_service_shared_libraries)
-LOCAL_CFLAGS := -Wall -std=c++14
+LOCAL_CFLAGS := -Wall -Werror -std=c++14
include $(BUILD_SHARED_LIBRARY)
# Unit tests for the Brillo audio service.
@@ -105,5 +105,5 @@
libbinderwrapper_test_support \
libchrome_test_helpers \
libgmock
-LOCAL_CFLAGS := -Wno-sign-compare -Wall
+LOCAL_CFLAGS := -Wno-sign-compare -Wall -Werror
include $(BUILD_NATIVE_TEST)
diff --git a/camera/Android.bp b/camera/Android.bp
index 4a2c96f..ba31c56 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -19,7 +19,7 @@
"-Wextra",
"-Werror",
"-fvisibility=hidden",
- "-std=c99",
+ "-std=c11",
],
product_variables: {
diff --git a/camera/docs/docs.html b/camera/docs/docs.html
index 004ecae..e861312 100644
--- a/camera/docs/docs.html
+++ b/camera/docs/docs.html
@@ -190,6 +190,8 @@
><a href="#controls_android.control.videoStabilizationMode">android.control.videoStabilizationMode</a></li>
<li
><a href="#controls_android.control.postRawSensitivityBoost">android.control.postRawSensitivityBoost</a></li>
+ <li
+ ><a href="#controls_android.control.enableZsl">android.control.enableZsl</a></li>
</ul>
</li>
<li>
@@ -290,6 +292,8 @@
><a href="#dynamic_android.control.videoStabilizationMode">android.control.videoStabilizationMode</a></li>
<li
><a href="#dynamic_android.control.postRawSensitivityBoost">android.control.postRawSensitivityBoost</a></li>
+ <li
+ ><a href="#dynamic_android.control.enableZsl">android.control.enableZsl</a></li>
</ul>
</li>
</ul> <!-- toc_section -->
@@ -4226,6 +4230,93 @@
<tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
<!-- end of entry -->
+
+ <tr class="entry" id="controls_android.control.enableZsl">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>enable<wbr/>Zsl
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public as boolean]</span>
+
+
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">FALSE</span>
+ <span class="entry_type_enum_notes"><p>Requests with <a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> == STILL_<wbr/>CAPTURE must be captured
+after previous requests.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">TRUE</span>
+ <span class="entry_type_enum_notes"><p>Requests with <a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> == STILL_<wbr/>CAPTURE may or may not be
+captured before previous requests.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Allow camera device to enable zero-shutter-lag mode for requests with
+<a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> == STILL_<wbr/>CAPTURE.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If enableZsl is <code>true</code>,<wbr/> the camera device may enable zero-shutter-lag mode for requests with
+STILL_<wbr/>CAPTURE capture intent.<wbr/> The camera device may use images captured in the past to
+produce output images for a zero-shutter-lag request.<wbr/> The result metadata including the
+<a href="#dynamic_android.sensor.timestamp">android.<wbr/>sensor.<wbr/>timestamp</a> reflects the source frames used to produce output images.<wbr/>
+Therefore,<wbr/> the contents of the output images and the result metadata may be out of order
+compared to previous regular requests.<wbr/> enableZsl does not affect requests with other
+capture intents.<wbr/></p>
+<p>For example,<wbr/> when requests are submitted in the following order:
+ Request A: enableZsl is ON,<wbr/> <a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> is PREVIEW
+ Request B: enableZsl is ON,<wbr/> <a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> is STILL_<wbr/>CAPTURE</p>
+<p>The output images for request B may have contents captured before the output images for
+request A,<wbr/> and the result metadata for request B may be older than the result metadata for
+request A.<wbr/></p>
+<p>Note that when enableZsl is <code>true</code>,<wbr/> it is not guaranteed to get output images captured in
+the past for requests with STILL_<wbr/>CAPTURE capture intent.<wbr/></p>
+<p>For applications targeting SDK versions O and newer,<wbr/> the value of enableZsl in
+TEMPLATE_<wbr/>STILL_<wbr/>CAPTURE template may be <code>true</code>.<wbr/> The value in other templates is always
+<code>false</code> if present.<wbr/></p>
+<p>For applications targeting SDK versions older than O,<wbr/> the value of enableZsl in all
+capture templates is always <code>false</code> if present.<wbr/></p>
+<p>For application-operated ZSL,<wbr/> use CAMERA3_<wbr/>TEMPLATE_<wbr/>ZERO_<wbr/>SHUTTER_<wbr/>LAG template.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>It is valid for HAL to produce regular output images for requests with STILL_<wbr/>CAPTURE
+capture intent.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
<!-- end of kind -->
@@ -8872,6 +8963,93 @@
<tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
<!-- end of entry -->
+
+ <tr class="entry" id="dynamic_android.control.enableZsl">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>control.<wbr/>enable<wbr/>Zsl
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">byte</span>
+
+ <span class="entry_type_visibility"> [public as boolean]</span>
+
+
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">FALSE</span>
+ <span class="entry_type_enum_notes"><p>Requests with <a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> == STILL_<wbr/>CAPTURE must be captured
+after previous requests.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">TRUE</span>
+ <span class="entry_type_enum_notes"><p>Requests with <a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> == STILL_<wbr/>CAPTURE may or may not be
+captured before previous requests.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Allow camera device to enable zero-shutter-lag mode for requests with
+<a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> == STILL_<wbr/>CAPTURE.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>If enableZsl is <code>true</code>,<wbr/> the camera device may enable zero-shutter-lag mode for requests with
+STILL_<wbr/>CAPTURE capture intent.<wbr/> The camera device may use images captured in the past to
+produce output images for a zero-shutter-lag request.<wbr/> The result metadata including the
+<a href="#dynamic_android.sensor.timestamp">android.<wbr/>sensor.<wbr/>timestamp</a> reflects the source frames used to produce output images.<wbr/>
+Therefore,<wbr/> the contents of the output images and the result metadata may be out of order
+compared to previous regular requests.<wbr/> enableZsl does not affect requests with other
+capture intents.<wbr/></p>
+<p>For example,<wbr/> when requests are submitted in the following order:
+ Request A: enableZsl is ON,<wbr/> <a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> is PREVIEW
+ Request B: enableZsl is ON,<wbr/> <a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> is STILL_<wbr/>CAPTURE</p>
+<p>The output images for request B may have contents captured before the output images for
+request A,<wbr/> and the result metadata for request B may be older than the result metadata for
+request A.<wbr/></p>
+<p>Note that when enableZsl is <code>true</code>,<wbr/> it is not guaranteed to get output images captured in
+the past for requests with STILL_<wbr/>CAPTURE capture intent.<wbr/></p>
+<p>For applications targeting SDK versions O and newer,<wbr/> the value of enableZsl in
+TEMPLATE_<wbr/>STILL_<wbr/>CAPTURE template may be <code>true</code>.<wbr/> The value in other templates is always
+<code>false</code> if present.<wbr/></p>
+<p>For applications targeting SDK versions older than O,<wbr/> the value of enableZsl in all
+capture templates is always <code>false</code> if present.<wbr/></p>
+<p>For application-operated ZSL,<wbr/> use CAMERA3_<wbr/>TEMPLATE_<wbr/>ZERO_<wbr/>SHUTTER_<wbr/>LAG template.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="5">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="5">
+ <p>It is valid for HAL to produce regular output images for requests with STILL_<wbr/>CAPTURE
+capture intent.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
+ <!-- end of entry -->
+
<!-- end of kind -->
diff --git a/camera/docs/metadata_properties.xml b/camera/docs/metadata_properties.xml
index a1a5fac..f800efe 100644
--- a/camera/docs/metadata_properties.xml
+++ b/camera/docs/metadata_properties.xml
@@ -2792,6 +2792,58 @@
<clone entry="android.control.postRawSensitivityBoost" kind="controls">
</clone>
</dynamic>
+ <controls>
+ <entry name="enableZsl" type="byte" visibility="public" enum="true" typedef="boolean">
+ <enum>
+ <value>FALSE
+ <notes>Requests with android.control.captureIntent == STILL_CAPTURE must be captured
+ after previous requests.</notes></value>
+ <value>TRUE
+ <notes>Requests with android.control.captureIntent == STILL_CAPTURE may or may not be
+ captured before previous requests.</notes></value>
+ </enum>
+ <description>Allow camera device to enable zero-shutter-lag mode for requests with
+ android.control.captureIntent == STILL_CAPTURE.
+ </description>
+ <details>
+ If enableZsl is `true`, the camera device may enable zero-shutter-lag mode for requests with
+ STILL_CAPTURE capture intent. The camera device may use images captured in the past to
+ produce output images for a zero-shutter-lag request. The result metadata including the
+ android.sensor.timestamp reflects the source frames used to produce output images.
+ Therefore, the contents of the output images and the result metadata may be out of order
+ compared to previous regular requests. enableZsl does not affect requests with other
+ capture intents.
+
+ For example, when requests are submitted in the following order:
+ Request A: enableZsl is ON, android.control.captureIntent is PREVIEW
+ Request B: enableZsl is ON, android.control.captureIntent is STILL_CAPTURE
+
+ The output images for request B may have contents captured before the output images for
+ request A, and the result metadata for request B may be older than the result metadata for
+ request A.
+
+ Note that when enableZsl is `true`, it is not guaranteed to get output images captured in
+ the past for requests with STILL_CAPTURE capture intent.
+
+ For applications targeting SDK versions O and newer, the value of enableZsl in
+ TEMPLATE_STILL_CAPTURE template may be `true`. The value in other templates is always
+ `false` if present.
+
+ For applications targeting SDK versions older than O, the value of enableZsl in all
+ capture templates is always `false` if present.
+
+ For application-operated ZSL, use CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG template.
+ </details>
+ <hal_details>
+ It is valid for HAL to produce regular output images for requests with STILL_CAPTURE
+ capture intent.
+ </hal_details>
+ </entry>
+ </controls>
+ <dynamic>
+ <clone entry="android.control.enableZsl" kind="controls">
+ </clone>
+ </dynamic>
</section>
<section name="demosaic">
<controls>
diff --git a/camera/docs/ndk_metadata_properties.xml b/camera/docs/ndk_metadata_properties.xml
index a424c3d..cb346f3 100644
--- a/camera/docs/ndk_metadata_properties.xml
+++ b/camera/docs/ndk_metadata_properties.xml
@@ -2810,6 +2810,58 @@
<clone entry="android.control.postRawSensitivityBoost" kind="controls">
</clone>
</dynamic>
+ <controls>
+ <entry name="enableZsl" type="byte" visibility="public" enum="true" typedef="boolean">
+ <enum>
+ <value>FALSE
+ <notes>Requests with android.control.captureIntent == STILL_CAPTURE must be captured
+ after previous requests.</notes></value>
+ <value>TRUE
+ <notes>Requests with android.control.captureIntent == STILL_CAPTURE may or may not be
+ captured before previous requests.</notes></value>
+ </enum>
+ <description>Allow camera device to enable zero-shutter-lag mode for requests with
+ android.control.captureIntent == STILL_CAPTURE.
+ </description>
+ <details>
+ If enableZsl is `true`, the camera device may enable zero-shutter-lag mode for requests with
+ STILL_CAPTURE capture intent. The camera device may use images captured in the past to
+ produce output images for a zero-shutter-lag request. The result metadata including the
+ android.sensor.timestamp reflects the source frames used to produce output images.
+ Therefore, the contents of the output images and the result metadata may be out of order
+ compared to previous regular requests. enableZsl does not affect requests with other
+ capture intents.
+
+ For example, when requests are submitted in the following order:
+ Request A: enableZsl is `true`, android.control.captureIntent is PREVIEW
+ Request B: enableZsl is `true`, android.control.captureIntent is STILL_CAPTURE
+
+ The output images for request B may have contents captured before the output images for
+ request A, and the result metadata for request B may be older than the result metadata for
+ request A.
+
+ Note that when enableZsl is `true`, it is not guaranteed to get output images captured in the
+ past for requests with STILL_CAPTURE capture intent.
+
+ For applications targeting SDK versions O and newer, the value of enableZsl in
+ TEMPLATE_STILL_CAPTURE template may be `true`. The value in other templates is always
+ `false` if present.
+
+ For applications targeting SDK versions older than O, the value of enableZsl in all
+ capture templates is always `false` if present.
+
+ For application-operated ZSL, use CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG template.
+ </details>
+ <hal_details>
+ It is valid for HAL to produce regular output images for requests with STILL_CAPTURE
+ capture intent.
+ </hal_details>
+ </entry>
+ </controls>
+ <dynamic>
+ <clone entry="android.control.enableZsl" kind="controls">
+ </clone>
+ </dynamic>
</section>
<section name="demosaic">
<controls>
diff --git a/camera/include/system/camera_metadata.h b/camera/include/system/camera_metadata.h
index 9de902b..46e7ac0 100644
--- a/camera/include/system/camera_metadata.h
+++ b/camera/include/system/camera_metadata.h
@@ -20,7 +20,6 @@
#include <string.h>
#include <stdint.h>
#include <cutils/compiler.h>
-#include <system/camera_vendor_tags.h>
#ifdef __cplusplus
extern "C" {
@@ -279,6 +278,13 @@
camera_metadata_t *copy_camera_metadata(void *dst, size_t dst_size,
const camera_metadata_t *src);
+
+// Non-zero return values for validate_camera_metadata_structure
+enum {
+ CAMERA_METADATA_VALIDATION_ERROR = 1,
+ CAMERA_METADATA_VALIDATION_SHIFTED = 2,
+};
+
/**
* Validate that a metadata is structurally sane. That is, its internal
* state is such that we won't get buffer overflows or run into other
@@ -290,7 +296,11 @@
*
* The expected_size argument is optional.
*
- * Returns 0 on success. A non-0 value is returned on error.
+ * Returns 0: on success
+ * CAMERA_METADATA_VALIDATION_ERROR: on error
+ * CAMERA_METADATA_VALIDATION_SHIFTED: when the data is not properly aligned, but can be
+ * used as input of clone_camera_metadata and the returned metadata will be valid.
+ *
*/
ANDROID_API
int validate_camera_metadata_structure(const camera_metadata_t *metadata,
@@ -448,6 +458,29 @@
int get_camera_metadata_tag_type(uint32_t tag);
/**
+ * Retrieve human-readable name of section the tag is in. Returns NULL if
+ * no such tag is defined.
+ */
+ANDROID_API
+const char *get_local_camera_metadata_section_name(uint32_t tag,
+ const camera_metadata_t *meta);
+
+/**
+ * Retrieve human-readable name of tag (not including section). Returns NULL if
+ * no such tag is defined.
+ */
+ANDROID_API
+const char *get_local_camera_metadata_tag_name(uint32_t tag,
+ const camera_metadata_t *meta);
+
+/**
+ * Retrieve the type of a tag. Returns -1 if no such tag is defined.
+ */
+ANDROID_API
+int get_local_camera_metadata_tag_type(uint32_t tag,
+ const camera_metadata_t *meta);
+
+/**
* Set up vendor-specific tag query methods. These are needed to properly add
* entries with vendor-specified tags and to use the
* get_camera_metadata_section_name, _tag_name, and _tag_type methods with
diff --git a/camera/include/system/camera_metadata_tags.h b/camera/include/system/camera_metadata_tags.h
index 81dac87..9c2956f 100644
--- a/camera/include/system/camera_metadata_tags.h
+++ b/camera/include/system/camera_metadata_tags.h
@@ -160,6 +160,7 @@
ANDROID_CONTROL_AVAILABLE_MODES, // byte[] | public
ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE, // int32[] | public
ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST, // int32 | public
+ ANDROID_CONTROL_ENABLE_ZSL, // enum | public
ANDROID_CONTROL_END,
ANDROID_DEMOSAIC_MODE = // enum | system
@@ -605,6 +606,12 @@
ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE,
} camera_metadata_enum_android_control_awb_lock_available_t;
+// ANDROID_CONTROL_ENABLE_ZSL
+typedef enum camera_metadata_enum_android_control_enable_zsl {
+ ANDROID_CONTROL_ENABLE_ZSL_FALSE,
+ ANDROID_CONTROL_ENABLE_ZSL_TRUE,
+} camera_metadata_enum_android_control_enable_zsl_t;
+
// ANDROID_DEMOSAIC_MODE
typedef enum camera_metadata_enum_android_demosaic_mode {
diff --git a/camera/include/system/camera_vendor_tags.h b/camera/include/system/camera_vendor_tags.h
index 57cba49..0bb5426 100644
--- a/camera/include/system/camera_vendor_tags.h
+++ b/camera/include/system/camera_vendor_tags.h
@@ -22,6 +22,9 @@
#endif
#define CAMERA_METADATA_VENDOR_TAG_BOUNDARY 0x80000000u
+#define CAMERA_METADATA_INVALID_VENDOR_ID UINT64_MAX
+
+typedef uint64_t metadata_vendor_id_t;
/**
* Vendor tags:
@@ -90,6 +93,63 @@
void* reserved[8];
};
+struct vendor_tag_cache_ops {
+ /**
+ * Get the number of vendor tags supported on this platform. Used to
+ * calculate the size of buffer needed for holding the array of all tags
+ * returned by get_all_tags(). This must return -1 on error.
+ */
+ int (*get_tag_count)(metadata_vendor_id_t id);
+
+ /**
+ * Fill an array with all of the supported vendor tags on this platform.
+ * get_tag_count() must return the number of tags supported, and
+ * tag_array will be allocated with enough space to hold the number of tags
+ * returned by get_tag_count().
+ */
+ void (*get_all_tags)(uint32_t *tag_array, metadata_vendor_id_t id);
+
+ /**
+ * Get the vendor section name for a vendor-specified entry tag. This will
+ * only be called for vendor-defined tags.
+ *
+ * The naming convention for the vendor-specific section names should
+ * follow a style similar to the Java package style. For example,
+ * CameraZoom Inc. must prefix their sections with "com.camerazoom."
+ * This must return NULL if the tag is outside the bounds of
+ * vendor-defined sections.
+ *
+ * There may be different vendor-defined tag sections, for example the
+ * phone maker, the chipset maker, and the camera module maker may each
+ * have their own "com.vendor."-prefixed section.
+ *
+ * The memory pointed to by the return value must remain valid for the
+ * lifetime of the module, and is owned by the module.
+ */
+ const char *(*get_section_name)(uint32_t tag, metadata_vendor_id_t id);
+
+ /**
+ * Get the tag name for a vendor-specified entry tag. This is only called
+ * for vendor-defined tags, and must return NULL if it is not a
+ * vendor-defined tag.
+ *
+ * The memory pointed to by the return value must remain valid for the
+ * lifetime of the module, and is owned by the module.
+ */
+ const char *(*get_tag_name)(uint32_t tag, metadata_vendor_id_t id);
+
+ /**
+ * Get tag type for a vendor-specified entry tag. The type returned must be
+ * a valid type defined in camera_metadata.h. This method is only called
+ * for tags >= CAMERA_METADATA_VENDOR_TAG_BOUNDARY, and must return
+ * -1 if the tag is outside the bounds of the vendor-defined sections.
+ */
+ int (*get_tag_type)(uint32_t tag, metadata_vendor_id_t id);
+
+ /* Reserved for future use. These must be initialized to NULL. */
+ void* reserved[8];
+};
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/camera/src/camera_metadata.c b/camera/src/camera_metadata.c
index 156f5ab..dc80086 100644
--- a/camera/src/camera_metadata.c
+++ b/camera/src/camera_metadata.c
@@ -101,7 +101,8 @@
metadata_size_t data_count;
metadata_size_t data_capacity;
metadata_uptrdiff_t data_start; // Offset from camera_metadata
- uint8_t reserved[];
+ uint32_t padding; // padding to 8 bytes boundary
+ metadata_vendor_id_t vendor_id;
};
/**
@@ -120,6 +121,49 @@
camera_metadata_rational_t r;
} camera_metadata_data_t;
+_Static_assert(sizeof(metadata_size_t) == 4,
+ "Size of metadata_size_t must be 4");
+_Static_assert(sizeof(metadata_uptrdiff_t) == 4,
+ "Size of metadata_uptrdiff_t must be 4");
+_Static_assert(sizeof(metadata_vendor_id_t) == 8,
+ "Size of metadata_vendor_id_t must be 8");
+_Static_assert(sizeof(camera_metadata_data_t) == 8,
+ "Size of camera_metadata_data_t must be 8");
+
+_Static_assert(offsetof(camera_metadata_buffer_entry_t, tag) == 0,
+ "Offset of tag must be 0");
+_Static_assert(offsetof(camera_metadata_buffer_entry_t, count) == 4,
+ "Offset of count must be 4");
+_Static_assert(offsetof(camera_metadata_buffer_entry_t, data) == 8,
+ "Offset of data must be 8");
+_Static_assert(offsetof(camera_metadata_buffer_entry_t, type) == 12,
+ "Offset of type must be 12");
+_Static_assert(sizeof(camera_metadata_buffer_entry_t) == 16,
+ "Size of camera_metadata_buffer_entry_t must be 16");
+
+_Static_assert(offsetof(camera_metadata_t, size) == 0,
+ "Offset of size must be 0");
+_Static_assert(offsetof(camera_metadata_t, version) == 4,
+ "Offset of version must be 4");
+_Static_assert(offsetof(camera_metadata_t, flags) == 8,
+ "Offset of flags must be 8");
+_Static_assert(offsetof(camera_metadata_t, entry_count) == 12,
+ "Offset of entry_count must be 12");
+_Static_assert(offsetof(camera_metadata_t, entry_capacity) == 16,
+ "Offset of entry_capacity must be 16");
+_Static_assert(offsetof(camera_metadata_t, entries_start) == 20,
+ "Offset of entries_start must be 20");
+_Static_assert(offsetof(camera_metadata_t, data_count) == 24,
+ "Offset of data_count must be 24");
+_Static_assert(offsetof(camera_metadata_t, data_capacity) == 28,
+ "Offset of data_capacity must be 28");
+_Static_assert(offsetof(camera_metadata_t, data_start) == 32,
+ "Offset of data_start must be 32");
+_Static_assert(offsetof(camera_metadata_t, vendor_id) == 40,
+ "Offset of vendor_id must be 40");
+_Static_assert(sizeof(camera_metadata_t) == 48,
+ "Size of camera_metadata_t must be 48");
+
/**
* The preferred alignment of a packet of camera metadata. In general,
* this is the lowest common multiple of the constituents of a metadata
@@ -127,7 +171,7 @@
*/
#define MAX_ALIGNMENT(A, B) (((A) > (B)) ? (A) : (B))
#define METADATA_PACKET_ALIGNMENT \
- MAX_ALIGNMENT(MAX_ALIGNMENT(DATA_ALIGNMENT, METADATA_ALIGNMENT), ENTRY_ALIGNMENT);
+ MAX_ALIGNMENT(MAX_ALIGNMENT(DATA_ALIGNMENT, METADATA_ALIGNMENT), ENTRY_ALIGNMENT)
/** Versioning information */
#define CURRENT_METADATA_VERSION 1
@@ -236,6 +280,7 @@
size_t data_unaligned = (uint8_t*)(get_entries(metadata) +
metadata->entry_capacity) - (uint8_t*)metadata;
metadata->data_start = ALIGN_TO(data_unaligned, DATA_ALIGNMENT);
+ metadata->vendor_id = CAMERA_METADATA_INVALID_VENDOR_ID;
assert(validate_camera_metadata_structure(metadata, NULL) == OK);
return metadata;
@@ -253,6 +298,8 @@
// Start buffer list at aligned boundary
memory_needed = ALIGN_TO(memory_needed, DATA_ALIGNMENT);
memory_needed += sizeof(uint8_t[data_count]);
+ // Make sure camera metadata can be stacked in continuous memory
+ memory_needed = ALIGN_TO(memory_needed, METADATA_PACKET_ALIGNMENT);
return memory_needed;
}
@@ -298,6 +345,7 @@
metadata->flags = src->flags;
metadata->entry_count = src->entry_count;
metadata->data_count = src->data_count;
+ metadata->vendor_id = src->vendor_id;
memcpy(get_entries(metadata), get_entries(src),
sizeof(camera_metadata_buffer_entry_t[metadata->entry_count]));
@@ -345,9 +393,12 @@
if (metadata == NULL) {
ALOGE("%s: metadata is null!", __FUNCTION__);
- return ERROR;
+ return CAMERA_METADATA_VALIDATION_ERROR;
}
+ uintptr_t aligned_ptr = ALIGN_TO(metadata, METADATA_PACKET_ALIGNMENT);
+ const uintptr_t alignmentOffset = aligned_ptr - (uintptr_t) metadata;
+
// Check that the metadata pointer is well-aligned first.
{
static const struct {
@@ -369,14 +420,15 @@
};
for (size_t i = 0; i < sizeof(alignments)/sizeof(alignments[0]); ++i) {
- uintptr_t aligned_ptr = ALIGN_TO(metadata, alignments[i].alignment);
+ uintptr_t aligned_ptr = ALIGN_TO((uintptr_t) metadata + alignmentOffset,
+ alignments[i].alignment);
- if ((uintptr_t)metadata != aligned_ptr) {
+ if ((uintptr_t)metadata + alignmentOffset != aligned_ptr) {
ALOGE("%s: Metadata pointer is not aligned (actual %p, "
- "expected %p) to type %s",
+ "expected %p, offset %" PRIuPTR ") to type %s",
__FUNCTION__, metadata,
- (void*)aligned_ptr, alignments[i].name);
- return ERROR;
+ (void*)aligned_ptr, alignmentOffset, alignments[i].name);
+ return CAMERA_METADATA_VALIDATION_ERROR;
}
}
}
@@ -388,14 +440,14 @@
if (expected_size != NULL && metadata->size > *expected_size) {
ALOGE("%s: Metadata size (%" PRIu32 ") should be <= expected size (%zu)",
__FUNCTION__, metadata->size, *expected_size);
- return ERROR;
+ return CAMERA_METADATA_VALIDATION_ERROR;
}
if (metadata->entry_count > metadata->entry_capacity) {
ALOGE("%s: Entry count (%" PRIu32 ") should be <= entry capacity "
"(%" PRIu32 ")",
__FUNCTION__, metadata->entry_count, metadata->entry_capacity);
- return ERROR;
+ return CAMERA_METADATA_VALIDATION_ERROR;
}
if (metadata->data_count > metadata->data_capacity) {
@@ -403,7 +455,7 @@
"(%" PRIu32 ")",
__FUNCTION__, metadata->data_count, metadata->data_capacity);
android_errorWriteLog(SN_EVENT_LOG_ID, "30591838");
- return ERROR;
+ return CAMERA_METADATA_VALIDATION_ERROR;
}
const metadata_uptrdiff_t entries_end =
@@ -416,7 +468,7 @@
__FUNCTION__,
(metadata->entries_start + metadata->entry_capacity),
metadata->data_start);
- return ERROR;
+ return CAMERA_METADATA_VALIDATION_ERROR;
}
const metadata_uptrdiff_t data_end =
@@ -429,7 +481,7 @@
__FUNCTION__,
(metadata->data_start + metadata->data_capacity),
metadata->size);
- return ERROR;
+ return CAMERA_METADATA_VALIDATION_ERROR;
}
// Validate each entry
@@ -438,11 +490,12 @@
for (size_t i = 0; i < entry_count; ++i) {
- if ((uintptr_t)&entries[i] != ALIGN_TO(&entries[i], ENTRY_ALIGNMENT)) {
+ if ((uintptr_t)&entries[i] + alignmentOffset !=
+ ALIGN_TO((uintptr_t)&entries[i] + alignmentOffset, ENTRY_ALIGNMENT)) {
ALOGE("%s: Entry index %zu had bad alignment (address %p),"
" expected alignment %zu",
__FUNCTION__, i, &entries[i], ENTRY_ALIGNMENT);
- return ERROR;
+ return CAMERA_METADATA_VALIDATION_ERROR;
}
camera_metadata_buffer_entry_t entry = entries[i];
@@ -450,17 +503,17 @@
if (entry.type >= NUM_TYPES) {
ALOGE("%s: Entry index %zu had a bad type %d",
__FUNCTION__, i, entry.type);
- return ERROR;
+ return CAMERA_METADATA_VALIDATION_ERROR;
}
// TODO: fix vendor_tag_ops across processes so we don't need to special
// case vendor-specific tags
uint32_t tag_section = entry.tag >> 16;
- int tag_type = get_camera_metadata_tag_type(entry.tag);
+ int tag_type = get_local_camera_metadata_tag_type(entry.tag, metadata);
if (tag_type != (int)entry.type && tag_section < VENDOR_SECTION) {
ALOGE("%s: Entry index %zu had tag type %d, but the type was %d",
__FUNCTION__, i, tag_type, entry.type);
- return ERROR;
+ return CAMERA_METADATA_VALIDATION_ERROR;
}
size_t data_size;
@@ -468,7 +521,7 @@
entry.count) != OK) {
ALOGE("%s: Entry data size is invalid. type: %u count: %u", __FUNCTION__, entry.type,
entry.count);
- return ERROR;
+ return CAMERA_METADATA_VALIDATION_ERROR;
}
if (data_size != 0) {
@@ -476,13 +529,14 @@
(camera_metadata_data_t*) (get_data(metadata) +
entry.data.offset);
- if ((uintptr_t)data != ALIGN_TO(data, DATA_ALIGNMENT)) {
+ if ((uintptr_t)data + alignmentOffset !=
+ ALIGN_TO((uintptr_t)data + alignmentOffset, DATA_ALIGNMENT)) {
ALOGE("%s: Entry index %zu had bad data alignment (address %p),"
" expected align %zu, (tag name %s, data size %zu)",
__FUNCTION__, i, data, DATA_ALIGNMENT,
- get_camera_metadata_tag_name(entry.tag) ?: "unknown",
- data_size);
- return ERROR;
+ get_local_camera_metadata_tag_name(entry.tag, metadata) ?
+ : "unknown", data_size);
+ return CAMERA_METADATA_VALIDATION_ERROR;
}
size_t data_entry_end = entry.data.offset + data_size;
@@ -492,20 +546,23 @@
ALOGE("%s: Entry index %zu data ends (%zu) beyond the capacity "
"%" PRIu32, __FUNCTION__, i, data_entry_end,
metadata->data_capacity);
- return ERROR;
+ return CAMERA_METADATA_VALIDATION_ERROR;
}
} else if (entry.count == 0) {
if (entry.data.offset != 0) {
ALOGE("%s: Entry index %zu had 0 items, but offset was non-0 "
"(%" PRIu32 "), tag name: %s", __FUNCTION__, i, entry.data.offset,
- get_camera_metadata_tag_name(entry.tag) ?: "unknown");
- return ERROR;
+ get_local_camera_metadata_tag_name(entry.tag, metadata) ? : "unknown");
+ return CAMERA_METADATA_VALIDATION_ERROR;
}
} // else data stored inline, so we look at value which can be anything.
}
- return OK;
+ if (alignmentOffset == 0) {
+ return OK;
+ }
+ return CAMERA_METADATA_VALIDATION_SHIFTED;
}
int append_camera_metadata(camera_metadata_t *dst,
@@ -519,6 +576,15 @@
if (dst->entry_capacity < src->entry_count + dst->entry_count) return ERROR;
if (dst->data_capacity < src->data_count + dst->data_count) return ERROR;
+ if ((dst->vendor_id != CAMERA_METADATA_INVALID_VENDOR_ID) &&
+ (src->vendor_id != CAMERA_METADATA_INVALID_VENDOR_ID)) {
+ if (dst->vendor_id != src->vendor_id) {
+ ALOGE("%s: Append for metadata from different vendors is"
+ "not supported!", __func__);
+ return ERROR;
+ }
+ }
+
memcpy(get_entries(dst) + dst->entry_count, get_entries(src),
sizeof(camera_metadata_buffer_entry_t[src->entry_count]));
memcpy(get_data(dst) + dst->data_count, get_data(src),
@@ -544,6 +610,10 @@
dst->entry_count += src->entry_count;
dst->data_count += src->data_count;
+ if (dst->vendor_id == CAMERA_METADATA_INVALID_VENDOR_ID) {
+ dst->vendor_id = src->vendor_id;
+ }
+
assert(validate_camera_metadata_structure(dst, NULL) == OK);
return OK;
}
@@ -607,7 +677,7 @@
const void *data,
size_t data_count) {
- int type = get_camera_metadata_tag_type(tag);
+ int type = get_local_camera_metadata_tag_type(tag, dst);
if (type == -1) {
ALOGE("%s: Unknown tag %04x.", __FUNCTION__, tag);
return ERROR;
@@ -826,10 +896,16 @@
}
static const vendor_tag_ops_t *vendor_tag_ops = NULL;
+static const struct vendor_tag_cache_ops *vendor_cache_ops = NULL;
-const char *get_camera_metadata_section_name(uint32_t tag) {
+// Declared in system/media/private/camera/include/camera_metadata_hidden.h
+const char *get_local_camera_metadata_section_name_vendor_id(uint32_t tag,
+ metadata_vendor_id_t id) {
uint32_t tag_section = tag >> 16;
- if (tag_section >= VENDOR_SECTION && vendor_tag_ops != NULL) {
+ if (tag_section >= VENDOR_SECTION && vendor_cache_ops != NULL &&
+ id != CAMERA_METADATA_INVALID_VENDOR_ID) {
+ return vendor_cache_ops->get_section_name(tag, id);
+ } else if (tag_section >= VENDOR_SECTION && vendor_tag_ops != NULL) {
return vendor_tag_ops->get_section_name(
vendor_tag_ops,
tag);
@@ -840,9 +916,14 @@
return camera_metadata_section_names[tag_section];
}
-const char *get_camera_metadata_tag_name(uint32_t tag) {
+// Declared in system/media/private/camera/include/camera_metadata_hidden.h
+const char *get_local_camera_metadata_tag_name_vendor_id(uint32_t tag,
+ metadata_vendor_id_t id) {
uint32_t tag_section = tag >> 16;
- if (tag_section >= VENDOR_SECTION && vendor_tag_ops != NULL) {
+ if (tag_section >= VENDOR_SECTION && vendor_cache_ops != NULL &&
+ id != CAMERA_METADATA_INVALID_VENDOR_ID) {
+ return vendor_cache_ops->get_tag_name(tag, id);
+ } else if (tag_section >= VENDOR_SECTION && vendor_tag_ops != NULL) {
return vendor_tag_ops->get_tag_name(
vendor_tag_ops,
tag);
@@ -855,9 +936,14 @@
return tag_info[tag_section][tag_index].tag_name;
}
-int get_camera_metadata_tag_type(uint32_t tag) {
+// Declared in system/media/private/camera/include/camera_metadata_hidden.h
+int get_local_camera_metadata_tag_type_vendor_id(uint32_t tag,
+ metadata_vendor_id_t id) {
uint32_t tag_section = tag >> 16;
- if (tag_section >= VENDOR_SECTION && vendor_tag_ops != NULL) {
+ if (tag_section >= VENDOR_SECTION && vendor_cache_ops != NULL &&
+ id != CAMERA_METADATA_INVALID_VENDOR_ID) {
+ return vendor_cache_ops->get_tag_type(tag, id);
+ } else if (tag_section >= VENDOR_SECTION && vendor_tag_ops != NULL) {
return vendor_tag_ops->get_tag_type(
vendor_tag_ops,
tag);
@@ -870,6 +956,42 @@
return tag_info[tag_section][tag_index].tag_type;
}
+const char *get_camera_metadata_section_name(uint32_t tag) {
+ return get_local_camera_metadata_section_name(tag, NULL);
+}
+
+const char *get_camera_metadata_tag_name(uint32_t tag) {
+ return get_local_camera_metadata_tag_name(tag, NULL);
+}
+
+int get_camera_metadata_tag_type(uint32_t tag) {
+ return get_local_camera_metadata_tag_type(tag, NULL);
+}
+
+const char *get_local_camera_metadata_section_name(uint32_t tag,
+ const camera_metadata_t *meta) {
+ metadata_vendor_id_t id = (NULL == meta) ? CAMERA_METADATA_INVALID_VENDOR_ID :
+ meta->vendor_id;
+
+ return get_local_camera_metadata_section_name_vendor_id(tag, id);
+}
+
+const char *get_local_camera_metadata_tag_name(uint32_t tag,
+ const camera_metadata_t *meta) {
+ metadata_vendor_id_t id = (NULL == meta) ? CAMERA_METADATA_INVALID_VENDOR_ID :
+ meta->vendor_id;
+
+ return get_local_camera_metadata_tag_name_vendor_id(tag, id);
+}
+
+int get_local_camera_metadata_tag_type(uint32_t tag,
+ const camera_metadata_t *meta) {
+ metadata_vendor_id_t id = (NULL == meta) ? CAMERA_METADATA_INVALID_VENDOR_ID :
+ meta->vendor_id;
+
+ return get_local_camera_metadata_tag_type_vendor_id(tag, id);
+}
+
int set_camera_metadata_vendor_tag_ops(const vendor_tag_query_ops_t* ops) {
// **DEPRECATED**
(void) ops;
@@ -883,6 +1005,33 @@
return OK;
}
+// Declared in system/media/private/camera/include/camera_metadata_hidden.h
+int set_camera_metadata_vendor_cache_ops(
+ const struct vendor_tag_cache_ops *query_cache_ops) {
+ vendor_cache_ops = query_cache_ops;
+ return OK;
+}
+
+// Declared in system/media/private/camera/include/camera_metadata_hidden.h
+void set_camera_metadata_vendor_id(camera_metadata_t *meta,
+ metadata_vendor_id_t id) {
+ if (NULL != meta) {
+ meta->vendor_id = id;
+ }
+}
+
+// Declared in system/media/private/camera/include/camera_metadata_hidden.h
+metadata_vendor_id_t get_camera_metadata_vendor_id(
+ const camera_metadata_t *meta) {
+ metadata_vendor_id_t ret = CAMERA_METADATA_INVALID_VENDOR_ID;
+
+ if (NULL != meta) {
+ ret = meta->vendor_id;
+ }
+
+ return ret;
+}
+
static void print_data(int fd, const uint8_t *data_ptr, uint32_t tag, int type,
int count,
int indentation);
@@ -915,11 +1064,11 @@
for (i=0; i < metadata->entry_count; i++, entry++) {
const char *tag_name, *tag_section;
- tag_section = get_camera_metadata_section_name(entry->tag);
+ tag_section = get_local_camera_metadata_section_name(entry->tag, metadata);
if (tag_section == NULL) {
tag_section = "unknownSection";
}
- tag_name = get_camera_metadata_tag_name(entry->tag);
+ tag_name = get_local_camera_metadata_tag_name(entry->tag, metadata);
if (tag_name == NULL) {
tag_name = "unknownTag";
}
diff --git a/camera/src/camera_metadata_tag_info.c b/camera/src/camera_metadata_tag_info.c
index 1716a84..23af44b 100644
--- a/camera/src/camera_metadata_tag_info.c
+++ b/camera/src/camera_metadata_tag_info.c
@@ -216,6 +216,8 @@
{ "postRawSensitivityBoostRange", TYPE_INT32 },
[ ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST - ANDROID_CONTROL_START ] =
{ "postRawSensitivityBoost", TYPE_INT32 },
+ [ ANDROID_CONTROL_ENABLE_ZSL - ANDROID_CONTROL_START ] =
+ { "enableZsl", TYPE_BYTE },
};
static tag_info_t android_demosaic[ANDROID_DEMOSAIC_END -
@@ -1350,6 +1352,21 @@
case ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST: {
break;
}
+ case ANDROID_CONTROL_ENABLE_ZSL: {
+ switch (value) {
+ case ANDROID_CONTROL_ENABLE_ZSL_FALSE:
+ msg = "FALSE";
+ ret = 0;
+ break;
+ case ANDROID_CONTROL_ENABLE_ZSL_TRUE:
+ msg = "TRUE";
+ ret = 0;
+ break;
+ default:
+ msg = "error: enum value out of range";
+ }
+ break;
+ }
case ANDROID_DEMOSAIC_MODE: {
switch (value) {
diff --git a/camera/tests/camera_metadata_tests.cpp b/camera/tests/camera_metadata_tests.cpp
index 121ce19..bcebf2e 100644
--- a/camera/tests/camera_metadata_tests.cpp
+++ b/camera/tests/camera_metadata_tests.cpp
@@ -1870,3 +1870,37 @@
}
}
}
+
+TEST(camera_metadata, buffer_alignment) {
+ // Verify that misaligned metadata buffers only fail VALIDATION_SHIFTED, nothing else
+ const size_t entry_capacity = 50;
+ const size_t data_capacity = 450;
+ const size_t offsetRange = 16;
+ const uint32_t validAlignment = 8;
+
+ camera_metadata_t *m = NULL;
+ m = allocate_camera_metadata(entry_capacity, data_capacity);
+
+ add_test_metadata(m, 15);
+
+ size_t m_size = get_camera_metadata_size(m);
+ size_t dst_size = m_size + offsetRange;
+ uint8_t *dst = new uint8_t[dst_size];
+
+ for (size_t i = 0; i < offsetRange; i++) {
+ memset(dst, 0, dst_size);
+ memcpy(dst + i, m, m_size);
+ camera_metadata_t *m_shifted = (camera_metadata_t*)(dst + i);
+
+ int err = validate_camera_metadata_structure(m_shifted, &m_size);
+ if (i % validAlignment == 0) {
+ ASSERT_EQ(OK, err) << "For alignment shift " << i << ", expected OK" ;
+ } else {
+ ASSERT_EQ(CAMERA_METADATA_VALIDATION_SHIFTED, err) <<
+ "For alignment shift " << i << ", expected VALIDATION_SHIFTED" ;
+ }
+ }
+
+ delete[] dst;
+ FINISH_USING_CAMERA_METADATA(m);
+}
diff --git a/private/camera/include/camera_metadata_hidden.h b/private/camera/include/camera_metadata_hidden.h
index c5e0a39..31f1ad1 100644
--- a/private/camera/include/camera_metadata_hidden.h
+++ b/private/camera/include/camera_metadata_hidden.h
@@ -42,6 +42,57 @@
ANDROID_API
int set_camera_metadata_vendor_ops(const vendor_tag_ops_t *query_ops);
+/**
+ * Set the global vendor tag cache operations object used to define vendor tag
+ * structure when parsing camera metadata with functions defined in
+ * system/media/camera/include/camera_metadata.h.
+ */
+ANDROID_API
+int set_camera_metadata_vendor_cache_ops(
+ const struct vendor_tag_cache_ops *query_cache_ops);
+
+/**
+ * Set the vendor id for a particular metadata buffer.
+ */
+ANDROID_API
+void set_camera_metadata_vendor_id(camera_metadata_t *meta,
+ metadata_vendor_id_t id);
+
+/**
+ * Retrieve the vendor id for a particular metadata buffer.
+ */
+ANDROID_API
+metadata_vendor_id_t get_camera_metadata_vendor_id(
+ const camera_metadata_t *meta);
+
+/**
+ * Retrieve the type of a tag. Returns -1 if no such tag is defined.
+ */
+ANDROID_API
+int get_local_camera_metadata_tag_type_vendor_id(uint32_t tag,
+ metadata_vendor_id_t id);
+
+/**
+ * Retrieve the name of a tag. Returns NULL if no such tag is defined.
+ */
+ANDROID_API
+const char *get_local_camera_metadata_tag_name_vendor_id(uint32_t tag,
+ metadata_vendor_id_t id);
+
+/**
+ * Retrieve the name of a tag section. Returns NULL if no such tag is defined.
+ */
+ANDROID_API
+const char *get_local_camera_metadata_section_name_vendor_id(uint32_t tag,
+ metadata_vendor_id_t id);
+
+/**
+ * Retrieve the type of a tag. Returns -1 if no such tag is defined.
+ */
+ANDROID_API
+int get_local_camera_metadata_tag_type_vendor_id(uint32_t tag,
+ metadata_vendor_id_t id);
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/radio/include/system/radio_metadata.h b/radio/include/system/radio_metadata.h
index 7dc35cc..45db916 100644
--- a/radio/include/system/radio_metadata.h
+++ b/radio/include/system/radio_metadata.h
@@ -46,7 +46,7 @@
RADIO_METADATA_KEY_MIN = RADIO_METADATA_KEY_RDS_PI,
RADIO_METADATA_KEY_MAX = RADIO_METADATA_KEY_CLOCK,
};
-typedef int radio_metadata_key_t;
+typedef int32_t radio_metadata_key_t;
enum {
RADIO_METADATA_TYPE_INVALID = -1,
@@ -56,7 +56,7 @@
RADIO_METADATA_TYPE_RAW = 2, /* raw binary data (icon or art) */
RADIO_METADATA_TYPE_CLOCK = 3, /* clock data, see radio_metadata_clock_t */
};
-typedef int radio_metadata_type_t;
+typedef int32_t radio_metadata_type_t;
typedef struct radio_metadata_clock {
uint64_t utc_seconds_since_epoch; /* Seconds since epoch at GMT + 0. */
@@ -90,8 +90,8 @@
*/
ANDROID_API
int radio_metadata_allocate(radio_metadata_t **metadata,
- const unsigned int channel,
- const unsigned int sub_channel);
+ const uint32_t channel,
+ const uint32_t sub_channel);
/*
* De-allocate a meta data buffer.
@@ -119,7 +119,7 @@
ANDROID_API
int radio_metadata_add_int(radio_metadata_t **metadata,
const radio_metadata_key_t key,
- const int value);
+ const int32_t value);
/*
* Add an text meta data to the buffer.
@@ -159,7 +159,7 @@
int radio_metadata_add_raw(radio_metadata_t **metadata,
const radio_metadata_key_t key,
const unsigned char *value,
- const unsigned int size);
+ const size_t size);
/*
* Add a clock meta data to the buffer.
@@ -255,11 +255,11 @@
*/
ANDROID_API
int radio_metadata_get_at_index(const radio_metadata_t *metadata,
- const unsigned int index,
+ const uint32_t index,
radio_metadata_key_t *key,
radio_metadata_type_t *type,
void **value,
- unsigned int *size);
+ size_t *size);
/*
* Get a meta data with the specified key.
@@ -284,7 +284,24 @@
const radio_metadata_key_t key,
radio_metadata_type_t *type,
void **value,
- unsigned int *size);
+ size_t *size);
+
+/*
+ * Get channel and sub channel associated with metadata.
+ *
+ * arguments:
+ * - metadata: the meta data buffer
+ * - channel: address where to return the channel.
+ * - sub_channel: address where to return the sub channel.
+ *
+ * returns:
+ * 0 if successfully added
+ * -EINVAL if the buffer passed is invalid
+ */
+ANDROID_API
+int radio_metadata_get_channel(radio_metadata_t *metadata,
+ uint32_t *channel,
+ uint32_t *sub_channel);
#ifdef __cplusplus
}
diff --git a/radio/src/radio_metadata.c b/radio/src/radio_metadata.c
index 21a73fc..9e593fb 100644
--- a/radio/src/radio_metadata.c
+++ b/radio/src/radio_metadata.c
@@ -56,14 +56,16 @@
return true;
}
-int check_size(radio_metadata_buffer_t **metadata_ptr, const unsigned int size_int)
+int check_size(radio_metadata_buffer_t **metadata_ptr, const uint32_t size_int)
{
radio_metadata_buffer_t *metadata = *metadata_ptr;
- unsigned int index_offset = metadata->size_int - metadata->count - 1;
- unsigned int data_offset = *((unsigned int *)metadata + index_offset);
- unsigned int req_size_int;
- unsigned int new_size_int;
+ uint32_t index_offset = metadata->size_int - metadata->count - 1;
+ uint32_t data_offset = *((uint32_t *)metadata + index_offset);
+ uint32_t req_size_int;
+ uint32_t new_size_int;
+ LOG_ALWAYS_FATAL_IF(metadata->size_int < (metadata->count + 1),
+ "%s: invalid size %u", __func__, metadata->size_int);
if (size_int == 0) {
return 0;
}
@@ -84,11 +86,11 @@
new_size_int *= 2;
ALOGV("%s growing from %u to %u", __func__, metadata->size_int, new_size_int);
- metadata = realloc(metadata, new_size_int * sizeof(unsigned int));
+ metadata = realloc(metadata, new_size_int * sizeof(uint32_t));
/* move index table */
- memmove((unsigned int *)metadata + new_size_int - (metadata->count + 1),
- (unsigned int *)metadata + metadata->size_int - (metadata->count + 1),
- (metadata->count + 1) * sizeof(unsigned int));
+ memmove((uint32_t *)metadata + new_size_int - (metadata->count + 1),
+ (uint32_t *)metadata + metadata->size_int - (metadata->count + 1),
+ (metadata->count + 1) * sizeof(uint32_t));
metadata->size_int = new_size_int;
*metadata_ptr = metadata;
@@ -100,17 +102,17 @@
const radio_metadata_key_t key,
const radio_metadata_type_t type,
const void *value,
- const unsigned int size)
+ const size_t size)
{
- unsigned int entry_size_int;
+ uint32_t entry_size_int;
int ret;
radio_metadata_entry_t *entry;
- unsigned int index_offset;
- unsigned int data_offset;
+ uint32_t index_offset;
+ uint32_t data_offset;
radio_metadata_buffer_t *metadata = *metadata_ptr;
- entry_size_int = size + sizeof(radio_metadata_entry_t);
- entry_size_int = (entry_size_int + sizeof(unsigned int) - 1) / sizeof(unsigned int);
+ entry_size_int = (uint32_t)(size + sizeof(radio_metadata_entry_t));
+ entry_size_int = (entry_size_int + sizeof(uint32_t) - 1) / sizeof(uint32_t);
ret = check_size(metadata_ptr, entry_size_int);
if (ret < 0) {
@@ -118,17 +120,18 @@
}
metadata = *metadata_ptr;
index_offset = metadata->size_int - metadata->count - 1;
- data_offset = *((unsigned int *)metadata + index_offset);
+ data_offset = *((uint32_t *)metadata + index_offset);
- entry = (radio_metadata_entry_t *)((unsigned int *)metadata + data_offset);
+ entry = (radio_metadata_entry_t *)((uint32_t *)metadata + data_offset);
entry->key = key;
entry->type = type;
- entry->size = size;
+ entry->size = (uint32_t)size;
memcpy(entry->data, value, size);
data_offset += entry_size_int;
- *((unsigned int *)metadata + index_offset -1) = data_offset;
+ *((uint32_t *)metadata + index_offset -1) = data_offset;
metadata->count++;
+
return 0;
}
@@ -137,29 +140,36 @@
const unsigned index,
bool check)
{
- unsigned int index_offset = metadata->size_int - index - 1;
- unsigned int data_offset = *((unsigned int *)metadata + index_offset);
+ uint32_t index_offset = metadata->size_int - index - 1;
+ uint32_t data_offset = *((uint32_t *)metadata + index_offset);
+ LOG_ALWAYS_FATAL_IF(metadata->size_int < (index + 1),
+ "%s: invalid size %u", __func__, metadata->size_int);
if (check) {
if (index >= metadata->count) {
return NULL;
}
- unsigned int min_offset;
- unsigned int max_offset;
- unsigned int min_entry_size_int;
- min_offset = (sizeof(radio_metadata_buffer_t) + sizeof(unsigned int) - 1) /
- sizeof(unsigned int);
+ uint32_t min_offset;
+ uint32_t max_offset;
+ uint32_t min_entry_size_int;
+ min_offset = (sizeof(radio_metadata_buffer_t) + sizeof(uint32_t) - 1) /
+ sizeof(uint32_t);
if (data_offset < min_offset) {
return NULL;
}
min_entry_size_int = 1 + sizeof(radio_metadata_entry_t);
- min_entry_size_int = (min_entry_size_int + sizeof(unsigned int) - 1) / sizeof(unsigned int);
+ min_entry_size_int = (min_entry_size_int + sizeof(uint32_t) - 1) / sizeof(uint32_t);
+
+ LOG_ALWAYS_FATAL_IF(metadata->size_int < (metadata->count + 1),
+ "%s: invalid size %u vs count %u", __func__,
+ metadata->size_int, metadata->count);
+
max_offset = metadata->size_int - metadata->count - 1 - min_entry_size_int;
if (data_offset > max_offset) {
return NULL;
}
}
- return (radio_metadata_entry_t *)((unsigned int *)metadata + data_offset);
+ return (radio_metadata_entry_t *)((uint32_t *)metadata + data_offset);
}
/**
@@ -175,11 +185,11 @@
}
int radio_metadata_allocate(radio_metadata_t **metadata,
- const unsigned int channel,
- const unsigned int sub_channel)
+ const uint32_t channel,
+ const uint32_t sub_channel)
{
radio_metadata_buffer_t *metadata_buf =
- (radio_metadata_buffer_t *)calloc(RADIO_METADATA_DEFAULT_SIZE, sizeof(unsigned int));
+ (radio_metadata_buffer_t *)calloc(RADIO_METADATA_DEFAULT_SIZE, sizeof(uint32_t));
if (metadata_buf == NULL) {
return -ENOMEM;
}
@@ -187,9 +197,9 @@
metadata_buf->channel = channel;
metadata_buf->sub_channel = sub_channel;
metadata_buf->size_int = RADIO_METADATA_DEFAULT_SIZE;
- *((unsigned int *)metadata_buf + RADIO_METADATA_DEFAULT_SIZE - 1) =
- (sizeof(radio_metadata_buffer_t) + sizeof(unsigned int) - 1) /
- sizeof(unsigned int);
+ *((uint32_t *)metadata_buf + RADIO_METADATA_DEFAULT_SIZE - 1) =
+ (sizeof(radio_metadata_buffer_t) + sizeof(uint32_t) - 1) /
+ sizeof(uint32_t);
*metadata = (radio_metadata_t *)metadata_buf;
return 0;
}
@@ -201,14 +211,14 @@
int radio_metadata_add_int(radio_metadata_t **metadata,
const radio_metadata_key_t key,
- const int value)
+ const int32_t value)
{
radio_metadata_type_t type = radio_metadata_type_of_key(key);
if (metadata == NULL || *metadata == NULL || type != RADIO_METADATA_TYPE_INT) {
return -EINVAL;
}
return add_metadata((radio_metadata_buffer_t **)metadata,
- key, type, &value, sizeof(int));
+ key, type, &value, sizeof(int32_t));
}
int radio_metadata_add_text(radio_metadata_t **metadata,
@@ -226,7 +236,7 @@
int radio_metadata_add_raw(radio_metadata_t **metadata,
const radio_metadata_key_t key,
const unsigned char *value,
- const unsigned int size)
+ const size_t size)
{
radio_metadata_type_t type = radio_metadata_type_of_key(key);
if (metadata == NULL || *metadata == NULL || type != RADIO_METADATA_TYPE_RAW || value == NULL) {
@@ -254,7 +264,7 @@
radio_metadata_buffer_t *src_metadata_buf = (radio_metadata_buffer_t *)src_metadata;
radio_metadata_buffer_t *dst_metadata_buf;
int status;
- unsigned int index;
+ uint32_t index;
if (dst_metadata == NULL || src_metadata == NULL) {
return -EINVAL;
@@ -275,7 +285,7 @@
radio_metadata_key_t key;
radio_metadata_type_t type;
void *value;
- unsigned int size;
+ size_t size;
status = radio_metadata_get_at_index(src_metadata, index, &key, &type, &value, &size);
if (status != 0)
continue;
@@ -290,8 +300,8 @@
{
radio_metadata_buffer_t *metadata_buf =
(radio_metadata_buffer_t *)metadata;
- unsigned int count;
- unsigned int min_entry_size_int;
+ uint32_t count;
+ uint32_t min_entry_size_int;
if (metadata_buf == NULL) {
return -EINVAL;
@@ -303,10 +313,10 @@
/* sanity check on entry count versus buffer size */
min_entry_size_int = 1 + sizeof(radio_metadata_entry_t);
- min_entry_size_int = (min_entry_size_int + sizeof(unsigned int) - 1) /
- sizeof(unsigned int);
+ min_entry_size_int = (min_entry_size_int + sizeof(uint32_t) - 1) /
+ sizeof(uint32_t);
if ((metadata_buf->count * min_entry_size_int + metadata_buf->count + 1 +
- (sizeof(radio_metadata_buffer_t) + sizeof(unsigned int) - 1) / sizeof(unsigned int)) >
+ (sizeof(radio_metadata_buffer_t) + sizeof(uint32_t) - 1) / sizeof(uint32_t)) >
metadata_buf->size_int) {
return -EINVAL;
}
@@ -343,7 +353,7 @@
if (metadata_buf == NULL) {
return 0;
}
- return (size_t)(metadata_buf->size_int * sizeof(unsigned int));
+ return metadata_buf->size_int * sizeof(uint32_t);
}
int radio_metadata_get_count(const radio_metadata_t *metadata)
@@ -358,11 +368,11 @@
}
int radio_metadata_get_at_index(const radio_metadata_t *metadata,
- const unsigned int index,
+ const uint32_t index,
radio_metadata_key_t *key,
radio_metadata_type_t *type,
void **value,
- unsigned int *size)
+ size_t *size)
{
radio_metadata_entry_t *entry;
radio_metadata_buffer_t *metadata_buf =
@@ -380,7 +390,7 @@
*key = entry->key;
*type = entry->type;
*value = (void *)entry->data;
- *size = entry->size;
+ *size = (size_t)entry->size;
return 0;
}
@@ -389,9 +399,9 @@
const radio_metadata_key_t key,
radio_metadata_type_t *type,
void **value,
- unsigned int *size)
+ size_t *size)
{
- unsigned int count;
+ uint32_t count;
radio_metadata_entry_t *entry = NULL;
radio_metadata_buffer_t *metadata_buf =
(radio_metadata_buffer_t *)metadata;
@@ -414,6 +424,21 @@
}
*type = entry->type;
*value = (void *)entry->data;
- *size = entry->size;
+ *size = (size_t)entry->size;
+ return 0;
+}
+
+int radio_metadata_get_channel(radio_metadata_t *metadata,
+ uint32_t *channel,
+ uint32_t *sub_channel)
+{
+ radio_metadata_buffer_t *metadata_buf =
+ (radio_metadata_buffer_t *)metadata;
+
+ if (metadata_buf == NULL || channel == NULL || sub_channel == NULL) {
+ return -EINVAL;
+ }
+ *channel = metadata_buf->channel;
+ *sub_channel = metadata_buf->sub_channel;
return 0;
}
diff --git a/radio/src/radio_metadata_hidden.h b/radio/src/radio_metadata_hidden.h
index 1b76aa0..8bdbad4 100644
--- a/radio/src/radio_metadata_hidden.h
+++ b/radio/src/radio_metadata_hidden.h
@@ -30,8 +30,8 @@
typedef struct radio_metadata_entry {
radio_metadata_key_t key;
radio_metadata_type_t type;
- unsigned int size;
- unsigned char data[];
+ uint32_t size;
+ uint8_t data[];
} radio_metadata_entry_t;
@@ -75,10 +75,10 @@
/* Radio meta data buffer header */
typedef struct radio_metadata_buffer {
- unsigned int channel; /* channel (frequency) this meta data is associated with */
- unsigned int sub_channel; /* sub channel this meta data is associated with */
- unsigned int size_int; /* Total size in 32 bit word units */
- unsigned int count; /* number of meta data entries */
+ uint32_t channel; /* channel (frequency) this meta data is associated with */
+ uint32_t sub_channel; /* sub channel this meta data is associated with */
+ uint32_t size_int; /* Total size in 32 bit word units */
+ uint32_t count; /* number of meta data entries */
} radio_metadata_buffer_t;