blob: be592af30f5d3d0cc83d6ad03ec56fd57b3c911d [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
213 AidlMQDesc* aidlMqDesc = NULL;
214 s = mTunerDvr->getQueueDesc(aidlMqDesc);
215 res = ClientHelper::getServiceSpecificErrorCode(s);
216 if (res != Result::SUCCESS) {
217 return res;
218 }
219
220 mDvrMQ = new (nothrow) AidlMQ(*aidlMqDesc);
221 EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrMQEventFlag);
222 return res;
223 }
Amy Zhang9a9ed602020-12-07 16:37:33 -0800224
225 if (mDvr != NULL) {
226 Result res = mDvr->configure(settings);
227 if (res == Result::SUCCESS) {
228 MQDescriptorSync<uint8_t> dvrMQDesc;
229 res = getQueueDesc(dvrMQDesc);
230 if (res == Result::SUCCESS) {
Amy Zhang2d7026b2021-01-22 18:07:51 -0800231 AidlMQDesc aidlMQDesc;
232 unsafeHidlToAidlMQDescriptor<uint8_t, int8_t, SynchronizedReadWrite>(
233 dvrMQDesc, &aidlMQDesc);
234 mDvrMQ = new (nothrow) AidlMessageQueue(aidlMQDesc);
Amy Zhang9a9ed602020-12-07 16:37:33 -0800235 EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrMQEventFlag);
236 }
237 }
238 return res;
239 }
240
241 return Result::INVALID_STATE;
242}
243
244Result DvrClient::attachFilter(sp<FilterClient> filterClient) {
Amy Zhang2d7026b2021-01-22 18:07:51 -0800245 if (mTunerDvr != NULL) {
246 Status s = mTunerDvr->attachFilter(filterClient->getAidlFilter());
247 return ClientHelper::getServiceSpecificErrorCode(s);
248 }
Amy Zhang9a9ed602020-12-07 16:37:33 -0800249
250 if (mDvr != NULL) {
251 sp<IFilter> hidlFilter = filterClient->getHalFilter();
252 if (hidlFilter == NULL) {
253 return Result::INVALID_ARGUMENT;
254 }
255 return mDvr->attachFilter(hidlFilter);
256 }
257
258 return Result::INVALID_STATE;
259}
260
261Result DvrClient::detachFilter(sp<FilterClient> filterClient) {
Amy Zhang2d7026b2021-01-22 18:07:51 -0800262 if (mTunerDvr != NULL) {
263 Status s = mTunerDvr->detachFilter(filterClient->getAidlFilter());
264 return ClientHelper::getServiceSpecificErrorCode(s);
265 }
Amy Zhang9a9ed602020-12-07 16:37:33 -0800266
267 if (mDvr != NULL) {
268 sp<IFilter> hidlFilter = filterClient->getHalFilter();
269 if (hidlFilter == NULL) {
270 return Result::INVALID_ARGUMENT;
271 }
272 return mDvr->detachFilter(hidlFilter);
273 }
274
275 return Result::INVALID_STATE;
276}
277
278Result DvrClient::start() {
Amy Zhang2d7026b2021-01-22 18:07:51 -0800279 if (mTunerDvr != NULL) {
280 Status s = mTunerDvr->start();
281 return ClientHelper::getServiceSpecificErrorCode(s);
282 }
Amy Zhang9a9ed602020-12-07 16:37:33 -0800283
284 if (mDvr != NULL) {
285 return mDvr->start();
286 }
287
288 return Result::INVALID_STATE;
289}
290
291Result DvrClient::stop() {
Amy Zhang2d7026b2021-01-22 18:07:51 -0800292 if (mTunerDvr != NULL) {
293 Status s = mTunerDvr->stop();
294 return ClientHelper::getServiceSpecificErrorCode(s);
295 }
Amy Zhang9a9ed602020-12-07 16:37:33 -0800296
297 if (mDvr != NULL) {
298 return mDvr->stop();
299 }
300
301 return Result::INVALID_STATE;
302}
303
304Result DvrClient::flush() {
Amy Zhang2d7026b2021-01-22 18:07:51 -0800305 if (mTunerDvr != NULL) {
306 Status s = mTunerDvr->flush();
307 return ClientHelper::getServiceSpecificErrorCode(s);
308 }
Amy Zhang9a9ed602020-12-07 16:37:33 -0800309
310 if (mDvr != NULL) {
311 return mDvr->flush();
312 }
313
314 return Result::INVALID_STATE;
315}
316
317Result DvrClient::close() {
Amy Zhang2d7026b2021-01-22 18:07:51 -0800318 if (mTunerDvr != NULL) {
319 Status s = mTunerDvr->close();
320 return ClientHelper::getServiceSpecificErrorCode(s);
321 }
Amy Zhang9a9ed602020-12-07 16:37:33 -0800322
323 if (mDvr != NULL) {
324 Result res = mDvr->close();
325 if (res == Result::SUCCESS) {
326 mDvr = NULL;
327 }
328 return res;
329 }
330
331 return Result::INVALID_STATE;
332}
333
334/////////////// IDvrCallback ///////////////////////
335
336HidlDvrCallback::HidlDvrCallback(sp<DvrClientCallback> dvrClientCallback)
337 : mDvrClientCallback(dvrClientCallback) {}
338
339Return<void> HidlDvrCallback::onRecordStatus(const RecordStatus status) {
340 if (mDvrClientCallback != NULL) {
341 mDvrClientCallback->onRecordStatus(status);
342 }
343 return Void();
344}
345
346Return<void> HidlDvrCallback::onPlaybackStatus(const PlaybackStatus status) {
347 if (mDvrClientCallback != NULL) {
348 mDvrClientCallback->onPlaybackStatus(status);
349 }
350 return Void();
351}
352
Amy Zhang2d7026b2021-01-22 18:07:51 -0800353/////////////// TunerDvrCallback ///////////////////////
354
355TunerDvrCallback::TunerDvrCallback(sp<DvrClientCallback> dvrClientCallback)
356 : mDvrClientCallback(dvrClientCallback) {}
357
358Status TunerDvrCallback::onRecordStatus(int status) {
359 if (mDvrClientCallback != NULL) {
360 mDvrClientCallback->onRecordStatus(static_cast<RecordStatus>(status));
361 return Status::ok();
362 }
363 return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_STATE));
364}
365
366Status TunerDvrCallback::onPlaybackStatus(int status) {
367 if (mDvrClientCallback != NULL) {
368 mDvrClientCallback->onPlaybackStatus(static_cast<PlaybackStatus>(status));
369 return Status::ok();
370 }
371 return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_STATE));
372}
373
Amy Zhang9a9ed602020-12-07 16:37:33 -0800374/////////////// DvrClient Helper Methods ///////////////////////
375
376Result DvrClient::getQueueDesc(MQDesc& dvrMQDesc) {
Amy Zhang9a9ed602020-12-07 16:37:33 -0800377 if (mDvr != NULL) {
378 Result res = Result::UNKNOWN_ERROR;
379 mDvr->getQueueDesc([&](Result r, const MQDesc& desc) {
380 dvrMQDesc = desc;
381 res = r;
382 });
383 return res;
384 }
385
386 return Result::INVALID_STATE;
387}
Amy Zhang2d7026b2021-01-22 18:07:51 -0800388
389TunerDvrSettings DvrClient::getAidlDvrSettingsFromHidl(DvrSettings settings) {
390 TunerDvrSettings s;
391 switch (settings.getDiscriminator()) {
392 case DvrSettings::hidl_discriminator::record: {
393 s.statusMask = static_cast<int>(settings.record().statusMask);
394 s.lowThreshold = static_cast<int>(settings.record().lowThreshold);
395 s.highThreshold = static_cast<int>(settings.record().highThreshold);
396 s.dataFormat = static_cast<int>(settings.record().dataFormat);
397 s.packetSize = static_cast<int>(settings.record().packetSize);
398 return s;
399 }
400 case DvrSettings::hidl_discriminator::playback: {
401 s.statusMask = static_cast<int>(settings.playback().statusMask);
402 s.lowThreshold = static_cast<int>(settings.playback().lowThreshold);
403 s.highThreshold = static_cast<int>(settings.playback().highThreshold);
404 s.dataFormat = static_cast<int>(settings.playback().dataFormat);
405 s.packetSize = static_cast<int>(settings.playback().packetSize);
406 return s;
407 }
408 default:
409 break;
410 }
411 return s;
412}
Amy Zhang9a9ed602020-12-07 16:37:33 -0800413} // namespace android