blob: 2ef817c171ae41992f549c1aa67e9b2769ffe291 [file] [log] [blame]
/*
* Copyright (C) 2021 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 "AidlConversion"
#include <sstream>
#include <type_traits>
#include <android_os_Parcel.h>
#include <binder/Parcel.h>
#include <jni.h>
#include <log/log.h>
#include <media/AidlConversion.h>
#include <system/audio.h>
#include "core_jni_helpers.h"
namespace {
using namespace android;
using media::audio::common::AudioChannelLayout;
using media::audio::common::AudioEncapsulationMode;
using media::audio::common::AudioFormatDescription;
using media::audio::common::AudioStreamType;
using media::audio::common::AudioUsage;
#define PACKAGE "android/media/audio/common"
#define CLASSNAME PACKAGE "/AidlConversion"
// Used for creating messages.
template <typename T>
struct type_info {
static constexpr const char* name = "";
};
#define TYPE_NAME_QUOTE(x) #x
#define TYPE_NAME_STRINGIFY(x) TYPE_NAME_QUOTE(x)
#define TYPE_NAME(n) \
template <> \
struct type_info<n> { \
static constexpr const char* name = TYPE_NAME_STRINGIFY(n); \
}
TYPE_NAME(AudioChannelLayout);
TYPE_NAME(AudioEncapsulationMode);
TYPE_NAME(AudioFormatDescription);
TYPE_NAME(AudioStreamType);
TYPE_NAME(AudioUsage);
TYPE_NAME(audio_encapsulation_mode_t);
TYPE_NAME(audio_stream_type_t);
TYPE_NAME(audio_usage_t);
template <typename AidlType, typename LegacyType, typename ConvFunc>
int aidl2legacy(JNIEnv* env, AidlType aidl, const ConvFunc& conv, LegacyType fallbackValue) {
const auto result = conv(aidl);
if (result.ok()) {
return result.value();
}
std::ostringstream msg;
msg << "Failed to convert " << type_info<AidlType>::name << " value "
<< static_cast<std::underlying_type_t<AidlType>>(aidl);
jniThrowException(env, "java/lang/IllegalArgumentException", msg.str().c_str());
return fallbackValue;
}
template <typename LegacyType, typename AidlType, typename ConvFunc>
int legacy2aidl(JNIEnv* env, LegacyType legacy, const ConvFunc& conv, AidlType fallbackValue) {
const auto result = conv(legacy);
if (result.ok()) {
return static_cast<std::underlying_type_t<AidlType>>(result.value());
}
std::ostringstream msg;
msg << "Failed to convert legacy " << type_info<LegacyType>::name << " value " << legacy;
jniThrowException(env, "java/lang/IllegalArgumentException", msg.str().c_str());
return static_cast<std::underlying_type_t<AidlType>>(fallbackValue);
}
template <typename AidlType, typename ConvFunc>
int aidlParcel2legacy(JNIEnv* env, jobject jParcel, const ConvFunc& conv, int fallbackValue) {
if (Parcel* parcel = parcelForJavaObject(env, jParcel); parcel != nullptr) {
AidlType aidl{};
if (status_t status = aidl.readFromParcel(parcel); status == OK) {
auto legacy = conv(aidl);
if (legacy.ok()) {
return legacy.value();
}
} else {
ALOGE("aidl2legacy: Failed to read from parcel: %s", statusToString(status).c_str());
}
std::ostringstream msg;
msg << "Failed to convert " << type_info<AidlType>::name << " value " << aidl.toString();
jniThrowException(env, "java/lang/IllegalArgumentException", msg.str().c_str());
} else {
ALOGE("aidl2legacy: Failed to retrieve the native parcel from Java parcel");
}
return fallbackValue;
}
template <typename LegacyType, typename ConvFunc>
jobject legacy2aidlParcel(JNIEnv* env, LegacyType legacy, const ConvFunc& conv) {
auto aidl = conv(legacy);
if (!aidl.ok()) {
std::ostringstream msg;
msg << "Failed to convert legacy " << type_info<LegacyType>::name << " value " << legacy;
jniThrowException(env, "java/lang/IllegalArgumentException", msg.str().c_str());
return 0;
}
if (jobject jParcel = createJavaParcelObject(env); jParcel != 0) {
if (Parcel* parcel = parcelForJavaObject(env, jParcel); parcel != nullptr) {
if (status_t status = aidl.value().writeToParcel(parcel); status == OK) {
parcel->setDataPosition(0);
return jParcel;
} else {
ALOGE("legacy2aidl: Failed to write to parcel: %s, aidl value: %s",
statusToString(status).c_str(), aidl.value().toString().c_str());
}
} else {
ALOGE("legacy2aidl: Failed to retrieve the native parcel from Java parcel");
}
env->DeleteLocalRef(jParcel);
} else {
ALOGE("legacy2aidl: Failed to create Java parcel");
}
return 0;
}
int aidl2legacy_AudioChannelLayout_Parcel_audio_channel_mask_t(JNIEnv* env, jobject,
jobject jParcel, jboolean isInput) {
return aidlParcel2legacy<AudioChannelLayout>(
env, jParcel,
[isInput](const AudioChannelLayout& l) {
return aidl2legacy_AudioChannelLayout_audio_channel_mask_t(l, isInput);
},
AUDIO_CHANNEL_INVALID);
}
jobject legacy2aidl_audio_channel_mask_t_AudioChannelLayout_Parcel(
JNIEnv* env, jobject, int /*audio_channel_mask_t*/ legacy, jboolean isInput) {
return legacy2aidlParcel(
env, static_cast<audio_channel_mask_t>(legacy), [isInput](audio_channel_mask_t m) {
return legacy2aidl_audio_channel_mask_t_AudioChannelLayout(m, isInput);
});
}
int aidl2legacy_AudioFormatDescription_Parcel_audio_format_t(JNIEnv* env, jobject,
jobject jParcel) {
return aidlParcel2legacy<
AudioFormatDescription>(env, jParcel, aidl2legacy_AudioFormatDescription_audio_format_t,
AUDIO_FORMAT_INVALID);
}
jobject legacy2aidl_audio_format_t_AudioFormatDescription_Parcel(JNIEnv* env, jobject,
int /*audio_format_t*/ legacy) {
return legacy2aidlParcel(env, static_cast<audio_format_t>(legacy),
legacy2aidl_audio_format_t_AudioFormatDescription);
}
jint aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t(JNIEnv* env, jobject,
jint aidl) {
return aidl2legacy(env, AudioEncapsulationMode(static_cast<int32_t>(aidl)),
android::aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t,
AUDIO_ENCAPSULATION_MODE_NONE);
}
jint legacy2aidl_audio_encapsulation_mode_t_AudioEncapsulationMode(JNIEnv* env, jobject,
jint legacy) {
return legacy2aidl(env, static_cast<audio_encapsulation_mode_t>(legacy),
android::legacy2aidl_audio_encapsulation_mode_t_AudioEncapsulationMode,
AudioEncapsulationMode::INVALID);
}
jint aidl2legacy_AudioStreamType_audio_stream_type_t(JNIEnv* env, jobject, jint aidl) {
return aidl2legacy(env, AudioStreamType(static_cast<int32_t>(aidl)),
android::aidl2legacy_AudioStreamType_audio_stream_type_t,
AUDIO_STREAM_DEFAULT);
}
jint legacy2aidl_audio_stream_type_t_AudioStreamType(JNIEnv* env, jobject, jint legacy) {
return legacy2aidl(env, static_cast<audio_stream_type_t>(legacy),
android::legacy2aidl_audio_stream_type_t_AudioStreamType,
AudioStreamType::INVALID);
}
jint aidl2legacy_AudioUsage_audio_usage_t(JNIEnv* env, jobject, jint aidl) {
return aidl2legacy(env, AudioUsage(static_cast<int32_t>(aidl)),
android::aidl2legacy_AudioUsage_audio_usage_t, AUDIO_USAGE_UNKNOWN);
}
jint legacy2aidl_audio_usage_t_AudioUsage(JNIEnv* env, jobject, jint legacy) {
return legacy2aidl(env, static_cast<audio_usage_t>(legacy),
android::legacy2aidl_audio_usage_t_AudioUsage, AudioUsage::INVALID);
}
const JNINativeMethod gMethods[] = {
{"aidl2legacy_AudioChannelLayout_Parcel_audio_channel_mask_t", "(Landroid/os/Parcel;Z)I",
reinterpret_cast<void*>(aidl2legacy_AudioChannelLayout_Parcel_audio_channel_mask_t)},
{"legacy2aidl_audio_channel_mask_t_AudioChannelLayout_Parcel", "(IZ)Landroid/os/Parcel;",
reinterpret_cast<void*>(legacy2aidl_audio_channel_mask_t_AudioChannelLayout_Parcel)},
{"aidl2legacy_AudioFormatDescription_Parcel_audio_format_t", "(Landroid/os/Parcel;)I",
reinterpret_cast<void*>(aidl2legacy_AudioFormatDescription_Parcel_audio_format_t)},
{"legacy2aidl_audio_format_t_AudioFormatDescription_Parcel", "(I)Landroid/os/Parcel;",
reinterpret_cast<void*>(legacy2aidl_audio_format_t_AudioFormatDescription_Parcel)},
{"aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t", "(I)I",
reinterpret_cast<void*>(aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t)},
{"legacy2aidl_audio_encapsulation_mode_t_AudioEncapsulationMode", "(I)I",
reinterpret_cast<void*>(legacy2aidl_audio_encapsulation_mode_t_AudioEncapsulationMode)},
{"aidl2legacy_AudioStreamType_audio_stream_type_t", "(I)I",
reinterpret_cast<void*>(aidl2legacy_AudioStreamType_audio_stream_type_t)},
{"legacy2aidl_audio_stream_type_t_AudioStreamType", "(I)I",
reinterpret_cast<void*>(legacy2aidl_audio_stream_type_t_AudioStreamType)},
{"aidl2legacy_AudioUsage_audio_usage_t", "(I)I",
reinterpret_cast<void*>(aidl2legacy_AudioUsage_audio_usage_t)},
{"legacy2aidl_audio_usage_t_AudioUsage", "(I)I",
reinterpret_cast<void*>(legacy2aidl_audio_usage_t_AudioUsage)},
};
} // namespace
int register_android_media_audio_common_AidlConversion(JNIEnv* env) {
return RegisterMethodsOrDie(env, CLASSNAME, gMethods, NELEM(gMethods));
}