blob: 39ec944fb00b879d0fcbb857184d5cb735aa7e9d [file] [log] [blame]
/*
* Copyright (C) 2025 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 "MmapStreamInterface"
#include <android/media/BnMmapStreamCallback.h>
#include <media/AudioSystem.h>
#include <media/IAudioFlinger.h>
#include <media/MmapStreamCallback.h>
#include <media/MmapStreamInterface.h>
namespace android {
using media::IMmapStream;
using aidl_utils::statusTFromBinderStatus;
class MmapStreamCallbackAdapter : public android::media::BnMmapStreamCallback {
public:
explicit MmapStreamCallbackAdapter(const sp<MmapStreamCallback>& callback)
: mCallback(callback) {}
::android::binder::Status onTearDown(int32_t portId) final {
const audio_port_handle_t handle = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_int32_t_audio_port_handle_t(portId));
if (const auto callback = mCallback.promote()) {
callback->onTearDown(handle);
} else {
ALOGW_IF(mCallbackWarn++ < kSpamLimit, "%s: null callback", __func__);
}
return binder::Status::ok();
}
::android::binder::Status onVolumeChanged(float volume) final {
if (const auto callback = mCallback.promote()) {
callback->onVolumeChanged(volume);
} else {
ALOGW_IF(mCallbackWarn++ < kSpamLimit, "%s: null callback", __func__);
}
return binder::Status::ok();
}
::android::binder::Status onRoutingChanged(const ::std::vector<int32_t>& deviceIds) final {
const std::vector<audio_port_handle_t> legacyDeviceIds = VALUE_OR_RETURN_BINDER_STATUS(
convertContainer<std::vector<audio_port_handle_t>>(
deviceIds, aidl2legacy_int32_t_audio_port_handle_t));
if (const auto callback = mCallback.promote()) {
callback->onRoutingChanged(legacyDeviceIds);
} else {
ALOGW_IF(mCallbackWarn++ < kSpamLimit, "%s: null callback", __func__);
}
return binder::Status::ok();
}
private:
static constexpr uint32_t kSpamLimit = 30;
const wp<MmapStreamCallback> mCallback;
std::atomic_uint32_t mCallbackWarn = 0;
};
// static
status_t MmapStreamInterface::buildRequest(bool isOutput,
const audio_attributes_t& attr,
const audio_config_base_t& config,
const AudioClient& client,
const DeviceIdVector& deviceIds,
audio_session_t sessionId,
const sp<MmapStreamCallback>& callback,
const audio_offload_info_t* offloadInfo,
media::OpenMmapRequest* request)
{
request->isOutput = isOutput;
request->attr = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_attributes_t_AudioAttributes(attr));
request->config = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_config_base_t_AudioConfigBase(
config, !isOutput));
request->client = VALUE_OR_RETURN_STATUS(
legacy2aidl_AudioClient_AudioClient(client));
request->deviceIds = VALUE_OR_RETURN_STATUS(
convertContainer<std::vector<int32_t>>(
deviceIds, legacy2aidl_audio_port_handle_t_int32_t));
request->sessionId = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_session_t_int32_t(sessionId));
request->callback = sp<MmapStreamCallbackAdapter>::make(callback);
request->offloadInfo = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_offload_info_t_AudioOffloadInfo(
offloadInfo ? *offloadInfo : AUDIO_INFO_INITIALIZER));
return NO_ERROR;
}
// static
status_t MmapStreamInterface::parseResponse(const media::OpenMmapResponse& response,
bool isOutput,
audio_config_base_t* config,
DeviceIdVector* deviceIds,
audio_session_t* sessionId,
audio_port_handle_t* handle)
{
*config = VALUE_OR_RETURN_STATUS(
aidl2legacy_AudioConfigBase_audio_config_base_t(
response.config, !isOutput));
*deviceIds = VALUE_OR_RETURN_STATUS(
convertContainer<std::vector<audio_port_handle_t>>(
response.deviceIds, aidl2legacy_int32_t_audio_port_handle_t));
*sessionId = VALUE_OR_RETURN_STATUS(
aidl2legacy_int32_t_audio_session_t(response.sessionId));
*handle = VALUE_OR_RETURN_STATUS(
aidl2legacy_int32_t_audio_port_handle_t(response.portId));
return NO_ERROR;
}
// static
status_t MmapStreamInterface::openMmapStream(bool isOutput,
const audio_attributes_t& attr,
audio_config_base_t* config,
const AudioClient& client,
DeviceIdVector* deviceIds,
audio_session_t* sessionId,
const sp<MmapStreamCallback>& callback,
const audio_offload_info_t* offloadInfo,
sp<MmapStreamInterface>& interface,
audio_port_handle_t* handle)
{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == nullptr) {
return NO_INIT;
}
media::OpenMmapRequest request;
sp<MmapStreamCallbackAdapter> callbackAdapter;
status_t status = buildRequest(isOutput, attr, *config, client, *deviceIds,
*sessionId, callback, offloadInfo, &request);
if (status != NO_ERROR) {
ALOGW("%s: buildRequest failed with status: %d", __func__, status);
return status;
}
media::OpenMmapResponse response;
status = af->openMmapStream(request, &response);
if (status != NO_ERROR) {
ALOGW("%s: openMmapStream failed with status: %d", __func__, status);
return status;
}
status = parseResponse(response, isOutput, config, deviceIds, sessionId, handle);
if (status != NO_ERROR) {
ALOGW("%s: parseResponse failed with status: %d", __func__, status);
return status;
}
interface = sp<MmapStreamInterface>::make(*config, response.stream, request.callback);
return NO_ERROR;
}
// static
status_t MmapStreamInterface::parseRequest(const media::OpenMmapRequest& request,
bool* isOutput,
audio_attributes_t* attr,
audio_config_base_t* config,
AudioClient* client,
DeviceIdVector* deviceIds,
audio_session_t* sessionId,
sp<media::IMmapStreamCallback>* callback,
audio_offload_info_t* offloadInfo) {
*isOutput = request.isOutput;
*attr = VALUE_OR_RETURN_STATUS(
aidl2legacy_AudioAttributes_audio_attributes_t(request.attr));
*config = VALUE_OR_RETURN_STATUS(
aidl2legacy_AudioConfigBase_audio_config_base_t(
request.config, !*isOutput));
*client = VALUE_OR_RETURN_STATUS(
aidl2legacy_AudioClient_AudioClient(request.client));
*deviceIds = VALUE_OR_RETURN_STATUS(
convertContainer<DeviceIdVector>(
request.deviceIds, aidl2legacy_int32_t_audio_port_handle_t));
*sessionId = VALUE_OR_RETURN_STATUS(
aidl2legacy_int32_t_audio_session_t(request.sessionId));
*callback = request.callback;
if (offloadInfo != nullptr) {
*offloadInfo = VALUE_OR_RETURN_STATUS(
aidl2legacy_AudioOffloadInfo_audio_offload_info_t(request.offloadInfo));
}
return NO_ERROR;
}
// static
status_t MmapStreamInterface::buildResponse(bool isOutput,
const audio_config_base_t& config,
const DeviceIdVector& deviceIds,
audio_session_t sessionId,
const sp<IMmapStream>& interface,
audio_port_handle_t portId,
media::OpenMmapResponse* response) {
response->config = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_config_base_t_AudioConfigBase(
config, !isOutput));
response->deviceIds = VALUE_OR_RETURN_STATUS(
convertContainer<std::vector<int32_t>>(
deviceIds, legacy2aidl_audio_port_handle_t_int32_t));
response->sessionId = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_session_t_int32_t(sessionId));
response->stream = interface;
response->portId = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_port_handle_t_int32_t(portId));
return NO_ERROR;
}
MmapStreamInterface::MmapStreamInterface(const audio_config_base_t& config,
const sp<media::IMmapStream>& stream,
const sp<media::IMmapStreamCallback>& callback)
: mConfig(config),
mStream(stream),
mCallback(callback)
{}
status_t MmapStreamInterface::createMmapBuffer(
int32_t minSizeFrames, struct audio_mmap_buffer_info* info) {
media::MmapBufferInfo bufferInfo;
RETURN_STATUS_IF_ERROR(
statusTFromBinderStatus(mStream->createMmapBuffer(minSizeFrames, &bufferInfo)));
info->shared_memory_address = nullptr; // local only
binder::unique_fd ufd(bufferInfo.sharedFd.release());
info->shared_memory_fd = ufd.release();
info->buffer_size_frames = bufferInfo.bufferSizeFrames;
info->burst_size_frames = bufferInfo.burstSizeFrames;
info->flags = (audio_mmap_buffer_flag)bufferInfo.flags;
ALOGD("%s: bptr: %p buffer_size_frames: %d burst_size_frames: %d flags:%#x",
__func__, &bufferInfo, bufferInfo.bufferSizeFrames,
bufferInfo.burstSizeFrames, bufferInfo.flags);
return NO_ERROR;
}
status_t MmapStreamInterface::getMmapPosition(struct audio_mmap_position* position) {
media::IMmapStream::MmapStreamPosition aidlPosition;
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mStream->getMmapPosition(&aidlPosition)));
position->time_nanoseconds = aidlPosition.timeNanos;
position->position_frames = aidlPosition.positionFrames;
return NO_ERROR;
}
status_t MmapStreamInterface::getObservablePosition(uint64_t* position, int64_t* timeNanos) {
media::IMmapStream::MmapObservablePosition observablePosition;
RETURN_STATUS_IF_ERROR(
statusTFromBinderStatus(mStream->getObservablePosition(&observablePosition)));
*position = observablePosition.positionFrames;
*timeNanos = observablePosition.timeNanos;
return NO_ERROR;
}
status_t MmapStreamInterface::start(
const AudioClient& client, const audio_attributes_t* attr, audio_port_handle_t *handle) {
const auto aidlClient = VALUE_OR_RETURN_STATUS(legacy2aidl_AudioClient_AudioClient(client));
::std::optional<::android::media::audio::common::AudioAttributes> aidlAttr;
if (attr) {
aidlAttr = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_attributes_t_AudioAttributes(*attr));
}
const int32_t aidlPriorPortId =
VALUE_OR_RETURN_STATUS(legacy2aidl_audio_port_handle_t_int32_t(*handle));
int32_t portId;
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
mStream->start(aidlClient, aidlAttr, aidlPriorPortId, &portId)));
*handle = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_audio_port_handle_t(portId));
return NO_ERROR;
}
status_t MmapStreamInterface::stop(audio_port_handle_t handle) {
const int32_t portId =
VALUE_OR_RETURN_STATUS(legacy2aidl_audio_port_handle_t_int32_t(handle));
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mStream->stop(portId)));
return NO_ERROR;
}
status_t MmapStreamInterface::standby() {
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mStream->standby()));
return NO_ERROR;
}
status_t MmapStreamInterface::reportData(const void* buffer, size_t frameCount) {
const auto* const begin = static_cast<const uint8_t*>(buffer);
std::vector<uint8_t> aidlBuffer(
begin, begin + frameCount * audio_bytes_per_sample(mConfig.format));
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mStream->reportData(aidlBuffer)));
return NO_ERROR;
}
status_t MmapStreamInterface::drain() {
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mStream->drain()));
return NO_ERROR;
}
status_t MmapStreamInterface::activate() {
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mStream->activate()));
return NO_ERROR;
}
} // namespace android