client.cpp revision 1c19944e022e628356404ea731640e144401e7e2
1/*
2 * Copyright (C) 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 "Codec2Client"
19#include <log/log.h>
20
21#include <codec2/hidl/client.h>
22
23#include <hardware/google/media/c2/1.0/IComponentListener.h>
24#include <hardware/google/media/c2/1.0/IConfigurable.h>
25#include <hardware/google/media/c2/1.0/IComponentInterface.h>
26#include <hardware/google/media/c2/1.0/IComponent.h>
27#include <hardware/google/media/c2/1.0/IComponentStore.h>
28#include <android/hardware/media/bufferpool/1.0/IClientManager.h>
29
30#include <C2PlatformSupport.h>
31#include <C2BufferPriv.h>
32#include <C2Debug.h>
33#include <bufferpool/ClientManager.h>
34#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
35#include <hidl/HidlSupport.h>
36#include <cutils/properties.h>
37
38#include <deque>
39#include <limits>
40#include <map>
41#include <type_traits>
42#include <vector>
43
44namespace android {
45
46using ::android::hardware::hidl_vec;
47using ::android::hardware::hidl_string;
48using ::android::hardware::Return;
49using ::android::hardware::Void;
50
51using namespace ::hardware::google::media::c2::V1_0;
52using namespace ::hardware::google::media::c2::V1_0::utils;
53using namespace ::android::hardware::media::bufferpool::V1_0;
54using namespace ::android::hardware::media::bufferpool::V1_0::implementation;
55
56namespace /* unnamed */ {
57
58// c2_status_t value that corresponds to hwbinder transaction failure.
59constexpr c2_status_t C2_TRANSACTION_FAILED = C2_CORRUPTED;
60
61// List of known IComponentStore services.
62constexpr const char* kClientNames[] = {
63        "default",
64        "software",
65    };
66
67typedef std::array<
68        std::shared_ptr<Codec2Client>,
69        std::extent<decltype(kClientNames)>::value> ClientList;
70
71// Convenience methods to obtain known clients.
72size_t getClientCount() {
73    // TODO: this may not work if there is no default service
74    return std::extent<decltype(kClientNames)>::value;
75}
76
77std::shared_ptr<Codec2Client> getClient(size_t index) {
78    return Codec2Client::CreateFromService(kClientNames[index]);
79}
80
81ClientList getClientList() {
82    ClientList list;
83    for (size_t i = 0; i < list.size(); ++i) {
84        list[i] = getClient(i);
85    }
86    return list;
87}
88
89} // unnamed
90
91// Codec2ConfigurableClient
92
93const C2String& Codec2ConfigurableClient::getName() const {
94    return mName;
95}
96
97Codec2ConfigurableClient::Base* Codec2ConfigurableClient::base() const {
98    return static_cast<Base*>(mBase.get());
99}
100
101Codec2ConfigurableClient::Codec2ConfigurableClient(
102        const sp<Codec2ConfigurableClient::Base>& base) : mBase(base) {
103    Return<void> transStatus = base->getName(
104            [this](const hidl_string& name) {
105                mName = name.c_str();
106            });
107    if (!transStatus.isOk()) {
108        ALOGE("Cannot obtain name from IConfigurable.");
109    }
110}
111
112c2_status_t Codec2ConfigurableClient::query(
113        const std::vector<C2Param*> &stackParams,
114        const std::vector<C2Param::Index> &heapParamIndices,
115        c2_blocking_t mayBlock,
116        std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
117    hidl_vec<ParamIndex> indices(
118            stackParams.size() + heapParamIndices.size());
119    size_t numIndices = 0;
120    for (C2Param* const& stackParam : stackParams) {
121        if (!stackParam) {
122            ALOGW("query -- null stack param encountered.");
123            continue;
124        }
125        indices[numIndices++] = static_cast<ParamIndex>(stackParam->index());
126    }
127    size_t numStackIndices = numIndices;
128    for (const C2Param::Index& index : heapParamIndices) {
129        indices[numIndices++] =
130                static_cast<ParamIndex>(static_cast<uint32_t>(index));
131    }
132    indices.resize(numIndices);
133    if (heapParams) {
134        heapParams->reserve(heapParams->size() + numIndices);
135    }
136    c2_status_t status;
137    Return<void> transStatus = base()->query(
138            indices,
139            mayBlock == C2_MAY_BLOCK,
140            [&status, &numStackIndices, &stackParams, heapParams](
141                    Status s, const Params& p) {
142                status = static_cast<c2_status_t>(s);
143                if (status != C2_OK && status != C2_BAD_INDEX) {
144                    ALOGE("query -- call failed. "
145                            "Error code = %d", static_cast<int>(status));
146                    return;
147                }
148                std::vector<C2Param*> paramPointers;
149                c2_status_t parseStatus = parseParamsBlob(&paramPointers, p);
150                if (parseStatus != C2_OK) {
151                    ALOGE("query -- error while parsing params. "
152                            "Error code = %d", static_cast<int>(status));
153                    status = parseStatus;
154                    return;
155                }
156                size_t i = 0;
157                for (auto it = paramPointers.begin(); it != paramPointers.end(); ) {
158                    C2Param* paramPointer = *it;
159                    if (numStackIndices > 0) {
160                        --numStackIndices;
161                        if (!paramPointer) {
162                            ALOGW("query -- null stack param.");
163                            ++it;
164                            continue;
165                        }
166                        for (; i < stackParams.size() && !stackParams[i]; ) {
167                            ++i;
168                        }
169                        if (i >= stackParams.size()) {
170                            ALOGE("query -- unexpected error.");
171                            status = C2_CORRUPTED;
172                            return;
173                        }
174                        if (stackParams[i]->index() != paramPointer->index()) {
175                            ALOGW("query -- param skipped. index = %d",
176                                    static_cast<int>(stackParams[i]->index()));
177                            stackParams[i++]->invalidate();
178                            continue;
179                        }
180                        if (!stackParams[i++]->updateFrom(*paramPointer)) {
181                            ALOGW("query -- param update failed. index = %d",
182                                    static_cast<int>(paramPointer->index()));
183                        }
184                    } else {
185                        if (!paramPointer) {
186                            ALOGW("query -- null heap param.");
187                            ++it;
188                            continue;
189                        }
190                        if (!heapParams) {
191                            ALOGW("query -- extra stack param.");
192                        }
193                        heapParams->emplace_back(C2Param::Copy(*paramPointer));
194                    }
195                    ++it;
196                }
197            });
198    if (!transStatus.isOk()) {
199        ALOGE("query -- transaction failed.");
200        return C2_TRANSACTION_FAILED;
201    }
202    return status;
203}
204
205c2_status_t Codec2ConfigurableClient::config(
206        const std::vector<C2Param*> &params,
207        c2_blocking_t mayBlock,
208        std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
209    Params hidlParams;
210    Status hidlStatus = createParamsBlob(&hidlParams, params);
211    if (hidlStatus != Status::OK) {
212        ALOGE("config -- bad input.");
213        return C2_TRANSACTION_FAILED;
214    }
215    c2_status_t status;
216    Return<void> transStatus = base()->config(
217            hidlParams,
218            mayBlock == C2_MAY_BLOCK,
219            [&status, &params, failures](
220                    Status s,
221                    const hidl_vec<SettingResult> f,
222                    const Params& o) {
223                status = static_cast<c2_status_t>(s);
224                if (status != C2_OK) {
225                    ALOGE("config -- call failed. "
226                            "Error code = %d", static_cast<int>(status));
227                    return;
228                }
229                size_t i = failures->size();
230                failures->resize(i + f.size());
231                for (const SettingResult& sf : f) {
232                    status = objcpy(&(*failures)[i++], sf);
233                    if (status != C2_OK) {
234                        ALOGE("config -- invalid returned SettingResult. "
235                                "Error code = %d", static_cast<int>(status));
236                        return;
237                    }
238                }
239                status = updateParamsFromBlob(params, o);
240            });
241    if (!transStatus.isOk()) {
242        ALOGE("config -- transaction failed.");
243        return C2_TRANSACTION_FAILED;
244    }
245    return status;
246}
247
248c2_status_t Codec2ConfigurableClient::querySupportedParams(
249        std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
250    // TODO: Cache and query properly!
251    c2_status_t status;
252    Return<void> transStatus = base()->querySupportedParams(
253            std::numeric_limits<uint32_t>::min(),
254            std::numeric_limits<uint32_t>::max(),
255            [&status, params](
256                    Status s,
257                    const hidl_vec<ParamDescriptor>& p) {
258                status = static_cast<c2_status_t>(s);
259                if (status != C2_OK) {
260                    ALOGE("querySupportedParams -- call failed. "
261                            "Error code = %d", static_cast<int>(status));
262                    return;
263                }
264                size_t i = params->size();
265                params->resize(i + p.size());
266                for (const ParamDescriptor& sp : p) {
267                    status = objcpy(&(*params)[i++], sp);
268                    if (status != C2_OK) {
269                        ALOGE("querySupportedParams -- "
270                                "invalid returned ParamDescriptor. "
271                                "Error code = %d", static_cast<int>(status));
272                        return;
273                    }
274                }
275            });
276    if (!transStatus.isOk()) {
277        ALOGE("querySupportedParams -- transaction failed.");
278        return C2_TRANSACTION_FAILED;
279    }
280    return status;
281}
282
283c2_status_t Codec2ConfigurableClient::querySupportedValues(
284        std::vector<C2FieldSupportedValuesQuery>& fields,
285        c2_blocking_t mayBlock) const {
286    hidl_vec<FieldSupportedValuesQuery> inFields(fields.size());
287    for (size_t i = 0; i < fields.size(); ++i) {
288        Status hidlStatus = objcpy(&inFields[i], fields[i]);
289        if (hidlStatus != Status::OK) {
290            ALOGE("querySupportedValues -- bad input");
291            return C2_TRANSACTION_FAILED;
292        }
293    }
294
295    c2_status_t status;
296    Return<void> transStatus = base()->querySupportedValues(
297            inFields,
298            mayBlock == C2_MAY_BLOCK,
299            [&status, &inFields, &fields](
300                    Status s,
301                    const hidl_vec<FieldSupportedValuesQueryResult>& r) {
302                status = static_cast<c2_status_t>(s);
303                if (status != C2_OK) {
304                    ALOGE("querySupportedValues -- call failed. "
305                            "Error code = %d", static_cast<int>(status));
306                    return;
307                }
308                if (r.size() != fields.size()) {
309                    ALOGE("querySupportedValues -- input and output lists "
310                            "have different sizes.");
311                    status = C2_CORRUPTED;
312                    return;
313                }
314                for (size_t i = 0; i < fields.size(); ++i) {
315                    status = objcpy(&fields[i], inFields[i], r[i]);
316                    if (status != C2_OK) {
317                        ALOGE("querySupportedValues -- invalid returned value. "
318                                "Error code = %d", static_cast<int>(status));
319                        return;
320                    }
321                }
322            });
323    if (!transStatus.isOk()) {
324        ALOGE("querySupportedValues -- transaction failed.");
325        return C2_TRANSACTION_FAILED;
326    }
327    return status;
328}
329
330// Codec2Client
331
332Codec2Client::Base* Codec2Client::base() const {
333    return static_cast<Base*>(mBase.get());
334}
335
336Codec2Client::Codec2Client(const sp<Codec2Client::Base>& base, std::string instanceName) :
337    Codec2ConfigurableClient(base), mListed(false), mInstanceName(instanceName) {
338    Return<sp<IClientManager>> transResult = base->getPoolClientManager();
339    if (!transResult.isOk()) {
340        ALOGE("getPoolClientManager -- failed transaction.");
341    } else {
342        mHostPoolManager = static_cast<sp<IClientManager>>(transResult);
343    }
344}
345
346c2_status_t Codec2Client::createComponent(
347        const C2String& name,
348        const std::shared_ptr<Codec2Client::Listener>& listener,
349        std::shared_ptr<Codec2Client::Component>* const component) {
350
351    // TODO: Add support for Bufferpool
352
353    struct HidlListener : public IComponentListener {
354        std::weak_ptr<Component> component;
355        std::weak_ptr<Listener> base;
356
357        virtual Return<void> onWorkDone(const WorkBundle& workBundle) override {
358            std::list<std::unique_ptr<C2Work>> workItems;
359            c2_status_t status = objcpy(&workItems, workBundle);
360            if (status != C2_OK) {
361                ALOGE("onWorkDone -- received corrupted WorkBundle. "
362                        "status = %d.", static_cast<int>(status));
363                return Void();
364            }
365            // release input buffers potentially held by the component from queue
366            std::shared_ptr<Codec2Client::Component> strongComponent = component.lock();
367            if (strongComponent) {
368                std::vector<uint64_t> inputDone;
369                for (const std::unique_ptr<C2Work> &work : workItems) {
370                    if (work) {
371                        inputDone.emplace_back(work->input.ordinal.frameIndex.peeku());
372                    }
373                }
374                strongComponent->handleOnWorkDone(inputDone);
375            }
376            if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
377                listener->onWorkDone(component, workItems);
378            } else {
379                ALOGW("onWorkDone -- listener died.");
380            }
381            return Void();
382        }
383
384        virtual Return<void> onTripped(
385                const hidl_vec<SettingResult>& settingResults) override {
386            std::vector<std::shared_ptr<C2SettingResult>> c2SettingResults(
387                    settingResults.size());
388            c2_status_t status;
389            for (size_t i = 0; i < settingResults.size(); ++i) {
390                std::unique_ptr<C2SettingResult> c2SettingResult;
391                status = objcpy(&c2SettingResult, settingResults[i]);
392                if (status != C2_OK) {
393                    ALOGE("onTripped -- received corrupted SettingResult. "
394                            "status = %d.", static_cast<int>(status));
395                    return Void();
396                }
397                c2SettingResults[i] = std::move(c2SettingResult);
398            }
399            if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
400                listener->onTripped(component, c2SettingResults);
401            } else {
402                ALOGW("onTripped -- listener died.");
403            }
404            return Void();
405        }
406
407        virtual Return<void> onError(Status s, uint32_t errorCode) override {
408            ALOGE("onError -- status = %d, errorCode = %u.",
409                    static_cast<int>(s),
410                    static_cast<unsigned>(errorCode));
411            if (std::shared_ptr<Listener> listener = base.lock()) {
412                listener->onError(component, s == Status::OK ?
413                        errorCode : static_cast<c2_status_t>(s));
414            } else {
415                ALOGW("onError -- listener died.");
416            }
417            return Void();
418        }
419
420        virtual Return<void> onFramesRendered(
421                const hidl_vec<RenderedFrame>& renderedFrames) override {
422            if (std::shared_ptr<Listener> listener = base.lock()) {
423                std::vector<Codec2Client::Listener::RenderedFrame>
424                        rfs(renderedFrames.size());
425                for (size_t i = 0; i < rfs.size(); ++i) {
426                    rfs[i].bufferQueueId = static_cast<uint64_t>(
427                            renderedFrames[i].bufferQueueId);
428                    rfs[i].slotId = static_cast<int32_t>(
429                            renderedFrames[i].slotId);
430                    rfs[i].timestampNs = static_cast<int64_t>(
431                            renderedFrames[i].timestampNs);
432                }
433                listener->onFramesRendered(rfs);
434            } else {
435                ALOGW("onFramesRendered -- listener died.");
436            }
437            return Void();
438        }
439
440    };
441
442    c2_status_t status;
443    sp<HidlListener> hidlListener = new HidlListener();
444    hidlListener->base = listener;
445    Return<void> transStatus = base()->createComponent(
446            name,
447            hidlListener,
448            ClientManager::getInstance(),
449            [&status, component, hidlListener](
450                    Status s,
451                    const sp<IComponent>& c) {
452                status = static_cast<c2_status_t>(s);
453                if (status != C2_OK) {
454                    return;
455                }
456                *component = std::make_shared<Codec2Client::Component>(c);
457                hidlListener->component = *component;
458            });
459    if (!transStatus.isOk()) {
460        ALOGE("createComponent -- failed transaction.");
461        return C2_TRANSACTION_FAILED;
462    }
463
464    if (status != C2_OK) {
465        return status;
466    }
467
468    if (!*component) {
469        ALOGE("createComponent -- null component.");
470        return C2_CORRUPTED;
471    }
472
473    status = (*component)->setDeathListener(*component, listener);
474    if (status != C2_OK) {
475        ALOGE("createComponent -- setDeathListener returned error: %d.",
476                static_cast<int>(status));
477    }
478
479    (*component)->mBufferPoolSender.setReceiver(mHostPoolManager);
480    return status;
481}
482
483c2_status_t Codec2Client::createInterface(
484        const C2String& name,
485        std::shared_ptr<Codec2Client::Interface>* const interface) {
486    c2_status_t status;
487    Return<void> transStatus = base()->createInterface(
488            name,
489            [&status, interface](
490                    Status s,
491                    const sp<IComponentInterface>& i) {
492                status = static_cast<c2_status_t>(s);
493                if (status != C2_OK) {
494                    ALOGE("createInterface -- call failed. "
495                            "Error code = %d", static_cast<int>(status));
496                    return;
497                }
498                *interface = std::make_shared<Codec2Client::Interface>(i);
499            });
500    if (!transStatus.isOk()) {
501        ALOGE("createInterface -- failed transaction.");
502        return C2_TRANSACTION_FAILED;
503    }
504    return status;
505}
506
507c2_status_t Codec2Client::createInputSurface(
508        std::shared_ptr<Codec2Client::InputSurface>* const inputSurface) {
509    Return<sp<IInputSurface>> transResult = base()->createInputSurface();
510    if (!transResult.isOk()) {
511        ALOGE("createInputSurface -- failed transaction.");
512        return C2_TRANSACTION_FAILED;
513    }
514    *inputSurface = std::make_shared<InputSurface>(
515            static_cast<sp<IInputSurface>>(transResult));
516    if (!*inputSurface) {
517        ALOGE("createInputSurface -- failed to create client.");
518        return C2_CORRUPTED;
519    }
520    return C2_OK;
521}
522
523const std::vector<C2Component::Traits>& Codec2Client::listComponents() const {
524    std::lock_guard<std::mutex> lock(mMutex);
525    if (mListed) {
526        return mTraitsList;
527    }
528    Return<void> transStatus = base()->listComponents(
529            [this](const hidl_vec<IComponentStore::ComponentTraits>& t) {
530                mTraitsList.resize(t.size());
531                mAliasesBuffer.resize(t.size());
532                for (size_t i = 0; i < t.size(); ++i) {
533                    c2_status_t status = objcpy(
534                            &mTraitsList[i], &mAliasesBuffer[i], t[i]);
535                    if (status != C2_OK) {
536                        ALOGE("listComponents -- corrupted output.");
537                        return;
538                    }
539                }
540            });
541    if (!transStatus.isOk()) {
542        ALOGE("listComponents -- failed transaction.");
543    }
544    mListed = true;
545    return mTraitsList;
546}
547
548c2_status_t Codec2Client::copyBuffer(
549        const std::shared_ptr<C2Buffer>& src,
550        const std::shared_ptr<C2Buffer>& dst) {
551    // TODO: Implement?
552    (void)src;
553    (void)dst;
554    ALOGE("copyBuffer not implemented");
555    return C2_OMITTED;
556}
557
558std::shared_ptr<C2ParamReflector>
559        Codec2Client::getParamReflector() {
560    // TODO: this is not meant to be exposed as C2ParamReflector on the client side; instead, it
561    // should reflect the HAL API.
562    struct SimpleParamReflector : public C2ParamReflector {
563        virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::CoreIndex coreIndex) const {
564            hidl_vec<ParamIndex> indices(1);
565            indices[0] = static_cast<ParamIndex>(coreIndex.coreIndex());
566            std::unique_ptr<C2StructDescriptor> descriptor;
567            Return<void> transStatus = mBase->getStructDescriptors(
568                    indices,
569                    [&descriptor](
570                            Status s,
571                            const hidl_vec<StructDescriptor>& sd) {
572                        c2_status_t status = static_cast<c2_status_t>(s);
573                        if (status != C2_OK) {
574                            ALOGE("getStructDescriptors -- call failed. "
575                                    "Error code = %d", static_cast<int>(status));
576                            descriptor.reset();
577                            return;
578                        }
579                        if (sd.size() != 1) {
580                            ALOGD("getStructDescriptors -- returned vector of size %zu.",
581                                    sd.size());
582                            descriptor.reset();
583                            return;
584                        }
585                        status = objcpy(&descriptor, sd[0]);
586                        if (status != C2_OK) {
587                            ALOGD("getStructDescriptors -- failed to convert. "
588                                    "Error code = %d", static_cast<int>(status));
589                            descriptor.reset();
590                            return;
591                        }
592                    });
593            return descriptor;
594        }
595
596        SimpleParamReflector(sp<Base> base)
597            : mBase(base) { }
598
599        sp<Base> mBase;
600    };
601
602    return std::make_shared<SimpleParamReflector>(base());
603};
604
605std::shared_ptr<Codec2Client> Codec2Client::CreateFromService(
606        const char* instanceName, bool waitForService) {
607    if (!instanceName) {
608        return nullptr;
609    }
610    sp<Base> baseStore = waitForService ?
611            Base::getService(instanceName) :
612            Base::tryGetService(instanceName);
613    if (!baseStore) {
614        if (waitForService) {
615            ALOGE("Codec2.0 service inaccessible. Check the device manifest.");
616        } else {
617            ALOGW("Codec2.0 service not available right now. Try again later.");
618        }
619        return nullptr;
620    }
621    return std::make_shared<Codec2Client>(baseStore, instanceName);
622}
623
624c2_status_t Codec2Client::ForAllStores(
625        const std::string &key,
626        std::function<c2_status_t(const std::shared_ptr<Codec2Client>&)> predicate) {
627    c2_status_t status = C2_NO_INIT;  // no IComponentStores present
628
629    // Cache the mapping key -> index of Codec2Client in getClient().
630    static std::mutex key2IndexMutex;
631    static std::map<std::string, size_t> key2Index;
632
633    // By default try all stores. However, try the last known client first. If the last known
634    // client fails, retry once. We do this by pushing the last known client in front of the
635    // list of all clients.
636    std::deque<size_t> indices;
637    for (size_t index = getClientCount(); index > 0; ) {
638        indices.push_front(--index);
639    }
640
641    bool wasMapped = false;
642    std::unique_lock<std::mutex> lock(key2IndexMutex);
643    auto it = key2Index.find(key);
644    if (it != key2Index.end()) {
645        indices.push_front(it->second);
646        wasMapped = true;
647    }
648    lock.unlock();
649
650    for (size_t index : indices) {
651        std::shared_ptr<Codec2Client> client = getClient(index);
652        if (client) {
653            status = predicate(client);
654            if (status == C2_OK) {
655                lock.lock();
656                key2Index[key] = index; // update last known client index
657                return status;
658            }
659        }
660        if (wasMapped) {
661            ALOGI("Could not find '%s' in last instance. Retrying...", key.c_str());
662            wasMapped = false;
663        }
664    }
665    return status;  // return the last status from a valid client
666}
667
668std::shared_ptr<Codec2Client::Component>
669        Codec2Client::CreateComponentByName(
670        const char* componentName,
671        const std::shared_ptr<Listener>& listener,
672        std::shared_ptr<Codec2Client>* owner) {
673    std::shared_ptr<Component> component;
674    c2_status_t status = ForAllStores(
675            componentName,
676            [owner, &component, componentName, &listener](
677                    const std::shared_ptr<Codec2Client> &client) -> c2_status_t {
678                c2_status_t status = client->createComponent(componentName, listener, &component);
679                if (status == C2_OK) {
680                    if (owner) {
681                        *owner = client;
682                    }
683                } else if (status != C2_NOT_FOUND) {
684                    ALOGD("IComponentStore(%s)::createComponent('%s') returned %s",
685                            client->getInstanceName().c_str(), componentName, asString(status));
686                }
687                return status;
688            });
689    if (status != C2_OK) {
690        ALOGI("Could not create component '%s' (%s)", componentName, asString(status));
691    }
692    return component;
693}
694
695std::shared_ptr<Codec2Client::Interface>
696        Codec2Client::CreateInterfaceByName(
697        const char* interfaceName,
698        std::shared_ptr<Codec2Client>* owner) {
699    std::shared_ptr<Interface> interface;
700    c2_status_t status = ForAllStores(
701            interfaceName,
702            [owner, &interface, interfaceName](
703                    const std::shared_ptr<Codec2Client> &client) -> c2_status_t {
704                c2_status_t status = client->createInterface(interfaceName, &interface);
705                if (status == C2_OK) {
706                    if (owner) {
707                        *owner = client;
708                    }
709                } else if (status != C2_NOT_FOUND) {
710                    ALOGD("IComponentStore(%s)::createInterface('%s') returned %s",
711                            client->getInstanceName().c_str(), interfaceName, asString(status));
712                }
713                return status;
714            });
715    if (status != C2_OK) {
716        ALOGI("Could not create interface '%s' (%s)", interfaceName, asString(status));
717    }
718    return interface;
719}
720
721const std::vector<C2Component::Traits>& Codec2Client::ListComponents() {
722    static std::vector<C2Component::Traits> traitsList = [](){
723        std::vector<C2Component::Traits> list;
724        size_t listSize = 0;
725        ClientList clientList = getClientList();
726        for (const std::shared_ptr<Codec2Client>& client : clientList) {
727            if (!client) {
728                continue;
729            }
730            listSize += client->listComponents().size();
731        }
732        list.reserve(listSize);
733        for (const std::shared_ptr<Codec2Client>& client : clientList) {
734            if (!client) {
735                continue;
736            }
737            list.insert(
738                    list.end(),
739                    client->listComponents().begin(),
740                    client->listComponents().end());
741        }
742        return list;
743    }();
744
745    return traitsList;
746}
747
748// Codec2Client::Listener
749
750Codec2Client::Listener::~Listener() {
751}
752
753// Codec2Client::Component
754
755Codec2Client::Component::Base* Codec2Client::Component::base() const {
756    return static_cast<Base*>(mBase.get());
757}
758
759Codec2Client::Component::Component(const sp<Codec2Client::Component::Base>& base) :
760    Codec2Client::Configurable(base),
761    mBufferPoolSender(nullptr) {
762}
763
764Codec2Client::Component::~Component() {
765}
766
767c2_status_t Codec2Client::Component::createBlockPool(
768        C2Allocator::id_t id,
769        C2BlockPool::local_id_t* blockPoolId,
770        std::shared_ptr<Codec2Client::Configurable>* configurable) {
771    c2_status_t status;
772    Return<void> transStatus = base()->createBlockPool(
773            static_cast<uint32_t>(id),
774            [&status, blockPoolId, configurable](
775                    Status s,
776                    uint64_t pId,
777                    const sp<IConfigurable>& c) {
778                status = static_cast<c2_status_t>(s);
779                configurable->reset();
780                if (status != C2_OK) {
781                    ALOGE("createBlockPool -- call failed. "
782                            "Error code = %d", static_cast<int>(status));
783                    return;
784                }
785                *blockPoolId = static_cast<C2BlockPool::local_id_t>(pId);
786                if (c) {  // TODO: configurable returned should not be nullptr
787                    *configurable = std::make_shared<Codec2Client::Configurable>(c);
788                }
789            });
790    if (!transStatus.isOk()) {
791        ALOGE("createBlockPool -- transaction failed.");
792        return C2_TRANSACTION_FAILED;
793    }
794    return status;
795}
796
797c2_status_t Codec2Client::Component::destroyBlockPool(
798        C2BlockPool::local_id_t localId) {
799    Return<Status> transResult = base()->destroyBlockPool(
800            static_cast<uint64_t>(localId));
801    if (!transResult.isOk()) {
802        ALOGE("destroyBlockPool -- transaction failed.");
803        return C2_TRANSACTION_FAILED;
804    }
805    return static_cast<c2_status_t>(static_cast<Status>(transResult));
806}
807
808void Codec2Client::Component::handleOnWorkDone(const std::vector<uint64_t> &inputDone) {
809    std::lock_guard<std::mutex> lock(mInputBuffersMutex);
810    for (uint64_t inputIndex : inputDone) {
811        auto it = mInputBuffers.find(inputIndex);
812        if (it == mInputBuffers.end()) {
813            ALOGI("unknown input index %llu in onWorkDone", (long long)inputIndex);
814        } else {
815            ALOGV("done with input index %llu with %zu buffers",
816                    (long long)inputIndex, it->second.size());
817            mInputBuffers.erase(it);
818        }
819    }
820}
821
822c2_status_t Codec2Client::Component::queue(
823        std::list<std::unique_ptr<C2Work>>* const items) {
824    // remember input buffers queued to hold reference to them
825    {
826        std::lock_guard<std::mutex> lock(mInputBuffersMutex);
827        for (const std::unique_ptr<C2Work> &work : *items) {
828            if (!work) {
829                continue;
830            }
831
832            uint64_t inputIndex = work->input.ordinal.frameIndex.peeku();
833            auto res = mInputBuffers.emplace(inputIndex, work->input.buffers);
834            if (!res.second) {
835                ALOGI("duplicate input index %llu in queue", (long long)inputIndex);
836                // TODO: append? - for now we are replacing
837                res.first->second = work->input.buffers;
838            }
839            ALOGV("qeueing input index %llu with %zu buffers",
840                    (long long)inputIndex, work->input.buffers.size());
841        }
842    }
843
844    WorkBundle workBundle;
845    Status hidlStatus = objcpy(&workBundle, *items, &mBufferPoolSender);
846    if (hidlStatus != Status::OK) {
847        ALOGE("queue -- bad input.");
848        return C2_TRANSACTION_FAILED;
849    }
850    Return<Status> transStatus = base()->queue(workBundle);
851    if (!transStatus.isOk()) {
852        ALOGE("queue -- transaction failed.");
853        return C2_TRANSACTION_FAILED;
854    }
855    c2_status_t status =
856            static_cast<c2_status_t>(static_cast<Status>(transStatus));
857    if (status != C2_OK) {
858        ALOGE("queue -- call failed. "
859                "Error code = %d", static_cast<int>(status));
860    }
861    return status;
862}
863
864c2_status_t Codec2Client::Component::flush(
865        C2Component::flush_mode_t mode,
866        std::list<std::unique_ptr<C2Work>>* const flushedWork) {
867    (void)mode; // Flush mode isn't supported in HIDL yet.
868    c2_status_t status;
869    Return<void> transStatus = base()->flush(
870            [&status, flushedWork](
871                    Status s, const WorkBundle& wb) {
872                status = static_cast<c2_status_t>(s);
873                if (status != C2_OK) {
874                    ALOGE("flush -- call failed. "
875                            "Error code = %d", static_cast<int>(status));
876                    return;
877                }
878                status = objcpy(flushedWork, wb);
879            });
880    if (!transStatus.isOk()) {
881        ALOGE("flush -- transaction failed.");
882        return C2_TRANSACTION_FAILED;
883    }
884
885    // Indices of flushed work items.
886    std::vector<uint64_t> flushedIndices;
887    for (const std::unique_ptr<C2Work> &work : *flushedWork) {
888        if (work) {
889            flushedIndices.emplace_back(work->input.ordinal.frameIndex.peeku());
890        }
891    }
892    for (uint64_t flushedIndex : flushedIndices) {
893        std::lock_guard<std::mutex> lock(mInputBuffersMutex);
894        auto it = mInputBuffers.find(flushedIndex);
895        if (it == mInputBuffers.end()) {
896            ALOGI("unknown input index %llu in flush", (long long)flushedIndex);
897        } else {
898            ALOGV("flushed input index %llu with %zu buffers",
899                    (long long)flushedIndex, it->second.size());
900            mInputBuffers.erase(it);
901        }
902    }
903
904    return status;
905}
906
907c2_status_t Codec2Client::Component::drain(C2Component::drain_mode_t mode) {
908    Return<Status> transStatus = base()->drain(
909            mode == C2Component::DRAIN_COMPONENT_WITH_EOS);
910    if (!transStatus.isOk()) {
911        ALOGE("drain -- transaction failed.");
912        return C2_TRANSACTION_FAILED;
913    }
914    c2_status_t status =
915            static_cast<c2_status_t>(static_cast<Status>(transStatus));
916    if (status != C2_OK) {
917        ALOGE("drain -- call failed. "
918                "Error code = %d", static_cast<int>(status));
919    }
920    return status;
921}
922
923c2_status_t Codec2Client::Component::start() {
924    Return<Status> transStatus = base()->start();
925    if (!transStatus.isOk()) {
926        ALOGE("start -- transaction failed.");
927        return C2_TRANSACTION_FAILED;
928    }
929    c2_status_t status =
930            static_cast<c2_status_t>(static_cast<Status>(transStatus));
931    if (status != C2_OK) {
932        ALOGE("start -- call failed. "
933                "Error code = %d", static_cast<int>(status));
934    }
935    return status;
936}
937
938c2_status_t Codec2Client::Component::stop() {
939    Return<Status> transStatus = base()->stop();
940    if (!transStatus.isOk()) {
941        ALOGE("stop -- transaction failed.");
942        return C2_TRANSACTION_FAILED;
943    }
944    c2_status_t status =
945            static_cast<c2_status_t>(static_cast<Status>(transStatus));
946    if (status != C2_OK) {
947        ALOGE("stop -- call failed. "
948                "Error code = %d", static_cast<int>(status));
949    }
950    mInputBuffersMutex.lock();
951    mInputBuffers.clear();
952    mInputBuffersMutex.unlock();
953    return status;
954}
955
956c2_status_t Codec2Client::Component::reset() {
957    Return<Status> transStatus = base()->reset();
958    if (!transStatus.isOk()) {
959        ALOGE("reset -- transaction failed.");
960        return C2_TRANSACTION_FAILED;
961    }
962    c2_status_t status =
963            static_cast<c2_status_t>(static_cast<Status>(transStatus));
964    if (status != C2_OK) {
965        ALOGE("reset -- call failed. "
966                "Error code = %d", static_cast<int>(status));
967    }
968    mInputBuffersMutex.lock();
969    mInputBuffers.clear();
970    mInputBuffersMutex.unlock();
971    return status;
972}
973
974c2_status_t Codec2Client::Component::release() {
975    Return<Status> transStatus = base()->release();
976    if (!transStatus.isOk()) {
977        ALOGE("release -- transaction failed.");
978        return C2_TRANSACTION_FAILED;
979    }
980    c2_status_t status =
981            static_cast<c2_status_t>(static_cast<Status>(transStatus));
982    if (status != C2_OK) {
983        ALOGE("release -- call failed. "
984                "Error code = %d", static_cast<int>(status));
985    }
986    mInputBuffersMutex.lock();
987    mInputBuffers.clear();
988    mInputBuffersMutex.unlock();
989    return status;
990}
991
992c2_status_t Codec2Client::Component::setOutputSurface(
993        C2BlockPool::local_id_t blockPoolId,
994        const sp<IGraphicBufferProducer>& surface) {
995    Return<Status> transStatus = base()->setOutputSurface(
996            static_cast<uint64_t>(blockPoolId), surface);
997    if (!transStatus.isOk()) {
998        ALOGE("setOutputSurface -- transaction failed.");
999        return C2_TRANSACTION_FAILED;
1000    }
1001    c2_status_t status =
1002            static_cast<c2_status_t>(static_cast<Status>(transStatus));
1003    if (status != C2_OK) {
1004        ALOGE("setOutputSurface -- call failed. "
1005                "Error code = %d", static_cast<int>(status));
1006    }
1007    return status;
1008}
1009
1010c2_status_t Codec2Client::Component::connectToOmxInputSurface(
1011        const sp<IGraphicBufferProducer>& producer,
1012        const sp<IGraphicBufferSource>& source) {
1013    Return<Status> transStatus = base()->connectToOmxInputSurface(
1014            producer, source);
1015    if (!transStatus.isOk()) {
1016        ALOGE("connectToOmxInputSurface -- transaction failed.");
1017        return C2_TRANSACTION_FAILED;
1018    }
1019    c2_status_t status =
1020            static_cast<c2_status_t>(static_cast<Status>(transStatus));
1021    if (status != C2_OK) {
1022        ALOGE("connectToOmxInputSurface -- call failed. "
1023                "Error code = %d", static_cast<int>(status));
1024    }
1025    return status;
1026}
1027
1028c2_status_t Codec2Client::Component::disconnectFromInputSurface() {
1029    Return<Status> transStatus = base()->disconnectFromInputSurface();
1030    if (!transStatus.isOk()) {
1031        ALOGE("disconnectToInputSurface -- transaction failed.");
1032        return C2_TRANSACTION_FAILED;
1033    }
1034    c2_status_t status =
1035            static_cast<c2_status_t>(static_cast<Status>(transStatus));
1036    if (status != C2_OK) {
1037        ALOGE("disconnectFromInputSurface -- call failed. "
1038                "Error code = %d", static_cast<int>(status));
1039    }
1040    return status;
1041}
1042
1043c2_status_t Codec2Client::Component::setDeathListener(
1044        const std::shared_ptr<Component>& component,
1045        const std::shared_ptr<Listener>& listener) {
1046
1047    struct HidlDeathRecipient : public hardware::hidl_death_recipient {
1048        std::weak_ptr<Component> component;
1049        std::weak_ptr<Listener> base;
1050
1051        virtual void serviceDied(
1052                uint64_t /* cookie */,
1053                const wp<::android::hidl::base::V1_0::IBase>& /* who */
1054                ) override {
1055            if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
1056                listener->onDeath(component);
1057            } else {
1058                ALOGW("onDeath -- listener died.");
1059            }
1060        }
1061    };
1062
1063    sp<HidlDeathRecipient> deathRecipient = new HidlDeathRecipient();
1064    deathRecipient->base = listener;
1065    deathRecipient->component = component;
1066
1067    component->mDeathRecipient = deathRecipient;
1068    Return<bool> transResult = component->base()->linkToDeath(
1069            component->mDeathRecipient, 0);
1070    if (!transResult.isOk()) {
1071        ALOGE("setDeathListener -- failed transaction: linkToDeath.");
1072        return C2_TRANSACTION_FAILED;
1073    }
1074    if (!static_cast<bool>(transResult)) {
1075        ALOGE("setDeathListener -- linkToDeath call failed.");
1076        return C2_CORRUPTED;
1077    }
1078    return C2_OK;
1079}
1080
1081// Codec2Client::InputSurface
1082
1083Codec2Client::InputSurface::Base* Codec2Client::InputSurface::base() const {
1084    return static_cast<Base*>(mBase.get());
1085}
1086
1087Codec2Client::InputSurface::InputSurface(const sp<IInputSurface>& base) :
1088    mBase(base),
1089    mGraphicBufferProducer(new
1090            ::android::hardware::graphics::bufferqueue::V1_0::utils::
1091            H2BGraphicBufferProducer(base)) {
1092}
1093
1094c2_status_t Codec2Client::InputSurface::connectToComponent(
1095        const std::shared_ptr<Codec2Client::Component>& component,
1096        std::shared_ptr<Connection>* connection) {
1097    c2_status_t status;
1098    Return<void> transStatus = base()->connectToComponent(
1099        component->base(),
1100        [&status, connection](
1101                Status s,
1102                const sp<IInputSurfaceConnection>& c) {
1103            status = static_cast<c2_status_t>(s);
1104            if (status != C2_OK) {
1105                ALOGE("connectToComponent -- call failed. "
1106                        "Error code = %d", static_cast<int>(status));
1107                return;
1108            }
1109            *connection = std::make_shared<Connection>(c);
1110        });
1111    if (!transStatus.isOk()) {
1112        ALOGE("connect -- transaction failed.");
1113        return C2_TRANSACTION_FAILED;
1114    }
1115    return status;
1116}
1117
1118std::shared_ptr<Codec2Client::Configurable>
1119        Codec2Client::InputSurface::getConfigurable() const {
1120    Return<sp<IConfigurable>> transResult = base()->getConfigurable();
1121    if (!transResult.isOk()) {
1122        ALOGW("getConfigurable -- transaction failed.");
1123        return nullptr;
1124    }
1125    if (!static_cast<sp<IConfigurable>>(transResult)) {
1126        ALOGW("getConfigurable -- null pointer.");
1127        return nullptr;
1128    }
1129    return std::make_shared<Configurable>(transResult);
1130}
1131
1132const sp<IGraphicBufferProducer>&
1133        Codec2Client::InputSurface::getGraphicBufferProducer() const {
1134    return mGraphicBufferProducer;
1135}
1136
1137// Codec2Client::InputSurfaceConnection
1138
1139Codec2Client::InputSurfaceConnection::Base*
1140        Codec2Client::InputSurfaceConnection::base() const {
1141    return static_cast<Base*>(mBase.get());
1142}
1143
1144Codec2Client::InputSurfaceConnection::InputSurfaceConnection(
1145        const sp<Codec2Client::InputSurfaceConnection::Base>& base) :
1146    mBase(base) {
1147}
1148
1149c2_status_t Codec2Client::InputSurfaceConnection::disconnect() {
1150    Return<Status> transResult = base()->disconnect();
1151    return static_cast<c2_status_t>(static_cast<Status>(transResult));
1152}
1153
1154}  // namespace android
1155
1156