blob: 66cced53f63312c74571e7970c00e56d32411ff1 [file] [log] [blame]
Chong Zhang66469272020-06-04 16:51:55 -07001/*
2 * Copyright (C) 2019 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// Unit Test for MediaTranscodingService.
18
19#include <aidl/android/media/BnTranscodingClientCallback.h>
20#include <aidl/android/media/IMediaTranscodingService.h>
21#include <aidl/android/media/ITranscodingClient.h>
22#include <aidl/android/media/ITranscodingClientCallback.h>
Chong Zhang66469272020-06-04 16:51:55 -070023#include <aidl/android/media/TranscodingRequestParcel.h>
Chong Zhangbc062482020-10-14 16:43:53 -070024#include <aidl/android/media/TranscodingSessionParcel.h>
25#include <aidl/android/media/TranscodingSessionPriority.h>
Chong Zhang66469272020-06-04 16:51:55 -070026#include <android-base/logging.h>
27#include <android/binder_manager.h>
28#include <android/binder_process.h>
29#include <binder/PermissionController.h>
30#include <cutils/multiuser.h>
31#include <fcntl.h>
32#include <gtest/gtest.h>
33#include <sys/stat.h>
34#include <sys/types.h>
35#include <utils/Log.h>
36
37#include <iostream>
38#include <list>
39
40#include "SimulatedTranscoder.h"
41
42namespace android {
43
44namespace media {
45
46using Status = ::ndk::ScopedAStatus;
47using aidl::android::media::BnTranscodingClientCallback;
48using aidl::android::media::IMediaTranscodingService;
49using aidl::android::media::ITranscodingClient;
50using aidl::android::media::ITranscodingClientCallback;
Chong Zhang66469272020-06-04 16:51:55 -070051using aidl::android::media::TranscodingRequestParcel;
Chong Zhangbc062482020-10-14 16:43:53 -070052using aidl::android::media::TranscodingSessionParcel;
53using aidl::android::media::TranscodingSessionPriority;
Chong Zhang66469272020-06-04 16:51:55 -070054using aidl::android::media::TranscodingVideoTrackFormat;
55
56constexpr int32_t kClientUseCallingPid = IMediaTranscodingService::USE_CALLING_PID;
57
58constexpr uid_t kClientUid = 5000;
59#define UID(n) (kClientUid + (n))
60
Chong Zhang3f23e982020-09-24 14:03:41 -070061constexpr pid_t kClientPid = 10000;
62#define PID(n) (kClientPid + (n))
63
Chong Zhang66469272020-06-04 16:51:55 -070064constexpr int32_t kClientId = 0;
65#define CLIENT(n) (kClientId + (n))
66
67constexpr const char* kClientName = "TestClient";
68constexpr const char* kClientPackageA = "com.android.tests.transcoding.testapp.A";
69constexpr const char* kClientPackageB = "com.android.tests.transcoding.testapp.B";
70constexpr const char* kClientPackageC = "com.android.tests.transcoding.testapp.C";
71
Chong Zhangb55c5452020-06-26 14:32:12 -070072constexpr const char* kTestActivityName = "/com.android.tests.transcoding.MainActivity";
73
Chong Zhang66469272020-06-04 16:51:55 -070074static status_t getUidForPackage(String16 packageName, userid_t userId, /*inout*/ uid_t& uid) {
75 PermissionController pc;
76 uid = pc.getPackageUid(packageName, 0);
77 if (uid <= 0) {
78 ALOGE("Unknown package: '%s'", String8(packageName).string());
79 return BAD_VALUE;
80 }
81
82 if (userId < 0) {
83 ALOGE("Invalid user: %d", userId);
84 return BAD_VALUE;
85 }
86
87 uid = multiuser_get_uid(userId, uid);
88 return NO_ERROR;
89}
90
91struct ShellHelper {
92 static bool RunCmd(const std::string& cmdStr) {
93 int ret = system(cmdStr.c_str());
94 if (ret != 0) {
95 ALOGE("Failed to run cmd: %s, exitcode %d", cmdStr.c_str(), ret);
96 return false;
97 }
98 return true;
99 }
100
101 static bool Start(const char* packageName, const char* activityName) {
102 return RunCmd("am start -W " + std::string(packageName) + std::string(activityName) +
103 " &> /dev/null");
104 }
105
106 static bool Stop(const char* packageName) {
107 return RunCmd("am force-stop " + std::string(packageName));
108 }
109};
110
111struct EventTracker {
112 struct Event {
113 enum { NoEvent, Start, Pause, Resume, Finished, Failed } type;
114 int64_t clientId;
Chong Zhangbc062482020-10-14 16:43:53 -0700115 int32_t sessionId;
Chong Zhang66469272020-06-04 16:51:55 -0700116 };
117
Chong Zhangbc062482020-10-14 16:43:53 -0700118#define DECLARE_EVENT(action) \
119 static Event action(int32_t clientId, int32_t sessionId) { \
120 return {Event::action, clientId, sessionId}; \
Chong Zhang66469272020-06-04 16:51:55 -0700121 }
122
123 DECLARE_EVENT(Start);
124 DECLARE_EVENT(Pause);
125 DECLARE_EVENT(Resume);
126 DECLARE_EVENT(Finished);
127 DECLARE_EVENT(Failed);
128
129 static constexpr Event NoEvent = {Event::NoEvent, 0, 0};
130
131 static std::string toString(const Event& event) {
132 std::string eventStr;
133 switch (event.type) {
134 case Event::Start:
135 eventStr = "Start";
136 break;
137 case Event::Pause:
138 eventStr = "Pause";
139 break;
140 case Event::Resume:
141 eventStr = "Resume";
142 break;
143 case Event::Finished:
144 eventStr = "Finished";
145 break;
146 case Event::Failed:
147 eventStr = "Failed";
148 break;
149 default:
150 return "NoEvent";
151 }
Chong Zhangbc062482020-10-14 16:43:53 -0700152 return "session {" + std::to_string(event.clientId) + ", " +
153 std::to_string(event.sessionId) + "}: " + eventStr;
Chong Zhang66469272020-06-04 16:51:55 -0700154 }
155
156 // Pop 1 event from front, wait for up to timeoutUs if empty.
157 const Event& pop(int64_t timeoutUs = 0) {
158 std::unique_lock lock(mLock);
159
160 if (mEventQueue.empty() && timeoutUs > 0) {
161 mCondition.wait_for(lock, std::chrono::microseconds(timeoutUs));
162 }
163
164 if (mEventQueue.empty()) {
165 mPoppedEvent = NoEvent;
166 } else {
167 mPoppedEvent = *mEventQueue.begin();
168 mEventQueue.pop_front();
169 }
170
171 return mPoppedEvent;
172 }
173
Chong Zhangf9077512020-09-21 21:02:06 -0700174 bool waitForSpecificEventAndPop(const Event& target, std::list<Event>* outEvents,
175 int64_t timeoutUs = 0) {
176 std::unique_lock lock(mLock);
177
178 auto startTime = std::chrono::system_clock::now();
Chong Zhangbbb4eac2020-11-18 11:12:06 -0800179 int64_t remainingUs = timeoutUs;
Chong Zhangf9077512020-09-21 21:02:06 -0700180
181 std::list<Event>::iterator it;
182 while (((it = std::find(mEventQueue.begin(), mEventQueue.end(), target)) ==
183 mEventQueue.end()) &&
Chong Zhangbbb4eac2020-11-18 11:12:06 -0800184 remainingUs > 0) {
185 std::cv_status status =
186 mCondition.wait_for(lock, std::chrono::microseconds(remainingUs));
Chong Zhangf9077512020-09-21 21:02:06 -0700187 if (status == std::cv_status::timeout) {
188 break;
189 }
190 std::chrono::microseconds elapsedTime = std::chrono::system_clock::now() - startTime;
Chong Zhangbbb4eac2020-11-18 11:12:06 -0800191 remainingUs = timeoutUs - elapsedTime.count();
Chong Zhangf9077512020-09-21 21:02:06 -0700192 }
193
194 if (it == mEventQueue.end()) {
195 return false;
196 }
197 *outEvents = std::list<Event>(mEventQueue.begin(), std::next(it));
198 mEventQueue.erase(mEventQueue.begin(), std::next(it));
199 return true;
200 }
201
Chong Zhang66469272020-06-04 16:51:55 -0700202 // Push 1 event to back.
Chong Zhangb55c5452020-06-26 14:32:12 -0700203 void append(const Event& event,
204 const TranscodingErrorCode err = TranscodingErrorCode::kNoError) {
Chong Zhang66469272020-06-04 16:51:55 -0700205 ALOGD("%s", toString(event).c_str());
206
207 std::unique_lock lock(mLock);
208
209 mEventQueue.push_back(event);
Chong Zhangb55c5452020-06-26 14:32:12 -0700210 mLastErr = err;
Chong Zhang66469272020-06-04 16:51:55 -0700211 mCondition.notify_one();
212 }
213
Chong Zhang98b8a372020-07-08 17:27:37 -0700214 void updateProgress(int progress) {
215 std::unique_lock lock(mLock);
216 mLastProgress = progress;
217 mUpdateCount++;
218 }
219
Chong Zhangf9077512020-09-21 21:02:06 -0700220 int getUpdateCount(int* lastProgress) {
Chong Zhang98b8a372020-07-08 17:27:37 -0700221 std::unique_lock lock(mLock);
222 *lastProgress = mLastProgress;
223 return mUpdateCount;
224 }
225
Chong Zhangb55c5452020-06-26 14:32:12 -0700226 TranscodingErrorCode getLastError() {
227 std::unique_lock lock(mLock);
228 return mLastErr;
229 }
230
Chong Zhang66469272020-06-04 16:51:55 -0700231private:
232 std::mutex mLock;
233 std::condition_variable mCondition;
234 Event mPoppedEvent;
235 std::list<Event> mEventQueue;
Chong Zhangb55c5452020-06-26 14:32:12 -0700236 TranscodingErrorCode mLastErr;
Chong Zhang98b8a372020-07-08 17:27:37 -0700237 int mUpdateCount = 0;
238 int mLastProgress = -1;
Chong Zhang66469272020-06-04 16:51:55 -0700239};
240
241// Operators for GTest macros.
242bool operator==(const EventTracker::Event& lhs, const EventTracker::Event& rhs) {
Chong Zhangbc062482020-10-14 16:43:53 -0700243 return lhs.type == rhs.type && lhs.clientId == rhs.clientId && lhs.sessionId == rhs.sessionId;
Chong Zhang66469272020-06-04 16:51:55 -0700244}
245
246std::ostream& operator<<(std::ostream& str, const EventTracker::Event& v) {
247 str << EventTracker::toString(v);
248 return str;
249}
250
Chong Zhang3f23e982020-09-24 14:03:41 -0700251static constexpr bool success = true;
252static constexpr bool fail = false;
253
254struct TestClientCallback : public BnTranscodingClientCallback,
255 public EventTracker,
256 public std::enable_shared_from_this<TestClientCallback> {
257 TestClientCallback(const char* packageName, int32_t id)
258 : mClientId(id), mClientPid(PID(id)), mClientUid(UID(id)), mPackageName(packageName) {
259 ALOGI("TestClientCallback %d created: pid %d, uid %d", id, PID(id), UID(id));
260
261 // Use package uid if that's available.
262 uid_t packageUid;
263 if (getUidForPackage(String16(packageName), 0 /*userId*/, packageUid) == NO_ERROR) {
264 mClientUid = packageUid;
265 }
Chong Zhang66469272020-06-04 16:51:55 -0700266 }
267
268 virtual ~TestClientCallback() { ALOGI("TestClientCallback %d destroyed", mClientId); }
269
270 Status openFileDescriptor(const std::string& in_fileUri, const std::string& in_mode,
271 ::ndk::ScopedFileDescriptor* _aidl_return) override {
272 ALOGD("@@@ openFileDescriptor: %s", in_fileUri.c_str());
273 int fd;
274 if (in_mode == "w" || in_mode == "rw") {
Chong Zhangb55c5452020-06-26 14:32:12 -0700275 int kOpenFlags;
276 if (in_mode == "w") {
277 // Write-only, create file if non-existent, truncate existing file.
278 kOpenFlags = O_WRONLY | O_CREAT | O_TRUNC;
279 } else {
280 // Read-Write, create if non-existent, no truncate (service will truncate if needed)
281 kOpenFlags = O_RDWR | O_CREAT;
282 }
Chong Zhang66469272020-06-04 16:51:55 -0700283 // User R+W permission.
284 constexpr int kFileMode = S_IRUSR | S_IWUSR;
285 fd = open(in_fileUri.c_str(), kOpenFlags, kFileMode);
286 } else {
287 fd = open(in_fileUri.c_str(), O_RDONLY);
288 }
289 _aidl_return->set(fd);
290 return Status::ok();
291 }
292
Chong Zhangbc062482020-10-14 16:43:53 -0700293 Status onTranscodingStarted(int32_t in_sessionId) override {
294 append(EventTracker::Start(mClientId, in_sessionId));
Chong Zhang66469272020-06-04 16:51:55 -0700295 return Status::ok();
296 }
297
Chong Zhangbc062482020-10-14 16:43:53 -0700298 Status onTranscodingPaused(int32_t in_sessionId) override {
299 append(EventTracker::Pause(mClientId, in_sessionId));
Chong Zhang66469272020-06-04 16:51:55 -0700300 return Status::ok();
301 }
302
Chong Zhangbc062482020-10-14 16:43:53 -0700303 Status onTranscodingResumed(int32_t in_sessionId) override {
304 append(EventTracker::Resume(mClientId, in_sessionId));
Chong Zhang66469272020-06-04 16:51:55 -0700305 return Status::ok();
306 }
307
308 Status onTranscodingFinished(
Chong Zhangbc062482020-10-14 16:43:53 -0700309 int32_t in_sessionId,
Chong Zhang66469272020-06-04 16:51:55 -0700310 const ::aidl::android::media::TranscodingResultParcel& /* in_result */) override {
Chong Zhangbc062482020-10-14 16:43:53 -0700311 append(Finished(mClientId, in_sessionId));
Chong Zhang66469272020-06-04 16:51:55 -0700312 return Status::ok();
313 }
314
Chong Zhangbc062482020-10-14 16:43:53 -0700315 Status onTranscodingFailed(int32_t in_sessionId,
Chong Zhangb55c5452020-06-26 14:32:12 -0700316 ::aidl::android::media::TranscodingErrorCode in_errorCode) override {
Chong Zhangbc062482020-10-14 16:43:53 -0700317 append(Failed(mClientId, in_sessionId), in_errorCode);
Chong Zhang66469272020-06-04 16:51:55 -0700318 return Status::ok();
319 }
320
Chong Zhangbc062482020-10-14 16:43:53 -0700321 Status onAwaitNumberOfSessionsChanged(int32_t /* in_sessionId */,
322 int32_t /* in_oldAwaitNumber */,
323 int32_t /* in_newAwaitNumber */) override {
Chong Zhang66469272020-06-04 16:51:55 -0700324 return Status::ok();
325 }
326
Chong Zhangbc062482020-10-14 16:43:53 -0700327 Status onProgressUpdate(int32_t /* in_sessionId */, int32_t in_progress) override {
Chong Zhang98b8a372020-07-08 17:27:37 -0700328 updateProgress(in_progress);
Chong Zhang66469272020-06-04 16:51:55 -0700329 return Status::ok();
330 }
331
Chong Zhang3f23e982020-09-24 14:03:41 -0700332 Status registerClient(const char* packageName,
333 const std::shared_ptr<IMediaTranscodingService>& service) {
334 // Override the default uid if the package uid is found.
335 uid_t uid;
336 if (getUidForPackage(String16(packageName), 0 /*userId*/, uid) == NO_ERROR) {
337 mClientUid = uid;
338 }
339
340 ALOGD("registering %s with uid %d", packageName, mClientUid);
341
342 std::shared_ptr<ITranscodingClient> client;
343 Status status =
344 service->registerClient(shared_from_this(), kClientName, packageName, &client);
345
346 mClient = status.isOk() ? client : nullptr;
347 return status;
348 }
349
350 Status unregisterClient() {
351 Status status;
352 if (mClient != nullptr) {
353 status = mClient->unregister();
354 mClient = nullptr;
355 }
356 return status;
357 }
358
359 template <bool expectation = success>
Chong Zhangbc062482020-10-14 16:43:53 -0700360 bool submit(int32_t sessionId, const char* sourceFilePath, const char* destinationFilePath,
361 TranscodingSessionPriority priority = TranscodingSessionPriority::kNormal,
Chong Zhang3f23e982020-09-24 14:03:41 -0700362 int bitrateBps = -1, int overridePid = -1, int overrideUid = -1) {
363 constexpr bool shouldSucceed = (expectation == success);
364 bool result;
365 TranscodingRequestParcel request;
Chong Zhangbc062482020-10-14 16:43:53 -0700366 TranscodingSessionParcel session;
Chong Zhang3f23e982020-09-24 14:03:41 -0700367
368 request.sourceFilePath = sourceFilePath;
369 request.destinationFilePath = destinationFilePath;
370 request.priority = priority;
371 request.clientPid = (overridePid == -1) ? mClientPid : overridePid;
372 request.clientUid = (overrideUid == -1) ? mClientUid : overrideUid;
Chong Zhangcf3f8ee2020-10-29 18:38:37 -0700373 request.clientPackageName = (overrideUid == -1) ? mPackageName : "";
Chong Zhang3f23e982020-09-24 14:03:41 -0700374 if (bitrateBps > 0) {
375 request.requestedVideoTrackFormat.emplace(TranscodingVideoTrackFormat());
376 request.requestedVideoTrackFormat->bitrateBps = bitrateBps;
377 }
Chong Zhangbc062482020-10-14 16:43:53 -0700378 Status status = mClient->submitRequest(request, &session, &result);
Chong Zhang3f23e982020-09-24 14:03:41 -0700379
380 EXPECT_TRUE(status.isOk());
381 EXPECT_EQ(result, shouldSucceed);
382 if (shouldSucceed) {
Chong Zhangbc062482020-10-14 16:43:53 -0700383 EXPECT_EQ(session.sessionId, sessionId);
Chong Zhang3f23e982020-09-24 14:03:41 -0700384 }
385
Chong Zhangbc062482020-10-14 16:43:53 -0700386 return status.isOk() && (result == shouldSucceed) &&
387 (!shouldSucceed || session.sessionId == sessionId);
Chong Zhang3f23e982020-09-24 14:03:41 -0700388 }
389
390 template <bool expectation = success>
Chong Zhangbc062482020-10-14 16:43:53 -0700391 bool cancel(int32_t sessionId) {
Chong Zhang3f23e982020-09-24 14:03:41 -0700392 constexpr bool shouldSucceed = (expectation == success);
393 bool result;
Chong Zhangbc062482020-10-14 16:43:53 -0700394 Status status = mClient->cancelSession(sessionId, &result);
Chong Zhang3f23e982020-09-24 14:03:41 -0700395
396 EXPECT_TRUE(status.isOk());
397 EXPECT_EQ(result, shouldSucceed);
398
399 return status.isOk() && (result == shouldSucceed);
400 }
401
402 template <bool expectation = success>
Chong Zhangbc062482020-10-14 16:43:53 -0700403 bool getSession(int32_t sessionId, const char* sourceFilePath,
404 const char* destinationFilePath) {
Chong Zhang3f23e982020-09-24 14:03:41 -0700405 constexpr bool shouldSucceed = (expectation == success);
406 bool result;
Chong Zhangbc062482020-10-14 16:43:53 -0700407 TranscodingSessionParcel session;
408 Status status = mClient->getSessionWithId(sessionId, &session, &result);
Chong Zhang3f23e982020-09-24 14:03:41 -0700409
410 EXPECT_TRUE(status.isOk());
411 EXPECT_EQ(result, shouldSucceed);
412 if (shouldSucceed) {
Chong Zhangbc062482020-10-14 16:43:53 -0700413 EXPECT_EQ(session.sessionId, sessionId);
414 EXPECT_EQ(session.request.sourceFilePath, sourceFilePath);
Chong Zhang3f23e982020-09-24 14:03:41 -0700415 }
416
417 return status.isOk() && (result == shouldSucceed) &&
Chong Zhangbc062482020-10-14 16:43:53 -0700418 (!shouldSucceed || (session.sessionId == sessionId &&
419 session.request.sourceFilePath == sourceFilePath &&
420 session.request.destinationFilePath == destinationFilePath));
Chong Zhang3f23e982020-09-24 14:03:41 -0700421 }
422
Chong Zhang66469272020-06-04 16:51:55 -0700423 int32_t mClientId;
Chong Zhang3f23e982020-09-24 14:03:41 -0700424 pid_t mClientPid;
425 uid_t mClientUid;
426 std::string mPackageName;
427 std::shared_ptr<ITranscodingClient> mClient;
Chong Zhang66469272020-06-04 16:51:55 -0700428};
429
430class MediaTranscodingServiceTestBase : public ::testing::Test {
431public:
432 MediaTranscodingServiceTestBase() { ALOGI("MediaTranscodingServiceTestBase created"); }
433
434 virtual ~MediaTranscodingServiceTestBase() {
435 ALOGI("MediaTranscodingServiceTestBase destroyed");
436 }
437
438 void SetUp() override {
439 // Need thread pool to receive callbacks, otherwise oneway callbacks are
440 // silently ignored.
441 ABinderProcess_startThreadPool();
442 ::ndk::SpAIBinder binder(AServiceManager_getService("media.transcoding"));
443 mService = IMediaTranscodingService::fromBinder(binder);
444 if (mService == nullptr) {
445 ALOGE("Failed to connect to the media.trascoding service.");
446 return;
447 }
Chong Zhang4fe34f92020-10-06 15:47:28 -0700448
Chong Zhang3f23e982020-09-24 14:03:41 -0700449 mClient1 = ::ndk::SharedRefBase::make<TestClientCallback>(kClientPackageA, 1);
450 mClient2 = ::ndk::SharedRefBase::make<TestClientCallback>(kClientPackageB, 2);
451 mClient3 = ::ndk::SharedRefBase::make<TestClientCallback>(kClientPackageC, 3);
Chong Zhang66469272020-06-04 16:51:55 -0700452 }
453
Chong Zhang3f23e982020-09-24 14:03:41 -0700454 Status registerOneClient(const std::shared_ptr<TestClientCallback>& callback) {
455 ALOGD("registering %s with uid %d", callback->mPackageName.c_str(), callback->mClientUid);
Chong Zhang66469272020-06-04 16:51:55 -0700456
457 std::shared_ptr<ITranscodingClient> client;
Chong Zhang3f23e982020-09-24 14:03:41 -0700458 Status status =
459 mService->registerClient(callback, kClientName, callback->mPackageName, &client);
460
461 if (status.isOk()) {
462 callback->mClient = client;
463 } else {
464 callback->mClient = nullptr;
465 }
466 return status;
Chong Zhang66469272020-06-04 16:51:55 -0700467 }
468
469 void registerMultipleClients() {
470 // Register 3 clients.
Chong Zhang3f23e982020-09-24 14:03:41 -0700471 EXPECT_TRUE(registerOneClient(mClient1).isOk());
472 EXPECT_TRUE(registerOneClient(mClient2).isOk());
473 EXPECT_TRUE(registerOneClient(mClient3).isOk());
Chong Zhang66469272020-06-04 16:51:55 -0700474
475 // Check the number of clients.
476 int32_t numOfClients;
477 Status status = mService->getNumOfClients(&numOfClients);
478 EXPECT_TRUE(status.isOk());
Chong Zhang4fe34f92020-10-06 15:47:28 -0700479 EXPECT_GE(numOfClients, 3);
Chong Zhang66469272020-06-04 16:51:55 -0700480 }
481
482 void unregisterMultipleClients() {
Chong Zhang66469272020-06-04 16:51:55 -0700483 // Unregister the clients.
Chong Zhang3f23e982020-09-24 14:03:41 -0700484 EXPECT_TRUE(mClient1->unregisterClient().isOk());
485 EXPECT_TRUE(mClient2->unregisterClient().isOk());
486 EXPECT_TRUE(mClient3->unregisterClient().isOk());
Chong Zhang66469272020-06-04 16:51:55 -0700487 }
488
Chong Zhang66469272020-06-04 16:51:55 -0700489 void deleteFile(const char* path) { unlink(path); }
490
491 std::shared_ptr<IMediaTranscodingService> mService;
Chong Zhang3f23e982020-09-24 14:03:41 -0700492 std::shared_ptr<TestClientCallback> mClient1;
493 std::shared_ptr<TestClientCallback> mClient2;
494 std::shared_ptr<TestClientCallback> mClient3;
Chong Zhang66469272020-06-04 16:51:55 -0700495};
496
497} // namespace media
498} // namespace android