1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker * Copyright (C) 2020 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker *
4*ec779b8eSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker *
8*ec779b8eSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker *
10*ec779b8eSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker */
16*ec779b8eSAndroid Build Coastguard Worker
17*ec779b8eSAndroid Build Coastguard Worker #include <media/AudioValidator.h>
18*ec779b8eSAndroid Build Coastguard Worker #include <cmath>
19*ec779b8eSAndroid Build Coastguard Worker
20*ec779b8eSAndroid Build Coastguard Worker namespace android {
21*ec779b8eSAndroid Build Coastguard Worker
22*ec779b8eSAndroid Build Coastguard Worker /** returns true if string is overflow */
23*ec779b8eSAndroid Build Coastguard Worker template <size_t size>
checkStringOverflow(const char (& s)[size])24*ec779b8eSAndroid Build Coastguard Worker bool checkStringOverflow(const char (&s)[size]) {
25*ec779b8eSAndroid Build Coastguard Worker return strnlen(s, size) >= size;
26*ec779b8eSAndroid Build Coastguard Worker }
27*ec779b8eSAndroid Build Coastguard Worker
safetyNetLog(status_t status,std::string_view bugNumber)28*ec779b8eSAndroid Build Coastguard Worker status_t safetyNetLog(status_t status, std::string_view bugNumber) {
29*ec779b8eSAndroid Build Coastguard Worker if (status != NO_ERROR && !bugNumber.empty()) {
30*ec779b8eSAndroid Build Coastguard Worker android_errorWriteLog(0x534e4554, bugNumber.data()); // SafetyNet logging
31*ec779b8eSAndroid Build Coastguard Worker }
32*ec779b8eSAndroid Build Coastguard Worker return status;
33*ec779b8eSAndroid Build Coastguard Worker }
34*ec779b8eSAndroid Build Coastguard Worker
validateAudioAttributes(const audio_attributes_t & attr,std::string_view bugNumber)35*ec779b8eSAndroid Build Coastguard Worker status_t AudioValidator::validateAudioAttributes(
36*ec779b8eSAndroid Build Coastguard Worker const audio_attributes_t& attr, std::string_view bugNumber)
37*ec779b8eSAndroid Build Coastguard Worker {
38*ec779b8eSAndroid Build Coastguard Worker status_t status = NO_ERROR;
39*ec779b8eSAndroid Build Coastguard Worker const size_t tagsMaxSize = AUDIO_ATTRIBUTES_TAGS_MAX_SIZE;
40*ec779b8eSAndroid Build Coastguard Worker if (strnlen(attr.tags, tagsMaxSize) >= tagsMaxSize) {
41*ec779b8eSAndroid Build Coastguard Worker status = BAD_VALUE;
42*ec779b8eSAndroid Build Coastguard Worker }
43*ec779b8eSAndroid Build Coastguard Worker return safetyNetLog(status, bugNumber);
44*ec779b8eSAndroid Build Coastguard Worker }
45*ec779b8eSAndroid Build Coastguard Worker
validateEffectDescriptor(const effect_descriptor_t & desc,std::string_view bugNumber)46*ec779b8eSAndroid Build Coastguard Worker status_t AudioValidator::validateEffectDescriptor(
47*ec779b8eSAndroid Build Coastguard Worker const effect_descriptor_t& desc, std::string_view bugNumber)
48*ec779b8eSAndroid Build Coastguard Worker {
49*ec779b8eSAndroid Build Coastguard Worker status_t status = NO_ERROR;
50*ec779b8eSAndroid Build Coastguard Worker if (checkStringOverflow(desc.name) || checkStringOverflow(desc.implementor)) {
51*ec779b8eSAndroid Build Coastguard Worker status = BAD_VALUE;
52*ec779b8eSAndroid Build Coastguard Worker }
53*ec779b8eSAndroid Build Coastguard Worker return safetyNetLog(status, bugNumber);
54*ec779b8eSAndroid Build Coastguard Worker }
55*ec779b8eSAndroid Build Coastguard Worker
validateAudioPortConfig(const struct audio_port_config & config,std::string_view bugNumber)56*ec779b8eSAndroid Build Coastguard Worker status_t AudioValidator::validateAudioPortConfig(
57*ec779b8eSAndroid Build Coastguard Worker const struct audio_port_config& config, std::string_view bugNumber)
58*ec779b8eSAndroid Build Coastguard Worker {
59*ec779b8eSAndroid Build Coastguard Worker status_t status = NO_ERROR;
60*ec779b8eSAndroid Build Coastguard Worker if (config.type == AUDIO_PORT_TYPE_DEVICE &&
61*ec779b8eSAndroid Build Coastguard Worker checkStringOverflow(config.ext.device.address)) {
62*ec779b8eSAndroid Build Coastguard Worker status = BAD_VALUE;
63*ec779b8eSAndroid Build Coastguard Worker }
64*ec779b8eSAndroid Build Coastguard Worker return safetyNetLog(status, bugNumber);
65*ec779b8eSAndroid Build Coastguard Worker }
66*ec779b8eSAndroid Build Coastguard Worker
67*ec779b8eSAndroid Build Coastguard Worker namespace {
68*ec779b8eSAndroid Build Coastguard Worker
69*ec779b8eSAndroid Build Coastguard Worker template <typename T, std::enable_if_t<std::is_same<T, struct audio_port>::value
70*ec779b8eSAndroid Build Coastguard Worker || std::is_same<T, struct audio_port_v7>::value, int> = 0>
validateAudioPortInternal(const T & port,std::string_view bugNumber={})71*ec779b8eSAndroid Build Coastguard Worker static status_t validateAudioPortInternal(const T& port, std::string_view bugNumber = {}) {
72*ec779b8eSAndroid Build Coastguard Worker status_t status = NO_ERROR;
73*ec779b8eSAndroid Build Coastguard Worker if (checkStringOverflow(port.name)) {
74*ec779b8eSAndroid Build Coastguard Worker status = BAD_VALUE;
75*ec779b8eSAndroid Build Coastguard Worker }
76*ec779b8eSAndroid Build Coastguard Worker if (AudioValidator::validateAudioPortConfig(port.active_config) != NO_ERROR) {
77*ec779b8eSAndroid Build Coastguard Worker status = BAD_VALUE;
78*ec779b8eSAndroid Build Coastguard Worker }
79*ec779b8eSAndroid Build Coastguard Worker if (port.type == AUDIO_PORT_TYPE_DEVICE &&
80*ec779b8eSAndroid Build Coastguard Worker checkStringOverflow(port.ext.device.address)) {
81*ec779b8eSAndroid Build Coastguard Worker status = BAD_VALUE;
82*ec779b8eSAndroid Build Coastguard Worker }
83*ec779b8eSAndroid Build Coastguard Worker return safetyNetLog(status, bugNumber);
84*ec779b8eSAndroid Build Coastguard Worker }
85*ec779b8eSAndroid Build Coastguard Worker
86*ec779b8eSAndroid Build Coastguard Worker } // namespace
87*ec779b8eSAndroid Build Coastguard Worker
validateAudioPort(const struct audio_port & port,std::string_view bugNumber)88*ec779b8eSAndroid Build Coastguard Worker status_t AudioValidator::validateAudioPort(
89*ec779b8eSAndroid Build Coastguard Worker const struct audio_port& port, std::string_view bugNumber)
90*ec779b8eSAndroid Build Coastguard Worker {
91*ec779b8eSAndroid Build Coastguard Worker return validateAudioPortInternal(port, bugNumber);
92*ec779b8eSAndroid Build Coastguard Worker }
93*ec779b8eSAndroid Build Coastguard Worker
validateAudioPort(const struct audio_port_v7 & port,std::string_view bugNumber)94*ec779b8eSAndroid Build Coastguard Worker status_t AudioValidator::validateAudioPort(
95*ec779b8eSAndroid Build Coastguard Worker const struct audio_port_v7& port, std::string_view bugNumber)
96*ec779b8eSAndroid Build Coastguard Worker {
97*ec779b8eSAndroid Build Coastguard Worker return validateAudioPortInternal(port, bugNumber);
98*ec779b8eSAndroid Build Coastguard Worker }
99*ec779b8eSAndroid Build Coastguard Worker
100*ec779b8eSAndroid Build Coastguard Worker /** returns BAD_VALUE if sanitization was required. */
validateAudioPatch(const struct audio_patch & patch,std::string_view bugNumber)101*ec779b8eSAndroid Build Coastguard Worker status_t AudioValidator::validateAudioPatch(
102*ec779b8eSAndroid Build Coastguard Worker const struct audio_patch& patch, std::string_view bugNumber)
103*ec779b8eSAndroid Build Coastguard Worker {
104*ec779b8eSAndroid Build Coastguard Worker status_t status = NO_ERROR;
105*ec779b8eSAndroid Build Coastguard Worker if (patch.num_sources > AUDIO_PATCH_PORTS_MAX) {
106*ec779b8eSAndroid Build Coastguard Worker status = BAD_VALUE;
107*ec779b8eSAndroid Build Coastguard Worker }
108*ec779b8eSAndroid Build Coastguard Worker if (patch.num_sinks > AUDIO_PATCH_PORTS_MAX) {
109*ec779b8eSAndroid Build Coastguard Worker status = BAD_VALUE;
110*ec779b8eSAndroid Build Coastguard Worker }
111*ec779b8eSAndroid Build Coastguard Worker for (size_t i = 0; i < patch.num_sources; i++) {
112*ec779b8eSAndroid Build Coastguard Worker if (validateAudioPortConfig(patch.sources[i]) != NO_ERROR) {
113*ec779b8eSAndroid Build Coastguard Worker status = BAD_VALUE;
114*ec779b8eSAndroid Build Coastguard Worker }
115*ec779b8eSAndroid Build Coastguard Worker }
116*ec779b8eSAndroid Build Coastguard Worker for (size_t i = 0; i < patch.num_sinks; i++) {
117*ec779b8eSAndroid Build Coastguard Worker if (validateAudioPortConfig(patch.sinks[i]) != NO_ERROR) {
118*ec779b8eSAndroid Build Coastguard Worker status = BAD_VALUE;
119*ec779b8eSAndroid Build Coastguard Worker }
120*ec779b8eSAndroid Build Coastguard Worker }
121*ec779b8eSAndroid Build Coastguard Worker return safetyNetLog(status, bugNumber);
122*ec779b8eSAndroid Build Coastguard Worker }
123*ec779b8eSAndroid Build Coastguard Worker
124*ec779b8eSAndroid Build Coastguard Worker /* static */
validateAudioDescriptionMixLevel(float leveldB)125*ec779b8eSAndroid Build Coastguard Worker status_t AudioValidator::validateAudioDescriptionMixLevel(float leveldB)
126*ec779b8eSAndroid Build Coastguard Worker {
127*ec779b8eSAndroid Build Coastguard Worker constexpr float MAX_AUDIO_DESCRIPTION_MIX_LEVEL = 48.f;
128*ec779b8eSAndroid Build Coastguard Worker return std::isnan(leveldB) || leveldB > MAX_AUDIO_DESCRIPTION_MIX_LEVEL ? BAD_VALUE : OK;
129*ec779b8eSAndroid Build Coastguard Worker }
130*ec779b8eSAndroid Build Coastguard Worker
131*ec779b8eSAndroid Build Coastguard Worker /* static */
validateDualMonoMode(audio_dual_mono_mode_t dualMonoMode)132*ec779b8eSAndroid Build Coastguard Worker status_t AudioValidator::validateDualMonoMode(audio_dual_mono_mode_t dualMonoMode)
133*ec779b8eSAndroid Build Coastguard Worker {
134*ec779b8eSAndroid Build Coastguard Worker switch (dualMonoMode) {
135*ec779b8eSAndroid Build Coastguard Worker case AUDIO_DUAL_MONO_MODE_OFF:
136*ec779b8eSAndroid Build Coastguard Worker case AUDIO_DUAL_MONO_MODE_LR:
137*ec779b8eSAndroid Build Coastguard Worker case AUDIO_DUAL_MONO_MODE_LL:
138*ec779b8eSAndroid Build Coastguard Worker case AUDIO_DUAL_MONO_MODE_RR:
139*ec779b8eSAndroid Build Coastguard Worker return OK;
140*ec779b8eSAndroid Build Coastguard Worker }
141*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
142*ec779b8eSAndroid Build Coastguard Worker }
143*ec779b8eSAndroid Build Coastguard Worker
144*ec779b8eSAndroid Build Coastguard Worker /* static */
validatePlaybackRateFallbackMode(audio_timestretch_fallback_mode_t fallbackMode)145*ec779b8eSAndroid Build Coastguard Worker status_t AudioValidator::validatePlaybackRateFallbackMode(
146*ec779b8eSAndroid Build Coastguard Worker audio_timestretch_fallback_mode_t fallbackMode)
147*ec779b8eSAndroid Build Coastguard Worker {
148*ec779b8eSAndroid Build Coastguard Worker switch (fallbackMode) {
149*ec779b8eSAndroid Build Coastguard Worker case AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT:
150*ec779b8eSAndroid Build Coastguard Worker // This is coarse sounding timestretching used for internal debugging,
151*ec779b8eSAndroid Build Coastguard Worker // not intended for general use.
152*ec779b8eSAndroid Build Coastguard Worker break; // warning if not listed.
153*ec779b8eSAndroid Build Coastguard Worker case AUDIO_TIMESTRETCH_FALLBACK_DEFAULT:
154*ec779b8eSAndroid Build Coastguard Worker case AUDIO_TIMESTRETCH_FALLBACK_MUTE:
155*ec779b8eSAndroid Build Coastguard Worker case AUDIO_TIMESTRETCH_FALLBACK_FAIL:
156*ec779b8eSAndroid Build Coastguard Worker return OK;
157*ec779b8eSAndroid Build Coastguard Worker }
158*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
159*ec779b8eSAndroid Build Coastguard Worker }
160*ec779b8eSAndroid Build Coastguard Worker
161*ec779b8eSAndroid Build Coastguard Worker /* static */
validatePlaybackRateStretchMode(audio_timestretch_stretch_mode_t stretchMode)162*ec779b8eSAndroid Build Coastguard Worker status_t AudioValidator::validatePlaybackRateStretchMode(
163*ec779b8eSAndroid Build Coastguard Worker audio_timestretch_stretch_mode_t stretchMode)
164*ec779b8eSAndroid Build Coastguard Worker {
165*ec779b8eSAndroid Build Coastguard Worker switch (stretchMode) {
166*ec779b8eSAndroid Build Coastguard Worker case AUDIO_TIMESTRETCH_STRETCH_DEFAULT:
167*ec779b8eSAndroid Build Coastguard Worker case AUDIO_TIMESTRETCH_STRETCH_VOICE:
168*ec779b8eSAndroid Build Coastguard Worker return OK;
169*ec779b8eSAndroid Build Coastguard Worker }
170*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
171*ec779b8eSAndroid Build Coastguard Worker }
172*ec779b8eSAndroid Build Coastguard Worker
173*ec779b8eSAndroid Build Coastguard Worker /* static */
validatePlaybackRate(const audio_playback_rate_t & playbackRate)174*ec779b8eSAndroid Build Coastguard Worker status_t AudioValidator::validatePlaybackRate(
175*ec779b8eSAndroid Build Coastguard Worker const audio_playback_rate_t& playbackRate)
176*ec779b8eSAndroid Build Coastguard Worker {
177*ec779b8eSAndroid Build Coastguard Worker if (playbackRate.mSpeed < 0.f || playbackRate.mPitch < 0.f) return BAD_VALUE;
178*ec779b8eSAndroid Build Coastguard Worker return validatePlaybackRateFallbackMode(playbackRate.mFallbackMode) ?:
179*ec779b8eSAndroid Build Coastguard Worker validatePlaybackRateStretchMode(playbackRate.mStretchMode);
180*ec779b8eSAndroid Build Coastguard Worker }
181*ec779b8eSAndroid Build Coastguard Worker
182*ec779b8eSAndroid Build Coastguard Worker }; // namespace android
183