Home | History | Annotate | Download | only in oboeservice
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "AAudioServiceStreamMMAP"
     18 //#define LOG_NDEBUG 0
     19 #include <utils/Log.h>
     20 
     21 #include <atomic>
     22 #include <iomanip>
     23 #include <iostream>
     24 #include <stdint.h>
     25 
     26 #include <utils/String16.h>
     27 #include <media/nbaio/AudioStreamOutSink.h>
     28 #include <media/MmapStreamInterface.h>
     29 
     30 #include "binding/AudioEndpointParcelable.h"
     31 #include "utility/AAudioUtilities.h"
     32 
     33 #include "AAudioServiceEndpointMMAP.h"
     34 #include "AAudioServiceStreamBase.h"
     35 #include "AAudioServiceStreamMMAP.h"
     36 #include "SharedMemoryProxy.h"
     37 
     38 using android::base::unique_fd;
     39 using namespace android;
     40 using namespace aaudio;
     41 
     42 /**
     43  * Service Stream that uses an MMAP buffer.
     44  */
     45 
     46 AAudioServiceStreamMMAP::AAudioServiceStreamMMAP(android::AAudioService &aAudioService,
     47                                                  bool inService)
     48         : AAudioServiceStreamBase(aAudioService)
     49         , mInService(inService) {
     50 }
     51 
     52 aaudio_result_t AAudioServiceStreamMMAP::close() {
     53     if (getState() == AAUDIO_STREAM_STATE_CLOSED) {
     54         return AAUDIO_OK;
     55     }
     56 
     57     stop();
     58 
     59     return AAudioServiceStreamBase::close();
     60 }
     61 
     62 // Open stream on HAL and pass information about the shared memory buffer back to the client.
     63 aaudio_result_t AAudioServiceStreamMMAP::open(const aaudio::AAudioStreamRequest &request) {
     64 
     65     sp<AAudioServiceStreamMMAP> keep(this);
     66 
     67     if (request.getConstantConfiguration().getSharingMode() != AAUDIO_SHARING_MODE_EXCLUSIVE) {
     68         ALOGE("%s() sharingMode mismatch %d", __func__,
     69               request.getConstantConfiguration().getSharingMode());
     70         return AAUDIO_ERROR_INTERNAL;
     71     }
     72 
     73     aaudio_result_t result = AAudioServiceStreamBase::open(request);
     74     if (result != AAUDIO_OK) {
     75         return result;
     76     }
     77 
     78     sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
     79     if (endpoint == nullptr) {
     80         ALOGE("%s() has no endpoint", __func__);
     81         return AAUDIO_ERROR_INVALID_STATE;
     82     }
     83 
     84     result = endpoint->registerStream(keep);
     85     if (result != AAUDIO_OK) {
     86         return result;
     87     }
     88 
     89     setState(AAUDIO_STREAM_STATE_OPEN);
     90 
     91     return AAUDIO_OK;
     92 }
     93 
     94 // Start the flow of data.
     95 aaudio_result_t AAudioServiceStreamMMAP::startDevice() {
     96     aaudio_result_t result = AAudioServiceStreamBase::startDevice();
     97     if (!mInService && result == AAUDIO_OK) {
     98         // Note that this can sometimes take 200 to 300 msec for a cold start!
     99         result = startClient(mMmapClient, &mClientHandle);
    100     }
    101     return result;
    102 }
    103 
    104 // Stop the flow of data such that start() can resume with loss of data.
    105 aaudio_result_t AAudioServiceStreamMMAP::pause() {
    106     if (!isRunning()) {
    107         return AAUDIO_OK;
    108     }
    109     aaudio_result_t result = AAudioServiceStreamBase::pause();
    110     // TODO put before base::pause()?
    111     if (!mInService) {
    112         (void) stopClient(mClientHandle);
    113     }
    114     return result;
    115 }
    116 
    117 aaudio_result_t AAudioServiceStreamMMAP::stop() {
    118     if (!isRunning()) {
    119         return AAUDIO_OK;
    120     }
    121     aaudio_result_t result = AAudioServiceStreamBase::stop();
    122     // TODO put before base::stop()?
    123     if (!mInService) {
    124         (void) stopClient(mClientHandle);
    125     }
    126     return result;
    127 }
    128 
    129 aaudio_result_t AAudioServiceStreamMMAP::startClient(const android::AudioClient& client,
    130                                                        audio_port_handle_t *clientHandle) {
    131     sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
    132     if (endpoint == nullptr) {
    133         ALOGE("%s() has no endpoint", __func__);
    134         return AAUDIO_ERROR_INVALID_STATE;
    135     }
    136     // Start the client on behalf of the application. Generate a new porthandle.
    137     aaudio_result_t result = endpoint->startClient(client, clientHandle);
    138     return result;
    139 }
    140 
    141 aaudio_result_t AAudioServiceStreamMMAP::stopClient(audio_port_handle_t clientHandle) {
    142     sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
    143     if (endpoint == nullptr) {
    144         ALOGE("%s() has no endpoint", __func__);
    145         return AAUDIO_ERROR_INVALID_STATE;
    146     }
    147     aaudio_result_t result = endpoint->stopClient(clientHandle);
    148     return result;
    149 }
    150 
    151 // Get free-running DSP or DMA hardware position from the HAL.
    152 aaudio_result_t AAudioServiceStreamMMAP::getFreeRunningPosition(int64_t *positionFrames,
    153                                                                   int64_t *timeNanos) {
    154     sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
    155     if (endpoint == nullptr) {
    156         ALOGE("%s() has no endpoint", __func__);
    157         return AAUDIO_ERROR_INVALID_STATE;
    158     }
    159     sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
    160             static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
    161 
    162     aaudio_result_t result = serviceEndpointMMAP->getFreeRunningPosition(positionFrames, timeNanos);
    163     if (result == AAUDIO_OK) {
    164         Timestamp timestamp(*positionFrames, *timeNanos);
    165         mAtomicStreamTimestamp.write(timestamp);
    166         *positionFrames = timestamp.getPosition();
    167         *timeNanos = timestamp.getNanoseconds();
    168     } else if (result != AAUDIO_ERROR_UNAVAILABLE) {
    169         disconnect();
    170     }
    171     return result;
    172 }
    173 
    174 // Get timestamp that was written by getFreeRunningPosition()
    175 aaudio_result_t AAudioServiceStreamMMAP::getHardwareTimestamp(int64_t *positionFrames,
    176                                                                 int64_t *timeNanos) {
    177 
    178     sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
    179     if (endpoint == nullptr) {
    180         ALOGE("%s() has no endpoint", __func__);
    181         return AAUDIO_ERROR_INVALID_STATE;
    182     }
    183     sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
    184             static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
    185 
    186     // TODO Get presentation timestamp from the HAL
    187     if (mAtomicStreamTimestamp.isValid()) {
    188         Timestamp timestamp = mAtomicStreamTimestamp.read();
    189         *positionFrames = timestamp.getPosition();
    190         *timeNanos = timestamp.getNanoseconds() + serviceEndpointMMAP->getHardwareTimeOffsetNanos();
    191         return AAUDIO_OK;
    192     } else {
    193         return AAUDIO_ERROR_UNAVAILABLE;
    194     }
    195 }
    196 
    197 // Get an immutable description of the data queue from the HAL.
    198 aaudio_result_t AAudioServiceStreamMMAP::getAudioDataDescription(
    199         AudioEndpointParcelable &parcelable)
    200 {
    201     sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
    202     if (endpoint == nullptr) {
    203         ALOGE("%s() has no endpoint", __func__);
    204         return AAUDIO_ERROR_INVALID_STATE;
    205     }
    206     sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
    207             static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
    208     return serviceEndpointMMAP->getDownDataDescription(parcelable);
    209 }
    210