1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "AidlConversion"
18
19 #include <sstream>
20 #include <type_traits>
21
22 #include <android_os_Parcel.h>
23 #include <binder/Parcel.h>
24 #include <jni.h>
25 #include <log/log.h>
26 #include <media/AidlConversion.h>
27 #include <system/audio.h>
28
29 #include "core_jni_helpers.h"
30
31 namespace {
32
33 using namespace android;
34 using media::audio::common::AudioChannelLayout;
35 using media::audio::common::AudioEncapsulationMode;
36 using media::audio::common::AudioFormatDescription;
37 using media::audio::common::AudioStreamType;
38 using media::audio::common::AudioUsage;
39
40 #define PACKAGE "android/media/audio/common"
41 #define CLASSNAME PACKAGE "/AidlConversion"
42
43 // Used for creating messages.
44 template <typename T>
45 struct type_info {
46 static constexpr const char* name = "";
47 };
48 #define TYPE_NAME_QUOTE(x) #x
49 #define TYPE_NAME_STRINGIFY(x) TYPE_NAME_QUOTE(x)
50 #define TYPE_NAME(n) \
51 template <> \
52 struct type_info<n> { \
53 static constexpr const char* name = TYPE_NAME_STRINGIFY(n); \
54 }
55
56 TYPE_NAME(AudioChannelLayout);
57 TYPE_NAME(AudioEncapsulationMode);
58 TYPE_NAME(AudioFormatDescription);
59 TYPE_NAME(AudioStreamType);
60 TYPE_NAME(AudioUsage);
61 TYPE_NAME(audio_encapsulation_mode_t);
62 TYPE_NAME(audio_stream_type_t);
63 TYPE_NAME(audio_usage_t);
64
65 template <typename AidlType, typename LegacyType, typename ConvFunc>
aidl2legacy(JNIEnv * env,AidlType aidl,const ConvFunc & conv,LegacyType fallbackValue)66 int aidl2legacy(JNIEnv* env, AidlType aidl, const ConvFunc& conv, LegacyType fallbackValue) {
67 const auto result = conv(aidl);
68 if (result.ok()) {
69 return result.value();
70 }
71 std::ostringstream msg;
72 msg << "Failed to convert " << type_info<AidlType>::name << " value "
73 << static_cast<std::underlying_type_t<AidlType>>(aidl);
74 jniThrowException(env, "java/lang/IllegalArgumentException", msg.str().c_str());
75 return fallbackValue;
76 }
77
78 template <typename LegacyType, typename AidlType, typename ConvFunc>
legacy2aidl(JNIEnv * env,LegacyType legacy,const ConvFunc & conv,AidlType fallbackValue)79 int legacy2aidl(JNIEnv* env, LegacyType legacy, const ConvFunc& conv, AidlType fallbackValue) {
80 const auto result = conv(legacy);
81 if (result.ok()) {
82 return static_cast<std::underlying_type_t<AidlType>>(result.value());
83 }
84 std::ostringstream msg;
85 msg << "Failed to convert legacy " << type_info<LegacyType>::name << " value " << legacy;
86 jniThrowException(env, "java/lang/IllegalArgumentException", msg.str().c_str());
87 return static_cast<std::underlying_type_t<AidlType>>(fallbackValue);
88 }
89
90 template <typename AidlType, typename ConvFunc>
aidlParcel2legacy(JNIEnv * env,jobject jParcel,const ConvFunc & conv,int fallbackValue)91 int aidlParcel2legacy(JNIEnv* env, jobject jParcel, const ConvFunc& conv, int fallbackValue) {
92 if (Parcel* parcel = parcelForJavaObject(env, jParcel); parcel != nullptr) {
93 AidlType aidl{};
94 if (status_t status = aidl.readFromParcel(parcel); status == OK) {
95 auto legacy = conv(aidl);
96 if (legacy.ok()) {
97 return legacy.value();
98 }
99 } else {
100 ALOGE("aidl2legacy: Failed to read from parcel: %s", statusToString(status).c_str());
101 }
102 std::ostringstream msg;
103 msg << "Failed to convert " << type_info<AidlType>::name << " value " << aidl.toString();
104 jniThrowException(env, "java/lang/IllegalArgumentException", msg.str().c_str());
105 } else {
106 ALOGE("aidl2legacy: Failed to retrieve the native parcel from Java parcel");
107 }
108 return fallbackValue;
109 }
110
111 template <typename LegacyType, typename ConvFunc>
legacy2aidlParcel(JNIEnv * env,LegacyType legacy,const ConvFunc & conv)112 jobject legacy2aidlParcel(JNIEnv* env, LegacyType legacy, const ConvFunc& conv) {
113 auto aidl = conv(legacy);
114 if (!aidl.ok()) {
115 std::ostringstream msg;
116 msg << "Failed to convert legacy " << type_info<LegacyType>::name << " value " << legacy;
117 jniThrowException(env, "java/lang/IllegalArgumentException", msg.str().c_str());
118 return 0;
119 }
120 if (jobject jParcel = createJavaParcelObject(env); jParcel != 0) {
121 if (Parcel* parcel = parcelForJavaObject(env, jParcel); parcel != nullptr) {
122 if (status_t status = aidl.value().writeToParcel(parcel); status == OK) {
123 parcel->setDataPosition(0);
124 return jParcel;
125 } else {
126 ALOGE("legacy2aidl: Failed to write to parcel: %s, aidl value: %s",
127 statusToString(status).c_str(), aidl.value().toString().c_str());
128 }
129 } else {
130 ALOGE("legacy2aidl: Failed to retrieve the native parcel from Java parcel");
131 }
132 env->DeleteLocalRef(jParcel);
133 } else {
134 ALOGE("legacy2aidl: Failed to create Java parcel");
135 }
136 return 0;
137 }
138
aidl2legacy_AudioChannelLayout_Parcel_audio_channel_mask_t(JNIEnv * env,jobject,jobject jParcel,jboolean isInput)139 int aidl2legacy_AudioChannelLayout_Parcel_audio_channel_mask_t(JNIEnv* env, jobject,
140 jobject jParcel, jboolean isInput) {
141 return aidlParcel2legacy<AudioChannelLayout>(
142 env, jParcel,
143 [isInput](const AudioChannelLayout& l) {
144 return aidl2legacy_AudioChannelLayout_audio_channel_mask_t(l, isInput);
145 },
146 AUDIO_CHANNEL_INVALID);
147 }
148
legacy2aidl_audio_channel_mask_t_AudioChannelLayout_Parcel(JNIEnv * env,jobject,int legacy,jboolean isInput)149 jobject legacy2aidl_audio_channel_mask_t_AudioChannelLayout_Parcel(
150 JNIEnv* env, jobject, int /*audio_channel_mask_t*/ legacy, jboolean isInput) {
151 return legacy2aidlParcel(
152 env, static_cast<audio_channel_mask_t>(legacy), [isInput](audio_channel_mask_t m) {
153 return legacy2aidl_audio_channel_mask_t_AudioChannelLayout(m, isInput);
154 });
155 }
156
aidl2legacy_AudioFormatDescription_Parcel_audio_format_t(JNIEnv * env,jobject,jobject jParcel)157 int aidl2legacy_AudioFormatDescription_Parcel_audio_format_t(JNIEnv* env, jobject,
158 jobject jParcel) {
159 return aidlParcel2legacy<
160 AudioFormatDescription>(env, jParcel, aidl2legacy_AudioFormatDescription_audio_format_t,
161 AUDIO_FORMAT_INVALID);
162 }
163
legacy2aidl_audio_format_t_AudioFormatDescription_Parcel(JNIEnv * env,jobject,int legacy)164 jobject legacy2aidl_audio_format_t_AudioFormatDescription_Parcel(JNIEnv* env, jobject,
165 int /*audio_format_t*/ legacy) {
166 return legacy2aidlParcel(env, static_cast<audio_format_t>(legacy),
167 legacy2aidl_audio_format_t_AudioFormatDescription);
168 }
169
aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t(JNIEnv * env,jobject,jint aidl)170 jint aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t(JNIEnv* env, jobject,
171 jint aidl) {
172 return aidl2legacy(env, AudioEncapsulationMode(static_cast<int32_t>(aidl)),
173 android::aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t,
174 AUDIO_ENCAPSULATION_MODE_NONE);
175 }
176
legacy2aidl_audio_encapsulation_mode_t_AudioEncapsulationMode(JNIEnv * env,jobject,jint legacy)177 jint legacy2aidl_audio_encapsulation_mode_t_AudioEncapsulationMode(JNIEnv* env, jobject,
178 jint legacy) {
179 return legacy2aidl(env, static_cast<audio_encapsulation_mode_t>(legacy),
180 android::legacy2aidl_audio_encapsulation_mode_t_AudioEncapsulationMode,
181 AudioEncapsulationMode::INVALID);
182 }
183
aidl2legacy_AudioStreamType_audio_stream_type_t(JNIEnv * env,jobject,jint aidl)184 jint aidl2legacy_AudioStreamType_audio_stream_type_t(JNIEnv* env, jobject, jint aidl) {
185 return aidl2legacy(env, AudioStreamType(static_cast<int32_t>(aidl)),
186 android::aidl2legacy_AudioStreamType_audio_stream_type_t,
187 AUDIO_STREAM_DEFAULT);
188 }
189
legacy2aidl_audio_stream_type_t_AudioStreamType(JNIEnv * env,jobject,jint legacy)190 jint legacy2aidl_audio_stream_type_t_AudioStreamType(JNIEnv* env, jobject, jint legacy) {
191 return legacy2aidl(env, static_cast<audio_stream_type_t>(legacy),
192 android::legacy2aidl_audio_stream_type_t_AudioStreamType,
193 AudioStreamType::INVALID);
194 }
195
aidl2legacy_AudioUsage_audio_usage_t(JNIEnv * env,jobject,jint aidl)196 jint aidl2legacy_AudioUsage_audio_usage_t(JNIEnv* env, jobject, jint aidl) {
197 return aidl2legacy(env, AudioUsage(static_cast<int32_t>(aidl)),
198 android::aidl2legacy_AudioUsage_audio_usage_t, AUDIO_USAGE_UNKNOWN);
199 }
200
legacy2aidl_audio_usage_t_AudioUsage(JNIEnv * env,jobject,jint legacy)201 jint legacy2aidl_audio_usage_t_AudioUsage(JNIEnv* env, jobject, jint legacy) {
202 return legacy2aidl(env, static_cast<audio_usage_t>(legacy),
203 android::legacy2aidl_audio_usage_t_AudioUsage, AudioUsage::INVALID);
204 }
205
206 const JNINativeMethod gMethods[] = {
207 {"aidl2legacy_AudioChannelLayout_Parcel_audio_channel_mask_t", "(Landroid/os/Parcel;Z)I",
208 reinterpret_cast<void*>(aidl2legacy_AudioChannelLayout_Parcel_audio_channel_mask_t)},
209 {"legacy2aidl_audio_channel_mask_t_AudioChannelLayout_Parcel", "(IZ)Landroid/os/Parcel;",
210 reinterpret_cast<void*>(legacy2aidl_audio_channel_mask_t_AudioChannelLayout_Parcel)},
211 {"aidl2legacy_AudioFormatDescription_Parcel_audio_format_t", "(Landroid/os/Parcel;)I",
212 reinterpret_cast<void*>(aidl2legacy_AudioFormatDescription_Parcel_audio_format_t)},
213 {"legacy2aidl_audio_format_t_AudioFormatDescription_Parcel", "(I)Landroid/os/Parcel;",
214 reinterpret_cast<void*>(legacy2aidl_audio_format_t_AudioFormatDescription_Parcel)},
215 {"aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t", "(I)I",
216 reinterpret_cast<void*>(aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t)},
217 {"legacy2aidl_audio_encapsulation_mode_t_AudioEncapsulationMode", "(I)I",
218 reinterpret_cast<void*>(legacy2aidl_audio_encapsulation_mode_t_AudioEncapsulationMode)},
219 {"aidl2legacy_AudioStreamType_audio_stream_type_t", "(I)I",
220 reinterpret_cast<void*>(aidl2legacy_AudioStreamType_audio_stream_type_t)},
221 {"legacy2aidl_audio_stream_type_t_AudioStreamType", "(I)I",
222 reinterpret_cast<void*>(legacy2aidl_audio_stream_type_t_AudioStreamType)},
223 {"aidl2legacy_AudioUsage_audio_usage_t", "(I)I",
224 reinterpret_cast<void*>(aidl2legacy_AudioUsage_audio_usage_t)},
225 {"legacy2aidl_audio_usage_t_AudioUsage", "(I)I",
226 reinterpret_cast<void*>(legacy2aidl_audio_usage_t_AudioUsage)},
227 };
228
229 } // namespace
230
register_android_media_audio_common_AidlConversion(JNIEnv * env)231 int register_android_media_audio_common_AidlConversion(JNIEnv* env) {
232 return RegisterMethodsOrDie(env, CLASSNAME, gMethods, NELEM(gMethods));
233 }
234