/* * Copyright (C) 2018 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. */ #define LOG_TAG "StreamHAL" #include "core/default/Stream.h" #include "common/all-versions/default/EffectMap.h" #include "core/default/Conversions.h" #include "core/default/Util.h" #include #include #include #include #include #include #include namespace android { namespace hardware { namespace audio { namespace CPP_VERSION { namespace implementation { Stream::Stream(audio_stream_t* stream) : mStream(stream) {} Stream::~Stream() { mStream = nullptr; } // static Result Stream::analyzeStatus(const char* funcName, int status) { return util::analyzeStatus("stream", funcName, status); } // static Result Stream::analyzeStatus(const char* funcName, int status, const std::vector& ignoreErrors) { return util::analyzeStatus("stream", funcName, status, ignoreErrors); } char* Stream::halGetParameters(const char* keys) { return mStream->get_parameters(mStream, keys); } int Stream::halSetParameters(const char* keysAndValues) { return mStream->set_parameters(mStream, keysAndValues); } // Methods from ::android::hardware::audio::CPP_VERSION::IStream follow. Return Stream::getFrameSize() { // Needs to be implemented by interface subclasses. But can't be declared as pure virtual, // since interface subclasses implementation do not inherit from this class. LOG_ALWAYS_FATAL("Stream::getFrameSize is pure abstract"); return uint64_t{}; } Return Stream::getFrameCount() { int halFrameCount; Result retval = getParam(AudioParameter::keyFrameCount, &halFrameCount); return retval == Result::OK ? halFrameCount : 0; } Return Stream::getBufferSize() { return mStream->get_buffer_size(mStream); } Return Stream::getSampleRate() { return mStream->get_sample_rate(mStream); } #if MAJOR_VERSION == 2 Return Stream::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) { return getSupportedSampleRates(getFormat(), _hidl_cb); } Return Stream::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) { return getSupportedChannelMasks(getFormat(), _hidl_cb); } #endif Return Stream::getSupportedSampleRates(AudioFormat format, getSupportedSampleRates_cb _hidl_cb) { AudioParameter context; context.addInt(String8(AUDIO_PARAMETER_STREAM_FORMAT), int(format)); String8 halListValue; Result result = getParam(AudioParameter::keyStreamSupportedSamplingRates, &halListValue, context); hidl_vec sampleRates; SortedVector halSampleRates; if (result == Result::OK) { halSampleRates = samplingRatesFromString(halListValue.string(), AudioParameter::valueListSeparator); sampleRates.setToExternal(halSampleRates.editArray(), halSampleRates.size()); // Legacy get_parameter does not return a status_t, thus can not advertise of failure. // Note that this method must succeed (non empty list) if the format is supported. if (sampleRates.size() == 0) { result = Result::NOT_SUPPORTED; } } #if MAJOR_VERSION == 2 _hidl_cb(sampleRates); #elif MAJOR_VERSION >= 4 _hidl_cb(result, sampleRates); #endif return Void(); } Return Stream::getSupportedChannelMasks(AudioFormat format, getSupportedChannelMasks_cb _hidl_cb) { AudioParameter context; context.addInt(String8(AUDIO_PARAMETER_STREAM_FORMAT), int(format)); String8 halListValue; Result result = getParam(AudioParameter::keyStreamSupportedChannels, &halListValue, context); hidl_vec channelMasks; SortedVector halChannelMasks; if (result == Result::OK) { halChannelMasks = channelMasksFromString(halListValue.string(), AudioParameter::valueListSeparator); channelMasks.resize(halChannelMasks.size()); for (size_t i = 0; i < halChannelMasks.size(); ++i) { channelMasks[i] = AudioChannelBitfield(halChannelMasks[i]); } // Legacy get_parameter does not return a status_t, thus can not advertise of failure. // Note that this method must succeed (non empty list) if the format is supported. if (channelMasks.size() == 0) { result = Result::NOT_SUPPORTED; } } #if MAJOR_VERSION == 2 _hidl_cb(channelMasks); #elif MAJOR_VERSION >= 4 _hidl_cb(result, channelMasks); #endif return Void(); } Return Stream::setSampleRate(uint32_t sampleRateHz) { return setParam(AudioParameter::keySamplingRate, static_cast(sampleRateHz)); } Return Stream::getChannelMask() { return AudioChannelBitfield(mStream->get_channels(mStream)); } Return Stream::setChannelMask(AudioChannelBitfield mask) { return setParam(AudioParameter::keyChannels, static_cast(mask)); } Return Stream::getFormat() { return AudioFormat(mStream->get_format(mStream)); } Return Stream::getSupportedFormats(getSupportedFormats_cb _hidl_cb) { String8 halListValue; Result result = getParam(AudioParameter::keyStreamSupportedFormats, &halListValue); hidl_vec formats; Vector halFormats; if (result == Result::OK) { halFormats = formatsFromString(halListValue.string(), AudioParameter::valueListSeparator); formats.resize(halFormats.size()); for (size_t i = 0; i < halFormats.size(); ++i) { formats[i] = AudioFormat(halFormats[i]); } } _hidl_cb(formats); return Void(); } Return Stream::setFormat(AudioFormat format) { return setParam(AudioParameter::keyFormat, static_cast(format)); } Return Stream::getAudioProperties(getAudioProperties_cb _hidl_cb) { uint32_t halSampleRate = mStream->get_sample_rate(mStream); audio_channel_mask_t halMask = mStream->get_channels(mStream); audio_format_t halFormat = mStream->get_format(mStream); _hidl_cb(halSampleRate, AudioChannelBitfield(halMask), AudioFormat(halFormat)); return Void(); } Return Stream::addEffect(uint64_t effectId) { effect_handle_t halEffect = EffectMap::getInstance().get(effectId); if (halEffect != NULL) { return analyzeStatus("add_audio_effect", mStream->add_audio_effect(mStream, halEffect)); } else { ALOGW("Invalid effect ID passed from client: %" PRIu64, effectId); return Result::INVALID_ARGUMENTS; } } Return Stream::removeEffect(uint64_t effectId) { effect_handle_t halEffect = EffectMap::getInstance().get(effectId); if (halEffect != NULL) { return analyzeStatus("remove_audio_effect", mStream->remove_audio_effect(mStream, halEffect)); } else { ALOGW("Invalid effect ID passed from client: %" PRIu64, effectId); return Result::INVALID_ARGUMENTS; } } Return Stream::standby() { return analyzeStatus("standby", mStream->standby(mStream)); } Return Stream::setHwAvSync(uint32_t hwAvSync) { return setParam(AudioParameter::keyStreamHwAvSync, static_cast(hwAvSync)); } #if MAJOR_VERSION == 2 Return Stream::getDevice() { int device = 0; Result retval = getParam(AudioParameter::keyRouting, &device); return retval == Result::OK ? static_cast(device) : AudioDevice::NONE; } Return Stream::setDevice(const DeviceAddress& address) { return setParam(AudioParameter::keyRouting, address); } Return Stream::getParameters(const hidl_vec& keys, getParameters_cb _hidl_cb) { getParametersImpl({} /* context */, keys, _hidl_cb); return Void(); } Return Stream::setParameters(const hidl_vec& parameters) { return setParametersImpl({} /* context */, parameters); } Return Stream::setConnectedState(const DeviceAddress& address, bool connected) { return setParam( connected ? AudioParameter::keyStreamConnect : AudioParameter::keyStreamDisconnect, address); } #elif MAJOR_VERSION >= 4 Return Stream::getDevices(getDevices_cb _hidl_cb) { int device = 0; Result retval = getParam(AudioParameter::keyRouting, &device); hidl_vec devices; if (retval == Result::OK) { devices.resize(1); devices[0].device = static_cast(device); } _hidl_cb(retval, devices); return Void(); } Return Stream::setDevices(const hidl_vec& devices) { // FIXME: can the legacy API set multiple device with address ? if (devices.size() > 1) { return Result::NOT_SUPPORTED; } DeviceAddress address; if (devices.size() == 1) { address = devices[0]; } else { address.device = AudioDevice::NONE; } return setParam(AudioParameter::keyRouting, address); } Return Stream::getParameters(const hidl_vec& context, const hidl_vec& keys, getParameters_cb _hidl_cb) { getParametersImpl(context, keys, _hidl_cb); return Void(); } Return Stream::setParameters(const hidl_vec& context, const hidl_vec& parameters) { return setParametersImpl(context, parameters); } #endif Return Stream::start() { return Result::NOT_SUPPORTED; } Return Stream::stop() { return Result::NOT_SUPPORTED; } Return Stream::createMmapBuffer(int32_t minSizeFrames __unused, createMmapBuffer_cb _hidl_cb) { Result retval(Result::NOT_SUPPORTED); MmapBufferInfo info; _hidl_cb(retval, info); return Void(); } Return Stream::getMmapPosition(getMmapPosition_cb _hidl_cb) { Result retval(Result::NOT_SUPPORTED); MmapPosition position; _hidl_cb(retval, position); return Void(); } Return Stream::close() { return Result::NOT_SUPPORTED; } Return Stream::debug(const hidl_handle& fd, const hidl_vec& /* options */) { if (fd.getNativeHandle() != nullptr && fd->numFds == 1) { analyzeStatus("dump", mStream->dump(mStream, fd->data[0])); } return Void(); } #if MAJOR_VERSION == 2 Return Stream::debugDump(const hidl_handle& fd) { return debug(fd, {} /* options */); } #endif } // namespace implementation } // namespace CPP_VERSION } // namespace audio } // namespace hardware } // namespace android