Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a02b6ef2 authored by Tomasz Wasilczyk's avatar Tomasz Wasilczyk
Browse files

Implement ProgramSelector at HIDL layer.

No front-end implementation yet.

Bug: b/32621193
Test: VTS
Change-Id: I48f034e709254836cad35bbeb4285c3c42a9e1cd
parent 2af8c52a
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -20,6 +20,27 @@ import @1.0::ITuner;

interface ITuner extends @1.0::ITuner {

    /**
     * Tune to a specified program.
     *
     * For AM/FM, it must be called when a valid configuration has been applied.
     * Automatically cancels pending scan, step or tune.
     *
     * If method returns OK, ITunerCallback.tuneComplete_1_1() MUST be called:
     * - once successfully tuned;
     * - after a time out;
     * - after a full band scan, if no station found.
     *
     * The tuned field of ProgramInfo should indicate if tuned to a valid
     * station or not.
     *
     * @param program Program to tune to.
     * @return result OK if successfully started tunning.
     *                INVALID_ARGUMENTS if invalid arguments are passed.
     *                NOT_INITIALIZED if another error occurs.
     */
    tune_1_1(ProgramSelector program) generates (Result result);

    /**
     * Retrieve current station information.
     * @return result OK if scan successfully started
+56 −28
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include "BroadcastRadio.h"
#include "Tuner.h"

#include <Utils.h>
#include <log/log.h>

namespace android {
@@ -70,6 +71,8 @@ Return<Result> Tuner::setConfiguration(const BandConfig& config) {

        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> Tuner::getConfiguration(getConfiguration_cb _hidl_cb) {
    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 @@ Return<Result> Tuner::scan(Direction direction, bool skipSubChannel __unused) {
    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 @@ Return<Result> Tuner::scan(Direction direction, bool skipSubChannel __unused) {
            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,16 +203,18 @@ Return<Result> Tuner::step(Direction direction, bool skipSubChannel __unused) {

        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);

@@ -209,19 +223,33 @@ Return<Result> Tuner::step(Direction direction, bool skipSubChannel __unused) {

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);

    if (utils::isAmFm(utils::getType(mCurrentProgram))) {
        ALOGW_IF(!mIsAmfmConfigSet, "AM/FM config not set");
        if (!mIsAmfmConfigSet) return Result::INVALID_STATE;
    if (channel < mAmfmConfig.lowerLimit || channel > mAmfmConfig.upperLimit) {

        auto freq = utils::getId(sel, IdentifierType::AMFM_FREQUENCY);
        if (freq < mAmfmConfig.lowerLimit || freq > mAmfmConfig.upperLimit) {
            return Result::INVALID_ARGUMENTS;
        }
    mIsTuneCompleted = false;
    }

    auto task = [this, channel]() {
    mIsTuneCompleted = false;
    auto task = [this, sel]() {
        lock_guard<mutex> lk(mMut);
        mCurrentProgram = channel;
        tuneInternalLocked();
        tuneInternalLocked(sel);
    };
    mThread.schedule(task, gDefaultDelay.tune);

+3 −2
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ struct Tuner : public ITuner {
    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 @@ struct Tuner : public ITuner {
    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
+24 −3
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@
 */
#include "VirtualProgram.h"

#include <Utils.h>

namespace android {
namespace hardware {
namespace broadcastradio {
@@ -29,10 +31,12 @@ VirtualProgram::operator ProgramInfo() const {
    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 @@ VirtualProgram::operator ProgramInfo() const {
    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
+1 −1
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@ namespace V1_1 {
namespace implementation {

struct VirtualProgram {
    uint32_t channel;  // TODO(b/32621193): Station Selector
    ProgramSelector selector;

    std::string programName = "";
    std::string songArtist = "";
Loading