OboeService: initial commit

This builds a standalone service that is easy to test.

Bug: 33269952
Test: test_oboe_api

Change-Id: I1890b1b974e728c2c0c15e24aa02121c2774bd56
Signed-off-by: Phil Burk <philburk@google.com>
diff --git a/services/oboeservice/OboeAudioService.cpp b/services/oboeservice/OboeAudioService.cpp
new file mode 100644
index 0000000..caddc1d
--- /dev/null
+++ b/services/oboeservice/OboeAudioService.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "OboeService"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <time.h>
+#include <pthread.h>
+
+#include <oboe/OboeDefinitions.h>
+
+#include "HandleTracker.h"
+#include "IOboeAudioService.h"
+#include "OboeService.h"
+#include "OboeAudioService.h"
+#include "OboeServiceStreamFakeHal.h"
+
+using namespace android;
+using namespace oboe;
+
+typedef enum
+{
+    OBOE_HANDLE_TYPE_STREAM,
+    OBOE_HANDLE_TYPE_COUNT
+} oboe_service_handle_type_t;
+static_assert(OBOE_HANDLE_TYPE_COUNT <= HANDLE_TRACKER_MAX_TYPES, "Too many handle types.");
+
+oboe_handle_t OboeAudioService::openStream(oboe::OboeStreamRequest &request,
+                                                oboe::OboeStreamConfiguration &configuration) {
+    OboeServiceStreamBase *serviceStream =  new OboeServiceStreamFakeHal();
+    ALOGD("OboeAudioService::openStream(): created serviceStream = %p", serviceStream);
+    oboe_result_t result = serviceStream->open(request, configuration);
+    if (result < 0) {
+        ALOGE("OboeAudioService::openStream(): open returned %d", result);
+        return result;
+    } else {
+        OboeStream handle = mHandleTracker.put(OBOE_HANDLE_TYPE_STREAM, serviceStream);
+        ALOGD("OboeAudioService::openStream(): handle = 0x%08X", handle);
+        if (handle < 0) {
+            delete serviceStream;
+        }
+        return handle;
+    }
+}
+
+oboe_result_t OboeAudioService::closeStream(oboe_handle_t streamHandle) {
+    OboeServiceStreamBase *serviceStream = (OboeServiceStreamBase *)
+            mHandleTracker.remove(OBOE_HANDLE_TYPE_STREAM,
+                                  streamHandle);
+    ALOGI("OboeAudioService.closeStream(0x%08X)", streamHandle);
+    if (serviceStream != nullptr) {
+        ALOGD("OboeAudioService::closeStream(): deleting serviceStream = %p", serviceStream);
+        delete serviceStream;
+        return OBOE_OK;
+    }
+    return OBOE_ERROR_INVALID_HANDLE;
+}
+
+OboeServiceStreamBase *OboeAudioService::convertHandleToServiceStream(
+        oboe_handle_t streamHandle) const {
+    return (OboeServiceStreamBase *) mHandleTracker.get(OBOE_HANDLE_TYPE_STREAM,
+                              (oboe_handle_t)streamHandle);
+}
+
+oboe_result_t OboeAudioService::getStreamDescription(
+                oboe_handle_t streamHandle,
+                oboe::AudioEndpointParcelable &parcelable) {
+    ALOGI("OboeAudioService::getStreamDescriptor(), streamHandle = 0x%08x", streamHandle);
+    OboeServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
+    ALOGI("OboeAudioService::getStreamDescriptor(), serviceStream = %p", serviceStream);
+    if (serviceStream == nullptr) {
+        return OBOE_ERROR_INVALID_HANDLE;
+    }
+    return serviceStream->getDescription(parcelable);
+}
+
+oboe_result_t OboeAudioService::startStream(oboe_handle_t streamHandle) {
+    OboeServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
+    ALOGI("OboeAudioService::startStream(), serviceStream = %p", serviceStream);
+    if (serviceStream == nullptr) {
+        return OBOE_ERROR_INVALID_HANDLE;
+    }
+    mLatestHandle = streamHandle;
+    return serviceStream->start();
+}
+
+oboe_result_t OboeAudioService::pauseStream(oboe_handle_t streamHandle) {
+    OboeServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
+    ALOGI("OboeAudioService::pauseStream(), serviceStream = %p", serviceStream);
+    if (serviceStream == nullptr) {
+        return OBOE_ERROR_INVALID_HANDLE;
+    }
+    return serviceStream->pause();
+}
+
+oboe_result_t OboeAudioService::flushStream(oboe_handle_t streamHandle) {
+    OboeServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
+    ALOGI("OboeAudioService::flushStream(), serviceStream = %p", serviceStream);
+    if (serviceStream == nullptr) {
+        return OBOE_ERROR_INVALID_HANDLE;
+    }
+    return serviceStream->flush();
+}
+
+void OboeAudioService::tickle() {
+    OboeServiceStreamBase *serviceStream = convertHandleToServiceStream(mLatestHandle);
+    //ALOGI("OboeAudioService::tickle(), serviceStream = %p", serviceStream);
+    if (serviceStream != nullptr) {
+        serviceStream->tickle();
+    }
+}
+
+oboe_result_t OboeAudioService::registerAudioThread(oboe_handle_t streamHandle,
+                                                         pid_t clientThreadId,
+                                                         oboe_nanoseconds_t periodNanoseconds) {
+    OboeServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
+    ALOGI("OboeAudioService::registerAudioThread(), serviceStream = %p", serviceStream);
+    if (serviceStream == nullptr) {
+        ALOGE("OboeAudioService::registerAudioThread(), serviceStream == nullptr");
+        return OBOE_ERROR_INVALID_HANDLE;
+    }
+    if (serviceStream->getRegisteredThread() != OboeServiceStreamBase::ILLEGAL_THREAD_ID) {
+        ALOGE("OboeAudioService::registerAudioThread(), thread already registered");
+        return OBOE_ERROR_INVALID_ORDER;
+    }
+    serviceStream->setRegisteredThread(clientThreadId);
+    // Boost client thread to SCHED_FIFO
+    struct sched_param sp;
+    memset(&sp, 0, sizeof(sp));
+    sp.sched_priority = 2; // TODO use 'requestPriority' function from frameworks/av/media/utils
+    int err = sched_setscheduler(clientThreadId, SCHED_FIFO, &sp);
+    if (err != 0){
+        ALOGE("OboeAudioService::sched_setscheduler() failed, errno = %d, priority = %d",
+              errno, sp.sched_priority);
+        return OBOE_ERROR_INTERNAL;
+    } else {
+        return OBOE_OK;
+    }
+}
+
+oboe_result_t OboeAudioService::unregisterAudioThread(oboe_handle_t streamHandle,
+                                                           pid_t clientThreadId) {
+    OboeServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
+    ALOGI("OboeAudioService::unregisterAudioThread(), serviceStream = %p", serviceStream);
+    if (serviceStream == nullptr) {
+        ALOGE("OboeAudioService::unregisterAudioThread(), serviceStream == nullptr");
+        return OBOE_ERROR_INVALID_HANDLE;
+    }
+    if (serviceStream->getRegisteredThread() != clientThreadId) {
+        ALOGE("OboeAudioService::unregisterAudioThread(), wrong thread");
+        return OBOE_ERROR_ILLEGAL_ARGUMENT;
+    }
+    serviceStream->setRegisteredThread(0);
+    return OBOE_OK;
+}