• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 #pragma once
18 
19 #include <algorithm>
20 #include <cstddef>
21 #include <cstdint>
22 #include <cstring>
23 #include <sstream>
24 #include <string>
25 #include <sys/types.h>
26 #include <type_traits>
27 #include <utils/Errors.h>
28 
29 #include <system/audio_effect.h>
30 
31 namespace android {
32 namespace effect {
33 namespace utils {
34 
35 /**
36  * A wrapper class of legacy effect_param_t to avoid raw pointer read/write everywhere.
37  * The wrapper use the reference of underlying effect_param_t structure, and does not manage
38  * ownership of the structure.
39  * Thread safety is not in consideration in this class for now.
40  */
41 class EffectParamWrapper {
42  public:
EffectParamWrapper(const effect_param_t & param)43   explicit EffectParamWrapper(const effect_param_t& param) : mParam(param) {}
44 
45   // validate command size to be at least parameterSize + valueSize after effect_param_t
validateCmdSize(size_t cmdSize)46   bool validateCmdSize(size_t cmdSize) const {
47     return (uint64_t)getPaddedParameterSize() + mParam.vsize + sizeof(effect_param_t) <=
48            cmdSize;
49   }
50 
51   /**
52    *  validate parameter and value size to be at least equals to the target size.
53    */
validateParamValueSize(size_t paramSize,size_t valueSize)54   bool validateParamValueSize(size_t paramSize, size_t valueSize) const {
55     return mParam.psize >= paramSize && mParam.vsize >= valueSize;
56   }
57 
toString()58   std::string toString() const {
59     std::ostringstream os;
60     os << "effect_param_t: { ";
61     os << "status: " << mParam.status << ", p: " << mParam.psize
62        << " (padded: " << getPaddedParameterSize() << "), v: " << mParam.vsize
63        << ", dataAddr: " << &mParam.data;
64     os << "}";
65     return os.str();
66   }
67 
copyDataWithCheck(void * dst,const void * src,size_t len,size_t offset,size_t max)68   status_t copyDataWithCheck(void* dst, const void* src, size_t len,
69                                     size_t offset, size_t max) {
70     if (!dst || !src || len + offset > max) {
71       return BAD_VALUE;
72     }
73     std::memcpy(dst, src, len);
74     return OK;
75   }
76 
readFromData(void * buf,size_t len,size_t offset,size_t max)77   status_t readFromData(void* buf, size_t len, size_t offset, size_t max) {
78     return copyDataWithCheck(buf, mParam.data + offset, len, offset, max);
79   }
80 
getStatus()81   status_t getStatus() const { return mParam.status; }
getPaddedParameterSize()82   size_t getPaddedParameterSize() const { return padding(mParam.psize); }
getParameterSize()83   size_t getParameterSize() const { return mParam.psize; }
getValueSize()84   size_t getValueSize() const { return mParam.vsize; }
getValueAddress()85   const uint8_t* getValueAddress() const {
86     return (uint8_t*)mParam.data + getPaddedParameterSize();
87   }
88 
getTotalSize()89   uint64_t getTotalSize() const {
90     return (uint64_t)sizeof(effect_param_t) + getPaddedParameterSize() + getValueSize();
91   }
92 
93   /**
94    * Get reference to effect_param_t.
95    */
getEffectParam()96   const effect_param_t& getEffectParam() const { return mParam; }
97 
98   bool operator==(const EffectParamWrapper& other) const {
99     return (&other == this) || 0 == std::memcmp(&mParam, &other.mParam, sizeof(effect_param_t));
100   }
101 
102   /**
103    * Padding psize to 32 bits aligned, because "start of value field inside
104    * the data field is always on a 32 bits boundary".
105    */
padding(size_t size)106   static constexpr inline size_t padding(size_t size) {
107     return ((size - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
108   }
109 
110  private:
111   /* member with variable sized type at end of class */
112   const effect_param_t& mParam;
113 };
114 
115 /**
116  * Reader class of effect_param_t data buffer.
117  */
118 class EffectParamReader : public EffectParamWrapper {
119  public:
EffectParamReader(const effect_param_t & param)120   explicit EffectParamReader(const effect_param_t& param)
121       : EffectParamWrapper(param), mValueROffset(getPaddedParameterSize()) {}
122 
123   /**
124    * Read n value of type T from data to buf, mParamROffset will advance n * sizeof(T) if success,
125    * no advance if failure.
126    */
127   template <typename T>
128   status_t readFromParameter(T* buf, size_t n = 1) {
129     size_t len = n * sizeof(T);
130     status_t ret = readFromData(buf, len, mParamROffset /* param offset */,
131                                 getParameterSize() /* max offset */);
132     if (OK == ret) {
133        mParamROffset += len;
134     }
135     return ret;
136   }
137 
138   /**
139    * Read number of value in type T from data to buf, mValueROffset will advance n * sizeof(T) if
140    * success, no advance if failure.
141    */
142   template <typename T>
143   status_t readFromValue(T* buf, size_t n = 1) {
144     size_t len = n * sizeof(T);
145     status_t ret = readFromData(buf, len, mValueROffset /* data offset */,
146                                 getPaddedParameterSize() + getValueSize() /* max offset */);
147     if (OK == ret) {
148        mValueROffset += len;
149     }
150     return ret;
151   }
152 
toString()153   std::string toString() const {
154     std::ostringstream os;
155     os << EffectParamWrapper::toString();
156     os << ", paramROffset: " << mParamROffset;
157     os << ", valueROffset: " << mValueROffset;
158     return os.str();
159   }
160 
reset()161   void reset() {
162     mParamROffset = 0;
163     mValueROffset = getPaddedParameterSize();
164   }
165 
166  private:
167   size_t mParamROffset = 0;
168   size_t mValueROffset = 0;
169 };
170 
171 /**
172  * Writer class of effect_param_t data buffer.
173  */
174 class EffectParamWriter : public EffectParamReader {
175  public:
EffectParamWriter(effect_param_t & param)176   explicit EffectParamWriter(effect_param_t& param)
177       : EffectParamReader(param), mParam(param), mValueWOffset(getPaddedParameterSize()) {
178   }
179 
180   /**
181    * Write n number of param in type T from buf to data, mParamWOffset will advance n * sizeof(T)
182    * if success, no advance if failure.
183    */
184   template <typename T>
185   status_t writeToParameter(const T* buf, size_t n = 1) {
186     size_t len = n * sizeof(T);
187     status_t ret = writeToData(buf, len, mParamWOffset /* data offset */,
188                                getParameterSize() /* max */);
189     if (OK == ret) {
190        mParamWOffset += len;
191     }
192     return ret;
193   }
194 
writeToData(const void * buf,size_t len,size_t offset,size_t max)195   status_t writeToData(const void* buf, size_t len, size_t offset, size_t max) {
196     return copyDataWithCheck(mParam.data + offset, buf, len, offset, max);
197   }
198   /**
199    * Write n number of value in type T from buf to data, mValueWOffset will advance n * sizeof(T)
200    * if success, no advance if failure.
201    */
202   template <typename T>
203   status_t writeToValue(const T* buf, size_t n = 1) {
204     size_t len = n * sizeof(T);
205     status_t ret = writeToData(buf, len, mValueWOffset /* data offset */,
206                                getPaddedParameterSize() + getValueSize() /* max */);
207     if (OK == ret) {
208        mValueWOffset += len;
209     }
210     return ret;
211   }
212 
213   /**
214    * Set the current value write offset to vsize.
215    * Together with getTotalSize(), can be used by getParameter to set replySize.
216    */
finishValueWrite()217   void finishValueWrite() { mParam.vsize = mValueWOffset - getPaddedParameterSize(); }
218 
setStatus(status_t status)219   void setStatus(status_t status) { mParam.status = status; }
220 
221   /**
222    * Overwrite the entire effect_param_t with input.
223    */
overwrite(const effect_param_t & param)224   status_t overwrite(const effect_param_t& param) {
225     EffectParamReader reader(param);
226     const auto size = reader.getTotalSize();
227     if (size > getTotalSize()) {
228        return BAD_VALUE;
229     }
230     std::memcpy((void *)&mParam, (void *)&reader.getEffectParam(), size);
231     reset();
232     mValueWOffset += reader.getValueSize();
233     return OK;
234   }
235 
236   /**
237    * Reset the offsets with underlying effect_param_t.
238    */
reset()239   void reset() {
240     EffectParamReader::reset();
241     mParamWOffset = 0;
242     mValueWOffset = getPaddedParameterSize();
243   }
244 
toString()245   std::string toString() const {
246     std::ostringstream os;
247     os << EffectParamReader::toString();
248     os << ", paramWOffset: " << mParamWOffset;
249     os << ", valueWOffset: " << mValueWOffset;
250     return os.str();
251   }
252 
253  private:
254   effect_param_t& mParam;
255   size_t mParamWOffset = 0;
256   size_t mValueWOffset = 0;
257 };
258 
ToString(const audio_uuid_t & uuid)259 inline std::string ToString(const audio_uuid_t& uuid) {
260     char str[64];
261     snprintf(str, sizeof(str), "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
262              uuid.timeLow, uuid.timeMid, uuid.timeHiAndVersion, uuid.clockSeq,
263              uuid.node[0], uuid.node[1], uuid.node[2], uuid.node[3],
264              uuid.node[4], uuid.node[5]);
265     return str;
266 }
267 
268 inline bool operator==(const audio_uuid_t& lhs, const audio_uuid_t& rhs) {
269   return lhs.timeLow == rhs.timeLow && lhs.timeMid == rhs.timeMid &&
270          lhs.timeHiAndVersion == rhs.timeHiAndVersion &&
271          lhs.clockSeq == rhs.clockSeq &&
272          std::memcmp(lhs.node, rhs.node, sizeof(lhs.node)) == 0;
273 }
274 
275 inline bool operator!=(const audio_uuid_t& lhs, const audio_uuid_t& rhs) {
276     return !(lhs == rhs);
277 }
278 
279 /**
280  * @brief Helper function to write a single parameter (type P) and value (type
281  * V) to effect_param_t, with optional buffer size check.
282  *
283  * Type P and V must be trivially copyable type to ensure safe copying to the
284  * effect_param_t structure.
285  *
286  * Usage:
287  *   effect_param_t *param = (effect_param_t *)buf;
288  *   if (OK != android::effect::utils::writeToEffectParam(param, p, v)) {
289  *       // error handling
290  *   }
291  *
292  * @param param The pointer to effect_param_t buffer.
293  * @param p The parameter to write into effect_param_t, 32 bit padded.
294  * @param v The value to write into effect_param_t, start of value field inside
295  * the data field is always on a 32 bits boundary.
296  * @param bufSize OPTIONAL: The size of the buffer pointer to effect_param_t. If
297  * a valid bufSize provide, it will be used to verify if it's big enough to
298  * write both param and value.
299  * @return status_t OK on success, BAD_VALUE on any failure.
300  * Specifically, BAD_VALUE is returned if:
301  * - The `param` pointer is null.
302  * - The `bufSize` is provided and is insufficient to hold the data.
303  */
304 template <typename P, typename V>
requires(std::is_trivially_copyable_v<P> && std::is_trivially_copyable_v<V>)305   requires(std::is_trivially_copyable_v<P> && std::is_trivially_copyable_v<V>)
306 status_t writeToEffectParam(effect_param_t* param, const P p, const V v,
307                             size_t bufSize = 0) {
308   const size_t pSize = EffectParamWrapper::padding(sizeof(P)),
309                vSize = sizeof(V);
310   if (!param ||
311       (bufSize != 0 && bufSize < sizeof(effect_param_t) + pSize + vSize)) {
312     return BAD_VALUE;
313   }
314 
315   param->psize = pSize;
316   param->vsize = vSize;
317   EffectParamWriter writer(*param);
318 
319   status_t ret = writer.writeToParameter(&p);
320   return ret == OK ? writer.writeToValue(&v) : ret;
321 }
322 
323 /**
324  * @brief Helper function to read a single parameter (type P) and value (type V)
325  * from effect_param_t.
326  *
327  * Type P and V must be trivially copyable type to ensure safe copying from the
328  * effect_param_t structure.
329  *
330  * Usage:
331  *   effect_param_t *param = (effect_param_t *)buf;
332  *   if (OK != android::effect::utils::readFromEffectParam(param, &p, &v)) {
333  *       // error handling
334  *   }
335  *
336  * @param param The pointer to effect_param_t buffer.
337  * @param p The pointer to the return parameter read from effect_param_t.
338  * @param v The pointer to the return value read from effect_param_t.
339  * @return status_t OK on success, BAD_VALUE on any failure.
340  * Specifically, BAD_VALUE is returned if:
341  * - Any of `param`, `p`, or `v` pointers is null.
342  * - The `psize` or `vsize` is smaller than the size of `P` and `V`.
343  *
344  * **Important:** Even in case of an error (return value `BAD_VALUE`), the
345  * memory location pointed to by `p` might be updated.
346  */
347 template <typename P, typename V>
requires(std::is_trivially_copyable_v<P> && std::is_trivially_copyable_v<V>)348   requires(std::is_trivially_copyable_v<P> && std::is_trivially_copyable_v<V>)
349 status_t readFromEffectParam(const effect_param_t* param, P* p, V* v) {
350   if (!param || !p || !v) return BAD_VALUE;
351 
352   const size_t pSize = sizeof(P), vSize = sizeof(V);
353   EffectParamReader reader(*param);
354   if (!reader.validateParamValueSize(pSize, vSize)) return BAD_VALUE;
355 
356   status_t ret = reader.readFromParameter(p);
357   return ret == OK ? reader.readFromValue(v) : ret;
358 }
359 
360 }  // namespace utils
361 }  // namespace effect
362 }  // namespace android
363