liboboe: initial checkin of core and legacy files.

Oboe C++ files that calls AudioTrack and AudioRecord.
Main C API implemented by src/core/OboeAudio.cpp

Test: gunit tests for the Legacy mode and handle tracker in tests folder
Bug: 33347409
Change-Id: I50f9fd99377efbd8de6fef1601e9af4c22c6ab46
Signed-off-by: Phil Burk <philburk@google.com>
diff --git a/media/liboboe/src/utility/AudioClock.h b/media/liboboe/src/utility/AudioClock.h
new file mode 100644
index 0000000..da2f74a
--- /dev/null
+++ b/media/liboboe/src/utility/AudioClock.h
@@ -0,0 +1,98 @@
+/*
+ * 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 UTILITY_AUDIOCLOCK_H
+#define UTILITY_AUDIOCLOCK_H
+
+#include <sys/types.h>
+#include <time.h>
+#include "oboe/OboeDefinitions.h"
+#include "oboe/OboeAudio.h"
+
+class AudioClock {
+public:
+    static oboe_nanoseconds_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC) {
+        struct timespec time;
+        int result = clock_gettime(clockId, &time);
+        if (result < 0) {
+            return -errno;
+        }
+        return (time.tv_sec * OBOE_NANOS_PER_SECOND) + time.tv_nsec;
+    }
+
+    /**
+     * Sleep until the specified absolute time.
+     * Return immediately with OBOE_ERROR_ILLEGAL_ARGUMENT if a negative
+     * nanoTime is specified.
+     *
+     * @param nanoTime time to wake up
+     * @param clockId CLOCK_MONOTONIC is default
+     * @return 0, a negative error, or 1 if the call is interrupted by a signal handler (EINTR)
+     */
+    static int sleepUntilNanoTime(oboe_nanoseconds_t nanoTime,
+                                  clockid_t clockId = CLOCK_MONOTONIC) {
+        if (nanoTime > 0) {
+            struct timespec time;
+            time.tv_sec = nanoTime / OBOE_NANOS_PER_SECOND;
+            // Calculate the fractional nanoseconds. Avoids expensive % operation.
+            time.tv_nsec = nanoTime - (time.tv_sec * OBOE_NANOS_PER_SECOND);
+            int err = clock_nanosleep(clockId, TIMER_ABSTIME, &time, nullptr);
+            switch (err) {
+            case EINTR:
+                return 1;
+            case 0:
+                return 0;
+            default:
+                // Subtract because clock_nanosleep() returns a positive error number!
+                return 0 - err;
+            }
+        } else {
+            return OBOE_ERROR_ILLEGAL_ARGUMENT;
+        }
+    }
+
+    /**
+     * Sleep for the specified number of relative nanoseconds in real-time.
+     * Return immediately with 0 if a negative nanoseconds is specified.
+     *
+     * @param nanoseconds time to sleep
+     * @param clockId CLOCK_MONOTONIC is default
+     * @return 0, a negative error, or 1 if the call is interrupted by a signal handler (EINTR)
+     */
+    static int sleepForNanos(oboe_nanoseconds_t nanoseconds, clockid_t clockId = CLOCK_MONOTONIC) {
+        if (nanoseconds > 0) {
+            struct timespec time;
+            time.tv_sec = nanoseconds / OBOE_NANOS_PER_SECOND;
+            // Calculate the fractional nanoseconds. Avoids expensive % operation.
+            time.tv_nsec = nanoseconds - (time.tv_sec * OBOE_NANOS_PER_SECOND);
+            const int flags = 0; // documented as relative sleep
+            int err = clock_nanosleep(clockId, flags, &time, nullptr);
+            switch (err) {
+            case EINTR:
+                return 1;
+            case 0:
+                return 0;
+            default:
+                // Subtract because clock_nanosleep() returns a positive error number!
+                return 0 - err;
+            }
+        }
+        return 0;
+    }
+};
+
+
+#endif // UTILITY_AUDIOCLOCK_H
diff --git a/media/liboboe/src/utility/HandleTracker.cpp b/media/liboboe/src/utility/HandleTracker.cpp
new file mode 100644
index 0000000..be2a64c
--- /dev/null
+++ b/media/liboboe/src/utility/HandleTracker.cpp
@@ -0,0 +1,213 @@
+/*
+ * 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.
+ *
+ */
+
+#define LOG_TAG "OboeAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <assert.h>
+
+#include <oboe/OboeDefinitions.h>
+#include "HandleTracker.h"
+
+// Handle format is: tgggiiii
+// where each letter is 4 bits, t=type, g=generation, i=index
+
+#define TYPE_SIZE           4
+#define GENERATION_SIZE    12
+#define INDEX_SIZE         16
+
+#define GENERATION_INVALID  0
+#define GENERATION_SHIFT    INDEX_SIZE
+
+#define TYPE_MASK           ((1 << TYPE_SIZE) - 1)
+#define GENERATION_MASK     ((1 << GENERATION_SIZE) - 1)
+#define INDEX_MASK          ((1 << INDEX_SIZE) - 1)
+
+#define SLOT_UNAVAILABLE    (-1)
+
+// Error if handle is negative so type is limited to bottom half.
+#define HANDLE_INVALID_TYPE TYPE_MASK
+
+static_assert(HANDLE_TRACKER_MAX_TYPES == (1 << (TYPE_SIZE - 1)),
+    "Mismatch between header and cpp.");
+static_assert(HANDLE_TRACKER_MAX_HANDLES == (1 << (INDEX_SIZE)),
+    "Mismatch between header and cpp.");
+
+HandleTracker::HandleTracker(uint32_t maxHandles)
+        : mMaxHandleCount(maxHandles)
+        , mHandleAddresses(nullptr)
+        , mHandleHeaders(nullptr)
+{
+    assert(maxHandles <= HANDLE_TRACKER_MAX_HANDLES);
+    // Allocate arrays to hold addresses and validation info.
+    mHandleAddresses = (handle_tracker_address_t *) new handle_tracker_address_t[maxHandles];
+    if (mHandleAddresses != nullptr) {
+        mHandleHeaders = new handle_tracker_header_t[maxHandles];
+        if (mHandleHeaders != nullptr) {
+            // Initialize linked list of free nodes. NULL terminated.
+            for (uint32_t i = 0; i < (maxHandles - 1); i++) {
+                mHandleAddresses[i] = &mHandleAddresses[i + 1]; // point to next node
+                mHandleHeaders[i] = 0;
+            }
+            mNextFreeAddress = &mHandleAddresses[0];
+            mHandleAddresses[maxHandles - 1] = nullptr;
+            mHandleHeaders[maxHandles - 1] = 0;
+        } else {
+            delete[] mHandleAddresses; // so the class appears uninitialized
+        }
+    }
+}
+
+HandleTracker::~HandleTracker()
+{
+    delete[] mHandleAddresses;
+    delete[] mHandleHeaders;
+}
+
+bool HandleTracker::isInitialized() const {
+    return mHandleAddresses != nullptr;
+}
+
+handle_tracker_slot_t HandleTracker::allocateSlot() {
+    void **allocated = mNextFreeAddress;
+    if (allocated == nullptr) {
+        return SLOT_UNAVAILABLE;
+    }
+    // Remove this slot from the head of the linked list.
+    mNextFreeAddress = (void **) *allocated;
+    return (allocated - mHandleAddresses);
+}
+
+handle_tracker_generation_t HandleTracker::nextGeneration(handle_tracker_slot_t index) {
+    handle_tracker_generation_t generation = (mHandleHeaders[index] + 1) & GENERATION_MASK;
+    // Avoid generation zero so that 0x0 is not a valid handle.
+    if (generation == GENERATION_INVALID) {
+        generation++;
+    }
+    return generation;
+}
+
+oboe_handle_t HandleTracker::put(handle_tracker_type_t type, void *address)
+{
+    if (type < 0 || type >= HANDLE_TRACKER_MAX_TYPES) {
+        return static_cast<oboe_handle_t>(OBOE_ERROR_OUT_OF_RANGE);
+    }
+    if (!isInitialized()) {
+        return static_cast<oboe_handle_t>(OBOE_ERROR_NO_MEMORY);
+    }
+
+    // Find an empty slot.
+    handle_tracker_slot_t index = allocateSlot();
+    if (index == SLOT_UNAVAILABLE) {
+        ALOGE("HandleTracker::put() no room for more handles");
+        return static_cast<oboe_handle_t>(OBOE_ERROR_NO_FREE_HANDLES);
+    }
+
+    // Cycle the generation counter so stale handles can be detected.
+    handle_tracker_generation_t generation = nextGeneration(index); // reads header table
+    handle_tracker_header_t inputHeader = buildHeader(type, generation);
+
+    // These two writes may need to be observed by other threads or cores during get().
+    mHandleHeaders[index] = inputHeader;
+    mHandleAddresses[index] = address;
+    // TODO use store release to enforce memory order with get()
+
+    // Generate a handle.
+    oboe_handle_t handle = buildHandle(inputHeader, index);
+
+    //ALOGD("HandleTracker::put(%p) returns 0x%08x", address, handle);
+    return handle;
+}
+
+handle_tracker_slot_t HandleTracker::handleToIndex(handle_tracker_type_t type,
+                                                   oboe_handle_t handle) const
+{
+    // Validate the handle.
+    handle_tracker_slot_t index = extractIndex(handle);
+    if (index >= mMaxHandleCount) {
+        ALOGE("HandleTracker::handleToIndex() invalid handle = 0x%08X", handle);
+        return static_cast<oboe_handle_t>(OBOE_ERROR_INVALID_HANDLE);
+    }
+    handle_tracker_generation_t handleGeneration = extractGeneration(handle);
+    handle_tracker_header_t inputHeader = buildHeader(type, handleGeneration);
+    if (inputHeader != mHandleHeaders[index]) {
+        ALOGE("HandleTracker::handleToIndex() inputHeader = 0x%08x != mHandleHeaders[%d] = 0x%08x",
+             inputHeader, index, mHandleHeaders[index]);
+        return static_cast<oboe_handle_t>(OBOE_ERROR_INVALID_HANDLE);
+    }
+    return index;
+}
+
+handle_tracker_address_t HandleTracker::get(handle_tracker_type_t type, oboe_handle_t handle) const
+{
+    if (!isInitialized()) {
+        return nullptr;
+    }
+    handle_tracker_slot_t index = handleToIndex(type, handle);
+    if (index >= 0) {
+        return mHandleAddresses[index];
+    } else {
+        return nullptr;
+    }
+}
+
+handle_tracker_address_t HandleTracker::remove(handle_tracker_type_t type, oboe_handle_t handle) {
+    if (!isInitialized()) {
+        return nullptr;
+    }
+    handle_tracker_slot_t index = handleToIndex(type,handle);
+    if (index >= 0) {
+        handle_tracker_address_t address = mHandleAddresses[index];
+
+        // Invalidate the header type but preserve the generation count.
+        handle_tracker_generation_t generation = mHandleHeaders[index] & GENERATION_MASK;
+        handle_tracker_header_t inputHeader = buildHeader(
+                (handle_tracker_type_t) HANDLE_INVALID_TYPE, generation);
+        mHandleHeaders[index] = inputHeader;
+
+        // Add this slot to the head of the linked list.
+        mHandleAddresses[index] = mNextFreeAddress;
+        mNextFreeAddress = (handle_tracker_address_t *) &mHandleAddresses[index];
+        return address;
+    } else {
+        return nullptr;
+    }
+}
+
+oboe_handle_t HandleTracker::buildHandle(handle_tracker_header_t typeGeneration,
+                                         handle_tracker_slot_t index) {
+    return (oboe_handle_t)((typeGeneration << GENERATION_SHIFT) | (index & INDEX_MASK));
+}
+
+handle_tracker_header_t HandleTracker::buildHeader(handle_tracker_type_t type,
+                                    handle_tracker_generation_t generation)
+{
+    return (handle_tracker_header_t) (((type & TYPE_MASK) << GENERATION_SIZE)
+        | (generation & GENERATION_MASK));
+}
+
+handle_tracker_slot_t HandleTracker::extractIndex(oboe_handle_t handle)
+{
+    return handle & INDEX_MASK;
+}
+
+handle_tracker_generation_t HandleTracker::extractGeneration(oboe_handle_t handle)
+{
+    return (handle >> GENERATION_SHIFT) & GENERATION_MASK;
+}
diff --git a/media/liboboe/src/utility/HandleTracker.h b/media/liboboe/src/utility/HandleTracker.h
new file mode 100644
index 0000000..da5b654
--- /dev/null
+++ b/media/liboboe/src/utility/HandleTracker.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright 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 UTILITY_HANDLETRACKER_H
+#define UTILITY_HANDLETRACKER_H
+
+#include <stdint.h>
+
+typedef int32_t  handle_tracker_type_t;       // what kind of handle
+typedef int32_t  handle_tracker_slot_t;       // index in allocation table
+typedef int32_t  handle_tracker_generation_t; // incremented when slot used
+typedef uint16_t handle_tracker_header_t;     // combines type and generation
+typedef void    *handle_tracker_address_t;    // address of something that is stored here
+
+#define HANDLE_TRACKER_MAX_TYPES    (1 << 3)
+#define HANDLE_TRACKER_MAX_HANDLES  (1 << 16)
+
+/**
+ * Represent Objects using an integer handle that can be used with Java.
+ * This also makes the 'C' ABI more robust.
+ *
+ * Note that this should only be called from a single thread.
+ * If you call it from more than one thread then you need to use your own mutex.
+ */
+class HandleTracker {
+
+public:
+    /**
+     * @param maxHandles cannot exceed HANDLE_TRACKER_MAX_HANDLES
+     */
+    HandleTracker(uint32_t maxHandles);
+    virtual ~HandleTracker();
+
+    /**
+     * Don't use if this returns false;
+     * @return true if the internal allocation succeeded
+     */
+    bool isInitialized() const;
+
+    /**
+     * Store a pointer and return a handle that can be used to retrieve the pointer.
+     *
+     * @param type the type of the object to be tracked
+     * @param address pointer to be converted to a handle
+     * @return a valid handle or a negative error
+     */
+    oboe_handle_t put(handle_tracker_type_t expectedType, handle_tracker_address_t address);
+
+    /**
+     * Get the original pointer associated with the handle.
+     * The handle will be validated to prevent stale handles from being reused.
+     * Note that the validation is designed to prevent common coding errors and not
+     * to prevent deliberate hacking.
+     *
+     * @param expectedType shouldmatch the type we passed to put()
+     * @param handle to be converted to a pointer
+     * @return address associated with handle or nullptr
+     */
+    handle_tracker_address_t get(handle_tracker_type_t expectedType, oboe_handle_t handle) const;
+
+    /**
+     * Free up the storage associated with the handle.
+     * Subsequent attempts to use the handle will fail.
+     *
+     * @param expectedType shouldmatch the type we passed to put()
+     * @param handle to be removed from tracking
+     * @return address associated with handle or nullptr if not found
+     */
+    handle_tracker_address_t remove(handle_tracker_type_t expectedType, oboe_handle_t handle);
+
+private:
+    const int32_t               mMaxHandleCount;   // size of array
+    // This is const after initialization.
+    handle_tracker_address_t  * mHandleAddresses;  // address of objects or a free linked list node
+    // This is const after initialization.
+    handle_tracker_header_t   * mHandleHeaders;    // combination of type and generation
+    handle_tracker_address_t  * mNextFreeAddress; // head of the linked list of free nodes in mHandleAddresses
+
+    /**
+     * Pull slot off of a list of empty slots.
+     * @return index or a negative error
+     */
+    handle_tracker_slot_t allocateSlot();
+
+    /**
+     * Validate the handle and return the corresponding index.
+     * @return slot index or a negative error
+     */
+    handle_tracker_slot_t handleToIndex(oboe_handle_t handle, handle_tracker_type_t type) const;
+
+    /**
+     * Construct a handle from a header and an index.
+     * @param header combination of a type and a generation
+     * @param index slot index returned from allocateSlot
+     * @return handle or a negative error
+     */
+    oboe_handle_t buildHandle(handle_tracker_header_t header, handle_tracker_slot_t index);
+
+    /**
+     * Combine a type and a generation field into a header.
+     */
+    static handle_tracker_header_t buildHeader(handle_tracker_type_t type,
+                handle_tracker_generation_t generation);
+
+    /**
+     * Extract the index from a handle.
+     * Does not validate the handle.
+     * @return index associated with a handle
+     */
+    static handle_tracker_slot_t extractIndex(oboe_handle_t handle);
+
+    /**
+     * Extract the generation from a handle.
+     * Does not validate the handle.
+     * @return generation associated with a handle
+     */
+    static handle_tracker_generation_t extractGeneration(oboe_handle_t handle);
+
+    /**
+     * Increment the generation for the slot, avoiding zero.
+     */
+    handle_tracker_generation_t nextGeneration(handle_tracker_slot_t index);
+
+};
+
+#endif //UTILITY_HANDLETRACKER_H
diff --git a/media/liboboe/src/utility/MonotonicCounter.h b/media/liboboe/src/utility/MonotonicCounter.h
new file mode 100644
index 0000000..befad21
--- /dev/null
+++ b/media/liboboe/src/utility/MonotonicCounter.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 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 UTILITY_MONOTONICCOUNTER_H
+#define UTILITY_MONOTONICCOUNTER_H
+
+#include <stdint.h>
+
+/**
+ * Maintain a 64-bit monotonic counter.
+ * Can be used to track a 32-bit counter that wraps or gets reset.
+ *
+ * Note that this is not atomic and has no interior locks.
+ * A caller will need to provide their own exterior locking
+ * if they need to use it from multiple threads.
+ */
+class MonotonicCounter {
+
+public:
+    MonotonicCounter() {};
+    virtual ~MonotonicCounter() {};
+
+    /**
+     * @return current value of the counter
+     */
+    int64_t get() const {
+        return mCounter64;
+    }
+
+    /**
+     * Advance the counter if delta is positive.
+     * @return current value of the counter
+     */
+    int64_t increment(int64_t delta) {
+        if (delta > 0) {
+            mCounter64 += delta;
+        }
+        return mCounter64;
+    }
+
+    /**
+     * Advance the 64-bit counter if (current32 - previousCurrent32) > 0.
+     * This can be used to convert a 32-bit counter that may be wrapping into
+     * a monotonic 64-bit counter.
+     *
+     * This counter32 should NOT be allowed to advance by more than 0x7FFFFFFF between calls.
+     * Think of the wrapping counter like a sine wave. If the frequency of the signal
+     * is more than half the sampling rate (Nyquist rate) then you cannot measure it properly.
+     * If the counter wraps around every 24 hours then we should measure it with a period
+     * of less than 12 hours.
+     *
+     * @return current value of the 64-bit counter
+     */
+    int64_t update32(int32_t counter32) {
+        int32_t delta = counter32 - mCounter32;
+        // protect against the mCounter64 going backwards
+        if (delta > 0) {
+            mCounter64 += delta;
+            mCounter32 = counter32;
+        }
+        return mCounter64;
+    }
+
+    /**
+     * Reset the stored value of the 32-bit counter.
+     * This is used if your counter32 has been reset to zero.
+     */
+    void reset32() {
+        mCounter32 = 0;
+    }
+
+private:
+    int64_t mCounter64 = 0;
+    int32_t mCounter32 = 0;
+};
+
+
+#endif //UTILITY_MONOTONICCOUNTER_H
diff --git a/media/liboboe/src/utility/OboeUtilities.cpp b/media/liboboe/src/utility/OboeUtilities.cpp
new file mode 100644
index 0000000..b28f7c7
--- /dev/null
+++ b/media/liboboe/src/utility/OboeUtilities.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright 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.
+ */
+
+#define LOG_TAG "OboeAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+
+#include "oboe/OboeDefinitions.h"
+#include "OboeUtilities.h"
+
+using namespace android;
+
+oboe_size_bytes_t OboeConvert_formatToSizeInBytes(oboe_audio_format_t format) {
+    oboe_datatype_t dataType = OBOE_AUDIO_FORMAT_DATA_TYPE(format);
+    oboe_size_bytes_t size;
+    switch (dataType) {
+        case OBOE_AUDIO_DATATYPE_UINT8:
+            size = sizeof(uint8_t);
+            break;
+        case OBOE_AUDIO_DATATYPE_INT16:
+            size = sizeof(int16_t);
+            break;
+        case OBOE_AUDIO_DATATYPE_INT32:
+        case OBOE_AUDIO_DATATYPE_INT824:
+            size = sizeof(int32_t);
+            break;
+        case OBOE_AUDIO_DATATYPE_FLOAT32:
+            size = sizeof(float);
+            break;
+        default:
+            size = OBOE_ERROR_ILLEGAL_ARGUMENT;
+            break;
+    }
+    return size;
+}
+
+// TODO This similar to a function in audio_utils. Consider using that instead.
+void OboeConvert_floatToPcm16(const float *source, int32_t numSamples, int16_t *destination) {
+    for (int i = 0; i < numSamples; i++) {
+        float fval = source[i];
+        fval += 1.0; // to avoid discontinuity at 0.0 caused by truncation
+        fval *= 32768.0f;
+        int32_t sample = (int32_t) fval;
+        // clip to 16-bit range
+        if (sample < 0) sample = 0;
+        else if (sample > 0x0FFFF) sample = 0x0FFFF;
+        sample -= 32768; // center at zero
+        destination[i] = (int16_t) sample;
+    }
+}
+
+void OboeConvert_pcm16ToFloat(const float *source, int32_t numSamples, int16_t *destination) {
+    for (int i = 0; i < numSamples; i++) {
+        destination[i] = source[i] * (1.0f / 32768.0f);
+    }
+}
+
+oboe_result_t OboeConvert_androidToOboeError(status_t error) {
+    if (error >= 0) {
+        return error;
+    }
+    oboe_result_t result;
+    switch (error) {
+    case OK:
+        result = OBOE_OK;
+        break;
+    case INVALID_OPERATION:
+        result = OBOE_ERROR_INVALID_STATE;
+        break;
+    case BAD_VALUE:
+        result = OBOE_ERROR_UNEXPECTED_VALUE;
+        break;
+    case WOULD_BLOCK:
+        result = OBOE_ERROR_WOULD_BLOCK;
+        break;
+    // TODO add more error codes
+    default:
+        result = OBOE_ERROR_INTERNAL;
+        break;
+    }
+    return result;
+}
+
+audio_format_t OboeConvert_oboeToAndroidDataFormat(oboe_audio_format_t oboeFormat) {
+    audio_format_t androidFormat;
+    switch (oboeFormat) {
+    case OBOE_AUDIO_FORMAT_PCM16:
+        androidFormat = AUDIO_FORMAT_PCM_16_BIT;
+        break;
+    case OBOE_AUDIO_FORMAT_PCM_FLOAT:
+        androidFormat = AUDIO_FORMAT_PCM_FLOAT;
+        break;
+    case OBOE_AUDIO_FORMAT_PCM824:
+        androidFormat = AUDIO_FORMAT_PCM_8_24_BIT;
+        break;
+    case OBOE_AUDIO_FORMAT_PCM32:
+        androidFormat = AUDIO_FORMAT_PCM_32_BIT;
+        break;
+    default:
+        androidFormat = AUDIO_FORMAT_DEFAULT;
+        ALOGE("OboeConvert_oboeToAndroidDataFormat 0x%08X unrecognized", oboeFormat);
+        break;
+    }
+    return androidFormat;
+}
+
+oboe_audio_format_t OboeConvert_androidToOboeDataFormat(audio_format_t androidFormat) {
+    oboe_audio_format_t oboeFormat = OBOE_AUDIO_FORMAT_INVALID;
+    switch (androidFormat) {
+    case AUDIO_FORMAT_PCM_16_BIT:
+        oboeFormat = OBOE_AUDIO_FORMAT_PCM16;
+        break;
+    case AUDIO_FORMAT_PCM_FLOAT:
+        oboeFormat = OBOE_AUDIO_FORMAT_PCM_FLOAT;
+        break;
+    case AUDIO_FORMAT_PCM_32_BIT:
+        oboeFormat = OBOE_AUDIO_FORMAT_PCM32;
+        break;
+    case AUDIO_FORMAT_PCM_8_24_BIT:
+        oboeFormat = OBOE_AUDIO_FORMAT_PCM824;
+        break;
+    default:
+        oboeFormat = OBOE_AUDIO_FORMAT_INVALID;
+        ALOGE("OboeConvert_androidToOboeDataFormat 0x%08X unrecognized", androidFormat);
+        break;
+    }
+    return oboeFormat;
+}
+
+oboe_size_bytes_t OboeConvert_framesToBytes(oboe_size_frames_t numFrames,
+                                            oboe_size_bytes_t bytesPerFrame,
+                                            oboe_size_bytes_t *sizeInBytes) {
+    // TODO implement more elegantly
+    const int32_t maxChannels = 256; // ridiculously large
+    const oboe_size_frames_t maxBytesPerFrame = maxChannels * sizeof(float);
+    // Prevent overflow by limiting multiplicands.
+    if (bytesPerFrame > maxBytesPerFrame || numFrames > (0x3FFFFFFF / maxBytesPerFrame)) {
+        ALOGE("size overflow, numFrames = %d, frameSize = %zd", numFrames, bytesPerFrame);
+        return OBOE_ERROR_OUT_OF_RANGE;
+    }
+    *sizeInBytes = numFrames * bytesPerFrame;
+    return OBOE_OK;
+}
diff --git a/media/liboboe/src/utility/OboeUtilities.h b/media/liboboe/src/utility/OboeUtilities.h
new file mode 100644
index 0000000..974ccf6
--- /dev/null
+++ b/media/liboboe/src/utility/OboeUtilities.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 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 UTILITY_OBOEUTILITIES_H
+#define UTILITY_OBOEUTILITIES_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <hardware/audio.h>
+
+#include "oboe/OboeDefinitions.h"
+
+oboe_result_t OboeConvert_androidToOboeError(android::status_t error);
+
+void OboeConvert_floatToPcm16(const float *source, int32_t numSamples, int16_t *destination);
+
+void OboeConvert_pcm16ToFloat(const int16_t *source, int32_t numSamples, float *destination);
+
+/**
+ * Calculate the number of bytes and prevent numeric overflow.
+ * @param numFrames frame count
+ * @param bytesPerFrame size of a frame in bytes
+ * @param sizeInBytes total size in bytes
+ * @return OBOE_OK or negative error, eg. OBOE_ERROR_OUT_OF_RANGE
+ */
+oboe_size_bytes_t OboeConvert_framesToBytes(oboe_size_frames_t numFrames,
+                                            oboe_size_bytes_t bytesPerFrame,
+                                            oboe_size_bytes_t *sizeInBytes);
+
+audio_format_t OboeConvert_oboeToAndroidDataFormat(oboe_audio_format_t oboe_format);
+
+oboe_audio_format_t OboeConvert_androidToOboeDataFormat(audio_format_t format);
+
+/**
+ * @return the size of a sample of the given format in bytes or OBOE_ERROR_ILLEGAL_ARGUMENT
+ */
+oboe_size_bytes_t OboeConvert_formatToSizeInBytes(oboe_audio_format_t format);
+
+#endif //UTILITY_OBOEUTILITIES_H
diff --git a/media/liboboe/src/utility/README.md b/media/liboboe/src/utility/README.md
new file mode 100644
index 0000000..9db926a
--- /dev/null
+++ b/media/liboboe/src/utility/README.md
@@ -0,0 +1,3 @@
+The utility folder contains things that may be shared between the Oboe client and server.
+They might also be handy outside Oboe.
+They generally do not depend on Oboe functionality.