1/*
2 * Copyright (c) 2022-2023 Shenzhen Kaihong DID Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <osal_mem.h>
17#include <servmgr_hdi.h>
18#include "codec_component_manager.h"
19#include "codec_internal.h"
20#include "codec_log_wrapper.h"
21#include "codec_util.h"
22#include "codec_types.h"
23
24struct CodecComponentManagerProxy {
25    struct CodecComponentManager instance;
26    struct HdfRemoteService *remoteOmx;
27};
28
29static struct CodecComponentManagerProxy g_codecComponentManagerProxy = {
30    .instance = {
31        .GetComponentNum = NULL,
32        .GetComponentCapabilityList = NULL,
33        .CreateComponent = NULL,
34        .DestroyComponent = NULL,
35        .AsObject = NULL,
36    },
37    .remoteOmx = NULL,
38};
39
40static void ReleaseSbuf(struct HdfSBuf *data, struct HdfSBuf *reply)
41{
42    if (data != NULL) {
43        HdfSbufRecycle(data);
44    }
45    if (reply != NULL) {
46        HdfSbufRecycle(reply);
47    }
48}
49
50static int32_t GetComponentNum()
51{
52    int32_t num = 0;
53    struct HdfSBuf *data = HdfSbufTypedObtain(SBUF_IPC);
54    if (data == NULL) {
55        CODEC_LOGE("Failed to obtain");
56        return HDF_FAILURE;
57    }
58    struct HdfSBuf *reply = HdfSbufTypedObtain(SBUF_IPC);
59    if (reply == NULL) {
60        CODEC_LOGE("Failed to obtain reply");
61        HdfSbufRecycle(data);
62        return HDF_FAILURE;
63    }
64
65    if (!HdfRemoteServiceWriteInterfaceToken(g_codecComponentManagerProxy.remoteOmx, data)) {
66        CODEC_LOGE("write interface token failed");
67        ReleaseSbuf(data, reply);
68        return HDF_FAILURE;
69    }
70
71    if (g_codecComponentManagerProxy.remoteOmx->dispatcher->Dispatch(
72        g_codecComponentManagerProxy.remoteOmx, CMD_CODEC_GET_COMPONENT_NUM, data, reply) != HDF_SUCCESS) {
73        CODEC_LOGE("dispatch request failed!");
74        ReleaseSbuf(data, reply);
75        return HDF_FAILURE;
76    }
77
78    if (!HdfSbufReadInt32(reply, &num)) {
79        CODEC_LOGE("read dataBlock->role failed!");
80        ReleaseSbuf(data, reply);
81        return HDF_FAILURE;
82    }
83
84    ReleaseSbuf(data, reply);
85    return num;
86}
87
88static int32_t GetComponentCapabilityList(CodecCompCapability *capList, int32_t count)
89{
90    struct HdfSBuf *data = HdfSbufTypedObtain(SBUF_IPC);
91    int32_t num = GetComponentNum();
92    if (data == NULL || count <= 0 || count > num) {
93        CODEC_LOGE("Failed to obtain");
94        return HDF_FAILURE;
95    }
96    struct HdfSBuf *reply = HdfSbufTypedObtain(SBUF_IPC);
97    if (reply == NULL) {
98        CODEC_LOGE("Failed to obtain reply");
99        HdfSbufRecycle(data);
100        return HDF_FAILURE;
101    }
102
103    if (!HdfRemoteServiceWriteInterfaceToken(g_codecComponentManagerProxy.remoteOmx, data)) {
104        CODEC_LOGE("write interface token failed");
105        ReleaseSbuf(data, reply);
106        return HDF_FAILURE;
107    }
108
109    if (!HdfSbufWriteInt32(data, count)) {
110        CODEC_LOGE("write count failed!");
111        ReleaseSbuf(data, reply);
112        return HDF_ERR_INVALID_PARAM;
113    }
114
115    if (g_codecComponentManagerProxy.remoteOmx->dispatcher->Dispatch(g_codecComponentManagerProxy.remoteOmx,
116                                                                     CMD_CODEC_GET_COMPONENT_CAPABILITY_LIST, data,
117                                                                     reply) != HDF_SUCCESS) {
118        CODEC_LOGE("dispatch request failed!");
119        ReleaseSbuf(data, reply);
120        return HDF_FAILURE;
121    }
122
123    for (int32_t i = 0; i < count; i++) {
124        if (!CodecCompCapabilityBlockUnmarshalling(reply, &(capList)[i])) {
125            CODEC_LOGE("read capbility %{public}d from sbuf failed!", i);
126            ReleaseSbuf(data, reply);
127            return HDF_FAILURE;
128        }
129    }
130
131    ReleaseSbuf(data, reply);
132    return HDF_SUCCESS;
133}
134
135static int32_t FillHdfSBufData(struct HdfSBuf *data, char *compName, int64_t appData,
136                               struct CodecCallbackType *callback)
137{
138    if (!HdfRemoteServiceWriteInterfaceToken(g_codecComponentManagerProxy.remoteOmx, data)) {
139        CODEC_LOGE("write interface token failed");
140        return HDF_FAILURE;
141    }
142    if (!HdfSbufWriteString(data, compName)) {
143        CODEC_LOGE("write paramName failed!");
144        return HDF_ERR_INVALID_PARAM;
145    }
146    if (!HdfSbufWriteInt64(data, appData)) {
147        CODEC_LOGE("write appData failed!");
148        return HDF_ERR_INVALID_PARAM;
149    }
150    if (HdfSbufWriteRemoteService(data, callback->remote) != 0) {
151        CODEC_LOGE("write callback failed!");
152        return HDF_ERR_INVALID_PARAM;
153    }
154    return HDF_SUCCESS;
155}
156
157static int32_t CreateComponent(struct CodecComponentType **component, uint32_t *componentId, char *compName,
158                               int64_t appData, struct CodecCallbackType *callback)
159{
160    struct HdfSBuf *data = HdfSbufTypedObtain(SBUF_IPC);
161    struct HdfSBuf *reply = HdfSbufTypedObtain(SBUF_IPC);
162    if (data == NULL || reply == NULL || componentId == NULL) {
163        CODEC_LOGE("HdfSubf malloc failed!");
164        ReleaseSbuf(data, reply);
165        return HDF_ERR_MALLOC_FAIL;
166    }
167
168    int32_t ret = FillHdfSBufData(data, compName, appData, callback);
169    if (ret != HDF_SUCCESS) {
170        ReleaseSbuf(data, reply);
171        return ret;
172    }
173
174    ret = g_codecComponentManagerProxy.remoteOmx->dispatcher->Dispatch(g_codecComponentManagerProxy.remoteOmx,
175                                                                       CMD_CREATE_COMPONENT, data, reply);
176    if (ret != HDF_SUCCESS) {
177        CODEC_LOGE("call failed! error code is %{public}d", ret);
178        ReleaseSbuf(data, reply);
179        return ret;
180    }
181
182    struct HdfRemoteService *componentRemote = HdfSbufReadRemoteService(reply);
183    if (componentRemote == NULL) {
184        CODEC_LOGE("read componentRemote failed!");
185        ReleaseSbuf(data, reply);
186        return HDF_ERR_INVALID_PARAM;
187    }
188    if (!HdfSbufReadUint32(reply, componentId)) {
189        CODEC_LOGE("read componentId failed!");
190        ReleaseSbuf(data, reply);
191        return HDF_ERR_INVALID_PARAM;
192    }
193    *component = CodecComponentTypeGet(componentRemote);
194    ReleaseSbuf(data, reply);
195#ifdef CONFIG_USE_JEMALLOC_DFX_INTF
196    ReleaseCodecCache();
197#endif
198    return ret;
199}
200
201static int32_t DestroyComponent(uint32_t componentId)
202{
203    int32_t ret;
204
205    struct HdfSBuf *data = HdfSbufTypedObtain(SBUF_IPC);
206    struct HdfSBuf *reply = HdfSbufTypedObtain(SBUF_IPC);
207    if (data == NULL || reply == NULL) {
208        CODEC_LOGE("HdfSubf malloc failed!");
209        ReleaseSbuf(data, reply);
210        return HDF_ERR_MALLOC_FAIL;
211    }
212
213    if (!HdfRemoteServiceWriteInterfaceToken(g_codecComponentManagerProxy.remoteOmx, data)) {
214        CODEC_LOGE("write interface token failed");
215        ReleaseSbuf(data, reply);
216        return HDF_FAILURE;
217    }
218
219    if (!HdfSbufWriteUint32(data, componentId)) {
220        CODEC_LOGE("write componentId failed!");
221        ReleaseSbuf(data, reply);
222        return HDF_ERR_INVALID_PARAM;
223    }
224
225    ret = g_codecComponentManagerProxy.remoteOmx->dispatcher->Dispatch(g_codecComponentManagerProxy.remoteOmx,
226                                                                       CMD_DESTROY_COMPONENT, data, reply);
227    if (ret != HDF_SUCCESS) {
228        CODEC_LOGE("call failed! error code is %{public}d", ret);
229        ReleaseSbuf(data, reply);
230        return ret;
231    }
232    ReleaseSbuf(data, reply);
233#ifdef CONFIG_USE_JEMALLOC_DFX_INTF
234    ReleaseCodecCache();
235#endif
236    return ret;
237}
238
239static int32_t InitCodecComponentManagerProxy(void)
240{
241    if (g_codecComponentManagerProxy.remoteOmx != NULL) {
242        return HDF_SUCCESS;
243    }
244
245    struct HDIServiceManager *serviceMgr = HDIServiceManagerGet();
246    if (serviceMgr == NULL) {
247        CODEC_LOGE("HDIServiceManager not found!");
248        return HDF_FAILURE;
249    }
250
251    struct HdfRemoteService *remoteOmx = serviceMgr->GetService(serviceMgr, CODEC_HDI_OMX_SERVICE_NAME);
252    HDIServiceManagerRelease(serviceMgr);
253    if (remoteOmx == NULL) {
254        CODEC_LOGE("CodecComponentTypeService not found!");
255        return HDF_FAILURE;
256    }
257    if (!HdfRemoteServiceSetInterfaceDesc(remoteOmx, "ohos.hdi.codec_service")) {
258        CODEC_LOGE("failed to init interface desc");
259        HdfRemoteServiceRecycle(remoteOmx);
260        return HDF_FAILURE;
261    }
262
263    g_codecComponentManagerProxy.remoteOmx = remoteOmx;
264    g_codecComponentManagerProxy.instance.GetComponentNum = GetComponentNum;
265    g_codecComponentManagerProxy.instance.GetComponentCapabilityList = GetComponentCapabilityList;
266    g_codecComponentManagerProxy.instance.CreateComponent = CreateComponent;
267    g_codecComponentManagerProxy.instance.DestroyComponent = DestroyComponent;
268
269    return HDF_SUCCESS;
270}
271
272struct CodecComponentManager *GetCodecComponentManager(void)
273{
274    if (InitCodecComponentManagerProxy() != HDF_SUCCESS) {
275        return NULL;
276    }
277    return &g_codecComponentManagerProxy.instance;
278}
279
280void CodecComponentManagerRelease(void)
281{
282    if (g_codecComponentManagerProxy.remoteOmx != NULL) {
283        HdfRemoteServiceRecycle(g_codecComponentManagerProxy.remoteOmx);
284        g_codecComponentManagerProxy.remoteOmx = NULL;
285    }
286}