Home | History | Annotate | Download | only in bufferpool
      1 /*
      2  * Copyright (C) 2018 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 "BufferPoolStatus"
     18 //#define LOG_NDEBUG 0
     19 
     20 #include <time.h>
     21 #include "BufferStatus.h"
     22 
     23 namespace android {
     24 namespace hardware {
     25 namespace media {
     26 namespace bufferpool {
     27 namespace V1_0 {
     28 namespace implementation {
     29 
     30 int64_t getTimestampNow() {
     31     int64_t stamp;
     32     struct timespec ts;
     33     // TODO: CLOCK_MONOTONIC_COARSE?
     34     clock_gettime(CLOCK_MONOTONIC, &ts);
     35     stamp = ts.tv_nsec / 1000;
     36     stamp += (ts.tv_sec * 1000000LL);
     37     return stamp;
     38 }
     39 
     40 static constexpr int kNumElementsInQueue = 1024*16;
     41 
     42 ResultStatus BufferStatusObserver::open(
     43         ConnectionId id, const QueueDescriptor** fmqDescPtr) {
     44     if (mBufferStatusQueues.find(id) != mBufferStatusQueues.end()) {
     45         // TODO: id collision log?
     46         return ResultStatus::CRITICAL_ERROR;
     47     }
     48     std::unique_ptr<BufferStatusQueue> queue =
     49             std::make_unique<BufferStatusQueue>(kNumElementsInQueue);
     50     if (!queue || queue->isValid() == false) {
     51         *fmqDescPtr = NULL;
     52         return ResultStatus::NO_MEMORY;
     53     } else {
     54         *fmqDescPtr = queue->getDesc();
     55     }
     56     auto result = mBufferStatusQueues.insert(
     57             std::make_pair(id, std::move(queue)));
     58     if (!result.second) {
     59         *fmqDescPtr = NULL;
     60         return ResultStatus::NO_MEMORY;
     61     }
     62     return ResultStatus::OK;
     63 }
     64 
     65 ResultStatus BufferStatusObserver::close(ConnectionId id) {
     66     if (mBufferStatusQueues.find(id) == mBufferStatusQueues.end()) {
     67         return ResultStatus::CRITICAL_ERROR;
     68     }
     69     mBufferStatusQueues.erase(id);
     70     return ResultStatus::OK;
     71 }
     72 
     73 void BufferStatusObserver::getBufferStatusChanges(std::vector<BufferStatusMessage> &messages) {
     74     for (auto it = mBufferStatusQueues.begin(); it != mBufferStatusQueues.end(); ++it) {
     75         BufferStatusMessage message;
     76         size_t avail = it->second->availableToRead();
     77         while (avail > 0) {
     78             if (!it->second->read(&message, 1)) {
     79                 // Since avaliable # of reads are already confirmed,
     80                 // this should not happen.
     81                 // TODO: error handling (spurious client?)
     82                 ALOGW("FMQ message cannot be read from %lld", (long long)it->first);
     83                 return;
     84             }
     85             message.connectionId = it->first;
     86             messages.push_back(message);
     87             --avail;
     88         }
     89     }
     90 }
     91 
     92 BufferStatusChannel::BufferStatusChannel(
     93         const QueueDescriptor &fmqDesc) {
     94     std::unique_ptr<BufferStatusQueue> queue =
     95             std::make_unique<BufferStatusQueue>(fmqDesc);
     96     if (!queue || queue->isValid() == false) {
     97         mValid = false;
     98         return;
     99     }
    100     mValid  = true;
    101     mBufferStatusQueue = std::move(queue);
    102 }
    103 
    104 bool BufferStatusChannel::isValid() {
    105     return mValid;
    106 }
    107 
    108 void BufferStatusChannel::postBufferRelease(
    109         ConnectionId connectionId,
    110         std::list<BufferId> &pending, std::list<BufferId> &posted) {
    111     if (mValid && pending.size() > 0) {
    112         size_t avail = mBufferStatusQueue->availableToWrite();
    113         avail = std::min(avail, pending.size());
    114         BufferStatusMessage message;
    115         for (size_t i = 0 ; i < avail; ++i) {
    116             BufferId id = pending.front();
    117             message.newStatus = BufferStatus::NOT_USED;
    118             message.bufferId = id;
    119             message.connectionId = connectionId;
    120             if (!mBufferStatusQueue->write(&message, 1)) {
    121                 // Since avaliable # of writes are already confirmed,
    122                 // this should not happen.
    123                 // TODO: error handing?
    124                 ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
    125                 return;
    126             }
    127             pending.pop_front();
    128             posted.push_back(id);
    129         }
    130     }
    131 }
    132 
    133 bool BufferStatusChannel::postBufferStatusMessage(
    134         TransactionId transactionId, BufferId bufferId,
    135         BufferStatus status, ConnectionId connectionId, ConnectionId targetId,
    136         std::list<BufferId> &pending, std::list<BufferId> &posted) {
    137     if (mValid) {
    138         size_t avail = mBufferStatusQueue->availableToWrite();
    139         size_t numPending = pending.size();
    140         if (avail >= numPending + 1) {
    141             BufferStatusMessage release, message;
    142             for (size_t i = 0; i < numPending; ++i) {
    143                 BufferId id = pending.front();
    144                 release.newStatus = BufferStatus::NOT_USED;
    145                 release.bufferId = id;
    146                 release.connectionId = connectionId;
    147                 if (!mBufferStatusQueue->write(&release, 1)) {
    148                     // Since avaliable # of writes are already confirmed,
    149                     // this should not happen.
    150                     // TODO: error handling?
    151                     ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
    152                     return false;
    153                 }
    154                 pending.pop_front();
    155                 posted.push_back(id);
    156             }
    157             message.transactionId = transactionId;
    158             message.bufferId = bufferId;
    159             message.newStatus = status;
    160             message.connectionId = connectionId;
    161             message.targetConnectionId = targetId;
    162             // TODO : timesatamp
    163             message.timestampUs = 0;
    164             if (!mBufferStatusQueue->write(&message, 1)) {
    165                 // Since avaliable # of writes are already confirmed,
    166                 // this should not happen.
    167                 ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
    168                 return false;
    169             }
    170             return true;
    171         }
    172     }
    173     return false;
    174 }
    175 
    176 }  // namespace implementation
    177 }  // namespace V1_0
    178 }  // namespace bufferpool
    179 }  // namespace media
    180 }  // namespace hardware
    181 }  // namespace android
    182 
    183