blob: 779318008a9b74fe25c1a8714cec04c1f0fd6235 [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() {
Amy Zhang2d7026b2021-01-22 18:07:51 -0800317 if (mTunerDvr != NULL) {
318 Status s = mTunerDvr->close();
Amy Zhangec3b4872021-02-11 15:38:20 -0800319 mTunerDvr = NULL;
Amy Zhang2d7026b2021-01-22 18:07:51 -0800320 return ClientHelper::getServiceSpecificErrorCode(s);
321 }
Amy Zhang9a9ed602020-12-07 16:37:33 -0800322
323 if (mDvr != NULL) {
324 Result res = mDvr->close();
Amy Zhangec3b4872021-02-11 15:38:20 -0800325 mDvr = NULL;
Amy Zhang9a9ed602020-12-07 16:37:33 -0800326 return res;
327 }
328
329 return Result::INVALID_STATE;
330}
331
332/////////////// IDvrCallback ///////////////////////
333
334HidlDvrCallback::HidlDvrCallback(sp<DvrClientCallback> dvrClientCallback)
335 : mDvrClientCallback(dvrClientCallback) {}
336
337Return<void> HidlDvrCallback::onRecordStatus(const RecordStatus status) {
338 if (mDvrClientCallback != NULL) {
339 mDvrClientCallback->onRecordStatus(status);
340 }
341 return Void();
342}
343
344Return<void> HidlDvrCallback::onPlaybackStatus(const PlaybackStatus status) {
345 if (mDvrClientCallback != NULL) {
346 mDvrClientCallback->onPlaybackStatus(status);
347 }
348 return Void();
349}
350
Amy Zhang2d7026b2021-01-22 18:07:51 -0800351/////////////// TunerDvrCallback ///////////////////////
352
353TunerDvrCallback::TunerDvrCallback(sp<DvrClientCallback> dvrClientCallback)
354 : mDvrClientCallback(dvrClientCallback) {}
355
356Status TunerDvrCallback::onRecordStatus(int status) {
357 if (mDvrClientCallback != NULL) {
358 mDvrClientCallback->onRecordStatus(static_cast<RecordStatus>(status));
359 return Status::ok();
360 }
361 return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_STATE));
362}
363
364Status TunerDvrCallback::onPlaybackStatus(int status) {
365 if (mDvrClientCallback != NULL) {
366 mDvrClientCallback->onPlaybackStatus(static_cast<PlaybackStatus>(status));
367 return Status::ok();
368 }
369 return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_STATE));
370}
371
Amy Zhang9a9ed602020-12-07 16:37:33 -0800372/////////////// DvrClient Helper Methods ///////////////////////
373
374Result DvrClient::getQueueDesc(MQDesc& dvrMQDesc) {
Amy Zhang9a9ed602020-12-07 16:37:33 -0800375 if (mDvr != NULL) {
376 Result res = Result::UNKNOWN_ERROR;
377 mDvr->getQueueDesc([&](Result r, const MQDesc& desc) {
378 dvrMQDesc = desc;
379 res = r;
380 });
381 return res;
382 }
383
384 return Result::INVALID_STATE;
385}
Amy Zhang2d7026b2021-01-22 18:07:51 -0800386
387TunerDvrSettings DvrClient::getAidlDvrSettingsFromHidl(DvrSettings settings) {
388 TunerDvrSettings s;
389 switch (settings.getDiscriminator()) {
390 case DvrSettings::hidl_discriminator::record: {
391 s.statusMask = static_cast<int>(settings.record().statusMask);
392 s.lowThreshold = static_cast<int>(settings.record().lowThreshold);
393 s.highThreshold = static_cast<int>(settings.record().highThreshold);
394 s.dataFormat = static_cast<int>(settings.record().dataFormat);
395 s.packetSize = static_cast<int>(settings.record().packetSize);
396 return s;
397 }
398 case DvrSettings::hidl_discriminator::playback: {
399 s.statusMask = static_cast<int>(settings.playback().statusMask);
400 s.lowThreshold = static_cast<int>(settings.playback().lowThreshold);
401 s.highThreshold = static_cast<int>(settings.playback().highThreshold);
402 s.dataFormat = static_cast<int>(settings.playback().dataFormat);
403 s.packetSize = static_cast<int>(settings.playback().packetSize);
404 return s;
405 }
406 default:
407 break;
408 }
409 return s;
410}
Amy Zhang9a9ed602020-12-07 16:37:33 -0800411} // namespace android