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

Commit f8f12edf authored by Hayden Gomes's avatar Hayden Gomes Committed by Android (Google) Code Review
Browse files

Merge changes from topic "HAL Audio Focus" into rvc-dev

* changes:
  Adding a lshal command for abandoning focus
  Adding --request command to default AudioControl HAL
  Adding basic lshal support for AudioControl
parents 1b33916a c4199eab
Loading
Loading
Loading
Loading
+167 −7
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "AudioControl.h"

#include <stdio.h>

#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/strings.h>

#include <hidl/HidlTransportSupport.h>
#include <hwbinder/IPCThreadState.h>
#include <private/android_filesystem_config.h>

#include "CloseHandle.h"

namespace android::hardware::automotive::audiocontrol::V2_0::implementation {

using ::android::base::EqualsIgnoreCase;
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_string;

static const float kLowerBound = -1.0f;
static const float kUpperBound = 1.0f;

AudioControl::AudioControl() {}

Return<sp<ICloseHandle>> AudioControl::registerFocusListener(const sp<IFocusListener>& listener) {
@@ -29,27 +59,29 @@ Return<sp<ICloseHandle>> AudioControl::registerFocusListener(const sp<IFocusList
}

Return<void> AudioControl::setBalanceTowardRight(float value) {
    // For completeness, lets bounds check the input...
    if (isValidValue(value)) {
        LOG(ERROR) << "Balance value out of range -1 to 1 at " << value;
    } else {
        // Just log in this default mock implementation
        LOG(INFO) << "Balance set to " << value;
    } else {
        LOG(ERROR) << "Balance value out of range -1 to 1 at " << value;
    }
    return Void();
}

Return<void> AudioControl::setFadeTowardFront(float value) {
    // For completeness, lets bounds check the input...
    if (isValidValue(value)) {
        LOG(ERROR) << "Fader value out of range -1 to 1 at " << value;
    } else {
    if (!isValidValue(value)) {
        // Just log in this default mock implementation
        LOG(INFO) << "Fader set to " << value;
    } else {
        LOG(ERROR) << "Fader value out of range -1 to 1 at " << value;
    }
    return Void();
}

bool AudioControl::isValidValue(float value) {
    return (value > kLowerBound) && (value < kUpperBound);
}

Return<void> AudioControl::onAudioFocusChange(hidl_bitfield<AudioUsage> usage, int zoneId,
                                              hidl_bitfield<AudioFocusChange> focusChange) {
    LOG(INFO) << "Focus changed: " << static_cast<int>(focusChange) << " for usage "
@@ -57,4 +89,132 @@ Return<void> AudioControl::onAudioFocusChange(hidl_bitfield<AudioUsage> usage, i
    return Void();
}

Return<void> AudioControl::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) {
    if (fd.getNativeHandle() == nullptr || fd->numFds == 0) {
        LOG(ERROR) << "Invalid parameters passed to debug()";
        return Void();
    }

    cmdDump(fd->data[0], options);
    return Void();
}

void AudioControl::cmdDump(int fd, const hidl_vec<hidl_string>& options) {
    if (options.size() == 0) {
        dump(fd);
        return;
    }

    std::string option = options[0];
    if (EqualsIgnoreCase(option, "--help")) {
        cmdHelp(fd);
    } else if (EqualsIgnoreCase(option, "--request")) {
        cmdRequestFocus(fd, options);
    } else if (EqualsIgnoreCase(option, "--abandon")) {
        cmdAbandonFocus(fd, options);
    } else {
        dprintf(fd, "Invalid option: %s\n", option.c_str());
    }
}

void AudioControl::dump(int fd) {
    if (mFocusListener == nullptr) {
        dprintf(fd, "No focus listener registered\n");
    } else {
        dprintf(fd, "Focus listener registered\n");
    }
}

void AudioControl::cmdHelp(int fd) const {
    dprintf(fd, "Usage: \n\n");
    dprintf(fd, "[no args]: dumps focus listener status\n");
    dprintf(fd, "--help: shows this help\n");
    dprintf(fd,
            "--request <USAGE> <ZONE_ID> <FOCUS_GAIN>: requests audio focus for specified "
            "usage (int), audio zone ID (int), and focus gain type (int)\n");
    dprintf(fd,
            "--abandon <USAGE> <ZONE_ID>: abandons audio focus for specified usage (int) and "
            "audio zone ID (int)\n");
}

void AudioControl::cmdRequestFocus(int fd, const hidl_vec<hidl_string>& options) {
    if (!checkCallerHasWritePermissions(fd) || !checkArgumentsSize(fd, options, 3)) return;

    hidl_bitfield<AudioUsage> usage;
    if (!safelyParseInt(options[1], &usage)) {
        dprintf(fd, "Non-integer usage provided with request: %s\n", options[1].c_str());
        return;
    }
    int zoneId;
    if (!safelyParseInt(options[2], &zoneId)) {
        dprintf(fd, "Non-integer zoneId provided with request: %s\n", options[2].c_str());
        return;
    }
    hidl_bitfield<AudioFocusChange> focusGain;
    if (!safelyParseInt(options[3], &focusGain)) {
        dprintf(fd, "Non-integer focusGain provided with request: %s\n", options[3].c_str());
        return;
    }

    if (mFocusListener == nullptr) {
        dprintf(fd, "Unable to request focus - no focus listener registered\n");
        return;
    }

    mFocusListener->requestAudioFocus(usage, zoneId, focusGain);
    dprintf(fd, "Requested focus for usage %d, zoneId %d, and focusGain %d\n", usage, zoneId,
            focusGain);
}

void AudioControl::cmdAbandonFocus(int fd, const hidl_vec<hidl_string>& options) {
    if (!checkCallerHasWritePermissions(fd) || !checkArgumentsSize(fd, options, 2)) return;

    hidl_bitfield<AudioUsage> usage;
    if (!safelyParseInt(options[1], &usage)) {
        dprintf(fd, "Non-integer usage provided with abandon: %s\n", options[1].c_str());
        return;
    }
    int zoneId;
    if (!safelyParseInt(options[2], &zoneId)) {
        dprintf(fd, "Non-integer zoneId provided with abandon: %s\n", options[2].c_str());
        return;
    }

    if (mFocusListener == nullptr) {
        dprintf(fd, "Unable to abandon focus - no focus listener registered\n");
        return;
    }

    mFocusListener->abandonAudioFocus(usage, zoneId);
    dprintf(fd, "Abandoned focus for usage %d and zoneId %d\n", usage, zoneId);
}

bool AudioControl::checkCallerHasWritePermissions(int fd) {
    // Double check that's only called by root - it should be be blocked at the HIDL debug() level,
    // but it doesn't hurt to make sure...
    if (hardware::IPCThreadState::self()->getCallingUid() != AID_ROOT) {
        dprintf(fd, "Must be root\n");
        return false;
    }
    return true;
}

bool AudioControl::checkArgumentsSize(int fd, const hidl_vec<hidl_string>& options,
                                      size_t expectedSize) {
    // options includes the command, so reducing size by one
    size_t size = options.size() - 1;
    if (size == expectedSize) {
        return true;
    }
    dprintf(fd, "Invalid number of arguments: required %zu, got %zu\n", expectedSize, size);
    return false;
}

bool AudioControl::safelyParseInt(std::string s, int* out) {
    if (!android::base::ParseInt(s, out)) {
        return false;
    }
    return true;
}

}  // namespace android::hardware::automotive::audiocontrol::V2_0::implementation
+12 −1
Original line number Diff line number Diff line
@@ -35,13 +35,24 @@ class AudioControl : public IAudioControl {
                                    hidl_bitfield<AudioFocusChange> focusChange);
    Return<void> setBalanceTowardRight(float value) override;
    Return<void> setFadeTowardFront(float value) override;
    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;

    // Implementation details
    AudioControl();

  private:
    sp<IFocusListener> mFocusListener;
    static bool isValidValue(float value) { return (value > 1.0f) || (value < -1.0f); }

    static bool checkArgumentsSize(int fd, const hidl_vec<hidl_string>& options, size_t minSize);
    static bool checkCallerHasWritePermissions(int fd);
    static bool isValidValue(float value);
    static bool safelyParseInt(std::string s, int* out);

    void cmdDump(int fd, const hidl_vec<hidl_string>& options);
    void cmdHelp(int fd) const;
    void cmdRequestFocus(int fd, const hidl_vec<hidl_string>& options);
    void cmdAbandonFocus(int fd, const hidl_vec<hidl_string>& options);
    void dump(int fd);
};

}  // namespace android::hardware::automotive::audiocontrol::V2_0::implementation