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