OSDN Git Service

Pass ProgramInfo over currentProgramInfoChanged and drop afSwitch_1_1.
[android-x86/hardware-interfaces.git] / broadcastradio / 1.1 / default / Tuner.cpp
1 /*
2  * Copyright (C) 2017 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 "BroadcastRadioDefault.tuner"
18 #define LOG_NDEBUG 0
19
20 #include "BroadcastRadio.h"
21 #include "Tuner.h"
22
23 #include <broadcastradio-utils/Utils.h>
24 #include <log/log.h>
25
26 namespace android {
27 namespace hardware {
28 namespace broadcastradio {
29 namespace V1_1 {
30 namespace implementation {
31
32 using namespace std::chrono_literals;
33
34 using V1_0::Band;
35 using V1_0::BandConfig;
36 using V1_0::Class;
37 using V1_0::Direction;
38 using utils::HalRevision;
39
40 using std::chrono::milliseconds;
41 using std::lock_guard;
42 using std::move;
43 using std::mutex;
44 using std::sort;
45 using std::vector;
46
47 const struct {
48     milliseconds config = 50ms;
49     milliseconds scan = 200ms;
50     milliseconds step = 100ms;
51     milliseconds tune = 150ms;
52 } gDefaultDelay;
53
54 Tuner::Tuner(V1_0::Class classId, const sp<V1_0::ITunerCallback>& callback)
55     : mClassId(classId),
56       mCallback(callback),
57       mCallback1_1(ITunerCallback::castFrom(callback).withDefault(nullptr)),
58       mVirtualRadio(getRadio(classId)),
59       mIsAnalogForced(false) {}
60
61 void Tuner::forceClose() {
62     lock_guard<mutex> lk(mMut);
63     mIsClosed = true;
64     mThread.cancelAll();
65 }
66
67 Return<Result> Tuner::setConfiguration(const BandConfig& config) {
68     ALOGV("%s", __func__);
69     lock_guard<mutex> lk(mMut);
70     if (mIsClosed) return Result::NOT_INITIALIZED;
71     if (mClassId != Class::AM_FM) {
72         ALOGE("Can't set AM/FM configuration on SAT/DT radio tuner");
73         return Result::INVALID_STATE;
74     }
75
76     if (config.lowerLimit >= config.upperLimit) return Result::INVALID_ARGUMENTS;
77
78     auto task = [this, config]() {
79         ALOGI("Setting AM/FM config");
80         lock_guard<mutex> lk(mMut);
81
82         mAmfmConfig = move(config);
83         mAmfmConfig.antennaConnected = true;
84         mCurrentProgram = utils::make_selector(mAmfmConfig.type, mAmfmConfig.lowerLimit);
85
86         if (mAmfmConfig.type == Band::FM_HD || mAmfmConfig.type == Band::FM) {
87             mVirtualRadio = std::ref(getFmRadio());
88         } else {
89             mVirtualRadio = std::ref(getAmRadio());
90         }
91
92         mIsAmfmConfigSet = true;
93         mCallback->configChange(Result::OK, mAmfmConfig);
94     };
95     mThread.schedule(task, gDefaultDelay.config);
96
97     return Result::OK;
98 }
99
100 Return<void> Tuner::getConfiguration(getConfiguration_cb _hidl_cb) {
101     ALOGV("%s", __func__);
102     lock_guard<mutex> lk(mMut);
103
104     if (!mIsClosed && mIsAmfmConfigSet) {
105         _hidl_cb(Result::OK, mAmfmConfig);
106     } else {
107         _hidl_cb(Result::NOT_INITIALIZED, {});
108     }
109     return {};
110 }
111
112 // makes ProgramInfo that points to no program
113 static ProgramInfo makeDummyProgramInfo(const ProgramSelector& selector) {
114     ProgramInfo info11 = {};
115     auto& info10 = info11.base;
116
117     utils::getLegacyChannel(selector, &info10.channel, &info10.subChannel);
118     info11.selector = selector;
119     info11.flags |= ProgramInfoFlags::MUTED;
120
121     return info11;
122 }
123
124 HalRevision Tuner::getHalRev() const {
125     if (mCallback1_1 != nullptr) {
126         return HalRevision::V1_1;
127     } else {
128         return HalRevision::V1_0;
129     }
130 }
131
132 void Tuner::tuneInternalLocked(const ProgramSelector& sel) {
133     VirtualProgram virtualProgram;
134     if (mVirtualRadio.get().getProgram(sel, virtualProgram)) {
135         mCurrentProgram = virtualProgram.selector;
136         mCurrentProgramInfo = virtualProgram.getProgramInfo(getHalRev());
137     } else {
138         mCurrentProgram = sel;
139         mCurrentProgramInfo = makeDummyProgramInfo(sel);
140     }
141     mIsTuneCompleted = true;
142
143     if (mCallback1_1 == nullptr) {
144         mCallback->tuneComplete(Result::OK, mCurrentProgramInfo.base);
145     } else {
146         mCallback1_1->tuneComplete_1_1(Result::OK, mCurrentProgramInfo.selector);
147         mCallback1_1->currentProgramInfoChanged(mCurrentProgramInfo);
148     }
149 }
150
151 Return<Result> Tuner::scan(Direction direction, bool skipSubChannel __unused) {
152     ALOGV("%s", __func__);
153     lock_guard<mutex> lk(mMut);
154     if (mIsClosed) return Result::NOT_INITIALIZED;
155
156     auto list = mVirtualRadio.get().getProgramList();
157
158     if (list.empty()) {
159         mIsTuneCompleted = false;
160         auto task = [this, direction]() {
161             ALOGI("Performing failed scan %s", toString(direction).c_str());
162
163             if (mCallback1_1 == nullptr) {
164                 mCallback->tuneComplete(Result::TIMEOUT, {});
165             } else {
166                 mCallback1_1->tuneComplete_1_1(Result::TIMEOUT, {});
167             }
168         };
169         mThread.schedule(task, gDefaultDelay.scan);
170
171         return Result::OK;
172     }
173
174     // Not optimal (O(sort) instead of O(n)), but not a big deal here;
175     // also, it's likely that list is already sorted (so O(n) anyway).
176     sort(list.begin(), list.end());
177     auto current = mCurrentProgram;
178     auto found = lower_bound(list.begin(), list.end(), VirtualProgram({current}));
179     if (direction == Direction::UP) {
180         if (found < list.end() - 1) {
181             if (utils::tunesTo(current, found->selector)) found++;
182         } else {
183             found = list.begin();
184         }
185     } else {
186         if (found > list.begin() && found != list.end()) {
187             found--;
188         } else {
189             found = list.end() - 1;
190         }
191     }
192     auto tuneTo = found->selector;
193
194     mIsTuneCompleted = false;
195     auto task = [this, tuneTo, direction]() {
196         ALOGI("Performing scan %s", toString(direction).c_str());
197
198         lock_guard<mutex> lk(mMut);
199         tuneInternalLocked(tuneTo);
200     };
201     mThread.schedule(task, gDefaultDelay.scan);
202
203     return Result::OK;
204 }
205
206 Return<Result> Tuner::step(Direction direction, bool skipSubChannel) {
207     ALOGV("%s", __func__);
208     lock_guard<mutex> lk(mMut);
209     if (mIsClosed) return Result::NOT_INITIALIZED;
210
211     ALOGW_IF(!skipSubChannel, "can't step to next frequency without ignoring subChannel");
212
213     if (!utils::isAmFm(utils::getType(mCurrentProgram))) {
214         ALOGE("Can't step in anything else than AM/FM");
215         return Result::NOT_INITIALIZED;
216     }
217
218     if (!mIsAmfmConfigSet) {
219         ALOGW("AM/FM config not set");
220         return Result::INVALID_STATE;
221     }
222     mIsTuneCompleted = false;
223
224     auto task = [this, direction]() {
225         ALOGI("Performing step %s", toString(direction).c_str());
226
227         lock_guard<mutex> lk(mMut);
228
229         auto current = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY, 0);
230
231         if (direction == Direction::UP) {
232             current += mAmfmConfig.spacings[0];
233         } else {
234             current -= mAmfmConfig.spacings[0];
235         }
236
237         if (current > mAmfmConfig.upperLimit) current = mAmfmConfig.lowerLimit;
238         if (current < mAmfmConfig.lowerLimit) current = mAmfmConfig.upperLimit;
239
240         tuneInternalLocked(utils::make_selector(mAmfmConfig.type, current));
241     };
242     mThread.schedule(task, gDefaultDelay.step);
243
244     return Result::OK;
245 }
246
247 Return<Result> Tuner::tune(uint32_t channel, uint32_t subChannel) {
248     ALOGV("%s(%d, %d)", __func__, channel, subChannel);
249     Band band;
250     {
251         lock_guard<mutex> lk(mMut);
252         band = mAmfmConfig.type;
253     }
254     return tuneByProgramSelector(utils::make_selector(band, channel, subChannel));
255 }
256
257 Return<Result> Tuner::tuneByProgramSelector(const ProgramSelector& sel) {
258     ALOGV("%s(%s)", __func__, toString(sel).c_str());
259     lock_guard<mutex> lk(mMut);
260     if (mIsClosed) return Result::NOT_INITIALIZED;
261
262     // checking if ProgramSelector is valid
263     auto programType = utils::getType(sel);
264     if (utils::isAmFm(programType)) {
265         if (!mIsAmfmConfigSet) {
266             ALOGW("AM/FM config not set");
267             return Result::INVALID_STATE;
268         }
269
270         auto freq = utils::getId(sel, IdentifierType::AMFM_FREQUENCY);
271         if (freq < mAmfmConfig.lowerLimit || freq > mAmfmConfig.upperLimit) {
272             return Result::INVALID_ARGUMENTS;
273         }
274     } else if (programType == ProgramType::DAB) {
275         if (!utils::hasId(sel, IdentifierType::DAB_SIDECC)) return Result::INVALID_ARGUMENTS;
276     } else if (programType == ProgramType::DRMO) {
277         if (!utils::hasId(sel, IdentifierType::DRMO_SERVICE_ID)) return Result::INVALID_ARGUMENTS;
278     } else if (programType == ProgramType::SXM) {
279         if (!utils::hasId(sel, IdentifierType::SXM_SERVICE_ID)) return Result::INVALID_ARGUMENTS;
280     } else {
281         return Result::INVALID_ARGUMENTS;
282     }
283
284     mIsTuneCompleted = false;
285     auto task = [this, sel]() {
286         lock_guard<mutex> lk(mMut);
287         tuneInternalLocked(sel);
288     };
289     mThread.schedule(task, gDefaultDelay.tune);
290
291     return Result::OK;
292 }
293
294 Return<Result> Tuner::cancel() {
295     ALOGV("%s", __func__);
296     lock_guard<mutex> lk(mMut);
297     if (mIsClosed) return Result::NOT_INITIALIZED;
298
299     mThread.cancelAll();
300     return Result::OK;
301 }
302
303 Return<Result> Tuner::cancelAnnouncement() {
304     ALOGV("%s", __func__);
305     lock_guard<mutex> lk(mMut);
306     if (mIsClosed) return Result::NOT_INITIALIZED;
307
308     return Result::OK;
309 }
310
311 Return<void> Tuner::getProgramInformation(getProgramInformation_cb _hidl_cb) {
312     ALOGV("%s", __func__);
313     return getProgramInformation_1_1([&](Result result, const ProgramInfo& info) {
314         _hidl_cb(result, info.base);
315     });
316 }
317
318 Return<void> Tuner::getProgramInformation_1_1(getProgramInformation_1_1_cb _hidl_cb) {
319     ALOGV("%s", __func__);
320     lock_guard<mutex> lk(mMut);
321
322     if (mIsClosed) {
323         _hidl_cb(Result::NOT_INITIALIZED, {});
324     } else if (mIsTuneCompleted) {
325         _hidl_cb(Result::OK, mCurrentProgramInfo);
326     } else {
327         _hidl_cb(Result::NOT_INITIALIZED, makeDummyProgramInfo(mCurrentProgram));
328     }
329     return {};
330 }
331
332 Return<ProgramListResult> Tuner::startBackgroundScan() {
333     ALOGV("%s", __func__);
334     lock_guard<mutex> lk(mMut);
335     if (mIsClosed) return ProgramListResult::NOT_INITIALIZED;
336
337     return ProgramListResult::UNAVAILABLE;
338 }
339
340 Return<void> Tuner::getProgramList(const hidl_vec<VendorKeyValue>& vendorFilter,
341                                    getProgramList_cb _hidl_cb) {
342     ALOGV("%s(%s)", __func__, toString(vendorFilter).substr(0, 100).c_str());
343     lock_guard<mutex> lk(mMut);
344     if (mIsClosed) {
345         _hidl_cb(ProgramListResult::NOT_INITIALIZED, {});
346         return {};
347     }
348
349     auto list = mVirtualRadio.get().getProgramList();
350     ALOGD("returning a list of %zu programs", list.size());
351     _hidl_cb(ProgramListResult::OK, getProgramInfoVector(list, getHalRev()));
352     return {};
353 }
354
355 Return<Result> Tuner::setAnalogForced(bool isForced) {
356     ALOGV("%s", __func__);
357     lock_guard<mutex> lk(mMut);
358     if (mIsClosed) return Result::NOT_INITIALIZED;
359
360     mIsAnalogForced = isForced;
361     return Result::OK;
362 }
363
364 Return<void> Tuner::isAnalogForced(isAnalogForced_cb _hidl_cb) {
365     ALOGV("%s", __func__);
366     lock_guard<mutex> lk(mMut);
367
368     if (mIsClosed) {
369         _hidl_cb(Result::NOT_INITIALIZED, false);
370     } else {
371         _hidl_cb(Result::OK, mIsAnalogForced);
372     }
373     return {};
374 }
375
376 }  // namespace implementation
377 }  // namespace V1_1
378 }  // namespace broadcastradio
379 }  // namespace hardware
380 }  // namespace android