Move ExtendedAudioBufferProvider and SingleStateQueue
Move ExtendedAudioBufferProvider.h to libaudioclient. This is
a more appropriate location because EABP extends AudioBufferProvider.
Move SingleStateQueue.h to libnbaio_mono. This is a more appropriate
location because SSQ is a non-blocking queue.
This allows to remove the dependency of libnbaio on libmedia
which is a good thing because libnbaio provides more low-level
abstractions than libmedia.
Also, replace a dependency of libnbaio on libbinder with
a dependency on libaudiohal header library.
Test: make
Change-Id: Ie48b523790cd8230695ec2e4710e50981b616289
diff --git a/media/libnbaio/Android.bp b/media/libnbaio/Android.bp
index 6345742..04ddcff 100644
--- a/media/libnbaio/Android.bp
+++ b/media/libnbaio/Android.bp
@@ -8,15 +8,14 @@
header_libs: [
"libaudioclient_headers",
"libaudio_system_headers",
- "libmedia_headers",
],
export_header_lib_headers: [
"libaudioclient_headers",
- "libmedia_headers",
],
shared_libs: [
"libaudioutils",
+ "libcutils",
"liblog",
"libutils",
],
@@ -25,6 +24,11 @@
],
export_include_dirs: ["include_mono"],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
}
// libnbaio_mono is the part of libnbaio that is available for vendors to use. Vendor modules can't
@@ -55,18 +59,7 @@
// ],
// static_libs: ["libsndfile"],
- shared_libs: [
- "libaudioutils",
- "libbinder",
- "libcutils",
- "liblog",
- "libutils",
- ],
-
- cflags: [
- "-Werror",
- "-Wall",
- ],
+ header_libs: ["libaudiohal_headers"],
export_include_dirs: ["include"],
}
diff --git a/media/libnbaio/include_mono/media/nbaio/MonoPipe.h b/media/libnbaio/include_mono/media/nbaio/MonoPipe.h
index c51d0fe..926d84a 100644
--- a/media/libnbaio/include_mono/media/nbaio/MonoPipe.h
+++ b/media/libnbaio/include_mono/media/nbaio/MonoPipe.h
@@ -19,7 +19,7 @@
#include <time.h>
#include <audio_utils/fifo.h>
-#include <media/SingleStateQueue.h>
+#include <media/nbaio/SingleStateQueue.h>
#include <media/nbaio/NBAIO.h>
namespace android {
diff --git a/media/libnbaio/include_mono/media/nbaio/SingleStateQueue.h b/media/libnbaio/include_mono/media/nbaio/SingleStateQueue.h
new file mode 100644
index 0000000..d423962
--- /dev/null
+++ b/media/libnbaio/include_mono/media/nbaio/SingleStateQueue.h
@@ -0,0 +1,175 @@
+/*
+ * 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 SINGLE_STATE_QUEUE_H
+#define SINGLE_STATE_QUEUE_H
+
+// Non-blocking single element state queue, or
+// Non-blocking single-reader / single-writer multi-word atomic load / store
+
+#include <stdint.h>
+#include <cutils/atomic.h>
+
+namespace android {
+
+template<typename T> class SingleStateQueue {
+
+public:
+
+ class Mutator;
+ class Observer;
+
+ enum SSQ_STATUS {
+ SSQ_PENDING, /* = 0 */
+ SSQ_READ,
+ SSQ_DONE,
+ };
+
+ struct Shared {
+ // needs to be part of a union so don't define constructor or destructor
+
+ friend class Mutator;
+ friend class Observer;
+
+private:
+ void init() { mAck = 0; mSequence = 0; }
+
+ volatile int32_t mAck;
+ volatile int32_t mSequence;
+ T mValue;
+ };
+
+ class Mutator {
+ public:
+ Mutator(Shared *shared)
+ : mSequence(0), mShared(shared)
+ {
+ // exactly one of Mutator and Observer must initialize, currently it is Observer
+ // shared->init();
+ }
+
+ // push new value onto state queue, overwriting previous value;
+ // returns a sequence number which can be used with ack()
+ int32_t push(const T& value)
+ {
+ Shared *shared = mShared;
+ int32_t sequence = mSequence;
+ sequence++;
+ android_atomic_acquire_store(sequence, &shared->mSequence);
+ shared->mValue = value;
+ sequence++;
+ android_atomic_release_store(sequence, &shared->mSequence);
+ mSequence = sequence;
+ // consider signalling a futex here, if we know that observer is waiting
+ return sequence;
+ }
+
+ // returns the status of the last state push. This may be a stale value.
+ //
+ // SSQ_PENDING, or 0, means it has not been observed
+ // SSQ_READ means it has been read
+ // SSQ_DONE means it has been acted upon, after Observer::done() is called
+ enum SSQ_STATUS ack() const
+ {
+ // in the case of SSQ_DONE, prevent any subtle data-races of subsequent reads
+ // being performed (out-of-order) before the ack read, should the caller be
+ // depending on sequentiality of reads.
+ const int32_t ack = android_atomic_acquire_load(&mShared->mAck);
+ return ack - mSequence & ~1 ? SSQ_PENDING /* seq differ */ :
+ ack & 1 ? SSQ_DONE : SSQ_READ;
+ }
+
+ // return true if a push with specified sequence number or later has been observed
+ bool ack(int32_t sequence) const
+ {
+ // this relies on 2's complement rollover to detect an ancient sequence number
+ return mShared->mAck - sequence >= 0;
+ }
+
+ private:
+ int32_t mSequence;
+ Shared * const mShared;
+ };
+
+ class Observer {
+ public:
+ Observer(Shared *shared)
+ : mSequence(0), mSeed(1), mShared(shared)
+ {
+ // exactly one of Mutator and Observer must initialize, currently it is Observer
+ shared->init();
+ }
+
+ // return true if value has changed
+ bool poll(T& value)
+ {
+ Shared *shared = mShared;
+ int32_t before = shared->mSequence;
+ if (before == mSequence) {
+ return false;
+ }
+ for (int tries = 0; ; ) {
+ const int MAX_TRIES = 5;
+ if (before & 1) {
+ if (++tries >= MAX_TRIES) {
+ return false;
+ }
+ before = shared->mSequence;
+ } else {
+ android_memory_barrier();
+ T temp = shared->mValue;
+ int32_t after = android_atomic_release_load(&shared->mSequence);
+ if (after == before) {
+ value = temp;
+ shared->mAck = before;
+ mSequence = before; // mSequence is even after poll success
+ return true;
+ }
+ if (++tries >= MAX_TRIES) {
+ return false;
+ }
+ before = after;
+ }
+ }
+ }
+
+ // (optional) used to indicate to the Mutator that the state that has been polled
+ // has also been acted upon.
+ void done()
+ {
+ const int32_t ack = mShared->mAck + 1;
+ // ensure all previous writes have been performed.
+ android_atomic_release_store(ack, &mShared->mAck); // mSequence is odd after "done"
+ }
+
+ private:
+ int32_t mSequence;
+ int mSeed; // for PRNG
+ Shared * const mShared;
+ };
+
+#if 0
+ SingleStateQueue(void /*Shared*/ *shared);
+ /*virtual*/ ~SingleStateQueue() { }
+
+ static size_t size() { return sizeof(Shared); }
+#endif
+
+};
+
+} // namespace android
+
+#endif // SINGLE_STATE_QUEUE_H