1 /*
2  * Copyright 2018 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_NDEBUG 0
18 #define LOG_TAG "Codec2-types"
19 #include <android-base/logging.h>
20 
21 #include <bufferpool/ClientManager.h>
22 #include <codec2/common/BufferTypes.h>
23 #include <codec2/common/ParamTypes.h>
24 #include <codec2/hidl/1.0/types.h>
25 
26 #include <C2AllocatorIon.h>
27 #include <C2AllocatorGralloc.h>
28 #include <C2BlockInternal.h>
29 #include <C2Buffer.h>
30 #include <C2Component.h>
31 #include <C2FenceFactory.h>
32 #include <C2PlatformSupport.h>
33 #include <C2Work.h>
34 
35 namespace android {
36 
37 using hardware::media::bufferpool::V2_0::implementation::ClientManager;
38 using hardware::media::c2::V1_0::BaseBlock;
39 using hardware::media::c2::V1_0::FieldSupportedValues;
40 using hardware::media::c2::V1_0::PrimitiveValue;
41 using hardware::media::c2::V1_0::ValueRange;
42 using hardware::media::c2::V1_0::utils::BufferPoolTypes;
43 using hardware::hidl_vec;
44 
45 // C2FieldSupportedValues -> FieldSupportedValues
46 template<>
objcpy(FieldSupportedValues * d,const C2FieldSupportedValues & s)47 bool objcpy(
48         FieldSupportedValues *d, const C2FieldSupportedValues &s) {
49     switch (s.type) {
50     case C2FieldSupportedValues::EMPTY: {
51             d->empty(::android::hidl::safe_union::V1_0::Monostate{});
52             break;
53         }
54     case C2FieldSupportedValues::RANGE: {
55             ValueRange range{};
56             if (!objcpy(&range, s.range)) {
57                 LOG(ERROR) << "Invalid C2FieldSupportedValues::range.";
58                 d->range(range);
59                 return false;
60             }
61             d->range(range);
62             break;
63         }
64     case C2FieldSupportedValues::VALUES: {
65             hidl_vec<PrimitiveValue> values;
66             copyVector<uint64_t>(&values, s.values);
67             d->values(values);
68             break;
69         }
70     case C2FieldSupportedValues::FLAGS: {
71             hidl_vec<PrimitiveValue> flags;
72             copyVector<uint64_t>(&flags, s.values);
73             d->flags(flags);
74             break;
75         }
76     default:
77         LOG(DEBUG) << "Unrecognized C2FieldSupportedValues::type_t "
78                    << "with underlying value " << underlying_value(s.type)
79                    << ".";
80         return false;
81     }
82     return true;
83 }
84 
85 // FieldSupportedValues -> C2FieldSupportedValues
86 template<>
objcpy(C2FieldSupportedValues * d,const FieldSupportedValues & s)87 bool objcpy(
88         C2FieldSupportedValues *d, const FieldSupportedValues &s) {
89     switch (s.getDiscriminator()) {
90     case FieldSupportedValues::hidl_discriminator::empty: {
91             d->type = C2FieldSupportedValues::EMPTY;
92             break;
93         }
94     case FieldSupportedValues::hidl_discriminator::range: {
95             d->type = C2FieldSupportedValues::RANGE;
96             if (!objcpy(&d->range, s.range())) {
97                 LOG(ERROR) << "Invalid FieldSupportedValues::range.";
98                 return false;
99             }
100             d->values.resize(0);
101             break;
102         }
103     case FieldSupportedValues::hidl_discriminator::values: {
104             d->type = C2FieldSupportedValues::VALUES;
105             copyVector<uint64_t>(&d->values, s.values());
106             break;
107         }
108     case FieldSupportedValues::hidl_discriminator::flags: {
109             d->type = C2FieldSupportedValues::FLAGS;
110             copyVector<uint64_t>(&d->values, s.flags());
111             break;
112         }
113     default:
114         LOG(WARNING) << "Unrecognized FieldSupportedValues::getDiscriminator()";
115         return false;
116     }
117     return true;
118 }
119 
120 template<>
objcpy(C2BaseBlock * d,const BaseBlock & s)121 bool objcpy(C2BaseBlock* d, const BaseBlock& s) {
122     switch (s.getDiscriminator()) {
123     case BaseBlock::hidl_discriminator::nativeBlock: {
124             if (s.nativeBlock() == nullptr) {
125                 LOG(ERROR) << "Null BaseBlock::nativeBlock handle";
126                 return false;
127             }
128             native_handle_t* sHandle =
129                     native_handle_clone(s.nativeBlock());
130             if (sHandle == nullptr) {
131                 LOG(ERROR) << "Null BaseBlock::nativeBlock.";
132                 return false;
133             }
134             const C2Handle *sC2Handle =
135                     reinterpret_cast<const C2Handle*>(sHandle);
136 
137             d->linear = _C2BlockFactory::CreateLinearBlock(sC2Handle);
138             if (d->linear) {
139                 d->type = C2BaseBlock::LINEAR;
140                 return true;
141             }
142 
143             d->graphic = _C2BlockFactory::CreateGraphicBlock(sC2Handle);
144             if (d->graphic) {
145                 d->type = C2BaseBlock::GRAPHIC;
146                 return true;
147             }
148 
149             LOG(ERROR) << "Unknown handle type in BaseBlock::nativeBlock.";
150             if (sHandle) {
151                 native_handle_close(sHandle);
152                 native_handle_delete(sHandle);
153             }
154             return false;
155         }
156     case BaseBlock::hidl_discriminator::pooledBlock: {
157             const BufferPoolTypes::BufferStatusMessage &bpMessage =
158                     s.pooledBlock();
159             sp<ClientManager> bp = ClientManager::getInstance();
160             std::shared_ptr<BufferPoolTypes::BufferPoolData> bpData;
161             native_handle_t *cHandle;
162             BufferPoolTypes::BufferPoolStatus bpStatus = bp->receive(
163                     bpMessage.connectionId,
164                     bpMessage.transactionId,
165                     bpMessage.bufferId,
166                     bpMessage.timestampUs,
167                     &cHandle,
168                     &bpData);
169             if (bpStatus != BufferPoolTypes::ResultStatus::OK) {
170                 LOG(ERROR) << "Failed to receive buffer from bufferpool -- "
171                            << "resultStatus = " << underlying_value(bpStatus)
172                            << ".";
173                 return false;
174             } else if (!bpData) {
175                 LOG(ERROR) << "No data in bufferpool transaction.";
176                 return false;
177             }
178 
179             d->linear = _C2BlockFactory::CreateLinearBlock(cHandle, bpData);
180             if (d->linear) {
181                 d->type = C2BaseBlock::LINEAR;
182                 return true;
183             }
184 
185             d->graphic = _C2BlockFactory::CreateGraphicBlock(cHandle, bpData);
186             if (d->graphic) {
187                 d->type = C2BaseBlock::GRAPHIC;
188                 return true;
189             }
190             if (cHandle) {
191                 // Though we got cloned handle, creating block failed.
192                 native_handle_close(cHandle);
193                 native_handle_delete(cHandle);
194             }
195 
196             LOG(ERROR) << "Unknown handle type in BaseBlock::pooledBlock.";
197             return false;
198         }
199     default:
200         LOG(ERROR) << "Unrecognized BaseBlock's discriminator with "
201                    << "underlying value "
202                    << underlying_value(s.getDiscriminator()) << ".";
203         return false;
204     }
205 }
206 
207 template<>
SetHandle(BaseBlock * block,const C2Handle * handle)208 void SetHandle(BaseBlock *block, const C2Handle *handle) {
209     block->nativeBlock(reinterpret_cast<const native_handle_t*>(handle));
210 }
211 
212 template<>
SetAHardwareBuffer(BaseBlock * block,AHardwareBuffer * pBuf)213 void SetAHardwareBuffer(BaseBlock *block, AHardwareBuffer *pBuf) {
214     (void) block;
215     (void) pBuf;
216     LOG(FATAL) << "This is not used";
217 }
218 
219 template<>
SetPooledBlock(BaseBlock * baseBlock,const typename BufferPoolTypes::BufferStatusMessage & pooledBlock)220 void SetPooledBlock<BufferPoolTypes>(
221         BaseBlock *baseBlock,
222         const typename BufferPoolTypes::BufferStatusMessage &pooledBlock) {
223     baseBlock->pooledBlock(pooledBlock);
224 }
225 
226 template<>
GetBufferPoolData(const std::shared_ptr<const _C2BlockPoolData> & blockPoolData,std::shared_ptr<typename BufferPoolTypes::BufferPoolData> * bpData)227 bool GetBufferPoolData<BufferPoolTypes>(
228         const std::shared_ptr<const _C2BlockPoolData>& blockPoolData,
229         std::shared_ptr<typename BufferPoolTypes::BufferPoolData> *bpData) {
230     return _C2BlockFactory::GetBufferPoolData(blockPoolData, bpData);
231 }
232 
233 namespace hardware {
234 namespace media {
235 namespace c2 {
236 namespace V1_0 {
237 namespace utils {
238 
239 using ::android::hardware::media::bufferpool::BufferPoolData;
240 using ::android::hardware::media::bufferpool::V2_0::ResultStatus;
241 using ::android::hardware::media::bufferpool::V2_0::implementation::
242         TransactionId;
243 
asString(Status status,const char * def)244 const char* asString(Status status, const char* def) {
245     return asString(static_cast<c2_status_t>(status), def);
246 }
247 
248 // C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
objcpy(FieldSupportedValuesQuery * d,const C2FieldSupportedValuesQuery & s)249 bool objcpy(
250         FieldSupportedValuesQuery* d,
251         const C2FieldSupportedValuesQuery& s) {
252     return ::android::objcpy(d, nullptr, s);
253 }
254 
255 // FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
objcpy(C2FieldSupportedValuesQuery * d,const FieldSupportedValuesQuery & s)256 bool objcpy(
257         C2FieldSupportedValuesQuery* d,
258         const FieldSupportedValuesQuery& s) {
259     return ::android::objcpy(d, s);
260 }
261 
262 // C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
objcpy(FieldSupportedValuesQueryResult * d,const C2FieldSupportedValuesQuery & s)263 bool objcpy(
264         FieldSupportedValuesQueryResult* d,
265         const C2FieldSupportedValuesQuery& s) {
266     return ::android::objcpy(nullptr, d, s);
267 }
268 
269 // FieldSupportedValuesQuery, FieldSupportedValuesQueryResult ->
270 // C2FieldSupportedValuesQuery
objcpy(C2FieldSupportedValuesQuery * d,const FieldSupportedValuesQuery & sq,const FieldSupportedValuesQueryResult & sr)271 bool objcpy(
272         C2FieldSupportedValuesQuery* d,
273         const FieldSupportedValuesQuery& sq,
274         const FieldSupportedValuesQueryResult& sr) {
275     return ::android::objcpy(d, sq, sr);
276 }
277 
278 // C2Component::Traits -> IComponentStore::ComponentTraits
objcpy(IComponentStore::ComponentTraits * d,const C2Component::Traits & s)279 bool objcpy(
280         IComponentStore::ComponentTraits *d,
281         const C2Component::Traits &s) {
282     return ::android::objcpy(d, s);
283 }
284 
285 // ComponentTraits -> C2Component::Traits, std::unique_ptr<std::vector<std::string>>
objcpy(C2Component::Traits * d,const IComponentStore::ComponentTraits & s)286 bool objcpy(
287         C2Component::Traits* d,
288         const IComponentStore::ComponentTraits& s) {
289     return ::android::objcpy(d, s);
290 }
291 
292 // C2SettingResult -> SettingResult
objcpy(SettingResult * d,const C2SettingResult & s)293 bool objcpy(SettingResult *d, const C2SettingResult &s) {
294     return ::android::objcpy(d, s);
295 }
296 
297 // SettingResult -> std::unique_ptr<C2SettingResult>
objcpy(std::unique_ptr<C2SettingResult> * d,const SettingResult & s)298 bool objcpy(std::unique_ptr<C2SettingResult> *d, const SettingResult &s) {
299     return ::android::objcpy(d, s);
300 }
301 
302 // C2ParamDescriptor -> ParamDescriptor
objcpy(ParamDescriptor * d,const C2ParamDescriptor & s)303 bool objcpy(ParamDescriptor *d, const C2ParamDescriptor &s) {
304     return ::android::objcpy(d, s);
305 }
306 
307 // ParamDescriptor -> C2ParamDescriptor
objcpy(std::shared_ptr<C2ParamDescriptor> * d,const ParamDescriptor & s)308 bool objcpy(std::shared_ptr<C2ParamDescriptor> *d, const ParamDescriptor &s) {
309     return ::android::objcpy(d, s);
310 }
311 
312 // C2StructDescriptor -> StructDescriptor
objcpy(StructDescriptor * d,const C2StructDescriptor & s)313 bool objcpy(StructDescriptor *d, const C2StructDescriptor &s) {
314     return ::android::objcpy(d, s);
315 }
316 
317 // StructDescriptor -> C2StructDescriptor
objcpy(std::unique_ptr<C2StructDescriptor> * d,const StructDescriptor & s)318 bool objcpy(std::unique_ptr<C2StructDescriptor> *d, const StructDescriptor &s) {
319     return ::android::objcpy(d, s);
320 }
321 
322 // DefaultBufferPoolSender's implementation
323 
DefaultBufferPoolSender(const sp<IClientManager> & receiverManager,std::chrono::steady_clock::duration refreshInterval)324 DefaultBufferPoolSender::DefaultBufferPoolSender(
325         const sp<IClientManager>& receiverManager,
326         std::chrono::steady_clock::duration refreshInterval)
327     : mReceiverManager(receiverManager),
328       mRefreshInterval(refreshInterval) {
329 }
330 
setReceiver(const sp<IClientManager> & receiverManager,std::chrono::steady_clock::duration refreshInterval)331 void DefaultBufferPoolSender::setReceiver(
332         const sp<IClientManager>& receiverManager,
333         std::chrono::steady_clock::duration refreshInterval) {
334     std::lock_guard<std::mutex> lock(mMutex);
335     if (mReceiverManager != receiverManager) {
336         mReceiverManager = receiverManager;
337         mConnections.clear();
338     }
339     mRefreshInterval = refreshInterval;
340 }
341 
send(const std::shared_ptr<BufferPoolData> & bpData,BufferStatusMessage * bpMessage)342 ResultStatus DefaultBufferPoolSender::send(
343         const std::shared_ptr<BufferPoolData>& bpData,
344         BufferStatusMessage* bpMessage) {
345     int64_t connectionId = bpData->mConnectionId;
346     if (connectionId == 0) {
347         LOG(WARNING) << "registerSender -- invalid sender connection id (0).";
348         return ResultStatus::CRITICAL_ERROR;
349     }
350     std::lock_guard<std::mutex> lock(mMutex);
351     if (!mReceiverManager) {
352         LOG(ERROR) << "No access to receiver's BufferPool.";
353         return ResultStatus::NOT_FOUND;
354     }
355     if (!mSenderManager) {
356         mSenderManager = ClientManager::getInstance();
357         if (!mSenderManager) {
358             LOG(ERROR) << "Failed to retrieve local BufferPool ClientManager.";
359             return ResultStatus::CRITICAL_ERROR;
360         }
361     }
362 
363     int64_t receiverConnectionId{0};
364     auto foundConnection = mConnections.find(connectionId);
365     bool isNewConnection = foundConnection == mConnections.end();
366     std::chrono::steady_clock::time_point now =
367             std::chrono::steady_clock::now();
368     if (isNewConnection ||
369             (now - foundConnection->second.lastSent > mRefreshInterval)) {
370         // Initialize the bufferpool connection.
371         ResultStatus rs =
372                 mSenderManager->registerSender(mReceiverManager,
373                                                connectionId,
374                                                &receiverConnectionId);
375         if ((rs != ResultStatus::OK) && (rs != ResultStatus::ALREADY_EXISTS)) {
376             LOG(WARNING) << "registerSender -- returned error: "
377                          << static_cast<int32_t>(rs)
378                          << ".";
379             return rs;
380         } else if (receiverConnectionId == 0) {
381             LOG(WARNING) << "registerSender -- "
382                             "invalid receiver connection id (0).";
383             return ResultStatus::CRITICAL_ERROR;
384         } else {
385             if (isNewConnection) {
386                 foundConnection = mConnections.try_emplace(
387                         connectionId, receiverConnectionId, now).first;
388             } else {
389                 foundConnection->second.receiverConnectionId = receiverConnectionId;
390             }
391         }
392     } else {
393         receiverConnectionId = foundConnection->second.receiverConnectionId;
394     }
395 
396     uint64_t transactionId;
397     int64_t timestampUs;
398     ResultStatus rs = mSenderManager->postSend(
399             receiverConnectionId, bpData, &transactionId, &timestampUs);
400     if (rs != ResultStatus::OK) {
401         LOG(ERROR) << "ClientManager::postSend -- returned error: "
402                    << static_cast<int32_t>(rs)
403                    << ".";
404         mConnections.erase(foundConnection);
405         return rs;
406     }
407     if (!bpMessage) {
408         LOG(ERROR) << "Null output parameter for BufferStatusMessage.";
409         mConnections.erase(foundConnection);
410         return ResultStatus::CRITICAL_ERROR;
411     }
412     bpMessage->connectionId = receiverConnectionId;
413     bpMessage->bufferId = bpData->mId;
414     bpMessage->transactionId = transactionId;
415     bpMessage->timestampUs = timestampUs;
416     foundConnection->second.lastSent = now;
417     return rs;
418 }
419 
420 // std::list<std::unique_ptr<C2Work>> -> WorkBundle
objcpy(WorkBundle * d,const std::list<std::unique_ptr<C2Work>> & s,BufferPoolSender * bufferPoolSender)421 bool objcpy(
422         WorkBundle* d,
423         const std::list<std::unique_ptr<C2Work>>& s,
424         BufferPoolSender* bufferPoolSender) {
425     return ::android::objcpy(d, s, bufferPoolSender);
426 }
427 
428 // WorkBundle -> std::list<std::unique_ptr<C2Work>>
objcpy(std::list<std::unique_ptr<C2Work>> * d,const WorkBundle & s)429 bool objcpy(std::list<std::unique_ptr<C2Work>>* d, const WorkBundle& s) {
430     return ::android::objcpy(d, s);
431 }
432 
433 // Params -> std::vector<C2Param*>
parseParamsBlob(std::vector<C2Param * > * params,const hidl_vec<uint8_t> & blob)434 bool parseParamsBlob(std::vector<C2Param*> *params, const hidl_vec<uint8_t> &blob) {
435     return ::android::parseParamsBlob(params, blob);
436 }
437 
438 // std::vector<const C2Param*> -> Params
createParamsBlob(hidl_vec<uint8_t> * blob,const std::vector<const C2Param * > & params)439 bool createParamsBlob(
440         hidl_vec<uint8_t> *blob,
441         const std::vector<const C2Param*> &params) {
442     return ::android::_createParamsBlob(blob, params);
443 }
444 
445 // std::vector<C2Param*> -> Params
createParamsBlob(hidl_vec<uint8_t> * blob,const std::vector<C2Param * > & params)446 bool createParamsBlob(
447         hidl_vec<uint8_t> *blob,
448         const std::vector<C2Param*> &params) {
449     return ::android::_createParamsBlob(blob, params);
450 }
451 
452 // std::vector<std::unique_ptr<C2Param>> -> Params
createParamsBlob(hidl_vec<uint8_t> * blob,const std::vector<std::unique_ptr<C2Param>> & params)453 bool createParamsBlob(
454         hidl_vec<uint8_t> *blob,
455         const std::vector<std::unique_ptr<C2Param>> &params) {
456     return ::android::_createParamsBlob(blob, params);
457 }
458 
459 // std::vector<std::unique_ptr<C2Tuning>> -> Params
createParamsBlob(hidl_vec<uint8_t> * blob,const std::vector<std::unique_ptr<C2Tuning>> & params)460 bool createParamsBlob(
461         hidl_vec<uint8_t> *blob,
462         const std::vector<std::unique_ptr<C2Tuning>> &params) {
463     return ::android::_createParamsBlob(blob, params);
464 }
465 
466 // std::vector<std::shared_ptr<const C2Info>> -> Params
createParamsBlob(hidl_vec<uint8_t> * blob,const std::vector<std::shared_ptr<const C2Info>> & params)467 bool createParamsBlob(
468         hidl_vec<uint8_t> *blob,
469         const std::vector<std::shared_ptr<const C2Info>> &params) {
470     return ::android::_createParamsBlob(blob, params);
471 }
472 
473 // Params -> std::vector<std::unique_ptr<C2Param>>
copyParamsFromBlob(std::vector<std::unique_ptr<C2Param>> * params,Params blob)474 bool copyParamsFromBlob(
475         std::vector<std::unique_ptr<C2Param>>* params,
476         Params blob) {
477     return ::android::_copyParamsFromBlob(params, blob);
478 }
479 
480 // Params -> std::vector<std::unique_ptr<C2Tuning>>
copyParamsFromBlob(std::vector<std::unique_ptr<C2Tuning>> * params,Params blob)481 bool copyParamsFromBlob(
482         std::vector<std::unique_ptr<C2Tuning>>* params,
483         Params blob) {
484     return ::android::_copyParamsFromBlob(params, blob);
485 }
486 
487 // Params -> update std::vector<std::unique_ptr<C2Param>>
updateParamsFromBlob(const std::vector<C2Param * > & params,const Params & blob)488 bool updateParamsFromBlob(
489         const std::vector<C2Param*>& params,
490         const Params& blob) {
491     return ::android::updateParamsFromBlob(params, blob);
492 }
493 
494 // Convert BufferPool ResultStatus to c2_status_t.
toC2Status(ResultStatus rs)495 c2_status_t toC2Status(ResultStatus rs) {
496     switch (rs) {
497     case ResultStatus::OK:
498         return C2_OK;
499     case ResultStatus::NO_MEMORY:
500         return C2_NO_MEMORY;
501     case ResultStatus::ALREADY_EXISTS:
502         return C2_DUPLICATE;
503     case ResultStatus::NOT_FOUND:
504         return C2_NOT_FOUND;
505     case ResultStatus::CRITICAL_ERROR:
506         return C2_CORRUPTED;
507     default:
508         LOG(WARNING) << "Unrecognized BufferPool ResultStatus: "
509                      << static_cast<int32_t>(rs) << ".";
510         return C2_CORRUPTED;
511     }
512 }
513 
514 // BufferQueue-Based Block Operations
beginTransferBufferQueueBlock(const C2ConstGraphicBlock & block)515 bool beginTransferBufferQueueBlock(const C2ConstGraphicBlock& block) {
516     return ::android::BeginTransferBufferQueueBlock(block);
517 }
518 
beginTransferBufferQueueBlocks(const std::list<std::unique_ptr<C2Work>> & workList,bool processInput,bool processOutput)519 void beginTransferBufferQueueBlocks(
520         const std::list<std::unique_ptr<C2Work>>& workList,
521         bool processInput,
522         bool processOutput) {
523     return ::android::BeginTransferBufferQueueBlocks(
524             workList, processInput, processOutput);
525 }
526 
endTransferBufferQueueBlock(const C2ConstGraphicBlock & block,bool transfer)527 bool endTransferBufferQueueBlock(const C2ConstGraphicBlock& block,
528                                  bool transfer) {
529     return ::android::EndTransferBufferQueueBlock(block, transfer);
530 }
531 
endTransferBufferQueueBlocks(const std::list<std::unique_ptr<C2Work>> & workList,bool transfer,bool processInput,bool processOutput)532 void endTransferBufferQueueBlocks(
533         const std::list<std::unique_ptr<C2Work>>& workList,
534         bool transfer,
535         bool processInput,
536         bool processOutput) {
537     return ::android::EndTransferBufferQueueBlocks(
538             workList, transfer, processInput, processOutput);
539 }
540 
displayBufferQueueBlock(const C2ConstGraphicBlock & block)541 bool displayBufferQueueBlock(const C2ConstGraphicBlock& block) {
542     return ::android::DisplayBufferQueueBlock(block);
543 }
544 
545 }  // namespace utils
546 }  // namespace V1_0
547 }  // namespace c2
548 }  // namespace media
549 }  // namespace hardware
550 }  // namespace android
551 
552