OboeAudioService: add thread to service for passing timestamps
Cleanup several TODOs.
Test: test_aaudio in CTS
Change-Id: I7fc956b6a21cbb592f98e1e5a8f43ebd6926d796
Signed-off-by: Phil Burk <philburk@google.com>
diff --git a/media/liboboe/src/binding/IOboeAudioService.cpp b/media/liboboe/src/binding/IOboeAudioService.cpp
index a3437b2..2584bc9 100644
--- a/media/liboboe/src/binding/IOboeAudioService.cpp
+++ b/media/liboboe/src/binding/IOboeAudioService.cpp
@@ -20,6 +20,7 @@
#include "binding/OboeStreamRequest.h"
#include "binding/OboeStreamConfiguration.h"
#include "binding/IOboeAudioService.h"
+#include "utility/OboeUtilities.h"
namespace android {
@@ -44,7 +45,7 @@
request.writeToParcel(&data);
status_t err = remote()->transact(OPEN_STREAM, data, &reply);
if (err != NO_ERROR) {
- return OBOE_ERROR_INTERNAL; // TODO consider another error
+ return OboeConvert_androidToOboeResult(err);
}
// parse reply
oboe_handle_t stream;
@@ -53,14 +54,14 @@
return stream;
}
- virtual oboe_result_t closeStream(int32_t streamHandle) override {
+ virtual oboe_result_t closeStream(oboe_handle_t streamHandle) override {
Parcel data, reply;
// send command
data.writeInterfaceToken(IOboeAudioService::getInterfaceDescriptor());
data.writeInt32(streamHandle);
status_t err = remote()->transact(CLOSE_STREAM, data, &reply);
if (err != NO_ERROR) {
- return OBOE_ERROR_INTERNAL; // TODO consider another error
+ return OboeConvert_androidToOboeResult(err);
}
// parse reply
oboe_result_t res;
@@ -69,14 +70,14 @@
}
virtual oboe_result_t getStreamDescription(oboe_handle_t streamHandle,
- AudioEndpointParcelable &parcelable) {
+ oboe::AudioEndpointParcelable &parcelable) {
Parcel data, reply;
// send command
data.writeInterfaceToken(IOboeAudioService::getInterfaceDescriptor());
data.writeInt32(streamHandle);
status_t err = remote()->transact(GET_STREAM_DESCRIPTION, data, &reply);
if (err != NO_ERROR) {
- return OBOE_ERROR_INTERNAL; // TODO consider another error
+ return OboeConvert_androidToOboeResult(err);
}
// parse reply
parcelable.readFromParcel(&reply);
@@ -97,7 +98,7 @@
data.writeInt32(streamHandle);
status_t err = remote()->transact(START_STREAM, data, &reply);
if (err != NO_ERROR) {
- return OBOE_ERROR_INTERNAL; // TODO consider another error
+ return OboeConvert_androidToOboeResult(err);
}
// parse reply
oboe_result_t res;
@@ -112,7 +113,7 @@
data.writeInt32(streamHandle);
status_t err = remote()->transact(PAUSE_STREAM, data, &reply);
if (err != NO_ERROR) {
- return OBOE_ERROR_INTERNAL; // TODO consider another error
+ return OboeConvert_androidToOboeResult(err);
}
// parse reply
oboe_result_t res;
@@ -127,7 +128,7 @@
data.writeInt32(streamHandle);
status_t err = remote()->transact(FLUSH_STREAM, data, &reply);
if (err != NO_ERROR) {
- return OBOE_ERROR_INTERNAL; // TODO consider another error
+ return OboeConvert_androidToOboeResult(err);
}
// parse reply
oboe_result_t res;
@@ -135,13 +136,6 @@
return res;
}
- virtual void tickle() override { // TODO remove after service thread implemented
- Parcel data;
- // send command
- data.writeInterfaceToken(IOboeAudioService::getInterfaceDescriptor());
- remote()->transact(TICKLE, data, nullptr);
- }
-
virtual oboe_result_t registerAudioThread(oboe_handle_t streamHandle, pid_t clientThreadId,
oboe_nanoseconds_t periodNanoseconds)
override {
@@ -153,7 +147,7 @@
data.writeInt64(periodNanoseconds);
status_t err = remote()->transact(REGISTER_AUDIO_THREAD, data, &reply);
if (err != NO_ERROR) {
- return OBOE_ERROR_INTERNAL; // TODO consider another error
+ return OboeConvert_androidToOboeResult(err);
}
// parse reply
oboe_result_t res;
@@ -170,7 +164,7 @@
data.writeInt32((int32_t) clientThreadId);
status_t err = remote()->transact(UNREGISTER_AUDIO_THREAD, data, &reply);
if (err != NO_ERROR) {
- return OBOE_ERROR_INTERNAL; // TODO consider another error
+ return OboeConvert_androidToOboeResult(err);
}
// parse reply
oboe_result_t res;
@@ -189,8 +183,8 @@
status_t BnOboeAudioService::onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags) {
OboeStream stream;
- OboeStreamRequest request;
- OboeStreamConfiguration configuration;
+ oboe::OboeStreamRequest request;
+ oboe::OboeStreamConfiguration configuration;
pid_t pid;
oboe_nanoseconds_t nanoseconds;
oboe_result_t result;
@@ -201,7 +195,7 @@
case OPEN_STREAM: {
request.readFromParcel(&data);
stream = openStream(request, configuration);
- ALOGD("BnOboeAudioService::onTransact OPEN_STREAM 0x%08X", stream);
+ ALOGD("BnOboeAudioService::onTransact OPEN_STREAM server handle = 0x%08X", stream);
reply->writeInt32(stream);
configuration.writeToParcel(reply);
return NO_ERROR;
@@ -221,12 +215,12 @@
oboe::AudioEndpointParcelable parcelable;
result = getStreamDescription(stream, parcelable);
if (result != OBOE_OK) {
- return -1; // FIXME
+ return OboeConvert_oboeToAndroidStatus(result);
}
parcelable.dump();
result = parcelable.validate();
if (result != OBOE_OK) {
- return -1; // FIXME
+ return OboeConvert_oboeToAndroidStatus(result);
}
parcelable.writeToParcel(reply);
reply->writeInt32(result);
@@ -281,12 +275,6 @@
return NO_ERROR;
} break;
- case TICKLE: {
- ALOGV("BnOboeAudioService::onTransact TICKLE");
- tickle();
- return NO_ERROR;
- } break;
-
default:
// ALOGW("BnOboeAudioService::onTransact not handled %u", code);
return BBinder::onTransact(code, data, reply, flags);
diff --git a/media/liboboe/src/binding/IOboeAudioService.h b/media/liboboe/src/binding/IOboeAudioService.h
index 4b4c99c..e2a9c15 100644
--- a/media/liboboe/src/binding/IOboeAudioService.h
+++ b/media/liboboe/src/binding/IOboeAudioService.h
@@ -29,13 +29,6 @@
#include "binding/OboeStreamRequest.h"
#include "binding/OboeStreamConfiguration.h"
-//using android::status_t;
-//using android::IInterface;
-//using android::BnInterface;
-
-using oboe::AudioEndpointParcelable;
-using oboe::OboeStreamRequest;
-using oboe::OboeStreamConfiguration;
namespace android {
@@ -45,16 +38,16 @@
DECLARE_META_INTERFACE(OboeAudioService);
- virtual oboe_handle_t openStream(OboeStreamRequest &request,
- OboeStreamConfiguration &configuration) = 0;
+ virtual oboe_handle_t openStream(oboe::OboeStreamRequest &request,
+ oboe::OboeStreamConfiguration &configuration) = 0;
- virtual oboe_result_t closeStream(int32_t streamHandle) = 0;
+ virtual oboe_result_t closeStream(oboe_handle_t streamHandle) = 0;
/* Get an immutable description of the in-memory queues
* used to communicate with the underlying HAL or Service.
*/
virtual oboe_result_t getStreamDescription(oboe_handle_t streamHandle,
- AudioEndpointParcelable &parcelable) = 0;
+ oboe::AudioEndpointParcelable &parcelable) = 0;
/**
* Start the flow of data.
@@ -79,14 +72,6 @@
virtual oboe_result_t unregisterAudioThread(oboe_handle_t streamHandle,
pid_t clientThreadId) = 0;
-
- /**
- * Poke server instead of running a background thread.
- * Cooperative multi-tasking for early development only.
- * TODO remove tickle() when service has its own thread.
- */
- virtual void tickle() { };
-
};
class BnOboeAudioService : public BnInterface<IOboeAudioService> {
diff --git a/media/liboboe/src/binding/OboeServiceDefinitions.h b/media/liboboe/src/binding/OboeServiceDefinitions.h
index ad00fe2..33a192f 100644
--- a/media/liboboe/src/binding/OboeServiceDefinitions.h
+++ b/media/liboboe/src/binding/OboeServiceDefinitions.h
@@ -37,8 +37,7 @@
PAUSE_STREAM,
FLUSH_STREAM,
REGISTER_AUDIO_THREAD,
- UNREGISTER_AUDIO_THREAD,
- TICKLE
+ UNREGISTER_AUDIO_THREAD
};
} // namespace android
@@ -53,8 +52,7 @@
PAUSE_STREAM,
FLUSH_STREAM,
REGISTER_AUDIO_THREAD,
- UNREGISTER_AUDIO_THREAD,
- TICKLE
+ UNREGISTER_AUDIO_THREAD
};
// TODO Expand this to include all the open parameters.
diff --git a/media/liboboe/src/binding/OboeStreamConfiguration.cpp b/media/liboboe/src/binding/OboeStreamConfiguration.cpp
index 4b8b5b2..124e964 100644
--- a/media/liboboe/src/binding/OboeStreamConfiguration.cpp
+++ b/media/liboboe/src/binding/OboeStreamConfiguration.cpp
@@ -65,10 +65,10 @@
}
switch (mAudioFormat) {
- case OBOE_AUDIO_FORMAT_PCM16:
+ case OBOE_AUDIO_FORMAT_PCM_I16:
case OBOE_AUDIO_FORMAT_PCM_FLOAT:
- case OBOE_AUDIO_FORMAT_PCM824:
- case OBOE_AUDIO_FORMAT_PCM32:
+ case OBOE_AUDIO_FORMAT_PCM_I8_24:
+ case OBOE_AUDIO_FORMAT_PCM_I32:
break;
default:
ALOGE("OboeStreamConfiguration.validate() invalid audioFormat = %d", mAudioFormat);
diff --git a/media/liboboe/src/client/AudioStreamInternal.cpp b/media/liboboe/src/client/AudioStreamInternal.cpp
index 0d169e1..dc6fe90 100644
--- a/media/liboboe/src/client/AudioStreamInternal.cpp
+++ b/media/liboboe/src/client/AudioStreamInternal.cpp
@@ -22,6 +22,7 @@
#include <assert.h>
#include <binder/IServiceManager.h>
+#include <utils/Mutex.h>
#include <oboe/OboeAudio.h>
@@ -40,16 +41,40 @@
using android::IServiceManager;
using android::defaultServiceManager;
using android::interface_cast;
+using android::Mutex;
using namespace oboe;
+static android::Mutex gServiceLock;
+static sp<IOboeAudioService> gOboeService;
+
+#define OBOE_SERVICE_NAME "OboeAudioService"
+
// Helper function to get access to the "OboeAudioService" service.
-static sp<IOboeAudioService> getOboeAudioService() {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("OboeAudioService"));
- // TODO: If the "OboeHack" service is not running, getService times out and binder == 0.
- sp<IOboeAudioService> service = interface_cast<IOboeAudioService>(binder);
- return service;
+// This code was modeled after frameworks/av/media/libaudioclient/AudioSystem.cpp
+static const sp<IOboeAudioService> getOboeAudioService() {
+ sp<IBinder> binder;
+ Mutex::Autolock _l(gServiceLock);
+ if (gOboeService == 0) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ // Try several times to get the service.
+ int retries = 4;
+ do {
+ binder = sm->getService(String16(OBOE_SERVICE_NAME)); // This will wait a while.
+ if (binder != 0) {
+ break;
+ }
+ } while (retries-- > 0);
+
+ if (binder != 0) {
+ // TODO Add linkToDeath() like in frameworks/av/media/libaudioclient/AudioSystem.cpp
+ // TODO Create a DeathRecipient that disconnects all active streams.
+ gOboeService = interface_cast<IOboeAudioService>(binder);
+ } else {
+ ALOGE("AudioStreamInternal could not get %s", OBOE_SERVICE_NAME);
+ }
+ }
+ return gOboeService;
}
AudioStreamInternal::AudioStreamInternal()
@@ -59,9 +84,6 @@
, mServiceStreamHandle(OBOE_HANDLE_INVALID)
, mFramesPerBurst(16)
{
- // TODO protect against mService being NULL;
- // TODO Model access to the service on frameworks/av/media/libaudioclient/AudioSystem.cpp
- mService = getOboeAudioService();
}
AudioStreamInternal::~AudioStreamInternal() {
@@ -69,6 +91,9 @@
oboe_result_t AudioStreamInternal::open(const AudioStreamBuilder &builder) {
+ const sp<IOboeAudioService>& service = getOboeAudioService();
+ if (service == 0) return OBOE_ERROR_NO_SERVICE;
+
oboe_result_t result = OBOE_OK;
OboeStreamRequest request;
OboeStreamConfiguration configuration;
@@ -78,7 +103,7 @@
return result;
}
- // Build the request.
+ // Build the request to send to the server.
request.setUserId(getuid());
request.setProcessId(getpid());
request.getConfiguration().setDeviceId(getDeviceId());
@@ -87,7 +112,7 @@
request.getConfiguration().setAudioFormat(getFormat());
request.dump();
- mServiceStreamHandle = mService->openStream(request, configuration);
+ mServiceStreamHandle = service->openStream(request, configuration);
ALOGD("AudioStreamInternal.open(): openStream returned mServiceStreamHandle = 0x%08X",
(unsigned int)mServiceStreamHandle);
if (mServiceStreamHandle < 0) {
@@ -105,10 +130,10 @@
setFormat(configuration.getAudioFormat());
oboe::AudioEndpointParcelable parcelable;
- result = mService->getStreamDescription(mServiceStreamHandle, parcelable);
+ result = service->getStreamDescription(mServiceStreamHandle, parcelable);
if (result != OBOE_OK) {
ALOGE("AudioStreamInternal.open(): getStreamDescriptor returns %d", result);
- mService->closeStream(mServiceStreamHandle);
+ service->closeStream(mServiceStreamHandle);
return result;
}
// resolve parcelable into a descriptor
@@ -133,11 +158,14 @@
oboe_result_t AudioStreamInternal::close() {
ALOGD("AudioStreamInternal.close(): mServiceStreamHandle = 0x%08X", mServiceStreamHandle);
if (mServiceStreamHandle != OBOE_HANDLE_INVALID) {
- mService->closeStream(mServiceStreamHandle);
+ oboe_handle_t serviceStreamHandle = mServiceStreamHandle;
mServiceStreamHandle = OBOE_HANDLE_INVALID;
+ const sp<IOboeAudioService>& oboeService = getOboeAudioService();
+ if (oboeService == 0) return OBOE_ERROR_NO_SERVICE;
+ oboeService->closeStream(serviceStreamHandle);
return OBOE_OK;
} else {
- return OBOE_ERROR_INVALID_STATE;
+ return OBOE_ERROR_INVALID_HANDLE;
}
}
@@ -148,11 +176,13 @@
if (mServiceStreamHandle == OBOE_HANDLE_INVALID) {
return OBOE_ERROR_INVALID_STATE;
}
+ const sp<IOboeAudioService>& oboeService = getOboeAudioService();
+ if (oboeService == 0) return OBOE_ERROR_NO_SERVICE;
startTime = Oboe_getNanoseconds(OBOE_CLOCK_MONOTONIC);
mClockModel.start(startTime);
processTimestamp(0, startTime);
setState(OBOE_STREAM_STATE_STARTING);
- return mService->startStream(mServiceStreamHandle);
+ return oboeService->startStream(mServiceStreamHandle);
}
oboe_result_t AudioStreamInternal::requestPause()
@@ -161,9 +191,11 @@
if (mServiceStreamHandle == OBOE_HANDLE_INVALID) {
return OBOE_ERROR_INVALID_STATE;
}
+ const sp<IOboeAudioService>& oboeService = getOboeAudioService();
+ if (oboeService == 0) return OBOE_ERROR_NO_SERVICE;
mClockModel.stop(Oboe_getNanoseconds(OBOE_CLOCK_MONOTONIC));
setState(OBOE_STREAM_STATE_PAUSING);
- return mService->pauseStream(mServiceStreamHandle);
+ return oboeService->pauseStream(mServiceStreamHandle);
}
oboe_result_t AudioStreamInternal::requestFlush() {
@@ -171,8 +203,10 @@
if (mServiceStreamHandle == OBOE_HANDLE_INVALID) {
return OBOE_ERROR_INVALID_STATE;
}
- setState(OBOE_STREAM_STATE_FLUSHING);
- return mService->flushStream(mServiceStreamHandle);
+ const sp<IOboeAudioService>& oboeService = getOboeAudioService();
+ if (oboeService == 0) return OBOE_ERROR_NO_SERVICE;
+setState(OBOE_STREAM_STATE_FLUSHING);
+ return oboeService->flushStream(mServiceStreamHandle);
}
void AudioStreamInternal::onFlushFromServer() {
@@ -208,7 +242,9 @@
if (mServiceStreamHandle == OBOE_HANDLE_INVALID) {
return OBOE_ERROR_INVALID_STATE;
}
- return mService->registerAudioThread(mServiceStreamHandle,
+ const sp<IOboeAudioService>& oboeService = getOboeAudioService();
+ if (oboeService == 0) return OBOE_ERROR_NO_SERVICE;
+ return oboeService->registerAudioThread(mServiceStreamHandle,
gettid(),
getPeriodNanoseconds());
}
@@ -218,7 +254,9 @@
if (mServiceStreamHandle == OBOE_HANDLE_INVALID) {
return OBOE_ERROR_INVALID_STATE;
}
- return mService->unregisterAudioThread(mServiceStreamHandle, gettid());
+ const sp<IOboeAudioService>& oboeService = getOboeAudioService();
+ if (oboeService == 0) return OBOE_ERROR_NO_SERVICE;
+ return oboeService->unregisterAudioThread(mServiceStreamHandle, gettid());
}
// TODO use oboe_clockid_t all the way down to AudioClock
@@ -305,9 +343,6 @@
oboe_result_t AudioStreamInternal::processCommands() {
oboe_result_t result = OBOE_OK;
- // Let the service run in case it is a fake service simulator.
- mService->tickle(); // TODO use real service thread
-
while (result == OBOE_OK) {
OboeServiceMessage message;
if (mAudioEndpoint.readUpCommand(&message) != 1) {
diff --git a/media/liboboe/src/client/AudioStreamInternal.h b/media/liboboe/src/client/AudioStreamInternal.h
index 6f37761..9459f97 100644
--- a/media/liboboe/src/client/AudioStreamInternal.h
+++ b/media/liboboe/src/client/AudioStreamInternal.h
@@ -114,7 +114,6 @@
AudioEndpoint mAudioEndpoint;
oboe_handle_t mServiceStreamHandle;
EndpointDescriptor mEndpointDescriptor;
- sp<IOboeAudioService> mService;
// Offset from underlying frame position.
oboe_position_frames_t mFramesOffsetFromService = 0;
oboe_position_frames_t mLastFramesRead = 0;
diff --git a/media/liboboe/src/core/OboeAudio.cpp b/media/liboboe/src/core/OboeAudio.cpp
index d98ca36..be563b5 100644
--- a/media/liboboe/src/core/OboeAudio.cpp
+++ b/media/liboboe/src/core/OboeAudio.cpp
@@ -96,6 +96,7 @@
OBOE_CASE_ENUM(OBOE_ERROR_WOULD_BLOCK);
OBOE_CASE_ENUM(OBOE_ERROR_INVALID_ORDER);
OBOE_CASE_ENUM(OBOE_ERROR_OUT_OF_RANGE);
+ OBOE_CASE_ENUM(OBOE_ERROR_NO_SERVICE);
}
return "Unrecognized Oboe error.";
}
@@ -285,7 +286,6 @@
OBOE_API oboe_result_t OboeStreamBuilder_delete(OboeStreamBuilder builder)
{
- // TODO protect the remove() with a Mutex
AudioStreamBuilder *streamBuilder = (AudioStreamBuilder *)
sHandleTracker.remove(OBOE_HANDLE_TYPE_STREAM_BUILDER, builder);
if (streamBuilder != nullptr) {
@@ -297,9 +297,9 @@
OBOE_API oboe_result_t OboeStream_close(OboeStream stream)
{
- // TODO protect the remove() with a Mutex
AudioStream *audioStream = (AudioStream *)
sHandleTracker.remove(OBOE_HANDLE_TYPE_STREAM, (oboe_handle_t)stream);
+ ALOGD("OboeStream_close(0x%08X), audioStream = %p", stream, audioStream);
if (audioStream != nullptr) {
audioStream->close();
delete audioStream;
diff --git a/media/liboboe/src/legacy/AudioStreamRecord.cpp b/media/liboboe/src/legacy/AudioStreamRecord.cpp
index 5854974..bf4bd36 100644
--- a/media/liboboe/src/legacy/AudioStreamRecord.cpp
+++ b/media/liboboe/src/legacy/AudioStreamRecord.cpp
@@ -90,7 +90,7 @@
if (status != OK) {
close();
ALOGE("AudioStreamRecord::open(), initCheck() returned %d", status);
- return OboeConvert_androidToOboeError(status);
+ return OboeConvert_androidToOboeResult(status);
}
// Get the actual rate.
@@ -121,11 +121,11 @@
// Get current position so we can detect when the track is playing.
status_t err = mAudioRecord->getPosition(&mPositionWhenStarting);
if (err != OK) {
- return OboeConvert_androidToOboeError(err);
+ return OboeConvert_androidToOboeResult(err);
}
err = mAudioRecord->start();
if (err != OK) {
- return OboeConvert_androidToOboeError(err);
+ return OboeConvert_androidToOboeResult(err);
} else {
setState(OBOE_STREAM_STATE_STARTING);
}
@@ -160,7 +160,7 @@
case OBOE_STREAM_STATE_STARTING:
err = mAudioRecord->getPosition(&position);
if (err != OK) {
- result = OboeConvert_androidToOboeError(err);
+ result = OboeConvert_androidToOboeResult(err);
} else if (position != mPositionWhenStarting) {
setState(OBOE_STREAM_STATE_STARTED);
}
@@ -193,7 +193,7 @@
if (bytesRead == WOULD_BLOCK) {
return 0;
} else if (bytesRead < 0) {
- return OboeConvert_androidToOboeError(bytesRead);
+ return OboeConvert_androidToOboeResult(bytesRead);
}
oboe_size_frames_t framesRead = (oboe_size_frames_t)(bytesRead / bytesPerFrame);
return (oboe_result_t) framesRead;
diff --git a/media/liboboe/src/legacy/AudioStreamRecord.h b/media/liboboe/src/legacy/AudioStreamRecord.h
index 02ff220..a884ed2 100644
--- a/media/liboboe/src/legacy/AudioStreamRecord.h
+++ b/media/liboboe/src/legacy/AudioStreamRecord.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef LEGACY_AUDIOSTREAMRECORD_H
-#define LEGACY_AUDIOSTREAMRECORD_H
+#ifndef LEGACY_AUDIO_STREAM_RECORD_H
+#define LEGACY_AUDIO_STREAM_RECORD_H
#include <media/AudioRecord.h>
#include <oboe/OboeAudio.h>
@@ -75,4 +75,4 @@
} /* namespace oboe */
-#endif /* LEGACY_AUDIOSTREAMRECORD_H */
+#endif /* LEGACY_AUDIO_STREAM_RECORD_H */
diff --git a/media/liboboe/src/legacy/AudioStreamTrack.cpp b/media/liboboe/src/legacy/AudioStreamTrack.cpp
index b2c4ee1..291e56c 100644
--- a/media/liboboe/src/legacy/AudioStreamTrack.cpp
+++ b/media/liboboe/src/legacy/AudioStreamTrack.cpp
@@ -87,12 +87,10 @@
// Did we get a valid track?
status_t status = mAudioTrack->initCheck();
ALOGD("AudioStreamTrack::open(), initCheck() returned %d", status);
- // FIXME - this should work - if (status != NO_ERROR) {
- // But initCheck() is returning 1 !
- if (status < 0) {
+ if (status != NO_ERROR) {
close();
ALOGE("AudioStreamTrack::open(), initCheck() returned %d", status);
- return OboeConvert_androidToOboeError(status);
+ return OboeConvert_androidToOboeResult(status);
}
// Get the actual values from the AudioTrack.
@@ -123,11 +121,11 @@
// Get current position so we can detect when the track is playing.
status_t err = mAudioTrack->getPosition(&mPositionWhenStarting);
if (err != OK) {
- return OboeConvert_androidToOboeError(err);
+ return OboeConvert_androidToOboeResult(err);
}
err = mAudioTrack->start();
if (err != OK) {
- return OboeConvert_androidToOboeError(err);
+ return OboeConvert_androidToOboeResult(err);
} else {
setState(OBOE_STREAM_STATE_STARTING);
}
@@ -147,7 +145,7 @@
mAudioTrack->pause();
status_t err = mAudioTrack->getPosition(&mPositionWhenPausing);
if (err != OK) {
- return OboeConvert_androidToOboeError(err);
+ return OboeConvert_androidToOboeResult(err);
}
return OBOE_OK;
}
@@ -191,7 +189,7 @@
if (mAudioTrack->stopped()) {
err = mAudioTrack->getPosition(&position);
if (err != OK) {
- return OboeConvert_androidToOboeError(err);
+ return OboeConvert_androidToOboeResult(err);
} else if (position == mPositionWhenPausing) {
// Has stream really stopped advancing?
setState(OBOE_STREAM_STATE_PAUSED);
@@ -203,7 +201,7 @@
{
err = mAudioTrack->getPosition(&position);
if (err != OK) {
- return OboeConvert_androidToOboeError(err);
+ return OboeConvert_androidToOboeResult(err);
} else if (position == 0) {
// Advance frames read to match written.
setState(OBOE_STREAM_STATE_FLUSHED);
@@ -239,7 +237,7 @@
return 0;
} else if (bytesWritten < 0) {
ALOGE("invalid write, returned %d", (int)bytesWritten);
- return OboeConvert_androidToOboeError(bytesWritten);
+ return OboeConvert_androidToOboeResult(bytesWritten);
}
oboe_size_frames_t framesWritten = (oboe_size_frames_t)(bytesWritten / bytesPerFrame);
incrementFramesWritten(framesWritten);
@@ -251,7 +249,7 @@
{
ssize_t result = mAudioTrack->setBufferSizeInFrames(requestedFrames);
if (result != OK) {
- return OboeConvert_androidToOboeError(result);
+ return OboeConvert_androidToOboeResult(result);
} else {
*actualFrames = result;
return OBOE_OK;
diff --git a/media/liboboe/src/legacy/AudioStreamTrack.h b/media/liboboe/src/legacy/AudioStreamTrack.h
index 8c40884..0c41331 100644
--- a/media/liboboe/src/legacy/AudioStreamTrack.h
+++ b/media/liboboe/src/legacy/AudioStreamTrack.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef LEGACY_AUDIOSTREAMTRACK_H
-#define LEGACY_AUDIOSTREAMTRACK_H
+#ifndef LEGACY_AUDIO_STREAM_TRACK_H
+#define LEGACY_AUDIO_STREAM_TRACK_H
#include <media/AudioTrack.h>
#include <oboe/OboeAudio.h>
@@ -75,4 +75,4 @@
} /* namespace oboe */
-#endif /* LEGACY_AUDIOSTREAMTRACK_H */
+#endif /* LEGACY_AUDIO_STREAM_TRACK_H */
diff --git a/media/liboboe/src/utility/AudioClock.h b/media/liboboe/src/utility/AudioClock.h
index 1a5c209..1779d8b 100644
--- a/media/liboboe/src/utility/AudioClock.h
+++ b/media/liboboe/src/utility/AudioClock.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef UTILITY_AUDIOCLOCK_H
-#define UTILITY_AUDIOCLOCK_H
+#ifndef UTILITY_AUDIO_CLOCK_H
+#define UTILITY_AUDIO_CLOCK_H
#include <stdint.h>
#include <time.h>
@@ -95,4 +95,4 @@
};
-#endif // UTILITY_AUDIOCLOCK_H
+#endif // UTILITY_AUDIO_CLOCK_H
diff --git a/media/liboboe/src/utility/HandleTracker.cpp b/media/liboboe/src/utility/HandleTracker.cpp
index bf5fb63..27cc1f8 100644
--- a/media/liboboe/src/utility/HandleTracker.cpp
+++ b/media/liboboe/src/utility/HandleTracker.cpp
@@ -19,13 +19,16 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
+#include <assert.h>
#include <new>
#include <stdint.h>
-#include <assert.h>
+#include <utils/Mutex.h>
#include <oboe/OboeDefinitions.h>
#include "HandleTracker.h"
+using android::Mutex;
+
// Handle format is: tgggiiii
// where each letter is 4 bits, t=type, g=generation, i=index
@@ -80,15 +83,17 @@
HandleTracker::~HandleTracker()
{
+ Mutex::Autolock _l(mLock);
delete[] mHandleAddresses;
delete[] mHandleHeaders;
+ mHandleAddresses = nullptr;
}
bool HandleTracker::isInitialized() const {
return mHandleAddresses != nullptr;
}
-handle_tracker_slot_t HandleTracker::allocateSlot() {
+handle_tracker_slot_t HandleTracker::allocateSlot_l() {
void **allocated = mNextFreeAddress;
if (allocated == nullptr) {
return SLOT_UNAVAILABLE;
@@ -98,7 +103,7 @@
return (allocated - mHandleAddresses);
}
-handle_tracker_generation_t HandleTracker::nextGeneration(handle_tracker_slot_t index) {
+handle_tracker_generation_t HandleTracker::nextGeneration_l(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) {
@@ -116,15 +121,17 @@
return static_cast<oboe_handle_t>(OBOE_ERROR_NO_MEMORY);
}
+ Mutex::Autolock _l(mLock);
+
// Find an empty slot.
- handle_tracker_slot_t index = allocateSlot();
+ handle_tracker_slot_t index = allocateSlot_l();
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_generation_t generation = nextGeneration_l(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().
@@ -150,6 +157,8 @@
}
handle_tracker_generation_t handleGeneration = extractGeneration(handle);
handle_tracker_header_t inputHeader = buildHeader(type, handleGeneration);
+ // We do not need to synchronize this access to mHandleHeaders because it is constant for
+ // the lifetime of the handle.
if (inputHeader != mHandleHeaders[index]) {
ALOGE("HandleTracker::handleToIndex() inputHeader = 0x%08x != mHandleHeaders[%d] = 0x%08x",
inputHeader, index, mHandleHeaders[index]);
@@ -165,6 +174,8 @@
}
handle_tracker_slot_t index = handleToIndex(type, handle);
if (index >= 0) {
+ // We do not need to synchronize this access to mHandleHeaders because this slot
+ // is allocated and, therefore, not part of the linked list of free slots.
return mHandleAddresses[index];
} else {
return nullptr;
@@ -175,6 +186,9 @@
if (!isInitialized()) {
return nullptr;
}
+
+ Mutex::Autolock _l(mLock);
+
handle_tracker_slot_t index = handleToIndex(type,handle);
if (index >= 0) {
handle_tracker_address_t address = mHandleAddresses[index];
diff --git a/media/liboboe/src/utility/HandleTracker.h b/media/liboboe/src/utility/HandleTracker.h
index 4c08321..f1bead8 100644
--- a/media/liboboe/src/utility/HandleTracker.h
+++ b/media/liboboe/src/utility/HandleTracker.h
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-#ifndef UTILITY_HANDLETRACKER_H
-#define UTILITY_HANDLETRACKER_H
+#ifndef UTILITY_HANDLE_TRACKER_H
+#define UTILITY_HANDLE_TRACKER_H
#include <stdint.h>
+#include <utils/Mutex.h>
typedef int32_t handle_tracker_type_t; // what kind of handle
typedef int32_t handle_tracker_slot_t; // index in allocation table
@@ -53,6 +54,8 @@
/**
* Store a pointer and return a handle that can be used to retrieve the pointer.
*
+ * It is safe to call put() or remove() from multiple threads.
+ *
* @param expectedType 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
@@ -75,6 +78,8 @@
* Free up the storage associated with the handle.
* Subsequent attempts to use the handle will fail.
*
+ * Do NOT remove() a handle while get() is being called for the same handle from another thread.
+ *
* @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
@@ -83,17 +88,28 @@
private:
const int32_t mMaxHandleCount; // size of array
- // This is const after initialization.
+ // This address is const after initialization.
handle_tracker_address_t * mHandleAddresses; // address of objects or a free linked list node
- // This is const after initialization.
+ // This address 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
+ // head of the linked list of free nodes in mHandleAddresses
+ handle_tracker_address_t * mNextFreeAddress;
+
+ // This Mutex protects the linked list of free nodes.
+ // The list is managed using mHandleAddresses and mNextFreeAddress.
+ // The data in mHandleHeaders is only changed by put() and remove().
+ android::Mutex mLock;
/**
* Pull slot off of a list of empty slots.
* @return index or a negative error
*/
- handle_tracker_slot_t allocateSlot();
+ handle_tracker_slot_t allocateSlot_l();
+
+ /**
+ * Increment the generation for the slot, avoiding zero.
+ */
+ handle_tracker_generation_t nextGeneration_l(handle_tracker_slot_t index);
/**
* Validate the handle and return the corresponding index.
@@ -107,7 +123,7 @@
* @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);
+ static oboe_handle_t buildHandle(handle_tracker_header_t header, handle_tracker_slot_t index);
/**
* Combine a type and a generation field into a header.
@@ -129,11 +145,6 @@
*/
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
+#endif //UTILITY_HANDLE_TRACKER_H
diff --git a/media/liboboe/src/utility/MonotonicCounter.h b/media/liboboe/src/utility/MonotonicCounter.h
index befad21..81d7f89 100644
--- a/media/liboboe/src/utility/MonotonicCounter.h
+++ b/media/liboboe/src/utility/MonotonicCounter.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef UTILITY_MONOTONICCOUNTER_H
-#define UTILITY_MONOTONICCOUNTER_H
+#ifndef UTILITY_MONOTONIC_COUNTER_H
+#define UTILITY_MONOTONIC_COUNTER_H
#include <stdint.h>
@@ -88,4 +88,4 @@
};
-#endif //UTILITY_MONOTONICCOUNTER_H
+#endif //UTILITY_MONOTONIC_COUNTER_H
diff --git a/media/liboboe/src/utility/OboeUtilities.cpp b/media/liboboe/src/utility/OboeUtilities.cpp
index d9d2e88..fcf4252 100644
--- a/media/liboboe/src/utility/OboeUtilities.cpp
+++ b/media/liboboe/src/utility/OboeUtilities.cpp
@@ -30,11 +30,11 @@
oboe_size_bytes_t OboeConvert_formatToSizeInBytes(oboe_audio_format_t format) {
oboe_size_bytes_t size = OBOE_ERROR_ILLEGAL_ARGUMENT;
switch (format) {
- case OBOE_AUDIO_FORMAT_PCM16:
+ case OBOE_AUDIO_FORMAT_PCM_I16:
size = sizeof(int16_t);
break;
- case OBOE_AUDIO_FORMAT_PCM32:
- case OBOE_AUDIO_FORMAT_PCM824:
+ case OBOE_AUDIO_FORMAT_PCM_I32:
+ case OBOE_AUDIO_FORMAT_PCM_I8_24:
size = sizeof(int32_t);
break;
case OBOE_AUDIO_FORMAT_PCM_FLOAT:
@@ -67,14 +67,47 @@
}
}
-oboe_result_t OboeConvert_androidToOboeError(status_t error) {
- if (error >= 0) {
- return error;
+status_t OboeConvert_oboeToAndroidStatus(oboe_result_t result) {
+ // This covers the case for OBOE_OK and for positive results.
+ if (result >= 0) {
+ return result;
+ }
+ status_t status;
+ switch (result) {
+ case OBOE_ERROR_DISCONNECTED:
+ case OBOE_ERROR_INVALID_HANDLE:
+ status = DEAD_OBJECT;
+ break;
+ case OBOE_ERROR_INVALID_STATE:
+ status = INVALID_OPERATION;
+ break;
+ case OBOE_ERROR_UNEXPECTED_VALUE: // TODO redundant?
+ case OBOE_ERROR_ILLEGAL_ARGUMENT:
+ status = BAD_VALUE;
+ break;
+ case OBOE_ERROR_WOULD_BLOCK:
+ status = WOULD_BLOCK;
+ break;
+ // TODO add more result codes
+ default:
+ status = UNKNOWN_ERROR;
+ break;
+ }
+ return status;
+}
+
+oboe_result_t OboeConvert_androidToOboeResult(status_t status) {
+ // This covers the case for OK and for positive result.
+ if (status >= 0) {
+ return status;
}
oboe_result_t result;
- switch (error) {
- case OK:
- result = OBOE_OK;
+ switch (status) {
+ case BAD_TYPE:
+ result = OBOE_ERROR_INVALID_HANDLE;
+ break;
+ case DEAD_OBJECT:
+ result = OBOE_ERROR_DISCONNECTED;
break;
case INVALID_OPERATION:
result = OBOE_ERROR_INVALID_STATE;
@@ -85,7 +118,7 @@
case WOULD_BLOCK:
result = OBOE_ERROR_WOULD_BLOCK;
break;
- // TODO add more error codes
+ // TODO add more status codes
default:
result = OBOE_ERROR_INTERNAL;
break;
@@ -96,16 +129,16 @@
audio_format_t OboeConvert_oboeToAndroidDataFormat(oboe_audio_format_t oboeFormat) {
audio_format_t androidFormat;
switch (oboeFormat) {
- case OBOE_AUDIO_FORMAT_PCM16:
+ case OBOE_AUDIO_FORMAT_PCM_I16:
androidFormat = AUDIO_FORMAT_PCM_16_BIT;
break;
case OBOE_AUDIO_FORMAT_PCM_FLOAT:
androidFormat = AUDIO_FORMAT_PCM_FLOAT;
break;
- case OBOE_AUDIO_FORMAT_PCM824:
+ case OBOE_AUDIO_FORMAT_PCM_I8_24:
androidFormat = AUDIO_FORMAT_PCM_8_24_BIT;
break;
- case OBOE_AUDIO_FORMAT_PCM32:
+ case OBOE_AUDIO_FORMAT_PCM_I32:
androidFormat = AUDIO_FORMAT_PCM_32_BIT;
break;
default:
@@ -120,16 +153,16 @@
oboe_audio_format_t oboeFormat = OBOE_AUDIO_FORMAT_INVALID;
switch (androidFormat) {
case AUDIO_FORMAT_PCM_16_BIT:
- oboeFormat = OBOE_AUDIO_FORMAT_PCM16;
+ oboeFormat = OBOE_AUDIO_FORMAT_PCM_I16;
break;
case AUDIO_FORMAT_PCM_FLOAT:
oboeFormat = OBOE_AUDIO_FORMAT_PCM_FLOAT;
break;
case AUDIO_FORMAT_PCM_32_BIT:
- oboeFormat = OBOE_AUDIO_FORMAT_PCM32;
+ oboeFormat = OBOE_AUDIO_FORMAT_PCM_I32;
break;
case AUDIO_FORMAT_PCM_8_24_BIT:
- oboeFormat = OBOE_AUDIO_FORMAT_PCM824;
+ oboeFormat = OBOE_AUDIO_FORMAT_PCM_I8_24;
break;
default:
oboeFormat = OBOE_AUDIO_FORMAT_INVALID;
diff --git a/media/liboboe/src/utility/OboeUtilities.h b/media/liboboe/src/utility/OboeUtilities.h
index 974ccf6..4096e2a 100644
--- a/media/liboboe/src/utility/OboeUtilities.h
+++ b/media/liboboe/src/utility/OboeUtilities.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef UTILITY_OBOEUTILITIES_H
-#define UTILITY_OBOEUTILITIES_H
+#ifndef UTILITY_OBOE_UTILITIES_H
+#define UTILITY_OBOE_UTILITIES_H
#include <stdint.h>
#include <sys/types.h>
@@ -25,7 +25,15 @@
#include "oboe/OboeDefinitions.h"
-oboe_result_t OboeConvert_androidToOboeError(android::status_t error);
+/**
+ * Convert an Oboe result into the closest matching Android status.
+ */
+android::status_t OboeConvert_oboeToAndroidStatus(oboe_result_t result);
+
+/**
+ * Convert an Android status into the closest matching Oboe result.
+ */
+oboe_result_t OboeConvert_androidToOboeResult(android::status_t status);
void OboeConvert_floatToPcm16(const float *source, int32_t numSamples, int16_t *destination);
@@ -51,4 +59,4 @@
*/
oboe_size_bytes_t OboeConvert_formatToSizeInBytes(oboe_audio_format_t format);
-#endif //UTILITY_OBOEUTILITIES_H
+#endif //UTILITY_OBOE_UTILITIES_H