blob: caddc1dbc2c6baa6356ced99e662c3be69c1f899 [file] [log] [blame]
/*
* 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;
}