Non-blocking audio I/O interface, WIP

Yet another abstraction similar to AudioTrack::Buffer and AudioBufferProvider,
but with support for streaming, non-blocking, and eventually PTS.

This is intended to be used as follows:
 - primary HAL output stream implements a Sink
 - primary HAL input stream implements a Source
 - Pipe implements a Sink
 - PipeReader implements a Source or TimedSource (not shown yet),
   which supports "read at PTS"
 - fast AudioTrack on server side will implement a Source using cblk
 - normal AudioTrack on server side will not be changed initially
 - fast AudioRecord on server side will implement a Sink using cblk
 - normal AudioRecord on server side will not be changed initially
 - fast mixer thread will read from Sources and write to a Sink,
   or (unlikely) implement a Source and multiple Sinks
 - Visualization and PCM logger will read from Source or TimedSource
 - A2DP normal mixer will be connected directly to its output stream
   and there will be a kind of OutputTrack for duplication that will
   read from a Sink with non-blocking write fed by the fast mixer.

Patch set 3 changes:
 - Add more implementations of NBAIO interfaces:
   added SourceAudioBufferProvider, MonoPipe, MonoPipeReader.
 - Added Format_sampleRate and Format_channelCount.
 - Extract out the roundUp() method.
 - Respond to most comments from previous code review.
 - The new classes are untested.

Patch set 4 changes:
 - Fix bugs in MonoPipe::write() and MonoPipeReader::read()
 - Fix bug initializing mFrameBitShift too early
 - renamed roundUp() to roundup()
 - Fix Android.mk
 - Add LOG_TAG an LOG_NDEBUG, use ALOG_ASSERT and utils/Log.h instead of assert
 - Fix build warnings
 - Move constructor and destructor bodies from .h to .cpp
 - Line length 100
 - Following naming conventions for #include double-include protector macros
 - Include what you use
 - More NBAIO logging
 - MonoPipe write can be blocking

Patch set 5 changes:
 - Address code review comments
 - Use a static library so unused implementations don't take memory
 - Comment out libsndfile dependency
 - Remove debugging LOGV and LOG_NDEBUG

Patch set 6 changes (would be 6 at old location, actually 2 at new location):
 - Address code review comments on patchset 5
 - For MonoPipe, allow the full pipe to be used, no need to omit one slot
 - Don't do atomic releasing stores unless needed

Still to do:
 - I'm not happy with the Pipe class names
 - Update build/ for new static library?

Change-Id: Ie6c61f05ce06b676b033be448a8ef9025a2ffcfd
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 257f62c..2cf77ce 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -2,6 +2,29 @@
 
 include $(CLEAR_VARS)
 
+LOCAL_SRC_FILES := \
+    AudioBufferProviderSource.cpp   \
+    AudioStreamOutSink.cpp          \
+    AudioStreamInSource.cpp         \
+    NBAIO.cpp                       \
+    MonoPipe.cpp                    \
+    MonoPipeReader.cpp              \
+    Pipe.cpp                        \
+    PipeReader.cpp                  \
+    roundup.c                       \
+    SourceAudioBufferProvider.cpp
+
+# libsndfile license is incompatible; uncomment to use for local debug only
+#LOCAL_SRC_FILES += LibsndfileSink.cpp LibsndfileSource.cpp
+#LOCAL_C_INCLUDES += path/to/libsndfile/src
+#LOCAL_STATIC_LIBRARIES += libsndfile
+
+LOCAL_MODULE := libnbaio
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
 LOCAL_SRC_FILES:=               \
     AudioFlinger.cpp            \
     AudioMixer.cpp.arm          \
@@ -31,6 +54,7 @@
     libpowermanager
 
 LOCAL_STATIC_LIBRARIES := \
+    libnbaio \
     libcpustats \
     libmedia_helper
 
diff --git a/services/audioflinger/AudioBufferProviderSource.cpp b/services/audioflinger/AudioBufferProviderSource.cpp
new file mode 100644
index 0000000..4342171
--- /dev/null
+++ b/services/audioflinger/AudioBufferProviderSource.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioBufferProviderSource"
+//#define LOG_NDEBUG 0
+
+#include <cutils/compiler.h>
+#include <utils/Log.h>
+#include "AudioBufferProviderSource.h"
+
+namespace android {
+
+AudioBufferProviderSource::AudioBufferProviderSource(AudioBufferProvider *provider,
+                                                     NBAIO_Format format) :
+    NBAIO_Source(format), mProvider(provider), mConsumed(0)
+{
+    ALOG_ASSERT(provider != NULL);
+    ALOG_ASSERT(format != Format_Invalid);
+}
+
+AudioBufferProviderSource::~AudioBufferProviderSource()
+{
+    if (mBuffer.raw != NULL) {
+        mProvider->releaseBuffer(&mBuffer);
+    }
+}
+
+ssize_t AudioBufferProviderSource::availableToRead()
+{
+    if (CC_UNLIKELY(!mNegotiated)) {
+        return NEGOTIATE;
+    }
+    return mBuffer.raw != NULL ? mBuffer.frameCount - mConsumed : 0;
+}
+
+ssize_t AudioBufferProviderSource::read(void *buffer, size_t count)
+{
+    if (CC_UNLIKELY(!mNegotiated)) {
+        return NEGOTIATE;
+    }
+    if (CC_UNLIKELY(mBuffer.raw == NULL)) {
+        mBuffer.frameCount = count;
+        status_t status = mProvider->getNextBuffer(&mBuffer, AudioBufferProvider::kInvalidPTS);
+        if (status != OK) {
+            return status == NOT_ENOUGH_DATA ? (ssize_t) WOULD_BLOCK : (ssize_t) status;
+        }
+        ALOG_ASSERT(mBuffer.raw != NULL);
+        // mConsumed is 0 either from constructor or after releaseBuffer()
+    }
+    size_t available = mBuffer.frameCount - mConsumed;
+    if (CC_UNLIKELY(count > available)) {
+        count = available;
+    }
+    // count could be zero, either because count was zero on entry or
+    // available is zero, but both are unlikely so don't check for that
+    memcpy(buffer, (char *) mBuffer.raw + (mConsumed << mBitShift), count << mBitShift);
+    if (CC_UNLIKELY((mConsumed += count) >= mBuffer.frameCount)) {
+        mProvider->releaseBuffer(&mBuffer);
+        mBuffer.raw = NULL;
+        mConsumed = 0;
+    }
+    mFramesRead += count;
+    // For better responsiveness with large values of count,
+    // return a short count rather than continuing with next buffer.
+    // This gives the caller a chance to interpolate other actions.
+    return count;
+}
+
+ssize_t AudioBufferProviderSource::readVia(readVia_t via, size_t total, void *user, size_t block)
+{
+    if (CC_UNLIKELY(!mNegotiated)) {
+        return NEGOTIATE;
+    }
+    if (CC_UNLIKELY(block == 0)) {
+        block = ~0;
+    }
+    for (size_t accumulator = 0; ; ) {
+        ALOG_ASSERT(accumulator <= total);
+        size_t count = total - accumulator;
+        if (CC_UNLIKELY(count == 0)) {
+            return accumulator;
+        }
+        if (CC_LIKELY(count > block)) {
+            count = block;
+        }
+        // 1 <= count <= block
+        if (CC_UNLIKELY(mBuffer.raw == NULL)) {
+            mBuffer.frameCount = count;
+            status_t status = mProvider->getNextBuffer(&mBuffer, AudioBufferProvider::kInvalidPTS);
+            if (CC_LIKELY(status == OK)) {
+                ALOG_ASSERT(mBuffer.raw != NULL && mBuffer.frameCount <= count);
+                // mConsumed is 0 either from constructor or after releaseBuffer()
+                continue;
+            }
+            // FIXME simplify logic - does the initial count and block checks again for no reason;
+            //       don't you just want to fall through to the size_t available line?
+            if (CC_LIKELY(status == NOT_ENOUGH_DATA)) {
+                status = WOULD_BLOCK;
+            }
+            return accumulator > 0 ? accumulator : (ssize_t) status;
+        }
+        size_t available = mBuffer.frameCount - mConsumed;
+        if (CC_UNLIKELY(count > available)) {
+            count = available;
+        }
+        if (CC_LIKELY(count > 0)) {
+            ssize_t ret = via(user, (char *) mBuffer.raw + (mConsumed << mBitShift), count);
+            if (CC_UNLIKELY(ret <= 0)) {
+                if (CC_LIKELY(accumulator > 0)) {
+                    return accumulator;
+                }
+                return ret;
+            }
+            ALOG_ASSERT((size_t) ret <= count);
+            mFramesRead += ret;
+            accumulator += ret;
+            if (CC_LIKELY((mConsumed += ret) < mBuffer.frameCount)) {
+                continue;
+            }
+        }
+        mProvider->releaseBuffer(&mBuffer);
+        mBuffer.raw = NULL;
+        mConsumed = 0;
+        // don't get next buffer until we really need it
+    }
+}
+
+}   // namespace android
diff --git a/services/audioflinger/AudioBufferProviderSource.h b/services/audioflinger/AudioBufferProviderSource.h
new file mode 100644
index 0000000..2b39937
--- /dev/null
+++ b/services/audioflinger/AudioBufferProviderSource.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Implementation of NBAIO_Source that wraps an AudioBufferProvider
+
+#ifndef ANDROID_AUDIO_BUFFER_PROVIDER_SOURCE_H
+#define ANDROID_AUDIO_BUFFER_PROVIDER_SOURCE_H
+
+#include "NBAIO.h"
+#include "AudioBufferProvider.h"
+
+namespace android {
+
+class AudioBufferProviderSource : public NBAIO_Source {
+
+public:
+    AudioBufferProviderSource(AudioBufferProvider *provider, NBAIO_Format format);
+    virtual ~AudioBufferProviderSource();
+
+    // NBAIO_Port interface
+
+    //virtual ssize_t negotiate(const NBAIO_Format offers[], size_t numOffers,
+    //                          NBAIO_Format counterOffers[], size_t& numCounterOffers);
+    //virtual NBAIO_Format format();
+
+    // NBAIO_Source interface
+
+    //virtual size_t framesRead() const;
+    //virtual size_t framesOverrun();
+    //virtual size_t overruns();
+    virtual ssize_t availableToRead();
+    virtual ssize_t read(void *buffer, size_t count);
+    virtual ssize_t readVia(readVia_t via, size_t total, void *user, size_t block);
+
+private:
+    AudioBufferProvider * const mProvider;
+    AudioBufferProvider::Buffer mBuffer;    // current buffer
+    size_t                      mConsumed;  // number of frames consumed so far from current buffer
+};
+
+}   // namespace android
+
+#endif  // ANDROID_AUDIO_BUFFER_PROVIDER_SOURCE_H
diff --git a/services/audioflinger/AudioStreamInSource.cpp b/services/audioflinger/AudioStreamInSource.cpp
new file mode 100644
index 0000000..8b4bebf
--- /dev/null
+++ b/services/audioflinger/AudioStreamInSource.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioStreamInSource"
+//#define LOG_NDEBUG 0
+
+#include <cutils/compiler.h>
+#include <utils/Log.h>
+#include "AudioStreamInSource.h"
+
+namespace android {
+
+AudioStreamInSource::AudioStreamInSource(audio_stream_in *stream) :
+        NBAIO_Source(),
+        mStream(stream),
+        mStreamBufferSizeBytes(0),
+        mFramesOverrun(0),
+        mOverruns(0)
+{
+    ALOG_ASSERT(stream != NULL);
+}
+
+AudioStreamInSource::~AudioStreamInSource()
+{
+}
+
+ssize_t AudioStreamInSource::negotiate(const NBAIO_Format offers[], size_t numOffers,
+                                      NBAIO_Format counterOffers[], size_t& numCounterOffers)
+{
+    if (mFormat == Format_Invalid) {
+        mStreamBufferSizeBytes = mStream->common.get_buffer_size(&mStream->common);
+        audio_format_t streamFormat = mStream->common.get_format(&mStream->common);
+        if (streamFormat == AUDIO_FORMAT_PCM_16_BIT) {
+            uint32_t sampleRate = mStream->common.get_sample_rate(&mStream->common);
+            audio_channel_mask_t channelMask =
+                    (audio_channel_mask_t) mStream->common.get_channels(&mStream->common);
+            mFormat = Format_from_SR_C(sampleRate, popcount(channelMask));
+            mBitShift = Format_frameBitShift(mFormat);
+        }
+    }
+    return NBAIO_Source::negotiate(offers, numOffers, counterOffers, numCounterOffers);
+}
+
+size_t AudioStreamInSource::framesOverrun()
+{
+    uint32_t framesOverrun = mStream->get_input_frames_lost(mStream);
+    if (framesOverrun > 0) {
+        mFramesOverrun += framesOverrun;
+        // FIXME only increment for contiguous ranges
+        ++mOverruns;
+    }
+    return mFramesOverrun;
+}
+
+ssize_t AudioStreamInSource::read(void *buffer, size_t count)
+{
+    if (CC_UNLIKELY(mFormat == Format_Invalid)) {
+        return NEGOTIATE;
+    }
+    ssize_t bytesRead = mStream->read(mStream, buffer, count << mBitShift);
+    if (bytesRead > 0) {
+        size_t framesRead = bytesRead >> mBitShift;
+        mFramesRead += framesRead;
+        return framesRead;
+    } else {
+        return bytesRead;
+    }
+}
+
+}   // namespace android
diff --git a/services/audioflinger/AudioStreamInSource.h b/services/audioflinger/AudioStreamInSource.h
new file mode 100644
index 0000000..07d8c89
--- /dev/null
+++ b/services/audioflinger/AudioStreamInSource.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_STREAM_IN_SOURCE_H
+#define ANDROID_AUDIO_STREAM_IN_SOURCE_H
+
+#include <hardware/audio.h>
+#include "NBAIO.h"
+
+namespace android {
+
+// not multi-thread safe
+class AudioStreamInSource : public NBAIO_Source {
+
+public:
+    AudioStreamInSource(audio_stream_in *stream);
+    virtual ~AudioStreamInSource();
+
+    // NBAIO_Port interface
+
+    virtual ssize_t negotiate(const NBAIO_Format offers[], size_t numOffers,
+                              NBAIO_Format counterOffers[], size_t& numCounterOffers);
+    //virtual NBAIO_Format format() const;
+
+    // NBAIO_Sink interface
+
+    //virtual size_t framesRead() const;
+    virtual size_t framesOverrun();
+    virtual size_t overruns() { (void) framesOverrun(); return mOverruns; }
+
+    // This is an over-estimate, and could dupe the caller into making a blocking read()
+    // FIXME Use an audio HAL API to query the buffer filling status when it's available.
+    virtual ssize_t availableToRead() { return mStreamBufferSizeBytes >> mBitShift; }
+
+    virtual ssize_t read(void *buffer, size_t count);
+
+    // NBAIO_Sink end
+
+#if 0   // until necessary
+    audio_stream_in *stream() const { return mStream; }
+#endif
+
+private:
+    audio_stream_in * const mStream;
+    size_t              mStreamBufferSizeBytes; // as reported by get_buffer_size()
+    size_t              mFramesOverrun;
+    size_t              mOverruns;
+};
+
+}   // namespace android
+
+#endif  // ANDROID_AUDIO_STREAM_IN_SOURCE_H
diff --git a/services/audioflinger/AudioStreamOutSink.cpp b/services/audioflinger/AudioStreamOutSink.cpp
new file mode 100644
index 0000000..8a5aa0c
--- /dev/null
+++ b/services/audioflinger/AudioStreamOutSink.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioStreamOutSink"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include "AudioStreamOutSink.h"
+
+namespace android {
+
+AudioStreamOutSink::AudioStreamOutSink(audio_stream_out *stream) :
+        NBAIO_Sink(),
+        mStream(stream),
+        mStreamBufferSizeBytes(0)
+{
+    ALOG_ASSERT(stream != NULL);
+}
+
+AudioStreamOutSink::~AudioStreamOutSink()
+{
+}
+
+ssize_t AudioStreamOutSink::negotiate(const NBAIO_Format offers[], size_t numOffers,
+                                      NBAIO_Format counterOffers[], size_t& numCounterOffers)
+{
+    if (mFormat == Format_Invalid) {
+        mStreamBufferSizeBytes = mStream->common.get_buffer_size(&mStream->common);
+        audio_format_t streamFormat = mStream->common.get_format(&mStream->common);
+        if (streamFormat == AUDIO_FORMAT_PCM_16_BIT) {
+            uint32_t sampleRate = mStream->common.get_sample_rate(&mStream->common);
+            audio_channel_mask_t channelMask =
+                    (audio_channel_mask_t) mStream->common.get_channels(&mStream->common);
+            mFormat = Format_from_SR_C(sampleRate, popcount(channelMask));
+            mBitShift = Format_frameBitShift(mFormat);
+        }
+    }
+    return NBAIO_Sink::negotiate(offers, numOffers, counterOffers, numCounterOffers);
+}
+
+ssize_t AudioStreamOutSink::write(const void *buffer, size_t count)
+{
+    if (!mNegotiated) {
+        return NEGOTIATE;
+    }
+    ALOG_ASSERT(mFormat != Format_Invalid);
+    ssize_t ret = mStream->write(mStream, buffer, count << mBitShift);
+    if (ret > 0) {
+        ret >>= mBitShift;
+        mFramesWritten += ret;
+    } else {
+        // FIXME verify HAL implementations are returning the correct error codes e.g. WOULD_BLOCK
+    }
+    return ret;
+}
+
+}   // namespace android
diff --git a/services/audioflinger/AudioStreamOutSink.h b/services/audioflinger/AudioStreamOutSink.h
new file mode 100644
index 0000000..1eff3f6
--- /dev/null
+++ b/services/audioflinger/AudioStreamOutSink.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_STREAM_OUT_SINK_H
+#define ANDROID_AUDIO_STREAM_OUT_SINK_H
+
+#include <hardware/audio.h>
+#include "NBAIO.h"
+
+namespace android {
+
+// not multi-thread safe
+class AudioStreamOutSink : public NBAIO_Sink {
+
+public:
+    AudioStreamOutSink(audio_stream_out *stream);
+    virtual ~AudioStreamOutSink();
+
+    // NBAIO_Port interface
+
+    virtual ssize_t negotiate(const NBAIO_Format offers[], size_t numOffers,
+                              NBAIO_Format counterOffers[], size_t& numCounterOffers);
+    //virtual NBAIO_Format format();
+
+    // NBAIO_Sink interface
+
+    //virtual size_t framesWritten() const;
+    //virtual size_t framesUnderrun() const;
+    //virtual size_t underruns() const;
+
+    // This is an over-estimate, and could dupe the caller into making a blocking write()
+    // FIXME Use an audio HAL API to query the buffer emptying status when it's available.
+    virtual ssize_t availableToWrite() const { return mStreamBufferSizeBytes >> mBitShift; }
+
+    virtual ssize_t write(const void *buffer, size_t count);
+
+    // NBAIO_Sink end
+
+#if 0   // until necessary
+    audio_stream_out *stream() const { return mStream; }
+#endif
+
+private:
+    audio_stream_out * const mStream;
+    size_t              mStreamBufferSizeBytes; // as reported by get_buffer_size()
+};
+
+}   // namespace android
+
+#endif  // ANDROID_AUDIO_STREAM_OUT_SINK_H
diff --git a/services/audioflinger/LibsndfileSink.cpp b/services/audioflinger/LibsndfileSink.cpp
new file mode 100644
index 0000000..efc1c8f
--- /dev/null
+++ b/services/audioflinger/LibsndfileSink.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LibsndfileSink"
+//#define LOG_NDEBUG 0
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include "LibsndfileSink.h"
+
+namespace android {
+
+LibsndfileSink::LibsndfileSink(SNDFILE *sndfile, const SF_INFO &sfinfo) :
+    NBAIO_Sink(Format_from_SR_C(sfinfo.samplerate, sfinfo.channels)),
+    mSndfile(sndfile)
+{
+}
+
+LibsndfileSink::~LibsndfileSink()
+{
+    // do not close mSndfile; we don't own it
+}
+
+ssize_t LibsndfileSink::write(const void *buffer, size_t count)
+{
+    if (!mNegotiated) {
+        return (ssize_t) NEGOTIATE;
+    }
+    if (mSndfile == NULL) {
+        return (ssize_t) NO_INIT;
+    }
+    sf_count_t actual = sf_writef_short(mSndfile, (short *) buffer, (sf_count_t) count);
+    mFramesWritten += actual;
+    return actual;
+}
+
+}   // namespace android
diff --git a/services/audioflinger/LibsndfileSink.h b/services/audioflinger/LibsndfileSink.h
new file mode 100644
index 0000000..f5d53d5
--- /dev/null
+++ b/services/audioflinger/LibsndfileSink.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_LIBSNDFILE_SINK_H
+#define ANDROID_AUDIO_LIBSNDFILE_SINK_H
+
+#include "NBAIO.h"
+#include "sndfile.h"
+
+// Implementation of NBAIO_Sink that wraps a libsndfile opened in SFM_WRITE mode
+
+namespace android {
+
+class LibsndfileSink : public NBAIO_Sink {
+
+public:
+    LibsndfileSink(SNDFILE *sndfile, const SF_INFO &sfinfo);
+    virtual ~LibsndfileSink();
+
+    // NBAIO_Port interface
+
+    //virtual ssize_t negotiate(const NBAIO_Format offers[], size_t numOffers,
+    //                          NBAIO_Format counterOffers[], size_t& numCounterOffers);
+    //virtual NBAIO_Format format() const;
+
+    // NBAIO_Sink interface
+
+    //virtual size_t framesWritten() const;
+    //virtual size_t framesUnderrun() const;
+    //virtual size_t underruns() const;
+    //virtual ssize_t availableToWrite() const;
+    virtual ssize_t write(const void *buffer, size_t count);
+    //virtual ssize_t writeVia(writeVia_t via, size_t total, void *user, size_t block);
+
+private:
+    SNDFILE *                   mSndfile;
+};
+
+}   // namespace android
+
+#endif  // ANDROID_AUDIO_LIBSNDFILE_SINK_H
diff --git a/services/audioflinger/LibsndfileSource.cpp b/services/audioflinger/LibsndfileSource.cpp
new file mode 100644
index 0000000..28317d6
--- /dev/null
+++ b/services/audioflinger/LibsndfileSource.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LibsndfileSource"
+//#define LOG_NDEBUG 0
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include "LibsndfileSource.h"
+
+namespace android {
+
+LibsndfileSource::LibsndfileSource(SNDFILE *sndfile, const SF_INFO &sfinfo, bool loop) :
+    NBAIO_Source(Format_from_SR_C(sfinfo.samplerate, sfinfo.channels)),
+    mSndfile(sndfile),
+    mEstimatedFramesUntilEOF(sfinfo.frames),
+    mLooping(loop && sfinfo.seekable),
+    mReadAnyFramesThisLoopCycle(false)
+{
+}
+
+LibsndfileSource::~LibsndfileSource()
+{
+    // do not close mSndfile; we don't own it
+}
+
+ssize_t LibsndfileSource::availableToRead()
+{
+    // after we reach the presumed EOF, report infinity just in case there's actually more
+    return !mLooping && mEstimatedFramesUntilEOF > 0 ? mEstimatedFramesUntilEOF : SSIZE_MAX;
+}
+
+ssize_t LibsndfileSource::read(void *buffer, size_t count)
+{
+    if (!mNegotiated) {
+        return (ssize_t) NEGOTIATE;
+    }
+    if (mSndfile == NULL) {
+        return (ssize_t) NO_INIT;
+    }
+    sf_count_t actual = sf_readf_short(mSndfile, (short *) buffer, (sf_count_t) count);
+    // Detect EOF by zero frames read, not by mFramesUntilEOF as it could be inaccurate
+    if (actual == 0) {
+        if (mLooping) {
+            if (mReadAnyFramesThisLoopCycle) {
+                (void) sf_seek(mSndfile, (sf_count_t) 0, SEEK_SET);
+                mReadAnyFramesThisLoopCycle = false;
+            } else {
+                // We didn't read any frames during the current loop cycle, so disable
+                // further looping to prevent the caller from busy waiting at read().
+                // This is especially important when looping an empty file.
+                mLooping = false;
+            }
+        }
+    } else {
+        mFramesRead += actual;
+        if (actual >= mEstimatedFramesUntilEOF) {
+            mEstimatedFramesUntilEOF = 0;
+        } else {
+            mEstimatedFramesUntilEOF -= actual;
+        }
+        mReadAnyFramesThisLoopCycle = true;
+    }
+    return actual;
+}
+
+}   // namespace android
diff --git a/services/audioflinger/LibsndfileSource.h b/services/audioflinger/LibsndfileSource.h
new file mode 100644
index 0000000..4fbdb4b
--- /dev/null
+++ b/services/audioflinger/LibsndfileSource.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_LIBSNDFILE_SOURCE_H
+#define ANDROID_AUDIO_LIBSNDFILE_SOURCE_H
+
+#include "NBAIO.h"
+#include "sndfile.h"
+
+// Implementation of NBAIO_Source that wraps a libsndfile opened in SFM_READ mode
+
+namespace android {
+
+class LibsndfileSource : public NBAIO_Source {
+
+public:
+    // If 'loop' is true and it permits seeking, then we'll act as an infinite source
+    LibsndfileSource(SNDFILE *sndfile, const SF_INFO &sfinfo, bool loop = false);
+    virtual ~LibsndfileSource();
+
+    // NBAIO_Port interface
+
+    //virtual ssize_t negotiate(const NBAIO_Format offers[], size_t numOffers,
+    //                          NBAIO_Format counterOffers[], size_t& numCounterOffers);
+    //virtual NBAIO_Format format() const;
+
+    // NBAIO_Source interface
+
+    //virtual size_t framesRead() const;
+    //virtual size_t framesOverrun();
+    //virtual size_t overruns();
+    virtual ssize_t availableToRead();
+    virtual ssize_t read(void *buffer, size_t count);
+    //virtual ssize_t readVia(readVia_t via, size_t total, void *user, size_t block);
+
+private:
+    SNDFILE *   mSndfile;
+    sf_count_t  mEstimatedFramesUntilEOF;
+    bool        mLooping;
+    bool        mReadAnyFramesThisLoopCycle;
+};
+
+}   // namespace android
+
+#endif  // ANDROID_AUDIO_LIBSNDFILE_SOURCE_H
diff --git a/services/audioflinger/MonoPipe.cpp b/services/audioflinger/MonoPipe.cpp
new file mode 100644
index 0000000..b0ddf83
--- /dev/null
+++ b/services/audioflinger/MonoPipe.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MonoPipe"
+//#define LOG_NDEBUG 0
+
+#include <cutils/atomic.h>
+#include <cutils/compiler.h>
+#include <utils/Log.h>
+#include "MonoPipe.h"
+#include "roundup.h"
+
+namespace android {
+
+MonoPipe::MonoPipe(size_t maxFrames, NBAIO_Format format, bool writeCanBlock) :
+        NBAIO_Sink(format),
+        mMaxFrames(roundup(maxFrames)),
+        mBuffer(malloc(mMaxFrames * Format_frameSize(format))),
+        mFront(0),
+        mRear(0),
+        mWriteCanBlock(writeCanBlock)
+{
+    if (writeCanBlock) {
+        // compute sleep time to be about 2/3 of a full pipe;
+        // this gives a balance between risk of underrun vs. too-frequent wakeups
+        mSleep.tv_sec = 0;
+        uint64_t ns = mMaxFrames * (666666667 / Format_sampleRate(format));
+        if (ns > 999999999) {
+            ns = 999999999;
+        }
+        mSleep.tv_nsec = ns;
+    }
+}
+
+MonoPipe::~MonoPipe()
+{
+    free(mBuffer);
+}
+
+ssize_t MonoPipe::availableToWrite() const
+{
+    if (CC_UNLIKELY(!mNegotiated)) {
+        return NEGOTIATE;
+    }
+    ssize_t ret = mMaxFrames - (mRear - android_atomic_acquire_load(&mFront));
+    ALOG_ASSERT((0 <= ret) && (ret <= mMaxFrames));
+    return ret;
+}
+
+ssize_t MonoPipe::write(const void *buffer, size_t count)
+{
+    // count == 0 is unlikely and not worth checking for explicitly; will be handled automatically
+    if (CC_UNLIKELY(!mNegotiated)) {
+        return NEGOTIATE;
+    }
+    size_t totalFramesWritten = 0;
+    for (;;) {
+        size_t written = availableToWrite();
+        if (CC_LIKELY(written > count)) {
+            written = count;
+        }
+        size_t rear = mRear & (mMaxFrames - 1);
+        size_t part1 = mMaxFrames - rear;
+        if (part1 > written) {
+            part1 = written;
+        }
+        if (CC_LIKELY(part1 > 0)) {
+            memcpy((char *) mBuffer + (rear << mBitShift), buffer, part1 << mBitShift);
+            if (CC_UNLIKELY(rear + part1 == mMaxFrames)) {
+                size_t part2 = written - part1;
+                if (CC_LIKELY(part2 > 0)) {
+                    memcpy(mBuffer, (char *) buffer + (part1 << mBitShift), part2 << mBitShift);
+                }
+            }
+            android_atomic_release_store(written + mRear, &mRear);
+            totalFramesWritten += written;
+        }
+        if ((count -= written) == 0 || !mWriteCanBlock) {
+            break;
+        }
+        buffer = (char *) buffer + (written << mBitShift);
+        // simulate blocking I/O by sleeping
+        nanosleep(&mSleep, NULL);
+    }
+    mFramesWritten += totalFramesWritten;
+    return totalFramesWritten;
+}
+
+}   // namespace android
diff --git a/services/audioflinger/MonoPipe.h b/services/audioflinger/MonoPipe.h
new file mode 100644
index 0000000..45e6bb4
--- /dev/null
+++ b/services/audioflinger/MonoPipe.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_MONO_PIPE_H
+#define ANDROID_AUDIO_MONO_PIPE_H
+
+#include <time.h>
+#include "NBAIO.h"
+
+namespace android {
+
+// MonoPipe is similar to Pipe except:
+//  - supports only a single reader, called MonoPipeReader
+//  - write() cannot overrun; instead it will return a short actual count if insufficient space
+//  - write() can optionally block if the pipe is full
+// Like Pipe, it is not multi-thread safe for either writer or reader
+// but writer and reader can be different threads.
+class MonoPipe : public NBAIO_Sink {
+
+    friend class MonoPipeReader;
+
+public:
+    // maxFrames will be rounded up to a power of 2, and all slots are available. Must be >= 2.
+    // Note: whatever shares this object with another thread needs to do so in an SMP-safe way (like
+    // creating it the object before creating the other thread, or storing the object with a
+    // release_store). Otherwise the other thread could see a partially-constructed object.
+    MonoPipe(size_t maxFrames, NBAIO_Format format, bool writeCanBlock = false);
+    virtual ~MonoPipe();
+
+    // NBAIO_Port interface
+
+    //virtual ssize_t negotiate(const NBAIO_Format offers[], size_t numOffers,
+    //                          NBAIO_Format counterOffers[], size_t& numCounterOffers);
+    //virtual NBAIO_Format format() const;
+
+    // NBAIO_Sink interface
+
+    //virtual size_t framesWritten() const;
+    //virtual size_t framesUnderrun() const;
+    //virtual size_t underruns() const;
+
+    virtual ssize_t availableToWrite() const;
+    virtual ssize_t write(const void *buffer, size_t count);
+    //virtual ssize_t writeVia(writeVia_t via, size_t total, void *user, size_t block);
+
+private:
+    const size_t    mMaxFrames;     // always a power of 2
+    void * const    mBuffer;
+    // mFront and mRear will never be separated by more than mMaxFrames.
+    // 32-bit overflow is possible if the pipe is active for a long time, but if that happens it's
+    // safe because we "&" with (mMaxFrames-1) at end of computations to calculate a buffer index.
+    volatile int32_t mFront;        // written by reader with android_atomic_release_store,
+                                    // read by writer with android_atomic_acquire_load
+    volatile int32_t mRear;         // written by writer with android_atomic_release_store,
+                                    // read by reader with android_atomic_acquire_load
+    const bool      mWriteCanBlock; // whether write() should block if the pipe is full
+    struct timespec mSleep;         // time to sleep if blocking is enabled and the pipe is full
+};
+
+}   // namespace android
+
+#endif  // ANDROID_AUDIO_MONO_PIPE_H
diff --git a/services/audioflinger/MonoPipeReader.cpp b/services/audioflinger/MonoPipeReader.cpp
new file mode 100644
index 0000000..b80d0c0
--- /dev/null
+++ b/services/audioflinger/MonoPipeReader.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MonoPipeReader"
+//#define LOG_NDEBUG 0
+
+#include <cutils/compiler.h>
+#include <utils/Log.h>
+#include "MonoPipeReader.h"
+
+namespace android {
+
+MonoPipeReader::MonoPipeReader(MonoPipe* pipe) :
+        NBAIO_Source(pipe->mFormat),
+        mPipe(pipe)
+{
+}
+
+MonoPipeReader::~MonoPipeReader()
+{
+}
+
+ssize_t MonoPipeReader::availableToRead()
+{
+    if (CC_UNLIKELY(!mNegotiated)) {
+        return NEGOTIATE;
+    }
+    ssize_t ret = android_atomic_acquire_load(&mPipe->mRear) - mPipe->mFront;
+    ALOG_ASSERT((0 <= ret) && (ret <= mMaxFrames));
+    return ret;
+}
+
+ssize_t MonoPipeReader::read(void *buffer, size_t count)
+{
+    // count == 0 is unlikely and not worth checking for explicitly; will be handled automatically
+    ssize_t red = availableToRead();
+    if (CC_UNLIKELY(red <= 0)) {
+        return red;
+    }
+    if (CC_LIKELY((size_t) red > count)) {
+        red = count;
+    }
+    size_t front = mPipe->mFront & (mPipe->mMaxFrames - 1);
+    size_t part1 = mPipe->mMaxFrames - front;
+    if (part1 > (size_t) red) {
+        part1 = red;
+    }
+    if (CC_LIKELY(part1 > 0)) {
+        memcpy(buffer, (char *) mPipe->mBuffer + (front << mBitShift), part1 << mBitShift);
+        if (CC_UNLIKELY(front + part1 == mPipe->mMaxFrames)) {
+            size_t part2 = red - part1;
+            if (CC_LIKELY(part2 > 0)) {
+                memcpy((char *) buffer + (part1 << mBitShift), mPipe->mBuffer, part2 << mBitShift);
+            }
+        }
+        android_atomic_release_store(red + mPipe->mFront, &mPipe->mFront);
+        mFramesRead += red;
+    }
+    return red;
+}
+
+}   // namespace android
diff --git a/services/audioflinger/MonoPipeReader.h b/services/audioflinger/MonoPipeReader.h
new file mode 100644
index 0000000..9bb0a94
--- /dev/null
+++ b/services/audioflinger/MonoPipeReader.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_MONO_PIPE_READER_H
+#define ANDROID_AUDIO_MONO_PIPE_READER_H
+
+#include "MonoPipe.h"
+
+namespace android {
+
+// MonoPipeReader is safe for only a single reader thread
+class MonoPipeReader : public NBAIO_Source {
+
+public:
+
+    // Construct a MonoPipeReader and associate it with a MonoPipe;
+    // any data already in the pipe is visible to this PipeReader.
+    // There can be only a single MonoPipeReader per MonoPipe.
+    // FIXME make this constructor a factory method of MonoPipe.
+    MonoPipeReader(MonoPipe* pipe);
+    virtual ~MonoPipeReader();
+
+    // NBAIO_Port interface
+
+    //virtual ssize_t negotiate(const NBAIO_Format offers[], size_t numOffers,
+    //                          NBAIO_Format counterOffers[], size_t& numCounterOffers);
+    //virtual NBAIO_Format format() const;
+
+    // NBAIO_Source interface
+
+    //virtual size_t framesRead() const;
+    //virtual size_t framesOverrun();
+    //virtual size_t overruns();
+
+    virtual ssize_t availableToRead();
+
+    virtual ssize_t read(void *buffer, size_t count);
+
+    // NBAIO_Source end
+
+#if 0   // until necessary
+    MonoPipe* pipe() const { return mPipe; }
+#endif
+
+private:
+    MonoPipe * const mPipe;
+};
+
+}   // namespace android
+
+#endif  // ANDROID_AUDIO_MONO_PIPE_READER_H
diff --git a/services/audioflinger/NBAIO.cpp b/services/audioflinger/NBAIO.cpp
new file mode 100644
index 0000000..9d71eae
--- /dev/null
+++ b/services/audioflinger/NBAIO.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "NBAIO"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include "NBAIO.h"
+
+namespace android {
+
+size_t Format_frameSize(NBAIO_Format format)
+{
+    switch (format) {
+    case Format_SR44_1_C2_I16:
+    case Format_SR48_C2_I16:
+        return 2 * sizeof(short);
+    case Format_SR44_1_C1_I16:
+    case Format_SR48_C1_I16:
+        return 1 * sizeof(short);
+    case Format_Invalid:
+    default:
+        return 0;
+    }
+}
+
+size_t Format_frameBitShift(NBAIO_Format format)
+{
+    switch (format) {
+    case Format_SR44_1_C2_I16:
+    case Format_SR48_C2_I16:
+        return 2;   // 1 << 2 == 2 * sizeof(short)
+    case Format_SR44_1_C1_I16:
+    case Format_SR48_C1_I16:
+        return 1;   // 1 << 1 == 1 * sizeof(short)
+    case Format_Invalid:
+    default:
+        return 0;
+    }
+}
+
+unsigned Format_sampleRate(NBAIO_Format format)
+{
+    switch (format) {
+    case Format_SR44_1_C1_I16:
+    case Format_SR44_1_C2_I16:
+        return 44100;
+    case Format_SR48_C1_I16:
+    case Format_SR48_C2_I16:
+        return 48000;
+    case Format_Invalid:
+    default:
+        return 0;
+    }
+}
+
+unsigned Format_channelCount(NBAIO_Format format)
+{
+    switch (format) {
+    case Format_SR44_1_C1_I16:
+    case Format_SR48_C1_I16:
+        return 1;
+    case Format_SR44_1_C2_I16:
+    case Format_SR48_C2_I16:
+        return 2;
+    case Format_Invalid:
+    default:
+        return 0;
+    }
+}
+
+NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount)
+{
+    if (sampleRate == 44100 && channelCount == 2) return Format_SR44_1_C2_I16;
+    if (sampleRate == 48000 && channelCount == 2) return Format_SR48_C2_I16;
+    if (sampleRate == 44100 && channelCount == 1) return Format_SR44_1_C1_I16;
+    if (sampleRate == 48000 && channelCount == 1) return Format_SR48_C1_I16;
+    return Format_Invalid;
+}
+
+// This is a default implementation; it is expected that subclasses will optimize this.
+ssize_t NBAIO_Sink::writeVia(writeVia_t via, size_t total, void *user, size_t block)
+{
+    if (!mNegotiated) {
+        return (ssize_t) NEGOTIATE;
+    }
+    static const size_t maxBlock = 32;
+    size_t frameSize = Format_frameSize(mFormat);
+    ALOG_ASSERT(frameSize > 0 && frameSize <= 8);
+    // double guarantees alignment for stack similar to what malloc() gives for heap
+    if (block == 0 || block > maxBlock) {
+        block = maxBlock;
+    }
+    double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)];
+    size_t accumulator = 0;
+    while (accumulator < total) {
+        size_t count = total - accumulator;
+        if (count > block) {
+            count = block;
+        }
+        ssize_t ret = via(user, buffer, count);
+        if (ret > 0) {
+            ALOG_ASSERT((size_t) ret <= count);
+            size_t maxRet = ret;
+            ret = write(buffer, maxRet);
+            if (ret > 0) {
+                ALOG_ASSERT((size_t) ret <= maxRet);
+                accumulator += ret;
+                continue;
+            }
+        }
+        return accumulator > 0 ? accumulator : ret;
+    }
+    return accumulator;
+}
+
+// This is a default implementation; it is expected that subclasses will optimize this.
+ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user, size_t block)
+{
+    if (!mNegotiated) {
+        return (ssize_t) NEGOTIATE;
+    }
+    static const size_t maxBlock = 32;
+    size_t frameSize = Format_frameSize(mFormat);
+    ALOG_ASSERT(frameSize > 0 && frameSize <= 8);
+    // double guarantees alignment for stack similar to what malloc() gives for heap
+    if (block == 0 || block > maxBlock) {
+        block = maxBlock;
+    }
+    double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)];
+    size_t accumulator = 0;
+    while (accumulator < total) {
+        size_t count = total - accumulator;
+        if (count > block) {
+            count = block;
+        }
+        ssize_t ret = read(buffer, count);
+        if (ret > 0) {
+            ALOG_ASSERT((size_t) ret <= count);
+            size_t maxRet = ret;
+            ret = via(user, buffer, maxRet);
+            if (ret > 0) {
+                ALOG_ASSERT((size_t) ret <= maxRet);
+                accumulator += ret;
+                continue;
+            }
+        }
+        return accumulator > 0 ? accumulator : ret;
+    }
+    return accumulator;
+}
+
+// Default implementation that only accepts my mFormat
+ssize_t NBAIO_Port::negotiate(const NBAIO_Format offers[], size_t numOffers,
+                                  NBAIO_Format counterOffers[], size_t& numCounterOffers)
+{
+    ALOGV("negotiate offers=%p numOffers=%u countersOffers=%p numCounterOffers=%u",
+            offers, numOffers, counterOffers, numCounterOffers);
+    if (mFormat != Format_Invalid) {
+        for (size_t i = 0; i < numOffers; ++i) {
+            if (offers[i] == mFormat) {
+                mNegotiated = true;
+                return i;
+            }
+        }
+        if (numCounterOffers > 0) {
+            counterOffers[0] = mFormat;
+        }
+        numCounterOffers = 1;
+    } else {
+        numCounterOffers = 0;
+    }
+    return (ssize_t) NEGOTIATE;
+}
+
+}   // namespace android
diff --git a/services/audioflinger/NBAIO.h b/services/audioflinger/NBAIO.h
new file mode 100644
index 0000000..b5ae0f1
--- /dev/null
+++ b/services/audioflinger/NBAIO.h
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_NBAIO_H
+#define ANDROID_AUDIO_NBAIO_H
+
+// Non-blocking audio I/O interface
+//
+// This header file has the abstract interfaces only.  Concrete implementation classes are declared
+// elsewhere.  Implementations _should_ be non-blocking for all methods, especially read() and
+// write(), but this is not enforced.  In general, implementations do not need to be multi-thread
+// safe, and any exceptions are noted in the particular implementation.
+
+#include <limits.h>
+#include <stdlib.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+// In addition to the usual status_t
+enum {
+    NEGOTIATE    = 0x80000010,  // Must (re-)negotiate format.  For negotiate() only, the offeree
+                                // doesn't accept offers, and proposes counter-offers
+    OVERRUN      = 0x80000011,  // availableToRead(), read(), or readVia() detected lost input due
+                                // to overrun; an event is counted and the caller should re-try
+    UNDERRUN     = 0x80000012,  // availableToWrite(), write(), or writeVia() detected a gap in
+                                // output due to underrun (not being called often enough, or with
+                                // enough data); an event is counted and the caller should re-try
+};
+
+// Negotiation of format is based on the data provider and data sink, or the data consumer and
+// data source, exchanging prioritized arrays of offers and counter-offers until a single offer is
+// mutually agreed upon.  Each offer is an NBAIO_Format.  For simplicity and performance,
+// NBAIO_Format is an enum that ties together the most important combinations of the various
+// attributes, rather than a struct with separate fields for format, sample rate, channel count,
+// interleave, packing, alignment, etc.  The reason is that NBAIO_Format tries to abstract out only
+// the combinations that are actually needed within AudioFligner.  If the list of combinations grows
+// too large, then this decision should be re-visited.
+enum NBAIO_Format {
+    Format_Invalid,
+    Format_SR44_1_C2_I16,   // 44.1 kHz PCM stereo interleaved 16-bit signed
+    Format_SR48_C2_I16,     // 48 kHz PCM stereo interleaved 16-bit signed
+    Format_SR44_1_C1_I16,   // 44.1 kHz PCM mono interleaved 16-bit signed
+    Format_SR48_C1_I16,     // 48 kHz PCM mono interleaved 16-bit signed
+};
+
+// Return the frame size of an NBAIO_Format in bytes
+size_t Format_frameSize(NBAIO_Format format);
+
+// Return the frame size of an NBAIO_Format as a bit shift
+size_t Format_frameBitShift(NBAIO_Format format);
+
+// Convert a sample rate in Hz and channel count to an NBAIO_Format
+NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount);
+
+// Return the sample rate in Hz of an NBAIO_Format
+unsigned Format_sampleRate(NBAIO_Format format);
+
+// Return the channel count of an NBAIO_Format
+unsigned Format_channelCount(NBAIO_Format format);
+
+// Callbacks used by NBAIO_Sink::writeVia() and NBAIO_Source::readVia() below.
+typedef ssize_t (*writeVia_t)(void *user, void *buffer, size_t count);
+typedef ssize_t (*readVia_t)(void *user, const void *buffer, size_t count);
+
+// Abstract class (interface) representing a data port.
+class NBAIO_Port : public RefBase {
+
+public:
+
+    // negotiate() must called first.  The purpose of negotiate() is to check compatibility of
+    // formats, not to automatically adapt if they are incompatible.  It's the responsibility of
+    // whoever sets up the graph connections to make sure formats are compatible, and this method
+    // just verifies that.  The edges are "dumb" and don't attempt to adapt to bad connections.
+    // How it works: offerer proposes an array of formats, in descending order of preference from
+    // offers[0] to offers[numOffers - 1].  If offeree accepts one of these formats, it returns
+    // the index of that offer.  Otherwise, offeree sets numCounterOffers to the number of
+    // counter-offers (up to a maximumum of the entry value of numCounterOffers), fills in the
+    // provided array counterOffers[] with its counter-offers, in descending order of preference
+    // from counterOffers[0] to counterOffers[numCounterOffers - 1], and returns NEGOTIATE.
+    // Note that since the offerer allocates space for counter-offers, but only the offeree knows
+    // how many counter-offers it has, there may be insufficient space for all counter-offers.
+    // In that case, the offeree sets numCounterOffers to the requested number of counter-offers
+    // (which is greater than the entry value of numCounterOffers), fills in as many of the most
+    // important counterOffers as will fit, and returns NEGOTIATE.  As this implies a re-allocation,
+    // it should be used as a last resort.  It is preferable for the offerer to simply allocate a
+    // larger space to begin with, and/or for the offeree to tolerate a smaller space than desired.
+    // Alternatively, the offerer can pass NULL for offers and counterOffers, and zero for
+    // numOffers. This indicates that it has not allocated space for any counter-offers yet.
+    // In this case, the offerree should set numCounterOffers appropriately and return NEGOTIATE.
+    // Then the offerer will allocate the correct amount of memory and retry.
+    // Format_Invalid is not allowed as either an offer or counter-offer.
+    // Returns:
+    //  >= 0        Offer accepted.
+    //  NEGOTIATE   No offer accepted, and counter-offer(s) optionally made. See above for details.
+    virtual ssize_t negotiate(const NBAIO_Format offers[], size_t numOffers,
+                              NBAIO_Format counterOffers[], size_t& numCounterOffers);
+
+    // Return the current negotiated format, or Format_Invalid if negotiation has not been done,
+    // or if re-negotiation is required.
+    virtual NBAIO_Format format() const { return mNegotiated ? mFormat : Format_Invalid; }
+
+protected:
+    NBAIO_Port(NBAIO_Format format) : mNegotiated(false), mFormat(format),
+                                      mBitShift(Format_frameBitShift(format)) { }
+    virtual ~NBAIO_Port() { }
+
+    // Implementations are free to ignore these if they don't need them
+
+    bool            mNegotiated;    // mNegotiated implies (mFormat != Format_Invalid)
+    NBAIO_Format    mFormat;        // (mFormat != Format_Invalid) does not imply mNegotiated
+    size_t          mBitShift;      // assign in parallel with any assignment to mFormat
+};
+
+// Abstract class (interface) representing a non-blocking data sink, for use by a data provider.
+class NBAIO_Sink : public NBAIO_Port {
+
+public:
+
+    // For the next two APIs:
+    // 32 bits rolls over after 27 hours at 44.1 kHz; if that concerns you then poll periodically.
+
+    // Return the number of frames written successfully since construction.
+    virtual size_t framesWritten() const { return mFramesWritten; }
+
+    // Number of frames lost due to underrun since construction.
+    virtual size_t framesUnderrun() const { return 0; }
+
+    // Number of underruns since construction, where a set of contiguous lost frames is one event.
+    virtual size_t underruns() const { return 0; }
+
+    // Estimate of number of frames that could be written successfully now without blocking.
+    // When a write() is actually attempted, the implementation is permitted to return a smaller or
+    // larger transfer count, however it will make a good faith effort to give an accurate estimate.
+    // Errors:
+    //  NEGOTIATE   (Re-)negotiation is needed.
+    //  UNDERRUN    write() has not been called frequently enough, or with enough frames to keep up.
+    //              An underrun event is counted, and the caller should re-try this operation.
+    //  WOULD_BLOCK Determining how many frames can be written without blocking would itself block.
+    virtual ssize_t availableToWrite() const { return SSIZE_MAX; }
+
+    // Transfer data to sink from single input buffer.  Implies a copy.
+    // Inputs:
+    //  buffer  Non-NULL buffer owned by provider.
+    //  count   Maximum number of frames to transfer.
+    // Return value:
+    //  > 0     Number of frames successfully transferred prior to first error.
+    //  = 0     Count was zero.
+    //  < 0     status_t error occurred prior to the first frame transfer.
+    // Errors:
+    //  NEGOTIATE   (Re-)negotiation is needed.
+    //  WOULD_BLOCK No frames can be transferred without blocking.
+    //  UNDERRUN    write() has not been called frequently enough, or with enough frames to keep up.
+    //              An underrun event is counted, and the caller should re-try this operation.
+    virtual ssize_t write(const void *buffer, size_t count) = 0;
+
+    // Transfer data to sink using a series of callbacks.  More suitable for zero-fill, synthesis,
+    // and non-contiguous transfers (e.g. circular buffer or writev).
+    // Inputs:
+    //  via     Callback function that the sink will call as many times as needed to consume data.
+    //  total   Estimate of the number of frames the provider has available.  This is an estimate,
+    //          and it can provide a different number of frames during the series of callbacks.
+    //  user    Arbitrary void * reserved for data provider.
+    //  block   Number of frames per block, that is a suggested value for 'count' in each callback.
+    //          Zero means no preference.  This parameter is a hint only, and may be ignored.
+    // Return value:
+    //  > 0     Total number of frames successfully transferred prior to first error.
+    //  = 0     Count was zero.
+    //  < 0     status_t error occurred prior to the first frame transfer.
+    // Errors:
+    //  NEGOTIATE   (Re-)negotiation is needed.
+    //  WOULD_BLOCK No frames can be transferred without blocking.
+    //  UNDERRUN    write() has not been called frequently enough, or with enough frames to keep up.
+    //              An underrun event is counted, and the caller should re-try this operation.
+    //
+    // The 'via' callback is called by the data sink as follows:
+    // Inputs:
+    //  user    Arbitrary void * reserved for data provider.
+    //  buffer  Non-NULL buffer owned by sink that callback should fill in with data,
+    //          up to a maximum of 'count' frames.
+    //  count   Maximum number of frames to transfer during this callback.
+    // Return value:
+    //  > 0     Number of frames successfully transferred during this callback prior to first error.
+    //  = 0     Count was zero.
+    //  < 0     status_t error occurred prior to the first frame transfer during this callback.
+    virtual ssize_t writeVia(writeVia_t via, size_t total, void *user, size_t block = 0);
+
+protected:
+    NBAIO_Sink(NBAIO_Format format = Format_Invalid) : NBAIO_Port(format), mFramesWritten(0) { }
+    virtual ~NBAIO_Sink() { }
+
+    // Implementations are free to ignore these if they don't need them
+    size_t  mFramesWritten;
+};
+
+// Abstract class (interface) representing a non-blocking data source, for use by a data consumer.
+class NBAIO_Source : public NBAIO_Port {
+
+public:
+
+    // For the next two APIs:
+    // 32 bits rolls over after 27 hours at 44.1 kHz; if that concerns you then poll periodically.
+
+    // Number of frames read successfully since construction.
+    virtual size_t framesRead() const { return mFramesRead; }
+
+    // Number of frames lost due to overrun since construction.
+    // Not const because implementations may need to do I/O.
+    virtual size_t framesOverrun() /*const*/ { return 0; }
+
+    // Number of overruns since construction, where a set of contiguous lost frames is one event.
+    // Not const because implementations may need to do I/O.
+    virtual size_t overruns() /*const*/ { return 0; }
+
+    // Estimate of number of frames that could be read successfully now.
+    // When a read() is actually attempted, the implementation is permitted to return a smaller or
+    // larger transfer count, however it will make a good faith effort to give an accurate estimate.
+    // Errors:
+    //  NEGOTIATE   (Re-)negotiation is needed.
+    //  OVERRUN     One or more frames were lost due to overrun, try again to read more recent data.
+    //  WOULD_BLOCK Determining how many frames can be read without blocking would itself block.
+    virtual ssize_t availableToRead() { return SSIZE_MAX; }
+
+    // Transfer data from source into single destination buffer.  Implies a copy.
+    // Inputs:
+    //  buffer  Non-NULL destination buffer owned by consumer.
+    //  count   Maximum number of frames to transfer.
+    // Return value:
+    //  > 0     Number of frames successfully transferred prior to first error.
+    //  = 0     Count was zero.
+    //  < 0     status_t error occurred prior to the first frame transfer.
+    // Errors:
+    //  NEGOTIATE   (Re-)negotiation is needed.
+    //  WOULD_BLOCK No frames can be transferred without blocking.
+    //  OVERRUN     read() has not been called frequently enough, or with enough frames to keep up.
+    //              One or more frames were lost due to overrun, try again to read more recent data.
+    virtual ssize_t read(void *buffer, size_t count) = 0;
+
+    // Transfer data from source using a series of callbacks.  More suitable for zero-fill,
+    // synthesis, and non-contiguous transfers (e.g. circular buffer or readv).
+    // Inputs:
+    //  via     Callback function that the source will call as many times as needed to provide data.
+    //  total   Estimate of the number of frames the consumer desires.  This is an estimate,
+    //          and it can consume a different number of frames during the series of callbacks.
+    //  user    Arbitrary void * reserved for data consumer.
+    //  block   Number of frames per block, that is a suggested value for 'count' in each callback.
+    //          Zero means no preference.  This parameter is a hint only, and may be ignored.
+    // Return value:
+    //  > 0     Total number of frames successfully transferred prior to first error.
+    //  = 0     Count was zero.
+    //  < 0     status_t error occurred prior to the first frame transfer.
+    // Errors:
+    //  NEGOTIATE   (Re-)negotiation is needed.
+    //  WOULD_BLOCK No frames can be transferred without blocking.
+    //  OVERRUN     read() has not been called frequently enough, or with enough frames to keep up.
+    //              One or more frames were lost due to overrun, try again to read more recent data.
+    //
+    // The 'via' callback is called by the data source as follows:
+    // Inputs:
+    //  user    Arbitrary void * reserved for data consumer.
+    //  dest    Non-NULL buffer owned by source that callback should consume data from,
+    //          up to a maximum of 'count' frames.
+    //  count   Maximum number of frames to transfer during this callback.
+    // Return value:
+    //  > 0     Number of frames successfully transferred during this callback prior to first error.
+    //  = 0     Count was zero.
+    //  < 0     status_t error occurred prior to the first frame transfer during this callback.
+    virtual ssize_t readVia(readVia_t via, size_t total, void *user, size_t block = 0);
+
+protected:
+    NBAIO_Source(NBAIO_Format format = Format_Invalid) : NBAIO_Port(format), mFramesRead(0) { }
+    virtual ~NBAIO_Source() { }
+
+    // Implementations are free to ignore these if they don't need them
+    size_t  mFramesRead;
+};
+
+}   // namespace android
+
+#endif  // ANDROID_AUDIO_NBAIO_H
diff --git a/services/audioflinger/Pipe.cpp b/services/audioflinger/Pipe.cpp
new file mode 100644
index 0000000..e5b3561
--- /dev/null
+++ b/services/audioflinger/Pipe.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Pipe"
+//#define LOG_NDEBUG 0
+
+#include <cutils/atomic.h>
+#include <cutils/compiler.h>
+#include <utils/Log.h>
+#include "Pipe.h"
+#include "roundup.h"
+
+namespace android {
+
+Pipe::Pipe(size_t maxFrames, NBAIO_Format format) :
+        NBAIO_Sink(format),
+        mMaxFrames(roundup(maxFrames)),
+        mBuffer(malloc(mMaxFrames * Format_frameSize(format))),
+        mRear(0),
+        mReaders(0)
+{
+}
+
+Pipe::~Pipe()
+{
+    ALOG_ASSERT(android_atomic_acquire_load(&mReaders) == 0);
+    free(mBuffer);
+}
+
+ssize_t Pipe::write(const void *buffer, size_t count)
+{
+    // count == 0 is unlikely and not worth checking for
+    if (CC_UNLIKELY(!mNegotiated)) {
+        return NEGOTIATE;
+    }
+    // write() is not multi-thread safe w.r.t. itself, so no mutex or atomic op needed to read mRear
+    size_t rear = mRear & (mMaxFrames - 1);
+    size_t written = mMaxFrames - rear;
+    if (CC_LIKELY(written > count)) {
+        written = count;
+    }
+    memcpy((char *) mBuffer + (rear << mBitShift), buffer, written << mBitShift);
+    if (CC_UNLIKELY(rear + written == mMaxFrames)) {
+        if (CC_UNLIKELY((count -= written) > rear)) {
+            count = rear;
+        }
+        if (CC_LIKELY(count > 0)) {
+            memcpy(mBuffer, (char *) buffer + (written << mBitShift), count << mBitShift);
+            written += count;
+        }
+    }
+    android_atomic_release_store(written + mRear, &mRear);
+    mFramesWritten += written;
+    return written;
+}
+
+}   // namespace android
diff --git a/services/audioflinger/Pipe.h b/services/audioflinger/Pipe.h
new file mode 100644
index 0000000..79a4eee
--- /dev/null
+++ b/services/audioflinger/Pipe.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_PIPE_H
+#define ANDROID_AUDIO_PIPE_H
+
+#include "NBAIO.h"
+
+namespace android {
+
+// Pipe is multi-thread safe for readers (see PipeReader), but safe for only a single writer thread.
+// It cannot UNDERRUN on write, unless we allow designation of a master reader that provides the
+// time-base. Readers can be added and removed dynamically, and it's OK to have no readers.
+class Pipe : public NBAIO_Sink {
+
+    friend class PipeReader;
+
+public:
+    // maxFrames will be rounded up to a power of 2, and all slots are available. Must be >= 2.
+    Pipe(size_t maxFrames, NBAIO_Format format);
+    virtual ~Pipe();
+
+    // NBAIO_Port interface
+
+    //virtual ssize_t negotiate(const NBAIO_Format offers[], size_t numOffers,
+    //                          NBAIO_Format counterOffers[], size_t& numCounterOffers);
+    //virtual NBAIO_Format format() const;
+
+    // NBAIO_Sink interface
+
+    //virtual size_t framesWritten() const;
+    //virtual size_t framesUnderrun() const;
+    //virtual size_t underruns() const;
+
+    // The write side of a pipe permits overruns; flow control is the caller's responsibility.
+    // It doesn't return +infinity because that would guarantee an overrun.
+    virtual ssize_t availableToWrite() const { return mMaxFrames; }
+
+    virtual ssize_t write(const void *buffer, size_t count);
+    //virtual ssize_t writeVia(writeVia_t via, size_t total, void *user, size_t block);
+
+private:
+    const size_t    mMaxFrames;     // always a power of 2
+    void * const    mBuffer;
+    volatile int32_t mRear;         // written by android_atomic_release_store
+    volatile int32_t mReaders;      // number of PipeReader clients currently attached to this Pipe
+};
+
+}   // namespace android
+
+#endif  // ANDROID_AUDIO_PIPE_H
diff --git a/services/audioflinger/PipeReader.cpp b/services/audioflinger/PipeReader.cpp
new file mode 100644
index 0000000..43bcb42
--- /dev/null
+++ b/services/audioflinger/PipeReader.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "PipeReader"
+//#define LOG_NDEBUG 0
+
+#include <cutils/compiler.h>
+#include <utils/Log.h>
+#include "PipeReader.h"
+
+namespace android {
+
+PipeReader::PipeReader(Pipe& pipe) :
+        NBAIO_Source(pipe.mFormat),
+        mPipe(pipe),
+        // any data already in the pipe is not visible to this PipeReader
+        mFront(android_atomic_acquire_load(&pipe.mRear)),
+        mFramesOverrun(0),
+        mOverruns(0)
+{
+    android_atomic_inc(&pipe.mReaders);
+}
+
+PipeReader::~PipeReader()
+{
+    int32_t readers = android_atomic_dec(&mPipe.mReaders);
+    ALOG_ASSERT(readers > 0);
+}
+
+ssize_t PipeReader::availableToRead()
+{
+    if (CC_UNLIKELY(!mNegotiated)) {
+        return NEGOTIATE;
+    }
+    int32_t rear = android_atomic_acquire_load(&mPipe.mRear);
+    // read() is not multi-thread safe w.r.t. itself, so no mutex or atomic op needed to read mFront
+    size_t avail = rear - mFront;
+    if (CC_UNLIKELY(avail > mPipe.mMaxFrames)) {
+        // Discard all but 3/4 of the most recent data in pipe to avoid another overrun immediately
+        int32_t oldFront = mFront;
+        mFront = rear - mPipe.mMaxFrames + (mPipe.mMaxFrames >> 2);
+        mFramesOverrun += (size_t) (mFront - oldFront);
+        ++mOverruns;
+        return OVERRUN;
+    }
+    return avail;
+}
+
+ssize_t PipeReader::read(void *buffer, size_t count)
+{
+    ssize_t avail = availableToRead();
+    if (CC_UNLIKELY(avail <= 0)) {
+        return avail;
+    }
+    // An overrun can occur from here on and be silently ignored,
+    // but it will be caught at next read()
+    if (CC_LIKELY(count > (size_t) avail)) {
+        count = avail;
+    }
+    size_t front = mFront & (mPipe.mMaxFrames - 1);
+    size_t red = mPipe.mMaxFrames - front;
+    if (CC_LIKELY(red > count)) {
+        red = count;
+    }
+    // In particular, an overrun during the memcpy will result in reading corrupt data
+    memcpy(buffer, (char *) mPipe.mBuffer + (front << mBitShift), red << mBitShift);
+    // We could re-read the rear pointer here to detect the corruption, but why bother?
+    if (CC_UNLIKELY(front + red == mPipe.mMaxFrames)) {
+        if (CC_UNLIKELY((count -= red) > front)) {
+            count = front;
+        }
+        if (CC_LIKELY(count > 0)) {
+            memcpy((char *) buffer + (red << mBitShift), mPipe.mBuffer, count << mBitShift);
+            red += count;
+        }
+    }
+    mFront += red;
+    mFramesRead += red;
+    return red;
+}
+
+}   // namespace android
diff --git a/services/audioflinger/PipeReader.h b/services/audioflinger/PipeReader.h
new file mode 100644
index 0000000..398353b
--- /dev/null
+++ b/services/audioflinger/PipeReader.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_PIPE_READER_H
+#define ANDROID_AUDIO_PIPE_READER_H
+
+#include "Pipe.h"
+
+namespace android {
+
+// PipeReader is safe for only a single thread
+class PipeReader : public NBAIO_Source {
+
+public:
+
+    // Construct a PipeReader and associate it with a Pipe
+    // FIXME make this constructor a factory method of Pipe.
+    PipeReader(Pipe& pipe);
+    virtual ~PipeReader();
+
+    // NBAIO_Port interface
+
+    //virtual ssize_t negotiate(const NBAIO_Format offers[], size_t numOffers,
+    //                          NBAIO_Format counterOffers[], size_t& numCounterOffers);
+    //virtual NBAIO_Format format() const;
+
+    // NBAIO_Source interface
+
+    //virtual size_t framesRead() const;
+    virtual size_t framesOverrun() { return mFramesOverrun; }
+    virtual size_t overruns()  { return mOverruns; }
+
+    virtual ssize_t availableToRead();
+
+    virtual ssize_t read(void *buffer, size_t count);
+
+    // NBAIO_Source end
+
+#if 0   // until necessary
+    Pipe& pipe() const { return mPipe; }
+#endif
+
+private:
+    Pipe&       mPipe;
+    int32_t     mFront;         // follows behind mPipe.mRear
+    size_t      mFramesOverrun;
+    size_t      mOverruns;
+};
+
+}   // namespace android
+
+#endif  // ANDROID_AUDIO_PIPE_READER_H
diff --git a/services/audioflinger/SourceAudioBufferProvider.cpp b/services/audioflinger/SourceAudioBufferProvider.cpp
new file mode 100644
index 0000000..e9e8c16
--- /dev/null
+++ b/services/audioflinger/SourceAudioBufferProvider.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SourceAudioBufferProvider"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include "SourceAudioBufferProvider.h"
+
+namespace android {
+
+SourceAudioBufferProvider::SourceAudioBufferProvider(const sp<NBAIO_Source>& source) :
+    mSource(source),
+    // mFrameBitShiftFormat below
+    mAllocated(NULL), mSize(0), mOffset(0), mRemaining(0), mGetCount(0)
+{
+    ALOG_ASSERT(source != 0);
+
+    // negotiate with source
+    NBAIO_Format counterOffers[1];
+    size_t numCounterOffers = 1;
+    ssize_t index = source->negotiate(NULL, 0, counterOffers, numCounterOffers);
+    ALOG_ASSERT(index == (ssize_t) NEGOTIATE && numCounterOffers > 0);
+    numCounterOffers = 0;
+    index = source->negotiate(counterOffers, 1, NULL, numCounterOffers);
+    ALOG_ASSERT(index == 0);
+    mFrameBitShift = Format_frameBitShift(source->format());
+}
+
+SourceAudioBufferProvider::~SourceAudioBufferProvider()
+{
+    free(mAllocated);
+}
+
+status_t SourceAudioBufferProvider::getNextBuffer(Buffer *buffer, int64_t pts)
+{
+    ALOG_ASSERT(buffer != NULL && buffer->frameCount > 0 && mGetCount == 0);
+    // any leftover data available?
+    if (mRemaining > 0) {
+        ALOG_ASSERT(mOffset + mRemaining <= mSize);
+        if (mRemaining < buffer->frameCount) {
+            buffer->frameCount = mRemaining;
+        }
+        buffer->raw = (char *) mAllocated + (mOffset << mFrameBitShift);
+        mGetCount = buffer->frameCount;
+        return OK;
+    }
+    // do we need to reallocate?
+    if (buffer->frameCount > mSize) {
+        free(mAllocated);
+        mAllocated = malloc(buffer->frameCount << mFrameBitShift);
+        mSize = buffer->frameCount;
+    }
+    // read from source
+    ssize_t actual = mSource->read(mAllocated, buffer->frameCount);
+    if (actual > 0) {
+        ALOG_ASSERT((size_t) actual <= buffer->frameCount);
+        mOffset = 0;
+        mRemaining = actual;
+        buffer->raw = mAllocated;
+        buffer->frameCount = actual;
+        mGetCount = actual;
+        return OK;
+    }
+    buffer->raw = NULL;
+    buffer->frameCount = 0;
+    mGetCount = 0;
+    return NOT_ENOUGH_DATA;
+}
+
+void SourceAudioBufferProvider::releaseBuffer(Buffer *buffer)
+{
+    ALOG_ASSERT((buffer != NULL) &&
+            (buffer->raw == (char *) mAllocated + (mOffset << mFrameBitShift)) &&
+            (buffer->frameCount <= mGetCount) &&
+            (mGetCount <= mRemaining) &&
+            (mOffset + mRemaining <= mSize));
+    mOffset += buffer->frameCount;
+    mRemaining -= buffer->frameCount;
+    buffer->raw = NULL;
+    buffer->frameCount = 0;
+    mGetCount = 0;
+}
+
+}   // namespace android
diff --git a/services/audioflinger/SourceAudioBufferProvider.h b/services/audioflinger/SourceAudioBufferProvider.h
new file mode 100644
index 0000000..3219d78
--- /dev/null
+++ b/services/audioflinger/SourceAudioBufferProvider.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Implementation of AudioBufferProvider that wraps an NBAIO_Source
+
+#ifndef ANDROID_SOURCE_AUDIO_BUFFER_PROVIDER_H
+#define ANDROID_SOURCE_AUDIO_BUFFER_PROVIDER_H
+
+#include "NBAIO.h"
+#include "AudioBufferProvider.h"
+
+namespace android {
+
+class SourceAudioBufferProvider : public AudioBufferProvider {
+
+public:
+    SourceAudioBufferProvider(const sp<NBAIO_Source>& source);
+    virtual ~SourceAudioBufferProvider();
+
+    // AudioBufferProvider interface
+    virtual status_t getNextBuffer(Buffer *buffer, int64_t pts);
+    virtual void     releaseBuffer(Buffer *buffer);
+
+private:
+    const sp<NBAIO_Source> mSource;     // the wrapped source
+    /*const*/ size_t    mFrameBitShift; // log2(frame size in bytes)
+    void*               mAllocated; // pointer to base of allocated memory
+    size_t              mSize;      // size of mAllocated in frames
+    size_t              mOffset;    // frame offset within mAllocated of valid data
+    size_t              mRemaining; // frame count within mAllocated of valid data
+    size_t              mGetCount;  // buffer.frameCount of the most recent getNextBuffer
+};
+
+}   // namespace android
+
+#endif  // ANDROID_SOURCE_AUDIO_BUFFER_PROVIDER_H
diff --git a/services/audioflinger/roundup.c b/services/audioflinger/roundup.c
new file mode 100644
index 0000000..4f9af6a
--- /dev/null
+++ b/services/audioflinger/roundup.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "roundup.h"
+
+unsigned roundup(unsigned v)
+{
+    // __builtin_clz is undefined for zero input
+    if (v == 0) {
+        v = 1;
+    }
+    int lz = __builtin_clz((int) v);
+    unsigned rounded = ((unsigned) 0x80000000) >> lz;
+    // 0x800000001 and higher are actually rounded _down_ to prevent overflow
+    if (v > rounded && lz > 0) {
+        rounded <<= 1;
+    }
+    return rounded;
+}
diff --git a/services/audioflinger/roundup.h b/services/audioflinger/roundup.h
new file mode 100644
index 0000000..4c3cc25
--- /dev/null
+++ b/services/audioflinger/roundup.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ROUNDUP_H
+#define ROUNDUP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Round up to the next highest power of 2
+unsigned roundup(unsigned v);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // ROUNDUP_H