Implement ProgramSelector at HIDL layer.
No front-end implementation yet.
Bug: b/32621193
Test: VTS
Change-Id: I48f034e709254836cad35bbeb4285c3c42a9e1cd
diff --git a/broadcastradio/1.1/default/Tuner.cpp b/broadcastradio/1.1/default/Tuner.cpp
index 9b39d36..bb07f36 100644
--- a/broadcastradio/1.1/default/Tuner.cpp
+++ b/broadcastradio/1.1/default/Tuner.cpp
@@ -20,6 +20,7 @@
#include "BroadcastRadio.h"
#include "Tuner.h"
+#include <Utils.h>
#include <log/log.h>
namespace android {
@@ -70,6 +71,8 @@
mAmfmConfig = move(config);
mAmfmConfig.antennaConnected = true;
+ mCurrentProgram = utils::make_selector(mAmfmConfig.type, mAmfmConfig.lowerLimit);
+
mIsAmfmConfigSet = true;
mCallback->configChange(Result::OK, mAmfmConfig);
};
@@ -90,28 +93,31 @@
return Void();
}
-// makes ProgramInfo that points to no channel
-static ProgramInfo makeDummyProgramInfo(uint32_t channel) {
+// makes ProgramInfo that points to no program
+static ProgramInfo makeDummyProgramInfo(const ProgramSelector& selector) {
ProgramInfo info11 = {};
auto& info10 = info11.base;
- info10.channel = channel;
+ utils::getLegacyChannel(selector, info10.channel, info10.subChannel);
+ info11.selector = selector;
info11.flags |= ProgramInfoFlags::MUTED;
return info11;
}
-void Tuner::tuneInternalLocked() {
+void Tuner::tuneInternalLocked(const ProgramSelector& sel) {
VirtualRadio* virtualRadio = nullptr;
if (mAmfmConfig.type == Band::FM_HD || mAmfmConfig.type == Band::FM) {
virtualRadio = &mVirtualFm;
}
VirtualProgram virtualProgram;
- if (virtualRadio != nullptr && virtualRadio->getProgram(mCurrentProgram, virtualProgram)) {
+ if (virtualRadio != nullptr && virtualRadio->getProgram(sel, virtualProgram)) {
+ mCurrentProgram = virtualProgram.selector;
mCurrentProgramInfo = static_cast<ProgramInfo>(virtualProgram);
} else {
- mCurrentProgramInfo = makeDummyProgramInfo(mCurrentProgram);
+ mCurrentProgram = sel;
+ mCurrentProgramInfo = makeDummyProgramInfo(sel);
}
mIsTuneCompleted = true;
@@ -152,7 +158,7 @@
auto found = lower_bound(list.begin(), list.end(), VirtualProgram({current}));
if (direction == Direction::UP) {
if (found < list.end() - 1) {
- if (found->channel == current) found++;
+ if (utils::tunesTo(current, found->selector)) found++;
} else {
found = list.begin();
}
@@ -163,25 +169,31 @@
found = list.end() - 1;
}
}
- auto tuneTo = found->channel;
+ auto tuneTo = found->selector;
mIsTuneCompleted = false;
auto task = [this, tuneTo, direction]() {
ALOGI("Performing scan %s", toString(direction).c_str());
lock_guard<mutex> lk(mMut);
- mCurrentProgram = tuneTo;
- tuneInternalLocked();
+ tuneInternalLocked(tuneTo);
};
mThread.schedule(task, gDefaultDelay.scan);
return Result::OK;
}
-Return<Result> Tuner::step(Direction direction, bool skipSubChannel __unused) {
+Return<Result> Tuner::step(Direction direction, bool skipSubChannel) {
ALOGV("%s", __func__);
+ ALOGW_IF(!skipSubChannel, "can't step to next frequency without ignoring subChannel");
lock_guard<mutex> lk(mMut);
+
+ if (!utils::isAmFm(utils::getType(mCurrentProgram))) {
+ ALOGE("Can't step in anything else than AM/FM");
+ return Result::NOT_INITIALIZED;
+ }
+
ALOGW_IF(!mIsAmfmConfigSet, "AM/FM config not set");
if (!mIsAmfmConfigSet) return Result::INVALID_STATE;
mIsTuneCompleted = false;
@@ -191,57 +203,73 @@
lock_guard<mutex> lk(mMut);
+ auto current = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY, 0);
+
if (direction == Direction::UP) {
- mCurrentProgram += mAmfmConfig.spacings[0];
+ current += mAmfmConfig.spacings[0];
} else {
- mCurrentProgram -= mAmfmConfig.spacings[0];
+ current -= mAmfmConfig.spacings[0];
}
- if (mCurrentProgram > mAmfmConfig.upperLimit) mCurrentProgram = mAmfmConfig.lowerLimit;
- if (mCurrentProgram < mAmfmConfig.lowerLimit) mCurrentProgram = mAmfmConfig.upperLimit;
+ if (current > mAmfmConfig.upperLimit) current = mAmfmConfig.lowerLimit;
+ if (current < mAmfmConfig.lowerLimit) current = mAmfmConfig.upperLimit;
- tuneInternalLocked();
+ tuneInternalLocked(utils::make_selector(mAmfmConfig.type, current));
};
mThread.schedule(task, gDefaultDelay.step);
return Result::OK;
}
-Return<Result> Tuner::tune(uint32_t channel, uint32_t subChannel) {
+Return<Result> Tuner::tune(uint32_t channel, uint32_t subChannel) {
ALOGV("%s(%d, %d)", __func__, channel, subChannel);
+ Band band;
+ {
+ lock_guard<mutex> lk(mMut);
+ band = mAmfmConfig.type;
+ }
+ return tune_1_1(utils::make_selector(band, channel, subChannel));
+}
+
+Return<Result> Tuner::tune_1_1(const ProgramSelector& sel) {
+ ALOGV("%s(%s)", __func__, toString(sel).c_str());
lock_guard<mutex> lk(mMut);
- ALOGW_IF(!mIsAmfmConfigSet, "AM/FM config not set");
- if (!mIsAmfmConfigSet) return Result::INVALID_STATE;
- if (channel < mAmfmConfig.lowerLimit || channel > mAmfmConfig.upperLimit) {
- return Result::INVALID_ARGUMENTS;
- }
- mIsTuneCompleted = false;
- auto task = [this, channel]() {
+ if (utils::isAmFm(utils::getType(mCurrentProgram))) {
+ ALOGW_IF(!mIsAmfmConfigSet, "AM/FM config not set");
+ if (!mIsAmfmConfigSet) return Result::INVALID_STATE;
+
+ auto freq = utils::getId(sel, IdentifierType::AMFM_FREQUENCY);
+ if (freq < mAmfmConfig.lowerLimit || freq > mAmfmConfig.upperLimit) {
+ return Result::INVALID_ARGUMENTS;
+ }
+ }
+
+ mIsTuneCompleted = false;
+ auto task = [this, sel]() {
lock_guard<mutex> lk(mMut);
- mCurrentProgram = channel;
- tuneInternalLocked();
+ tuneInternalLocked(sel);
};
mThread.schedule(task, gDefaultDelay.tune);
return Result::OK;
}
-Return<Result> Tuner::cancel() {
+Return<Result> Tuner::cancel() {
ALOGV("%s", __func__);
mThread.cancelAll();
return Result::OK;
}
-Return<void> Tuner::getProgramInformation(getProgramInformation_cb _hidl_cb) {
+Return<void> Tuner::getProgramInformation(getProgramInformation_cb _hidl_cb) {
ALOGV("%s", __func__);
return getProgramInformation_1_1([&](Result result, const ProgramInfo& info) {
_hidl_cb(result, info.base);
});
}
-Return<void> Tuner::getProgramInformation_1_1(getProgramInformation_1_1_cb _hidl_cb) {
+Return<void> Tuner::getProgramInformation_1_1(getProgramInformation_1_1_cb _hidl_cb) {
ALOGV("%s", __func__);
lock_guard<mutex> lk(mMut);
diff --git a/broadcastradio/1.1/default/Tuner.h b/broadcastradio/1.1/default/Tuner.h
index 7719d4d..17ee99f 100644
--- a/broadcastradio/1.1/default/Tuner.h
+++ b/broadcastradio/1.1/default/Tuner.h
@@ -39,6 +39,7 @@
Return<Result> scan(V1_0::Direction direction, bool skipSubChannel) override;
Return<Result> step(V1_0::Direction direction, bool skipSubChannel) override;
Return<Result> tune(uint32_t channel, uint32_t subChannel) override;
+ Return<Result> tune_1_1(const ProgramSelector& program) override;
Return<Result> cancel() override;
Return<void> getProgramInformation(getProgramInformation_cb _hidl_cb) override;
Return<void> getProgramInformation_1_1(getProgramInformation_1_1_cb _hidl_cb) override;
@@ -60,10 +61,10 @@
bool mIsAmfmConfigSet = false;
V1_0::BandConfig mAmfmConfig;
bool mIsTuneCompleted = false;
- uint32_t mCurrentProgram; // TODO(b/32621193): Station Selector
+ ProgramSelector mCurrentProgram = {};
ProgramInfo mCurrentProgramInfo = {};
- void tuneInternalLocked();
+ void tuneInternalLocked(const ProgramSelector& sel);
};
} // namespace implementation
diff --git a/broadcastradio/1.1/default/VirtualProgram.cpp b/broadcastradio/1.1/default/VirtualProgram.cpp
index df12a3e..ef8bd1c 100644
--- a/broadcastradio/1.1/default/VirtualProgram.cpp
+++ b/broadcastradio/1.1/default/VirtualProgram.cpp
@@ -15,6 +15,8 @@
*/
#include "VirtualProgram.h"
+#include <Utils.h>
+
namespace android {
namespace hardware {
namespace broadcastradio {
@@ -29,10 +31,12 @@
ProgramInfo info11 = {};
auto& info10 = info11.base;
- info10.channel = channel;
+ utils::getLegacyChannel(selector, info10.channel, info10.subChannel);
+ info11.selector = selector;
info10.tuned = true;
info10.stereo = true;
- info10.signalStrength = 100;
+ info10.digital = utils::isDigital(selector);
+ info10.signalStrength = info10.digital ? 100 : 80;
info10.metadata = hidl_vec<MetaData>({
{MetadataType::TEXT, MetadataKey::RDS_PS, {}, {}, programName, {}},
@@ -43,8 +47,25 @@
return info11;
}
+// Defining order on virtual programs, how they appear on band.
+// It's mostly for default implementation purposes, may not be complete or correct.
bool operator<(const VirtualProgram& lhs, const VirtualProgram& rhs) {
- return lhs.channel < rhs.channel;
+ auto& l = lhs.selector;
+ auto& r = rhs.selector;
+
+ // Two programs with the same primaryId is considered the same.
+ if (l.programType != r.programType) return l.programType < r.programType;
+ if (l.primaryId.type != r.primaryId.type) return l.primaryId.type < r.primaryId.type;
+ if (l.primaryId.value != r.primaryId.value) return l.primaryId.value < r.primaryId.value;
+
+ // A little exception for HD Radio subchannel - we check secondary ID too.
+ if (utils::hasId(l, IdentifierType::HD_SUBCHANNEL) &&
+ utils::hasId(r, IdentifierType::HD_SUBCHANNEL)) {
+ return utils::getId(l, IdentifierType::HD_SUBCHANNEL) <
+ utils::getId(r, IdentifierType::HD_SUBCHANNEL);
+ }
+
+ return false;
}
} // namespace implementation
diff --git a/broadcastradio/1.1/default/VirtualProgram.h b/broadcastradio/1.1/default/VirtualProgram.h
index 303513f..a4fd72c 100644
--- a/broadcastradio/1.1/default/VirtualProgram.h
+++ b/broadcastradio/1.1/default/VirtualProgram.h
@@ -26,7 +26,7 @@
namespace implementation {
struct VirtualProgram {
- uint32_t channel; // TODO(b/32621193): Station Selector
+ ProgramSelector selector;
std::string programName = "";
std::string songArtist = "";
diff --git a/broadcastradio/1.1/default/VirtualRadio.cpp b/broadcastradio/1.1/default/VirtualRadio.cpp
index 0eab7ae..acf37a4 100644
--- a/broadcastradio/1.1/default/VirtualRadio.cpp
+++ b/broadcastradio/1.1/default/VirtualRadio.cpp
@@ -15,25 +15,31 @@
*/
#include "VirtualRadio.h"
+#include <Utils.h>
+
namespace android {
namespace hardware {
namespace broadcastradio {
namespace V1_1 {
namespace implementation {
+using V1_0::Band;
+
using std::lock_guard;
using std::move;
using std::mutex;
using std::vector;
+using utils::make_selector;
+
vector<VirtualProgram> gInitialFmPrograms{
- {94900, "Wild 94.9", "Drake ft. Rihanna", "Too Good"},
- {96500, "KOIT", "Celine Dion", "All By Myself"},
- {97300, "Alice@97.3", "Drops of Jupiter", "Train"},
- {99700, "99.7 Now!", "The Chainsmokers", "Closer"},
- {101300, "101-3 KISS-FM", "Justin Timberlake", "Rock Your Body"},
- {103700, "iHeart80s @ 103.7", "Michael Jackson", "Billie Jean"},
- {106100, "106 KMEL", "Drake", "Marvins Room"},
+ {make_selector(Band::FM, 94900), "Wild 94.9", "Drake ft. Rihanna", "Too Good"},
+ {make_selector(Band::FM, 96500), "KOIT", "Celine Dion", "All By Myself"},
+ {make_selector(Band::FM, 97300), "Alice@97.3", "Drops of Jupiter", "Train"},
+ {make_selector(Band::FM, 99700), "99.7 Now!", "The Chainsmokers", "Closer"},
+ {make_selector(Band::FM, 101300), "101-3 KISS-FM", "Justin Timberlake", "Rock Your Body"},
+ {make_selector(Band::FM, 103700), "iHeart80s @ 103.7", "Michael Jackson", "Billie Jean"},
+ {make_selector(Band::FM, 106100), "106 KMEL", "Drake", "Marvins Room"},
};
VirtualRadio::VirtualRadio(VirtualRadio&& o) : mPrograms(move(o.mPrograms)) {}
@@ -45,10 +51,10 @@
return mPrograms;
}
-bool VirtualRadio::getProgram(uint32_t channel, VirtualProgram& programOut) {
+bool VirtualRadio::getProgram(const ProgramSelector& selector, VirtualProgram& programOut) {
lock_guard<mutex> lk(mMut);
for (auto&& program : mPrograms) {
- if (program.channel == channel) {
+ if (utils::tunesTo(selector, program.selector)) {
programOut = program;
return true;
}
diff --git a/broadcastradio/1.1/default/VirtualRadio.h b/broadcastradio/1.1/default/VirtualRadio.h
index e1918a0..23cb06c 100644
--- a/broadcastradio/1.1/default/VirtualRadio.h
+++ b/broadcastradio/1.1/default/VirtualRadio.h
@@ -33,7 +33,7 @@
VirtualRadio(std::vector<VirtualProgram> initialList);
std::vector<VirtualProgram> getProgramList();
- bool getProgram(uint32_t channel, VirtualProgram& program);
+ bool getProgram(const ProgramSelector& selector, VirtualProgram& program);
private:
std::mutex mMut;