blob: 0476216dcbed8bb5e7e9a0ec0999808a1ad43cd3 [file] [log] [blame]
Amy Zhang9a9ed602020-12-07 16:37:33 -08001/*
2 * Copyright 2020 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 "DvrClient"
18
19#include <android-base/logging.h>
Amy Zhang2d7026b2021-01-22 18:07:51 -080020#include <fmq/ConvertMQDescriptors.h>
Amy Zhang9a9ed602020-12-07 16:37:33 -080021#include <utils/Log.h>
22
Amy Zhang2d7026b2021-01-22 18:07:51 -080023#include "ClientHelper.h"
Amy Zhang9a9ed602020-12-07 16:37:33 -080024#include "DvrClient.h"
25
26using ::android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits;
27using ::android::hardware::tv::tuner::V1_0::Result;
28
29namespace android {
30
31/////////////// DvrClient ///////////////////////
32
Amy Zhang2d7026b2021-01-22 18:07:51 -080033DvrClient::DvrClient(shared_ptr<ITunerDvr> tunerDvr) {
34 mTunerDvr = tunerDvr;
Amy Zhang9a9ed602020-12-07 16:37:33 -080035 mFd = -1;
36 mDvrMQ = NULL;
37 mDvrMQEventFlag = NULL;
38}
39
40DvrClient::~DvrClient() {
Amy Zhang2d7026b2021-01-22 18:07:51 -080041 mTunerDvr = NULL;
Amy Zhang9a9ed602020-12-07 16:37:33 -080042 mDvr = NULL;
43 mFd = -1;
44 mDvrMQ = NULL;
45 mDvrMQEventFlag = NULL;
46}
47
48// TODO: remove after migration to Tuner Service is done.
49void DvrClient::setHidlDvr(sp<IDvr> dvr) {
50 mDvr = dvr;
51}
52
53void DvrClient::setFd(int fd) {
54 mFd = fd;
55}
56
57long DvrClient::readFromFile(long size) {
58 if (mDvrMQ == NULL || mDvrMQEventFlag == NULL) {
59 ALOGE("Failed to readFromFile. DVR mq is not configured");
60 return -1;
61 }
62 if (mFd < 0) {
63 ALOGE("Failed to readFromFile. File is not configured");
64 return -1;
65 }
66
67 long available = mDvrMQ->availableToWrite();
68 long write = min(size, available);
69
Amy Zhang2d7026b2021-01-22 18:07:51 -080070 AidlMQ::MemTransaction tx;
Amy Zhang9a9ed602020-12-07 16:37:33 -080071 long ret = 0;
72 if (mDvrMQ->beginWrite(write, &tx)) {
73 auto first = tx.getFirstRegion();
74 auto data = first.getAddress();
75 long length = first.getLength();
76 long firstToWrite = min(length, write);
77 ret = read(mFd, data, firstToWrite);
78
79 if (ret < 0) {
80 ALOGE("Failed to read from FD: %s", strerror(errno));
81 return -1;
82 }
83 if (ret < firstToWrite) {
84 ALOGW("file to MQ, first region: %ld bytes to write, but %ld bytes written",
85 firstToWrite, ret);
86 } else if (firstToWrite < write) {
87 ALOGD("write second region: %ld bytes written, %ld bytes in total", ret, write);
88 auto second = tx.getSecondRegion();
89 data = second.getAddress();
90 length = second.getLength();
91 int secondToWrite = std::min(length, write - firstToWrite);
92 ret += read(mFd, data, secondToWrite);
93 }
94 ALOGD("file to MQ: %ld bytes need to be written, %ld bytes written", write, ret);
95 if (!mDvrMQ->commitWrite(ret)) {
96 ALOGE("Error: failed to commit write!");
97 return -1;
98 }
99 } else {
100 ALOGE("dvrMq.beginWrite failed");
101 }
102
103 if (ret > 0) {
104 mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
105 }
106 return ret;
107}
108
Amy Zhang2d7026b2021-01-22 18:07:51 -0800109long DvrClient::readFromBuffer(int8_t* buffer, long size) {
Amy Zhang9a9ed602020-12-07 16:37:33 -0800110 if (mDvrMQ == NULL || mDvrMQEventFlag == NULL) {
111 ALOGE("Failed to readFromBuffer. DVR mq is not configured");
112 return -1;
113 }
114 if (buffer == nullptr) {
115 ALOGE("Failed to readFromBuffer. Buffer can't be null");
116 return -1;
117 }
118
119 long available = mDvrMQ->availableToWrite();
120 size = min(size, available);
121
122 if (mDvrMQ->write(buffer, size)) {
123 mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
124 } else {
125 ALOGD("Failed to write FMQ");
126 return -1;
127 }
128 return size;
129}
130
131long DvrClient::writeToFile(long size) {
132 if (mDvrMQ == NULL || mDvrMQEventFlag == NULL) {
133 ALOGE("Failed to writeToFile. DVR mq is not configured");
134 return -1;
135 }
136 if (mFd < 0) {
137 ALOGE("Failed to writeToFile. File is not configured");
138 return -1;
139 }
140
141 long available = mDvrMQ->availableToRead();
142 long toRead = min(size, available);
143
144 long ret = 0;
Amy Zhang2d7026b2021-01-22 18:07:51 -0800145 AidlMQ::MemTransaction tx;
Amy Zhang9a9ed602020-12-07 16:37:33 -0800146 if (mDvrMQ->beginRead(toRead, &tx)) {
147 auto first = tx.getFirstRegion();
148 auto data = first.getAddress();
149 long length = first.getLength();
150 long firstToRead = std::min(length, toRead);
151 ret = write(mFd, data, firstToRead);
152
153 if (ret < 0) {
154 ALOGE("Failed to write to FD: %s", strerror(errno));
155 return -1;
156 }
157 if (ret < firstToRead) {
158 ALOGW("MQ to file: %ld bytes read, but %ld bytes written", firstToRead, ret);
159 } else if (firstToRead < toRead) {
160 ALOGD("read second region: %ld bytes read, %ld bytes in total", ret, toRead);
161 auto second = tx.getSecondRegion();
162 data = second.getAddress();
163 length = second.getLength();
164 int secondToRead = toRead - firstToRead;
165 ret += write(mFd, data, secondToRead);
166 }
167 ALOGD("MQ to file: %ld bytes to be read, %ld bytes written", toRead, ret);
168 if (!mDvrMQ->commitRead(ret)) {
169 ALOGE("Error: failed to commit read!");
170 return 0;
171 }
172 } else {
173 ALOGE("dvrMq.beginRead failed");
174 }
175 if (ret > 0) {
176 mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
177 }
178
179 return ret;
180}
181
Amy Zhang2d7026b2021-01-22 18:07:51 -0800182long DvrClient::writeToBuffer(int8_t* buffer, long size) {
Amy Zhang9a9ed602020-12-07 16:37:33 -0800183 if (mDvrMQ == NULL || mDvrMQEventFlag == NULL) {
184 ALOGE("Failed to writetoBuffer. DVR mq is not configured");
185 return -1;
186 }
187 if (buffer == nullptr) {
188 ALOGE("Failed to writetoBuffer. Buffer can't be null");
189 return -1;
190 }
191
192 long available = mDvrMQ->availableToRead();
193 size = min(size, available);
194
195 if (mDvrMQ->read(buffer, size)) {
196 mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
197 } else {
198 ALOGD("Failed to write FMQ");
199 return -1;
200 }
201 return size;
202}
203
204Result DvrClient::configure(DvrSettings settings) {
Amy Zhang2d7026b2021-01-22 18:07:51 -0800205 if (mTunerDvr != NULL) {
206 TunerDvrSettings dvrSettings = getAidlDvrSettingsFromHidl(settings);
207 Status s = mTunerDvr->configure(dvrSettings);
208 Result res = ClientHelper::getServiceSpecificErrorCode(s);
209 if (res != Result::SUCCESS) {
210 return res;
211 }
212
Amy Zhangb5809be2021-01-26 16:27:23 -0800213 AidlMQDesc aidlMqDesc;
214 s = mTunerDvr->getQueueDesc(&aidlMqDesc);
Amy Zhang2d7026b2021-01-22 18:07:51 -0800215 res = ClientHelper::getServiceSpecificErrorCode(s);
216 if (res != Result::SUCCESS) {
217 return res;
218 }
Amy Zhangb5809be2021-01-26 16:27:23 -0800219 mDvrMQ = new (nothrow) AidlMQ(aidlMqDesc);
Amy Zhang2d7026b2021-01-22 18:07:51 -0800220 EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrMQEventFlag);
221 return res;
222 }
Amy Zhang9a9ed602020-12-07 16:37:33 -0800223
224 if (mDvr != NULL) {
225 Result res = mDvr->configure(settings);
226 if (res == Result::SUCCESS) {
227 MQDescriptorSync<uint8_t> dvrMQDesc;
228 res = getQueueDesc(dvrMQDesc);
229 if (res == Result::SUCCESS) {
Amy Zhang2d7026b2021-01-22 18:07:51 -0800230 AidlMQDesc aidlMQDesc;
231 unsafeHidlToAidlMQDescriptor<uint8_t, int8_t, SynchronizedReadWrite>(
232 dvrMQDesc, &aidlMQDesc);
233 mDvrMQ = new (nothrow) AidlMessageQueue(aidlMQDesc);
Amy Zhang9a9ed602020-12-07 16:37:33 -0800234 EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrMQEventFlag);
235 }
236 }
237 return res;
238 }
239
240 return Result::INVALID_STATE;
241}
242
243Result DvrClient::attachFilter(sp<FilterClient> filterClient) {
Amy Zhang2d7026b2021-01-22 18:07:51 -0800244 if (mTunerDvr != NULL) {
245 Status s = mTunerDvr->attachFilter(filterClient->getAidlFilter());
246 return ClientHelper::getServiceSpecificErrorCode(s);
247 }
Amy Zhang9a9ed602020-12-07 16:37:33 -0800248
249 if (mDvr != NULL) {
250 sp<IFilter> hidlFilter = filterClient->getHalFilter();
251 if (hidlFilter == NULL) {
252 return Result::INVALID_ARGUMENT;
253 }
254 return mDvr->attachFilter(hidlFilter);
255 }
256
257 return Result::INVALID_STATE;
258}
259
260Result DvrClient::detachFilter(sp<FilterClient> filterClient) {
Amy Zhang2d7026b2021-01-22 18:07:51 -0800261 if (mTunerDvr != NULL) {
262 Status s = mTunerDvr->detachFilter(filterClient->getAidlFilter());
263 return ClientHelper::getServiceSpecificErrorCode(s);
264 }
Amy Zhang9a9ed602020-12-07 16:37:33 -0800265
266 if (mDvr != NULL) {
267 sp<IFilter> hidlFilter = filterClient->getHalFilter();
268 if (hidlFilter == NULL) {
269 return Result::INVALID_ARGUMENT;
270 }
271 return mDvr->detachFilter(hidlFilter);
272 }
273
274 return Result::INVALID_STATE;
275}
276
277Result DvrClient::start() {
Amy Zhang2d7026b2021-01-22 18:07:51 -0800278 if (mTunerDvr != NULL) {
279 Status s = mTunerDvr->start();
280 return ClientHelper::getServiceSpecificErrorCode(s);
281 }
Amy Zhang9a9ed602020-12-07 16:37:33 -0800282
283 if (mDvr != NULL) {
284 return mDvr->start();
285 }
286
287 return Result::INVALID_STATE;
288}
289
290Result DvrClient::stop() {
Amy Zhang2d7026b2021-01-22 18:07:51 -0800291 if (mTunerDvr != NULL) {
292 Status s = mTunerDvr->stop();
293 return ClientHelper::getServiceSpecificErrorCode(s);
294 }
Amy Zhang9a9ed602020-12-07 16:37:33 -0800295
296 if (mDvr != NULL) {
297 return mDvr->stop();
298 }
299
300 return Result::INVALID_STATE;
301}
302
303Result DvrClient::flush() {
Amy Zhang2d7026b2021-01-22 18:07:51 -0800304 if (mTunerDvr != NULL) {
305 Status s = mTunerDvr->flush();
306 return ClientHelper::getServiceSpecificErrorCode(s);
307 }
Amy Zhang9a9ed602020-12-07 16:37:33 -0800308
309 if (mDvr != NULL) {
310 return mDvr->flush();
311 }
312
313 return Result::INVALID_STATE;
314}
315
316Result DvrClient::close() {
Henry Fangbc30a4b2021-03-15 13:27:37 -0700317 if (mDvrMQEventFlag != NULL) {
318 EventFlag::deleteEventFlag(&mDvrMQEventFlag);
319 }
320 mDvrMQ = NULL;
321
Amy Zhang2d7026b2021-01-22 18:07:51 -0800322 if (mTunerDvr != NULL) {
323 Status s = mTunerDvr->close();
Amy Zhangec3b4872021-02-11 15:38:20 -0800324 mTunerDvr = NULL;
Amy Zhang2d7026b2021-01-22 18:07:51 -0800325 return ClientHelper::getServiceSpecificErrorCode(s);
326 }
Amy Zhang9a9ed602020-12-07 16:37:33 -0800327
328 if (mDvr != NULL) {
329 Result res = mDvr->close();
Amy Zhangec3b4872021-02-11 15:38:20 -0800330 mDvr = NULL;
Amy Zhang9a9ed602020-12-07 16:37:33 -0800331 return res;
332 }
333
334 return Result::INVALID_STATE;
335}
336
337/////////////// IDvrCallback ///////////////////////
338
339HidlDvrCallback::HidlDvrCallback(sp<DvrClientCallback> dvrClientCallback)
340 : mDvrClientCallback(dvrClientCallback) {}
341
342Return<void> HidlDvrCallback::onRecordStatus(const RecordStatus status) {
343 if (mDvrClientCallback != NULL) {
344 mDvrClientCallback->onRecordStatus(status);
345 }
346 return Void();
347}
348
349Return<void> HidlDvrCallback::onPlaybackStatus(const PlaybackStatus status) {
350 if (mDvrClientCallback != NULL) {
351 mDvrClientCallback->onPlaybackStatus(status);
352 }
353 return Void();
354}
355
Amy Zhang2d7026b2021-01-22 18:07:51 -0800356/////////////// TunerDvrCallback ///////////////////////
357
358TunerDvrCallback::TunerDvrCallback(sp<DvrClientCallback> dvrClientCallback)
359 : mDvrClientCallback(dvrClientCallback) {}
360
361Status TunerDvrCallback::onRecordStatus(int status) {
362 if (mDvrClientCallback != NULL) {
363 mDvrClientCallback->onRecordStatus(static_cast<RecordStatus>(status));
364 return Status::ok();
365 }
366 return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_STATE));
367}
368
369Status TunerDvrCallback::onPlaybackStatus(int status) {
370 if (mDvrClientCallback != NULL) {
371 mDvrClientCallback->onPlaybackStatus(static_cast<PlaybackStatus>(status));
372 return Status::ok();
373 }
374 return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_STATE));
375}
376
Amy Zhang9a9ed602020-12-07 16:37:33 -0800377/////////////// DvrClient Helper Methods ///////////////////////
378
379Result DvrClient::getQueueDesc(MQDesc& dvrMQDesc) {
Amy Zhang9a9ed602020-12-07 16:37:33 -0800380 if (mDvr != NULL) {
381 Result res = Result::UNKNOWN_ERROR;
382 mDvr->getQueueDesc([&](Result r, const MQDesc& desc) {
383 dvrMQDesc = desc;
384 res = r;
385 });
386 return res;
387 }
388
389 return Result::INVALID_STATE;
390}
Amy Zhang2d7026b2021-01-22 18:07:51 -0800391
392TunerDvrSettings DvrClient::getAidlDvrSettingsFromHidl(DvrSettings settings) {
393 TunerDvrSettings s;
394 switch (settings.getDiscriminator()) {
395 case DvrSettings::hidl_discriminator::record: {
396 s.statusMask = static_cast<int>(settings.record().statusMask);
397 s.lowThreshold = static_cast<int>(settings.record().lowThreshold);
398 s.highThreshold = static_cast<int>(settings.record().highThreshold);
399 s.dataFormat = static_cast<int>(settings.record().dataFormat);
400 s.packetSize = static_cast<int>(settings.record().packetSize);
401 return s;
402 }
403 case DvrSettings::hidl_discriminator::playback: {
404 s.statusMask = static_cast<int>(settings.playback().statusMask);
405 s.lowThreshold = static_cast<int>(settings.playback().lowThreshold);
406 s.highThreshold = static_cast<int>(settings.playback().highThreshold);
407 s.dataFormat = static_cast<int>(settings.playback().dataFormat);
408 s.packetSize = static_cast<int>(settings.playback().packetSize);
409 return s;
410 }
411 default:
412 break;
413 }
414 return s;
415}
Amy Zhang9a9ed602020-12-07 16:37:33 -0800416} // namespace android