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/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) {