1 /*
2 * Copyright 2021 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_NDEBUG 0
18 #define LOG_TAG "DvrClient"
19
20 #include "DvrClient.h"
21
22 #include <aidl/android/hardware/tv/tuner/DemuxQueueNotifyBits.h>
23 #include <android-base/logging.h>
24 #include <inttypes.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 #include <utils/Log.h>
28
29 #include "ClientHelper.h"
30
31 using ::aidl::android::hardware::tv::tuner::DemuxQueueNotifyBits;
32
33 namespace android {
34 /////////////// DvrClient ///////////////////////
DvrClient(shared_ptr<ITunerDvr> tunerDvr)35 DvrClient::DvrClient(shared_ptr<ITunerDvr> tunerDvr) {
36 mTunerDvr = tunerDvr;
37 mFd = -1;
38 mDvrMQ = nullptr;
39 mDvrMQEventFlag = nullptr;
40 }
41
~DvrClient()42 DvrClient::~DvrClient() {
43 mTunerDvr = nullptr;
44 mFd = -1;
45 mDvrMQ = nullptr;
46 mDvrMQEventFlag = nullptr;
47 }
48
setFd(int32_t fd)49 void DvrClient::setFd(int32_t fd) {
50 mFd = fd;
51 }
52
readFromFile(int64_t size)53 int64_t DvrClient::readFromFile(int64_t size) {
54 if (mDvrMQ == nullptr || mDvrMQEventFlag == nullptr) {
55 ALOGE("Failed to readFromFile. DVR mq is not configured");
56 return -1;
57 }
58 if (mFd < 0) {
59 ALOGE("Failed to readFromFile. File is not configured");
60 return -1;
61 }
62
63 int64_t available = mDvrMQ->availableToWrite();
64 int64_t write = min(size, available);
65
66 AidlMQ::MemTransaction tx;
67 int64_t ret = 0;
68 if (mDvrMQ->beginWrite(write, &tx)) {
69 auto first = tx.getFirstRegion();
70 auto data = first.getAddress();
71 int64_t length = first.getLength();
72 int64_t firstToWrite = min(length, write);
73 ret = read(mFd, data, firstToWrite);
74
75 if (ret < 0) {
76 ALOGE("Failed to read from FD: %s", strerror(errno));
77 return -1;
78 }
79 if (ret < firstToWrite) {
80 ALOGW("file to MQ, first region: %" PRIu64 " bytes to write, but %" PRIu64
81 " bytes written",
82 firstToWrite, ret);
83 } else if (firstToWrite < write) {
84 ALOGV("write second region: %" PRIu64 " bytes written, %" PRIu64 " bytes in total", ret,
85 write);
86 auto second = tx.getSecondRegion();
87 data = second.getAddress();
88 length = second.getLength();
89 int64_t secondToWrite = std::min(length, write - firstToWrite);
90 ret += read(mFd, data, secondToWrite);
91 }
92 ALOGV("file to MQ: %" PRIu64 " bytes need to be written, %" PRIu64 " bytes written", write,
93 ret);
94 if (!mDvrMQ->commitWrite(ret)) {
95 ALOGE("Error: failed to commit write!");
96 return -1;
97 }
98 } else {
99 ALOGE("dvrMq.beginWrite failed");
100 }
101
102 if (ret > 0) {
103 mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
104 }
105 return ret;
106 }
107
readFromBuffer(int8_t * buffer,int64_t size)108 int64_t DvrClient::readFromBuffer(int8_t* buffer, int64_t size) {
109 if (mDvrMQ == nullptr || mDvrMQEventFlag == nullptr) {
110 ALOGE("Failed to readFromBuffer. DVR mq is not configured");
111 return -1;
112 }
113 if (buffer == nullptr) {
114 ALOGE("Failed to readFromBuffer. Buffer can't be null");
115 return -1;
116 }
117
118 int64_t available = mDvrMQ->availableToWrite();
119 size = min(size, available);
120
121 if (mDvrMQ->write(buffer, size)) {
122 mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
123 } else {
124 ALOGD("Failed to write FMQ");
125 return -1;
126 }
127 return size;
128 }
129
writeToFile(int64_t size)130 int64_t DvrClient::writeToFile(int64_t size) {
131 if (mDvrMQ == nullptr || mDvrMQEventFlag == nullptr) {
132 ALOGE("Failed to writeToFile. DVR mq is not configured");
133 return -1;
134 }
135 if (mFd < 0) {
136 ALOGE("Failed to writeToFile. File is not configured");
137 return -1;
138 }
139
140 int64_t available = mDvrMQ->availableToRead();
141 int64_t toRead = min(size, available);
142
143 int64_t ret = 0;
144 AidlMQ::MemTransaction tx;
145 if (mDvrMQ->beginRead(toRead, &tx)) {
146 auto first = tx.getFirstRegion();
147 auto data = first.getAddress();
148 int64_t length = first.getLength();
149 int64_t firstToRead = std::min(length, toRead);
150 ret = write(mFd, data, firstToRead);
151
152 if (ret < 0) {
153 ALOGE("Failed to write to FD: %s", strerror(errno));
154 return -1;
155 }
156 if (ret < firstToRead) {
157 ALOGW("MQ to file: %" PRIu64 " bytes read, but %" PRIu64 " bytes written", firstToRead,
158 ret);
159 } else if (firstToRead < toRead) {
160 ALOGV("read second region: %" PRIu64 " bytes read, %" PRIu64 " bytes in total", ret,
161 toRead);
162 auto second = tx.getSecondRegion();
163 data = second.getAddress();
164 length = second.getLength();
165 int32_t secondToRead = toRead - firstToRead;
166 ret += write(mFd, data, secondToRead);
167 }
168 ALOGV("MQ to file: %" PRIu64 " bytes to be read, %" PRIu64 " bytes written", toRead, ret);
169 if (!mDvrMQ->commitRead(ret)) {
170 ALOGE("Error: failed to commit read!");
171 return 0;
172 }
173 } else {
174 ALOGE("dvrMq.beginRead failed");
175 }
176 if (ret > 0) {
177 mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
178 }
179
180 return ret;
181 }
182
writeToBuffer(int8_t * buffer,int64_t size)183 int64_t DvrClient::writeToBuffer(int8_t* buffer, int64_t size) {
184 if (mDvrMQ == nullptr || mDvrMQEventFlag == nullptr) {
185 ALOGE("Failed to writetoBuffer. DVR mq is not configured");
186 return -1;
187 }
188 if (buffer == nullptr) {
189 ALOGE("Failed to writetoBuffer. Buffer can't be null");
190 return -1;
191 }
192
193 int64_t available = mDvrMQ->availableToRead();
194 size = min(size, available);
195
196 if (mDvrMQ->read(buffer, size)) {
197 mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
198 } else {
199 ALOGD("Failed to write FMQ");
200 return -1;
201 }
202 return size;
203 }
204
seekFile(int64_t pos)205 int64_t DvrClient::seekFile(int64_t pos) {
206 if (mFd < 0) {
207 ALOGE("Failed to seekFile. File is not configured");
208 return -1;
209 }
210 return lseek64(mFd, pos, SEEK_SET);
211 }
212
configure(DvrSettings settings)213 Result DvrClient::configure(DvrSettings settings) {
214 if (mTunerDvr != nullptr) {
215 Status s = mTunerDvr->configure(settings);
216 Result res = ClientHelper::getServiceSpecificErrorCode(s);
217 if (res != Result::SUCCESS) {
218 return res;
219 }
220
221 AidlMQDesc aidlMqDesc;
222 s = mTunerDvr->getQueueDesc(&aidlMqDesc);
223 res = ClientHelper::getServiceSpecificErrorCode(s);
224 if (res != Result::SUCCESS) {
225 return res;
226 }
227 mDvrMQ = new (nothrow) AidlMQ(aidlMqDesc);
228 EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrMQEventFlag);
229 return res;
230 }
231
232 return Result::INVALID_STATE;
233 }
234
attachFilter(sp<FilterClient> filterClient)235 Result DvrClient::attachFilter(sp<FilterClient> filterClient) {
236 if (filterClient == nullptr) {
237 return Result::INVALID_ARGUMENT;
238 }
239
240 if (mTunerDvr != nullptr) {
241 Status s = mTunerDvr->attachFilter(filterClient->getAidlFilter());
242 return ClientHelper::getServiceSpecificErrorCode(s);
243 }
244
245 return Result::INVALID_STATE;
246 }
247
detachFilter(sp<FilterClient> filterClient)248 Result DvrClient::detachFilter(sp<FilterClient> filterClient) {
249 if (filterClient == nullptr) {
250 return Result::INVALID_ARGUMENT;
251 }
252
253 if (mTunerDvr != nullptr) {
254 Status s = mTunerDvr->detachFilter(filterClient->getAidlFilter());
255 return ClientHelper::getServiceSpecificErrorCode(s);
256 }
257
258 return Result::INVALID_STATE;
259 }
260
start()261 Result DvrClient::start() {
262 if (mTunerDvr != nullptr) {
263 Status s = mTunerDvr->start();
264 return ClientHelper::getServiceSpecificErrorCode(s);
265 }
266
267 return Result::INVALID_STATE;
268 }
269
stop()270 Result DvrClient::stop() {
271 if (mTunerDvr != nullptr) {
272 Status s = mTunerDvr->stop();
273 return ClientHelper::getServiceSpecificErrorCode(s);
274 }
275
276 return Result::INVALID_STATE;
277 }
278
flush()279 Result DvrClient::flush() {
280 if (mTunerDvr != nullptr) {
281 Status s = mTunerDvr->flush();
282 return ClientHelper::getServiceSpecificErrorCode(s);
283 }
284
285 return Result::INVALID_STATE;
286 }
287
close()288 Result DvrClient::close() {
289 if (mDvrMQEventFlag != nullptr) {
290 EventFlag::deleteEventFlag(&mDvrMQEventFlag);
291 mDvrMQEventFlag = nullptr;
292 }
293 if (mDvrMQ != nullptr) {
294 delete mDvrMQ;
295 mDvrMQ = nullptr;
296 }
297
298 if (mTunerDvr != nullptr) {
299 Status s = mTunerDvr->close();
300 mTunerDvr = nullptr;
301 return ClientHelper::getServiceSpecificErrorCode(s);
302 }
303
304 return Result::INVALID_STATE;
305 }
setStatusCheckIntervalHint(int64_t durationInMs)306 Result DvrClient::setStatusCheckIntervalHint(int64_t durationInMs) {
307 if (mTunerDvr == nullptr) {
308 return Result::INVALID_STATE;
309 }
310 if (durationInMs < 0) {
311 return Result::INVALID_ARGUMENT;
312 }
313
314 Status s = mTunerDvr->setStatusCheckIntervalHint(durationInMs);
315 return ClientHelper::getServiceSpecificErrorCode(s);
316 }
317 /////////////// TunerDvrCallback ///////////////////////
TunerDvrCallback(sp<DvrClientCallback> dvrClientCallback)318 TunerDvrCallback::TunerDvrCallback(sp<DvrClientCallback> dvrClientCallback)
319 : mDvrClientCallback(dvrClientCallback) {}
320
onRecordStatus(RecordStatus status)321 Status TunerDvrCallback::onRecordStatus(RecordStatus status) {
322 if (mDvrClientCallback != nullptr) {
323 mDvrClientCallback->onRecordStatus(status);
324 return Status::ok();
325 }
326 return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_STATE));
327 }
328
onPlaybackStatus(PlaybackStatus status)329 Status TunerDvrCallback::onPlaybackStatus(PlaybackStatus status) {
330 if (mDvrClientCallback != nullptr) {
331 mDvrClientCallback->onPlaybackStatus(status);
332 return Status::ok();
333 }
334 return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_STATE));
335 }
336
337 } // namespace android
338