OSDN Git Service

release-request-e04bb055-13fc-41a1-8a9f-7fb10894ec3d-for-git_oc-mr1-release-4189380...
[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 <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::Direction;
37
38 using std::chrono::milliseconds;
39 using std::lock_guard;
40 using std::move;
41 using std::mutex;
42 using std::sort;
43 using std::vector;
44
45 const struct {
46     milliseconds config = 50ms;
47     milliseconds scan = 200ms;
48     milliseconds step = 100ms;
49     milliseconds tune = 150ms;
50 } gDefaultDelay;
51
52 Tuner::Tuner(const sp<V1_0::ITunerCallback>& callback)
53     : mCallback(callback),
54       mCallback1_1(ITunerCallback::castFrom(callback).withDefault(nullptr)),
55       mVirtualFm(make_fm_radio()) {}
56
57 void Tuner::forceClose() {
58     lock_guard<mutex> lk(mMut);
59     mIsClosed = true;
60     mThread.cancelAll();
61 }
62
63 Return<Result> Tuner::setConfiguration(const BandConfig& config) {
64     ALOGV("%s", __func__);
65
66     if (config.lowerLimit >= config.upperLimit) return Result::INVALID_ARGUMENTS;
67
68     auto task = [this, config]() {
69         ALOGI("Setting AM/FM config");
70         lock_guard<mutex> lk(mMut);
71
72         mAmfmConfig = move(config);
73         mAmfmConfig.antennaConnected = true;
74         mCurrentProgram = utils::make_selector(mAmfmConfig.type, mAmfmConfig.lowerLimit);
75
76         mIsAmfmConfigSet = true;
77         mCallback->configChange(Result::OK, mAmfmConfig);
78     };
79     mThread.schedule(task, gDefaultDelay.config);
80
81     return Result::OK;
82 }
83
84 Return<void> Tuner::getConfiguration(getConfiguration_cb _hidl_cb) {
85     ALOGV("%s", __func__);
86
87     lock_guard<mutex> lk(mMut);
88     if (mIsAmfmConfigSet) {
89         _hidl_cb(Result::OK, mAmfmConfig);
90     } else {
91         _hidl_cb(Result::NOT_INITIALIZED, {});
92     }
93     return Void();
94 }
95
96 // makes ProgramInfo that points to no program
97 static ProgramInfo makeDummyProgramInfo(const ProgramSelector& selector) {
98     ProgramInfo info11 = {};
99     auto& info10 = info11.base;
100
101     utils::getLegacyChannel(selector, info10.channel, info10.subChannel);
102     info11.selector = selector;
103     info11.flags |= ProgramInfoFlags::MUTED;
104
105     return info11;
106 }
107
108 bool Tuner::isFmLocked() {
109     if (!utils::isAmFm(utils::getType(mCurrentProgram))) return false;
110     return mAmfmConfig.type == Band::FM_HD || mAmfmConfig.type == Band::FM;
111 }
112
113 void Tuner::tuneInternalLocked(const ProgramSelector& sel) {
114     VirtualRadio* virtualRadio = nullptr;
115     if (isFmLocked()) {
116         virtualRadio = &mVirtualFm;
117     }
118
119     VirtualProgram virtualProgram;
120     if (virtualRadio != nullptr && virtualRadio->getProgram(sel, virtualProgram)) {
121         mCurrentProgram = virtualProgram.selector;
122         mCurrentProgramInfo = static_cast<ProgramInfo>(virtualProgram);
123     } else {
124         mCurrentProgram = sel;
125         mCurrentProgramInfo = makeDummyProgramInfo(sel);
126     }
127     mIsTuneCompleted = true;
128
129     mCallback->tuneComplete(Result::OK, mCurrentProgramInfo.base);
130     if (mCallback1_1 != nullptr) {
131         mCallback1_1->tuneComplete_1_1(Result::OK, mCurrentProgramInfo);
132     }
133 }
134
135 Return<Result> Tuner::scan(Direction direction, bool skipSubChannel __unused) {
136     ALOGV("%s", __func__);
137     lock_guard<mutex> lk(mMut);
138     vector<VirtualProgram> list;
139
140     if (isFmLocked()) {
141         list = mVirtualFm.getProgramList();
142     }
143
144     if (list.empty()) {
145         mIsTuneCompleted = false;
146         auto task = [this, direction]() {
147             ALOGI("Performing failed scan %s", toString(direction).c_str());
148
149             mCallback->tuneComplete(Result::TIMEOUT, {});
150             if (mCallback1_1 != nullptr) {
151                 mCallback1_1->tuneComplete_1_1(Result::TIMEOUT, {});
152             }
153         };
154         mThread.schedule(task, gDefaultDelay.scan);
155
156         return Result::OK;
157     }
158
159     // Not optimal (O(sort) instead of O(n)), but not a big deal here;
160     // also, it's likely that list is already sorted (so O(n) anyway).
161     sort(list.begin(), list.end());
162     auto current = mCurrentProgram;
163     auto found = lower_bound(list.begin(), list.end(), VirtualProgram({current}));
164     if (direction == Direction::UP) {
165         if (found < list.end() - 1) {
166             if (utils::tunesTo(current, found->selector)) found++;
167         } else {
168             found = list.begin();
169         }
170     } else {
171         if (found > list.begin() && found != list.end()) {
172             found--;
173         } else {
174             found = list.end() - 1;
175         }
176     }
177     auto tuneTo = found->selector;
178
179     mIsTuneCompleted = false;
180     auto task = [this, tuneTo, direction]() {
181         ALOGI("Performing scan %s", toString(direction).c_str());
182
183         lock_guard<mutex> lk(mMut);
184         tuneInternalLocked(tuneTo);
185     };
186     mThread.schedule(task, gDefaultDelay.scan);
187
188     return Result::OK;
189 }
190
191 Return<Result> Tuner::step(Direction direction, bool skipSubChannel) {
192     ALOGV("%s", __func__);
193     ALOGW_IF(!skipSubChannel, "can't step to next frequency without ignoring subChannel");
194
195     lock_guard<mutex> lk(mMut);
196
197     if (!utils::isAmFm(utils::getType(mCurrentProgram))) {
198         ALOGE("Can't step in anything else than AM/FM");
199         return Result::NOT_INITIALIZED;
200     }
201
202     ALOGW_IF(!mIsAmfmConfigSet, "AM/FM config not set");
203     if (!mIsAmfmConfigSet) return Result::INVALID_STATE;
204     mIsTuneCompleted = false;
205
206     auto task = [this, direction]() {
207         ALOGI("Performing step %s", toString(direction).c_str());
208
209         lock_guard<mutex> lk(mMut);
210
211         auto current = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY, 0);
212
213         if (direction == Direction::UP) {
214             current += mAmfmConfig.spacings[0];
215         } else {
216             current -= mAmfmConfig.spacings[0];
217         }
218
219         if (current > mAmfmConfig.upperLimit) current = mAmfmConfig.lowerLimit;
220         if (current < mAmfmConfig.lowerLimit) current = mAmfmConfig.upperLimit;
221
222         tuneInternalLocked(utils::make_selector(mAmfmConfig.type, current));
223     };
224     mThread.schedule(task, gDefaultDelay.step);
225
226     return Result::OK;
227 }
228
229 Return<Result> Tuner::tune(uint32_t channel, uint32_t subChannel) {
230     ALOGV("%s(%d, %d)", __func__, channel, subChannel);
231     Band band;
232     {
233         lock_guard<mutex> lk(mMut);
234         band = mAmfmConfig.type;
235     }
236     return tune_1_1(utils::make_selector(band, channel, subChannel));
237 }
238
239 Return<Result> Tuner::tune_1_1(const ProgramSelector& sel) {
240     ALOGV("%s(%s)", __func__, toString(sel).c_str());
241
242     lock_guard<mutex> lk(mMut);
243
244     if (utils::isAmFm(utils::getType(mCurrentProgram))) {
245         ALOGW_IF(!mIsAmfmConfigSet, "AM/FM config not set");
246         if (!mIsAmfmConfigSet) return Result::INVALID_STATE;
247
248         auto freq = utils::getId(sel, IdentifierType::AMFM_FREQUENCY);
249         if (freq < mAmfmConfig.lowerLimit || freq > mAmfmConfig.upperLimit) {
250             return Result::INVALID_ARGUMENTS;
251         }
252     }
253
254     mIsTuneCompleted = false;
255     auto task = [this, sel]() {
256         lock_guard<mutex> lk(mMut);
257         tuneInternalLocked(sel);
258     };
259     mThread.schedule(task, gDefaultDelay.tune);
260
261     return Result::OK;
262 }
263
264 Return<Result> Tuner::cancel() {
265     ALOGV("%s", __func__);
266     mThread.cancelAll();
267     return Result::OK;
268 }
269
270 Return<void> Tuner::getProgramInformation(getProgramInformation_cb _hidl_cb) {
271     ALOGV("%s", __func__);
272     return getProgramInformation_1_1([&](Result result, const ProgramInfo& info) {
273         _hidl_cb(result, info.base);
274     });
275 }
276
277 Return<void> Tuner::getProgramInformation_1_1(getProgramInformation_1_1_cb _hidl_cb) {
278     ALOGV("%s", __func__);
279
280     lock_guard<mutex> lk(mMut);
281     if (mIsTuneCompleted) {
282         _hidl_cb(Result::OK, mCurrentProgramInfo);
283     } else {
284         _hidl_cb(Result::NOT_INITIALIZED, makeDummyProgramInfo(mCurrentProgram));
285     }
286     return Void();
287 }
288
289 Return<ProgramListResult> Tuner::startBackgroundScan() {
290     ALOGV("%s", __func__);
291     return ProgramListResult::UNAVAILABLE;
292 }
293
294 Return<void> Tuner::getProgramList(const hidl_string& filter __unused, getProgramList_cb _hidl_cb) {
295     ALOGV("%s", __func__);
296     lock_guard<mutex> lk(mMut);
297
298     auto& virtualRadio = mVirtualFm;
299     if (!isFmLocked()) {
300         ALOGI("bands other than FM are not supported yet");
301         _hidl_cb(ProgramListResult::OK, {});
302         return Void();
303     }
304
305     auto list = virtualRadio.getProgramList();
306     ALOGD("returning a list of %zu programs", list.size());
307     _hidl_cb(ProgramListResult::OK, vector<ProgramInfo>(list.begin(), list.end()));
308     return Void();
309 }
310
311 Return<void> Tuner::isAnalogForced(isAnalogForced_cb _hidl_cb) {
312     ALOGV("%s", __func__);
313     // TODO(b/36864090): implement
314     _hidl_cb(Result::INVALID_STATE, false);
315     return Void();
316 }
317
318 Return<Result> Tuner::setAnalogForced(bool isForced __unused) {
319     ALOGV("%s", __func__);
320     // TODO(b/36864090): implement
321     return Result::INVALID_STATE;
322 }
323
324 }  // namespace implementation
325 }  // namespace V1_1
326 }  // namespace broadcastradio
327 }  // namespace hardware
328 }  // namespace android