media.omx VTS test baseline
Change-Id: I0cb1997e9cc0427fdfe8091de84e8cb75c7bab14
Test GetPortIndices
Tests support for omx index type: OMX_IndexParamAudioInit,
OMX_IndexParamImageInit, OMX_IndexParamVideoInit, OMX_IndexParamOtherInit.
Change-Id: I50c7c70c8e000684ef02a6e372be32f9c178e74d
Test Port Enabling/Disabling
Enumerate the list of ports available on the component.
Test if they can be disabled and enabled. This test is carried
when the component is in Loaded state. Also, omx-il specification
allows enabling and disabling all ports at once by passing the
argument OMX_ALL. The behavior of the component on this argument
is tested. Disable and enable a port index that is not supported
by the component is also tested.
Change-Id: I1ab3cc3652a63d05bd0c3ceae92e01ebd4aae12d
Test State Transitions
Change the states of the component from loaded->idle->execute->idle->loaded
While the component is switching states, make sure the below dependencies are met.
1. When the component is switching from Loaded to Idle,
ensure this transition does not take place until the supplier has provided
the ports their necessary buffers
2. When the component is switching from Idle to execute,
change the buffer owner from Client to Component.
3. When the component is switching from execute to Idle,
ensure the client got all the buffers it supplied to the component back.
4. When the component is switching from Idle to loaded,
ensure this transition takes place only after freeing all the buffers
Change-Id: I7c3f6f65adf3afda4e54ca7cafb5bb7799a5b2d6
Test for Flush
When the component is in execute state and as buffers are being
exchanged between client and component, call a flush. Test that all
the unprocessed buffers are returned to the client
Change-Id: I00f4c356df0e832aecc457a53163532e82ead9a3
Fix object labels for master and component
This changes maintains consistency across Vts test folders
Change-Id: I0f3e40db04876a3dab170936037c42f994d67c18
Audio_enc/Audio_dec folders are removed.
The current folders needs work. We will revisit this again
Change-Id: Ic8287288d0727f1384e096b846e0066b2ec9f95f
Fix Object labels for common
Change-Id: I8f19a339983aa81d581ed3d55780180f8d976382
Test Port Definition structures
Tests support for omx index type OMX_IndexParamPortDefinition
Change-Id: I45d82199c6cf20f24aa42d9fea69bd1c88a51757
Bug fix : Pass i/o buffer structure information while dequeueing messages
Also fixed sending false port id during freeBuffer call.
Change-Id: Id5c4f67cccea6b577880e42ee0d294cc55d534ad
Test port reconfiguration and buffer flow in audio decoder
In the current commit we have added tests for audio decoder
components. The selected component decodes an elementary stream
and in this process port reconfiguration, buffer flow and flush
are tested.
Test: mma
Change-Id: I42c8397f704f5fa69878efe91932c477ac66d1b2
diff --git a/media/Android.bp b/media/Android.bp
old mode 100644
new mode 100755
index f2abc67..34ecf17
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -2,4 +2,7 @@
subdirs = [
"1.0",
"omx/1.0",
+ "omx/1.0/vts/functional/master",
+ "omx/1.0/vts/functional/component",
+ "omx/1.0/vts/functional/audio",
]
diff --git a/media/omx/1.0/vts/functional/audio/Android.bp b/media/omx/1.0/vts/functional/audio/Android.bp
new file mode 100644
index 0000000..d6c73ce
--- /dev/null
+++ b/media/omx/1.0/vts/functional/audio/Android.bp
@@ -0,0 +1,79 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalMediaOmxV1_0TargetAudioEncTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalMediaOmxV1_0TargetAudioEncTest.cpp",
+ "media_audio_hidl_test_common.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libhidlmemory",
+ "libhidltransport",
+ "libhwbinder",
+ "libnativehelper",
+ "libutils",
+ "libstagefright_foundation",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "android.hardware.media.omx@1.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+ include_dirs: [
+ "frameworks/native/include/media/openmax/",
+ "hardware/interfaces/media/omx/1.0/vts/functional/common",
+ ],
+}
+
+cc_test {
+ name: "VtsHalMediaOmxV1_0TargetAudioDecTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalMediaOmxV1_0TargetAudioDecTest.cpp",
+ "media_audio_hidl_test_common.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libhidlmemory",
+ "libhidltransport",
+ "libhwbinder",
+ "libnativehelper",
+ "libutils",
+ "libstagefright_foundation",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "android.hardware.media.omx@1.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+ include_dirs: [
+ "frameworks/native/include/media/openmax/",
+ "hardware/interfaces/media/omx/1.0/vts/functional/common",
+ ],
+}
+
+
diff --git a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp
new file mode 100644
index 0000000..7c21753
--- /dev/null
+++ b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioDecTest.cpp
@@ -0,0 +1,687 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "media_omx_hidl_audio_dec_test"
+#include <android-base/logging.h>
+
+#include <android/hardware/media/omx/1.0/IOmx.h>
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+#include <android/hardware/media/omx/1.0/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMapper.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+
+using ::android::hardware::media::omx::V1_0::IOmx;
+using ::android::hardware::media::omx::V1_0::IOmxObserver;
+using ::android::hardware::media::omx::V1_0::IOmxNode;
+using ::android::hardware::media::omx::V1_0::Message;
+using ::android::hardware::media::omx::V1_0::CodecBuffer;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::hidl::memory::V1_0::IMapper;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <getopt.h>
+#include <media_audio_hidl_test_common.h>
+#include <media_hidl_test_common.h>
+#include <fstream>
+
+// A class for test environment setup
+class ComponentTestEnvironment : public ::testing::Environment {
+ public:
+ virtual void SetUp() {}
+ virtual void TearDown() {}
+
+ ComponentTestEnvironment() : instance("default") {}
+
+ void setInstance(const char* _instance) { instance = _instance; }
+
+ void setComponent(const char* _component) { component = _component; }
+
+ void setRole(const char* _role) { role = _role; }
+
+ void setQuirks(int _quirks) { quirks = _quirks; }
+
+ const hidl_string getInstance() const { return instance; }
+
+ const hidl_string getComponent() const { return component; }
+
+ const hidl_string getRole() const { return role; }
+
+ int getQuirks() const { return quirks; }
+
+ int initFromOptions(int argc, char** argv) {
+ static struct option options[] = {
+ {"instance", required_argument, 0, 'I'},
+ {"component", required_argument, 0, 'C'},
+ {"role", required_argument, 0, 'R'},
+ {"quirks", required_argument, 0, 'Q'},
+ {0, 0, 0, 0}};
+
+ while (true) {
+ int index = 0;
+ int c = getopt_long(argc, argv, "I:C:Q:R:", options, &index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'I':
+ setInstance(optarg);
+ break;
+ case 'C':
+ setComponent(optarg);
+ break;
+ case 'Q':
+ setQuirks(atoi(optarg));
+ break;
+ case 'R':
+ setRole(optarg);
+ break;
+ case '?':
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr,
+ "unrecognized option: %s\n\n"
+ "usage: %s <gtest options> <test options>\n\n"
+ "test options are:\n\n"
+ "-I, --instance: HAL instance to test\n"
+ "-C, --component: OMX component to test\n"
+ "-R, --Role: OMX component Role\n"
+ "-Q, --quirks: Component quirks\n",
+ argv[optind ?: 1], argv[0]);
+ return 2;
+ }
+ return 0;
+ }
+
+ private:
+ hidl_string instance;
+ hidl_string component;
+ hidl_string role;
+ // to be removed when IOmxNode::setQuirks is removed
+ int quirks;
+};
+
+static ComponentTestEnvironment* gEnv = nullptr;
+
+class AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ android::hardware::media::omx::V1_0::Status status;
+ omx = ::testing::VtsHalHidlTargetTestBase::getService<IOmx>(
+ gEnv->getInstance());
+ ASSERT_NE(omx, nullptr);
+ observer = new CodecObserver();
+ ASSERT_NE(observer, nullptr);
+ ASSERT_EQ(strncmp(gEnv->getComponent().c_str(), "OMX.", 4), 0)
+ << "Invalid Component Name";
+ EXPECT_TRUE(omx->allocateNode(
+ gEnv->getComponent(), observer,
+ [&](android::hardware::media::omx::V1_0::Status _s,
+ sp<IOmxNode> const& _nl) {
+ status = _s;
+ this->omxNode = _nl;
+ })
+ .isOk());
+ ASSERT_NE(omxNode, nullptr);
+ ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role";
+ struct StringToName {
+ const char* Name;
+ standardComp CompName;
+ };
+ const StringToName kStringToName[] = {
+ {"mp3", mp3}, {"amrnb", amrnb}, {"amrwb", amrwb},
+ {"aac", aac}, {"vorbis", vorbis}, {"opus", opus},
+ {"pcm", pcm}, {"flac", flac},
+ };
+ const size_t kNumStringToName =
+ sizeof(kStringToName) / sizeof(kStringToName[0]);
+ const char* pch;
+ char substring[OMX_MAX_STRINGNAME_SIZE];
+ strcpy(substring, gEnv->getRole().c_str());
+ pch = strchr(substring, '.');
+ ASSERT_NE(pch, nullptr);
+ compName = unknown_comp;
+ for (size_t i = 0; i < kNumStringToName; ++i) {
+ if (!strcasecmp(pch + 1, kStringToName[i].Name)) {
+ compName = kStringToName[i].CompName;
+ break;
+ }
+ }
+ ASSERT_NE(compName, unknown_comp);
+ struct CompToCoding {
+ standardComp CompName;
+ OMX_AUDIO_CODINGTYPE eEncoding;
+ };
+ static const CompToCoding kCompToCoding[] = {
+ {mp3, OMX_AUDIO_CodingMP3},
+ {amrnb, OMX_AUDIO_CodingAMR},
+ {amrwb, OMX_AUDIO_CodingAMR},
+ {aac, OMX_AUDIO_CodingAAC},
+ {vorbis, OMX_AUDIO_CodingVORBIS},
+ {pcm, OMX_AUDIO_CodingPCM},
+ {opus, (OMX_AUDIO_CODINGTYPE)OMX_AUDIO_CodingAndroidOPUS},
+ {flac, OMX_AUDIO_CodingFLAC},
+ };
+ static const size_t kNumCompToCoding =
+ sizeof(kCompToCoding) / sizeof(kCompToCoding[0]);
+ size_t i;
+ for (i = 0; i < kNumCompToCoding; ++i) {
+ if (kCompToCoding[i].CompName == compName) {
+ eEncoding = kCompToCoding[i].eEncoding;
+ break;
+ }
+ }
+ ASSERT_NE(i, kNumCompToCoding);
+ }
+
+ virtual void TearDown() override {
+ if (omxNode != nullptr) {
+ EXPECT_TRUE((omxNode->freeNode()).isOk());
+ omxNode = nullptr;
+ }
+ }
+
+ enum standardComp {
+ mp3,
+ amrnb,
+ amrwb,
+ aac,
+ vorbis,
+ opus,
+ pcm,
+ flac,
+ unknown_comp,
+ };
+
+ sp<IOmx> omx;
+ sp<CodecObserver> observer;
+ sp<IOmxNode> omxNode;
+ standardComp compName;
+ OMX_AUDIO_CODINGTYPE eEncoding;
+};
+
+void setDefaultPortParam(
+ sp<IOmxNode> omxNode, OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE eEncoding,
+ int32_t nChannels = 2, int32_t nSampleRate = 44100,
+ OMX_NUMERICALDATATYPE eNumData = OMX_NumericalDataSigned,
+ int32_t nBitPerSample = 16) {
+ android::hardware::media::omx::V1_0::Status status;
+ OMX_PARAM_PORTDEFINITIONTYPE portDef;
+ status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
+ &portDef);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+
+ portDef.format.audio.bFlagErrorConcealment = OMX_TRUE;
+ portDef.format.audio.eEncoding = eEncoding;
+ status = setPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
+ &portDef);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+
+ switch ((int)eEncoding) {
+ case OMX_AUDIO_CodingPCM:
+ setupPCMPort(omxNode, portIndex, nChannels, eNumData, nBitPerSample,
+ nSampleRate);
+ break;
+ default:
+ ASSERT_TRUE(false);
+ break;
+ }
+}
+
+void getInputChannelInfo(sp<IOmxNode> omxNode, OMX_U32 kPortIndexInput,
+ OMX_AUDIO_CODINGTYPE eEncoding, int32_t* nChannels,
+ int32_t* nSampleRate) {
+ *nChannels = 0;
+ *nSampleRate = 0;
+ android::hardware::media::omx::V1_0::Status status;
+
+ switch ((int)eEncoding) {
+ case OMX_AUDIO_CodingPCM: {
+ OMX_AUDIO_PARAM_PCMMODETYPE param;
+ status = getPortParam(omxNode, OMX_IndexParamAudioPcm,
+ kPortIndexInput, ¶m);
+ ASSERT_EQ(status,
+ ::android::hardware::media::omx::V1_0::Status::OK);
+ *nChannels = param.nChannels;
+ *nSampleRate = param.nSamplingRate;
+ break;
+ }
+ case OMX_AUDIO_CodingMP3: {
+ OMX_AUDIO_PARAM_MP3TYPE param;
+ status = getPortParam(omxNode, OMX_IndexParamAudioMp3,
+ kPortIndexInput, ¶m);
+ ASSERT_EQ(status,
+ ::android::hardware::media::omx::V1_0::Status::OK);
+ *nChannels = param.nChannels;
+ *nSampleRate = param.nSampleRate;
+ break;
+ }
+ case OMX_AUDIO_CodingFLAC: {
+ OMX_AUDIO_PARAM_FLACTYPE param;
+ status = getPortParam(omxNode, OMX_IndexParamAudioFlac,
+ kPortIndexInput, ¶m);
+ ASSERT_EQ(status,
+ ::android::hardware::media::omx::V1_0::Status::OK);
+ *nChannels = param.nChannels;
+ *nSampleRate = param.nSampleRate;
+ break;
+ }
+ case OMX_AUDIO_CodingAndroidOPUS: {
+ OMX_AUDIO_PARAM_ANDROID_OPUSTYPE param;
+ status = getPortParam(omxNode,
+ (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidOpus,
+ kPortIndexInput, ¶m);
+ ASSERT_EQ(status,
+ ::android::hardware::media::omx::V1_0::Status::OK);
+ *nChannels = param.nChannels;
+ *nSampleRate = param.nSampleRate;
+ break;
+ }
+ case OMX_AUDIO_CodingVORBIS: {
+ OMX_AUDIO_PARAM_VORBISTYPE param;
+ status = getPortParam(omxNode, OMX_IndexParamAudioVorbis,
+ kPortIndexInput, ¶m);
+ ASSERT_EQ(status,
+ ::android::hardware::media::omx::V1_0::Status::OK);
+ *nChannels = param.nChannels;
+ *nSampleRate = param.nSampleRate;
+ break;
+ }
+ case OMX_AUDIO_CodingAMR: {
+ OMX_AUDIO_PARAM_AMRTYPE param;
+ status = getPortParam(omxNode, OMX_IndexParamAudioAmr,
+ kPortIndexInput, ¶m);
+ ASSERT_EQ(status,
+ ::android::hardware::media::omx::V1_0::Status::OK);
+ *nChannels = param.nChannels;
+ *nSampleRate = 8000;
+ break;
+ }
+ case OMX_AUDIO_CodingAAC: {
+ OMX_AUDIO_PARAM_AACPROFILETYPE param;
+ status = getPortParam(omxNode, OMX_IndexParamAudioAac,
+ kPortIndexInput, ¶m);
+ ASSERT_EQ(status,
+ ::android::hardware::media::omx::V1_0::Status::OK);
+ *nChannels = param.nChannels;
+ *nSampleRate = param.nSampleRate;
+ break;
+ }
+ default:
+ ASSERT_TRUE(false);
+ break;
+ }
+}
+
+void GetURLForComponent(AudioDecHidlTest::standardComp comp, const char** mURL,
+ const char** info) {
+ struct CompToURL {
+ AudioDecHidlTest::standardComp comp;
+ const char* mURL;
+ const char* info;
+ };
+ static const CompToURL kCompToURL[] = {
+ {AudioDecHidlTest::standardComp::mp3,
+ "/sdcard/raw/MP3_48KHz_128kbps_s_1_17_CBR.audio.mp3",
+ "/sdcard/raw/MP3_48KHz_128kbps_s_1_17_CBR.audio.info"},
+ {AudioDecHidlTest::standardComp::aac,
+ "/sdcard/raw/H264_500_AAC_128.audio.aac",
+ "/sdcard/raw/H264_500_AAC_128.audio.info"},
+ {AudioDecHidlTest::standardComp::amrnb,
+ "/sdcard/raw/H264_320_AMRNB_6.audio.amr",
+ "/sdcard/raw/H264_320_AMRNB_6.audio.info"},
+ {AudioDecHidlTest::standardComp::amrwb, "", ""},
+ {AudioDecHidlTest::standardComp::vorbis, "", ""},
+ {AudioDecHidlTest::standardComp::opus, "", ""},
+ {AudioDecHidlTest::standardComp::flac, "", ""},
+ };
+
+ for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) {
+ if (kCompToURL[i].comp == comp) {
+ *mURL = kCompToURL[i].mURL;
+ *info = kCompToURL[i].info;
+ return;
+ }
+ }
+}
+
+void flushAllPorts(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
+ android::Vector<BufferInfo>* iBuffer,
+ android::Vector<BufferInfo>* oBuffer,
+ OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput) {
+ android::hardware::media::omx::V1_0::Status status;
+ Message msg;
+ // Flush
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush),
+ kPortIndexInput);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandFlush);
+ ASSERT_EQ(msg.data.eventData.data2, kPortIndexInput);
+ // test if client got all its buffers back
+ for (size_t i = 0; i < iBuffer->size(); ++i) {
+ EXPECT_EQ((*iBuffer)[i].owner, client);
+ }
+
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush),
+ kPortIndexOutput);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandFlush);
+ ASSERT_EQ(msg.data.eventData.data2, kPortIndexOutput);
+ // test if client got all its buffers back
+ for (size_t i = 0; i < oBuffer->size(); ++i) {
+ EXPECT_EQ((*oBuffer)[i].owner, client);
+ }
+}
+
+void decodeNFrames(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
+ android::Vector<BufferInfo>* iBuffer,
+ android::Vector<BufferInfo>* oBuffer,
+ OMX_AUDIO_CODINGTYPE eEncoding, OMX_U32 kPortIndexInput,
+ OMX_U32 kPortIndexOutput, uint32_t nFrames,
+ std::ifstream& eleStream, std::ifstream& eleInfo) {
+ android::hardware::media::omx::V1_0::Status status;
+ Message msg;
+
+ // dispatch output buffers
+ for (size_t i = 0; i < oBuffer->size(); i++) {
+ dispatchOutputBuffer(omxNode, oBuffer, i);
+ }
+ // dispatch input buffers
+ int bytesCount = 0;
+ for (size_t i = 0; i < iBuffer->size(); i++) {
+ char* ipBuffer = static_cast<char*>(
+ static_cast<void*>((*iBuffer)[i].mMemory->getPointer()));
+ if (!(eleInfo >> bytesCount)) break;
+ eleStream.read(ipBuffer, bytesCount);
+ ASSERT_EQ(eleStream.gcount(), bytesCount);
+ dispatchInputBuffer(omxNode, iBuffer, i, bytesCount, 0, 0);
+ }
+
+ while (nFrames != 0) {
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
+ if (status == android::hardware::media::omx::V1_0::Status::OK &&
+ msg.type == Message::Type::EVENT &&
+ msg.data.eventData.event == OMX_EventPortSettingsChanged) {
+ ASSERT_EQ(msg.data.eventData.data1, kPortIndexOutput);
+
+ status = omxNode->sendCommand(
+ toRawCommandType(OMX_CommandPortDisable), kPortIndexOutput);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer,
+ oBuffer);
+ if (status ==
+ android::hardware::media::omx::V1_0::Status::TIMED_OUT) {
+ for (size_t i = 0; i < oBuffer->size(); ++i) {
+ // test if client got all its buffers back
+ EXPECT_EQ((*oBuffer)[i].owner, client);
+ // free the buffers
+ status =
+ omxNode->freeBuffer(kPortIndexOutput, (*oBuffer)[i].id);
+ ASSERT_EQ(status,
+ android::hardware::media::omx::V1_0::Status::OK);
+ }
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
+ iBuffer, oBuffer);
+ ASSERT_EQ(status,
+ android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortDisable);
+ ASSERT_EQ(msg.data.eventData.data2, kPortIndexOutput);
+
+ // Port Reconfigurations
+ int32_t nChannels;
+ int32_t nSampleRate;
+ getInputChannelInfo(omxNode, kPortIndexInput, eEncoding,
+ &nChannels, &nSampleRate);
+ setDefaultPortParam(omxNode, kPortIndexOutput,
+ OMX_AUDIO_CodingPCM, nChannels,
+ nSampleRate);
+
+ // If you can disable a port, then you should be able to enable
+ // it as well
+ status = omxNode->sendCommand(
+ toRawCommandType(OMX_CommandPortEnable), kPortIndexOutput);
+ ASSERT_EQ(status,
+ android::hardware::media::omx::V1_0::Status::OK);
+
+ // do not enable the port until all the buffers are supplied
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
+ iBuffer, oBuffer);
+ ASSERT_EQ(
+ status,
+ android::hardware::media::omx::V1_0::Status::TIMED_OUT);
+
+ allocatePortBuffers(omxNode, oBuffer, kPortIndexOutput);
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
+ iBuffer, oBuffer);
+ ASSERT_EQ(status,
+ android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortEnable);
+ ASSERT_EQ(msg.data.eventData.data2, kPortIndexOutput);
+
+ // dispatch output buffers
+ for (size_t i = 0; i < oBuffer->size(); i++) {
+ dispatchOutputBuffer(omxNode, oBuffer, i);
+ }
+ } else {
+ ASSERT_TRUE(false);
+ }
+ continue;
+ }
+ size_t index = 0;
+ if ((index = getEmptyBufferID(iBuffer)) < iBuffer->size()) {
+ char* ipBuffer = static_cast<char*>(
+ static_cast<void*>((*iBuffer)[index].mMemory->getPointer()));
+ if (!(eleInfo >> bytesCount)) break;
+ eleStream.read(ipBuffer, bytesCount);
+ ASSERT_EQ(eleStream.gcount(), bytesCount);
+ dispatchInputBuffer(omxNode, iBuffer, index, bytesCount, 0, 0);
+ }
+ if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) {
+ dispatchOutputBuffer(omxNode, oBuffer, index);
+ }
+ nFrames--;
+ }
+}
+
+// Set Component Role
+TEST_F(AudioDecHidlTest, SetRole) {
+ android::hardware::media::omx::V1_0::Status status;
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+// Enumerate Port Format
+TEST_F(AudioDecHidlTest, EnumeratePortFormat) {
+ android::hardware::media::omx::V1_0::Status status;
+ uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ OMX_PORT_PARAM_TYPE params;
+ status = getParam(omxNode, OMX_IndexParamAudioInit, ¶ms);
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(params.nPorts, 2U);
+ kPortIndexInput = params.nStartPortNumber;
+ kPortIndexOutput = kPortIndexInput + 1;
+ }
+ status = setAudioPortFormat(omxNode, kPortIndexInput, eEncoding);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ status = setAudioPortFormat(omxNode, kPortIndexOutput, OMX_AUDIO_CodingPCM);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+// Decode Test
+TEST_F(AudioDecHidlTest, DecodeTest) {
+ android::hardware::media::omx::V1_0::Status status;
+ uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ OMX_PORT_PARAM_TYPE params;
+ status = getParam(omxNode, OMX_IndexParamAudioInit, ¶ms);
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(params.nPorts, 2U);
+ kPortIndexInput = params.nStartPortNumber;
+ kPortIndexOutput = kPortIndexInput + 1;
+ }
+ const char *mURL = nullptr, *info = nullptr;
+ GetURLForComponent(compName, &mURL, &info);
+ EXPECT_NE(mURL, nullptr);
+ EXPECT_NE(info, nullptr);
+
+ std::ifstream eleStream, eleInfo;
+ eleStream.open(mURL, std::ifstream::binary);
+ ASSERT_EQ(eleStream.is_open(), true);
+ eleInfo.open(info);
+ ASSERT_EQ(eleInfo.is_open(), true);
+
+ if (eEncoding == OMX_AUDIO_CodingPCM)
+ setDefaultPortParam(omxNode, kPortIndexInput, eEncoding);
+ int32_t nChannels;
+ int32_t nSampleRate;
+ getInputChannelInfo(omxNode, kPortIndexInput, eEncoding, &nChannels,
+ &nSampleRate);
+ setDefaultPortParam(omxNode, kPortIndexOutput, OMX_AUDIO_CodingPCM,
+ nChannels, nSampleRate);
+
+ Message msg;
+ android::Vector<BufferInfo> iBuffer, oBuffer;
+
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateIdle);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
+
+ allocatePortBuffers(omxNode, &iBuffer, kPortIndexInput);
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
+ allocatePortBuffers(omxNode, &oBuffer, kPortIndexOutput);
+
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
+
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateExecuting);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateExecuting);
+
+ // Port Reconfiguration
+ decodeNFrames(omxNode, observer, &iBuffer, &oBuffer, eEncoding,
+ kPortIndexInput, kPortIndexOutput, (1 << 12), eleStream,
+ eleInfo);
+
+ // flush
+ flushAllPorts(omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput,
+ kPortIndexOutput);
+
+ // set state to Idle
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateIdle);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
+
+ // set state to Loaded
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateLoaded);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // dont change state until all buffers are freed
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
+
+ for (size_t i = 0; i < iBuffer.size(); ++i) {
+ status = omxNode->freeBuffer(kPortIndexInput, iBuffer[i].id);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ }
+
+ // dont change state until all buffers are freed
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
+
+ for (size_t i = 0; i < oBuffer.size(); ++i) {
+ status = omxNode->freeBuffer(kPortIndexOutput, oBuffer[i].id);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ }
+
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateLoaded);
+
+ eleInfo.close();
+ eleStream.close();
+}
+
+int main(int argc, char** argv) {
+ gEnv = new ComponentTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ }
+ return status;
+}
diff --git a/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp
new file mode 100644
index 0000000..6a88b1a
--- /dev/null
+++ b/media/omx/1.0/vts/functional/audio/VtsHalMediaOmxV1_0TargetAudioEncTest.cpp
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "media_omx_hidl_audio_enc_test"
+#include <android-base/logging.h>
+
+#include <android/hardware/media/omx/1.0/IOmx.h>
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+#include <android/hardware/media/omx/1.0/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMapper.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+
+using ::android::hardware::media::omx::V1_0::IOmx;
+using ::android::hardware::media::omx::V1_0::IOmxObserver;
+using ::android::hardware::media::omx::V1_0::IOmxNode;
+using ::android::hardware::media::omx::V1_0::Message;
+using ::android::hardware::media::omx::V1_0::CodecBuffer;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::hidl::memory::V1_0::IMapper;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <getopt.h>
+#include <media_audio_hidl_test_common.h>
+#include <media_hidl_test_common.h>
+#include <fstream>
+
+// A class for test environment setup
+class ComponentTestEnvironment : public ::testing::Environment {
+ public:
+ virtual void SetUp() {}
+ virtual void TearDown() {}
+
+ ComponentTestEnvironment() : instance("default") {}
+
+ void setInstance(const char* _instance) { instance = _instance; }
+
+ void setComponent(const char* _component) { component = _component; }
+
+ void setRole(const char* _role) { role = _role; }
+
+ void setQuirks(int _quirks) { quirks = _quirks; }
+
+ const hidl_string getInstance() const { return instance; }
+
+ const hidl_string getComponent() const { return component; }
+
+ const hidl_string getRole() const { return role; }
+
+ int getQuirks() const { return quirks; }
+
+ int initFromOptions(int argc, char** argv) {
+ static struct option options[] = {
+ {"instance", required_argument, 0, 'I'},
+ {"component", required_argument, 0, 'C'},
+ {"role", required_argument, 0, 'R'},
+ {"quirks", required_argument, 0, 'Q'},
+ {0, 0, 0, 0}};
+
+ while (true) {
+ int index = 0;
+ int c = getopt_long(argc, argv, "I:C:Q:R:", options, &index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'I':
+ setInstance(optarg);
+ break;
+ case 'C':
+ setComponent(optarg);
+ break;
+ case 'Q':
+ setQuirks(atoi(optarg));
+ break;
+ case 'R':
+ setRole(optarg);
+ break;
+ case '?':
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr,
+ "unrecognized option: %s\n\n"
+ "usage: %s <gtest options> <test options>\n\n"
+ "test options are:\n\n"
+ "-I, --instance: HAL instance to test\n"
+ "-C, --component: OMX component to test\n"
+ "-R, --Role: OMX component Role\n"
+ "-Q, --quirks: Component quirks\n",
+ argv[optind ?: 1], argv[0]);
+ return 2;
+ }
+ return 0;
+ }
+
+ private:
+ hidl_string instance;
+ hidl_string component;
+ hidl_string role;
+ // to be removed when IOmxNode::setQuirks is removed
+ int quirks;
+};
+
+static ComponentTestEnvironment* gEnv = nullptr;
+
+class AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ android::hardware::media::omx::V1_0::Status status;
+ omx = ::testing::VtsHalHidlTargetTestBase::getService<IOmx>(
+ gEnv->getInstance());
+ ASSERT_NE(omx, nullptr);
+ observer = new CodecObserver();
+ ASSERT_NE(observer, nullptr);
+ ASSERT_EQ(strncmp(gEnv->getComponent().c_str(), "OMX.", 4), 0)
+ << "Invalid Component Name";
+ EXPECT_TRUE(omx->allocateNode(
+ gEnv->getComponent(), observer,
+ [&](android::hardware::media::omx::V1_0::Status _s,
+ sp<IOmxNode> const& _nl) {
+ status = _s;
+ this->omxNode = _nl;
+ })
+ .isOk());
+ ASSERT_NE(omxNode, nullptr);
+ ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role";
+ struct StringToName {
+ const char* Name;
+ standardComp CompName;
+ };
+ const StringToName kStringToName[] = {
+ {"mp3", mp3}, {"amrnb", amrnb}, {"amrwb", amrwb},
+ {"aac", aac}, {"vorbis", vorbis}, {"opus", opus},
+ {"pcm", pcm}, {"flac", flac},
+ };
+ const size_t kNumStringToName =
+ sizeof(kStringToName) / sizeof(kStringToName[0]);
+ const char* pch;
+ char substring[OMX_MAX_STRINGNAME_SIZE];
+ strcpy(substring, gEnv->getRole().c_str());
+ pch = strchr(substring, '.');
+ ASSERT_NE(pch, nullptr);
+ compName = unknown_comp;
+ for (size_t i = 0; i < kNumStringToName; ++i) {
+ if (!strcasecmp(pch + 1, kStringToName[i].Name)) {
+ compName = kStringToName[i].CompName;
+ break;
+ }
+ }
+ ASSERT_NE(compName, unknown_comp);
+ struct CompToCoding {
+ standardComp CompName;
+ OMX_AUDIO_CODINGTYPE eEncoding;
+ };
+ static const CompToCoding kCompToCoding[] = {
+ {mp3, OMX_AUDIO_CodingMP3},
+ {amrnb, OMX_AUDIO_CodingAMR},
+ {amrwb, OMX_AUDIO_CodingAMR},
+ {aac, OMX_AUDIO_CodingAAC},
+ {vorbis, OMX_AUDIO_CodingVORBIS},
+ {pcm, OMX_AUDIO_CodingPCM},
+ {opus, (OMX_AUDIO_CODINGTYPE)OMX_AUDIO_CodingAndroidOPUS},
+ {flac, OMX_AUDIO_CodingFLAC},
+ };
+ static const size_t kNumCompToCoding =
+ sizeof(kCompToCoding) / sizeof(kCompToCoding[0]);
+ size_t i;
+ for (i = 0; i < kNumCompToCoding; ++i) {
+ if (kCompToCoding[i].CompName == compName) {
+ eEncoding = kCompToCoding[i].eEncoding;
+ break;
+ }
+ }
+ ASSERT_NE(i, kNumCompToCoding);
+ }
+
+ virtual void TearDown() override {
+ if (omxNode != nullptr) {
+ EXPECT_TRUE((omxNode->freeNode()).isOk());
+ omxNode = nullptr;
+ }
+ }
+
+ enum standardComp {
+ mp3,
+ amrnb,
+ amrwb,
+ aac,
+ vorbis,
+ opus,
+ pcm,
+ flac,
+ unknown_comp,
+ };
+
+ sp<IOmx> omx;
+ sp<CodecObserver> observer;
+ sp<IOmxNode> omxNode;
+ standardComp compName;
+ OMX_AUDIO_CODINGTYPE eEncoding;
+};
+
+// Set Component Role
+TEST_F(AudioEncHidlTest, SetRole) {
+ android::hardware::media::omx::V1_0::Status status;
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+// Enumerate Port Format
+TEST_F(AudioEncHidlTest, EnumeratePortFormat) {
+ android::hardware::media::omx::V1_0::Status status;
+ uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ OMX_PORT_PARAM_TYPE params;
+ status = getParam(omxNode, OMX_IndexParamAudioInit, ¶ms);
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(params.nPorts, 2U);
+ kPortIndexInput = params.nStartPortNumber;
+ kPortIndexOutput = kPortIndexInput + 1;
+ }
+ status = setAudioPortFormat(omxNode, kPortIndexInput, OMX_AUDIO_CodingPCM);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ status = setAudioPortFormat(omxNode, kPortIndexOutput, eEncoding);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+int main(int argc, char** argv) {
+ gEnv = new ComponentTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ }
+ return status;
+}
diff --git a/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.cpp b/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.cpp
new file mode 100644
index 0000000..e01e9aa
--- /dev/null
+++ b/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.cpp
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "media_omx_hidl_audio_test_common"
+#include <android-base/logging.h>
+
+#include <android/hardware/media/omx/1.0/IOmx.h>
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+#include <android/hardware/media/omx/1.0/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMapper.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+
+using ::android::hardware::media::omx::V1_0::IOmx;
+using ::android::hardware::media::omx::V1_0::IOmxObserver;
+using ::android::hardware::media::omx::V1_0::IOmxNode;
+using ::android::hardware::media::omx::V1_0::Message;
+using ::android::hardware::media::omx::V1_0::CodecBuffer;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::hidl::memory::V1_0::IMapper;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <hidlmemory/mapping.h>
+#include <media_audio_hidl_test_common.h>
+#include <media_hidl_test_common.h>
+#include <memory>
+
+void allocatePortBuffers(sp<IOmxNode> omxNode,
+ android::Vector<BufferInfo>* buffArray,
+ OMX_U32 portIndex) {
+ android::hardware::media::omx::V1_0::Status status;
+ OMX_PARAM_PORTDEFINITIONTYPE portDef;
+
+ buffArray->clear();
+
+ sp<IAllocator> allocator = IAllocator::getService("ashmem");
+ EXPECT_NE(allocator, nullptr);
+
+ status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
+ &portDef);
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ for (size_t i = 0; i < portDef.nBufferCountActual; i++) {
+ BufferInfo buffer;
+ buffer.owner = client;
+ buffer.omxBuffer.type = CodecBuffer::Type::SHARED_MEM;
+ buffer.omxBuffer.attr.preset.rangeOffset = 0;
+ buffer.omxBuffer.attr.preset.rangeLength = 0;
+ bool success;
+ allocator->allocate(
+ portDef.nBufferSize,
+ [&success, &buffer](bool _s,
+ ::android::hardware::hidl_memory const& mem) {
+ success = _s;
+ buffer.omxBuffer.sharedMemory = mem;
+ });
+ ASSERT_EQ(success, true);
+ buffer.mMemory = mapMemory(buffer.omxBuffer.sharedMemory);
+ ASSERT_NE(buffer.mMemory, nullptr);
+ omxNode->useBuffer(
+ portIndex, buffer.omxBuffer,
+ [&status, &buffer](android::hardware::media::omx::V1_0::Status _s,
+ uint32_t id) {
+ status = _s;
+ buffer.id = id;
+ });
+ buffArray->push(buffer);
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ }
+}
+
+size_t getEmptyBufferID(android::Vector<BufferInfo>* buffArray) {
+ for (size_t i = 0; i < buffArray->size(); i++) {
+ if ((*buffArray)[i].owner == client) return i;
+ }
+ return buffArray->size();
+}
+
+void dispatchInputBuffer(sp<IOmxNode> omxNode,
+ android::Vector<BufferInfo>* buffArray,
+ size_t bufferIndex, int bytesCount, uint32_t flags,
+ uint64_t timestamp) {
+ android::hardware::media::omx::V1_0::Status status;
+ CodecBuffer t;
+ t.sharedMemory = android::hardware::hidl_memory();
+ t.nativeHandle = android::hardware::hidl_handle();
+ t.type = CodecBuffer::Type::PRESET;
+ t.attr.preset.rangeOffset = 0;
+ t.attr.preset.rangeLength = bytesCount;
+ native_handle_t* fenceNh = native_handle_create(0, 0);
+ ASSERT_NE(fenceNh, nullptr);
+ status = omxNode->emptyBuffer((*buffArray)[bufferIndex].id, t, flags,
+ timestamp, fenceNh);
+ native_handle_close(fenceNh);
+ native_handle_delete(fenceNh);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ buffArray->editItemAt(bufferIndex).owner = component;
+}
+
+void dispatchOutputBuffer(sp<IOmxNode> omxNode,
+ android::Vector<BufferInfo>* buffArray,
+ size_t bufferIndex) {
+ android::hardware::media::omx::V1_0::Status status;
+ CodecBuffer t;
+ t.sharedMemory = android::hardware::hidl_memory();
+ t.nativeHandle = android::hardware::hidl_handle();
+ t.type = CodecBuffer::Type::PRESET;
+ t.attr.preset.rangeOffset = 0;
+ t.attr.preset.rangeLength = 0;
+ native_handle_t* fenceNh = native_handle_create(0, 0);
+ ASSERT_NE(fenceNh, nullptr);
+ status = omxNode->fillBuffer((*buffArray)[bufferIndex].id, t, fenceNh);
+ native_handle_close(fenceNh);
+ native_handle_delete(fenceNh);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ buffArray->editItemAt(bufferIndex).owner = component;
+}
+
+Return<android::hardware::media::omx::V1_0::Status> setAudioPortFormat(
+ sp<IOmxNode> omxNode, OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE encoding) {
+ OMX_U32 index = 0;
+ OMX_AUDIO_PARAM_PORTFORMATTYPE portFormat;
+ std::vector<OMX_AUDIO_CODINGTYPE> eEncoding;
+ android::hardware::media::omx::V1_0::Status status;
+
+ while (1) {
+ portFormat.nIndex = index;
+ status = getPortParam(omxNode, OMX_IndexParamAudioPortFormat, portIndex,
+ &portFormat);
+ if (status != ::android::hardware::media::omx::V1_0::Status::OK) break;
+ eEncoding.push_back(portFormat.eEncoding);
+ index++;
+ if (index == 512) {
+ EXPECT_LE(index, 512U)
+ << "Expecting OMX_ErrorNoMore but not received";
+ break;
+ }
+ }
+ if (!index) return status;
+ for (index = 0; index < eEncoding.size(); index++) {
+ if (eEncoding[index] == encoding) {
+ portFormat.eEncoding = eEncoding[index];
+ break;
+ }
+ }
+ if (index == eEncoding.size()) {
+ ALOGI("setting default Port format");
+ portFormat.eEncoding = eEncoding[0];
+ }
+ // In setParam call nIndex shall be ignored as per omx-il specification.
+ // see how this holds up by corrupting nIndex
+ portFormat.nIndex = RANDOM_INDEX;
+ status = setPortParam(omxNode, OMX_IndexParamAudioPortFormat, portIndex,
+ &portFormat);
+ return status;
+}
+
+Return<android::hardware::media::omx::V1_0::Status> setRole(
+ sp<IOmxNode> omxNode, const char* role) {
+ OMX_PARAM_COMPONENTROLETYPE params;
+ strcpy((char*)params.cRole, role);
+ return setParam(omxNode, OMX_IndexParamStandardComponentRole, ¶ms);
+}
+
+void setupPCMPort(sp<IOmxNode> omxNode, OMX_U32 portIndex, int32_t nChannels,
+ OMX_NUMERICALDATATYPE eNumData, int32_t nBitPerSample,
+ int32_t nSamplingRate) {
+ OMX_AUDIO_PARAM_PCMMODETYPE param;
+ android::hardware::media::omx::V1_0::Status status;
+ status = getPortParam(omxNode, OMX_IndexParamAudioPcm, portIndex, ¶m);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ param.nChannels = nChannels;
+ param.eNumData = eNumData;
+ param.eEndian = OMX_EndianBig;
+ param.bInterleaved = OMX_TRUE;
+ param.nBitPerSample = nBitPerSample;
+ param.nSamplingRate = nSamplingRate;
+ param.ePCMMode = OMX_AUDIO_PCMModeLinear;
+ switch (nChannels) {
+ case 1:
+ param.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
+ break;
+ case 2:
+ param.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
+ param.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+ break;
+ default:
+ EXPECT_TRUE(false);
+ }
+ status = setPortParam(omxNode, OMX_IndexParamAudioPcm, portIndex, ¶m);
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+void setupMP3Port(sp<IOmxNode> omxNode, OMX_U32 portIndex,
+ OMX_AUDIO_MP3STREAMFORMATTYPE eFormat, int32_t nChannels,
+ int32_t nBitRate, int32_t nSampleRate, bool isEncoder) {
+ if (isEncoder == false) return;
+ OMX_AUDIO_PARAM_MP3TYPE param;
+ android::hardware::media::omx::V1_0::Status status;
+ status = getPortParam(omxNode, OMX_IndexParamAudioMp3, portIndex, ¶m);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ param.nChannels = nChannels;
+ param.nBitRate = nBitRate;
+ param.nSampleRate = nSampleRate;
+ param.nAudioBandWidth = 0;
+ param.eChannelMode = (nChannels == 1) ? OMX_AUDIO_ChannelModeMono
+ : OMX_AUDIO_ChannelModeStereo;
+ param.eFormat = eFormat;
+ status = setPortParam(omxNode, OMX_IndexParamAudioMp3, portIndex, ¶m);
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+void setupFLACPort(sp<IOmxNode> omxNode, OMX_U32 portIndex, int32_t nChannels,
+ int32_t nSampleRate, int32_t nCompressionLevel,
+ bool isEncoder) {
+ if (isEncoder == false) return;
+ android::hardware::media::omx::V1_0::Status status;
+ OMX_AUDIO_PARAM_FLACTYPE param;
+ status = getPortParam(omxNode, OMX_IndexParamAudioFlac, portIndex, ¶m);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ param.nChannels = nChannels;
+ param.nSampleRate = nSampleRate;
+ param.nCompressionLevel = nCompressionLevel;
+ status = setPortParam(omxNode, OMX_IndexParamAudioFlac, portIndex, ¶m);
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+void setupOPUSPort(sp<IOmxNode> omxNode, OMX_U32 portIndex, int32_t nChannels,
+ int32_t nBitRate, int32_t nSampleRate, bool isEncoder) {
+ if (isEncoder == false) return;
+ android::hardware::media::omx::V1_0::Status status;
+ OMX_AUDIO_PARAM_ANDROID_OPUSTYPE param;
+ status =
+ getPortParam(omxNode, (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidOpus,
+ portIndex, ¶m);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ param.nChannels = nChannels;
+ param.nBitRate = nBitRate;
+ param.nSampleRate = nSampleRate;
+ status =
+ setPortParam(omxNode, (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidOpus,
+ portIndex, ¶m);
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+void setupAMRPort(sp<IOmxNode> omxNode, OMX_U32 portIndex, int32_t nBitRate,
+ OMX_AUDIO_AMRBANDMODETYPE eAMRBandMode, bool isEncoder) {
+ if (isEncoder == false) return;
+ android::hardware::media::omx::V1_0::Status status;
+ OMX_AUDIO_PARAM_AMRTYPE param;
+ status = getPortParam(omxNode, OMX_IndexParamAudioAmr, portIndex, ¶m);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ param.nChannels = 1;
+ param.nBitRate = nBitRate;
+ param.eAMRBandMode = eAMRBandMode;
+ status = setPortParam(omxNode, OMX_IndexParamAudioAmr, portIndex, ¶m);
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+void setupVORBISPort(sp<IOmxNode> omxNode, OMX_U32 portIndex, int32_t nChannels,
+ int32_t nBitRate, int32_t nSampleRate, int32_t nQuality,
+ bool isEncoder) {
+ if (isEncoder == false) return;
+ android::hardware::media::omx::V1_0::Status status;
+ OMX_AUDIO_PARAM_VORBISTYPE param;
+ status =
+ getPortParam(omxNode, OMX_IndexParamAudioVorbis, portIndex, ¶m);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ param.nChannels = nChannels;
+ param.nBitRate = nBitRate;
+ param.nSampleRate = nSampleRate;
+ param.nQuality = nQuality;
+ status =
+ setPortParam(omxNode, OMX_IndexParamAudioVorbis, portIndex, ¶m);
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+void setupAACPort(sp<IOmxNode> omxNode, OMX_U32 portIndex,
+ OMX_AUDIO_AACPROFILETYPE eAACProfile,
+ OMX_AUDIO_AACSTREAMFORMATTYPE eAACStreamFormat,
+ int32_t nChannels, int32_t nBitRate, int32_t nSampleRate,
+ bool isEncoder) {
+ if (isEncoder == false) return;
+ android::hardware::media::omx::V1_0::Status status;
+ OMX_AUDIO_PARAM_AACPROFILETYPE param;
+ status = getPortParam(omxNode, OMX_IndexParamAudioAac, portIndex, ¶m);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ param.nChannels = nChannels;
+ param.nSampleRate = nSampleRate;
+ param.nBitRate = nBitRate;
+ param.eAACProfile = eAACProfile;
+ param.eAACStreamFormat = eAACStreamFormat;
+ param.eChannelMode = (nChannels == 1) ? OMX_AUDIO_ChannelModeMono
+ : OMX_AUDIO_ChannelModeStereo;
+ status = setPortParam(omxNode, OMX_IndexParamAudioAac, portIndex, ¶m);
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
diff --git a/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.h b/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.h
new file mode 100644
index 0000000..bdf5d52
--- /dev/null
+++ b/media/omx/1.0/vts/functional/audio/media_audio_hidl_test_common.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEDIA_AUDIO_HIDL_TEST_COMMON_H
+#define MEDIA_AUDIO_HIDL_TEST_COMMON_H
+
+#include <media_hidl_test_common.h>
+/*
+ * Random Index used for monkey testing while get/set parameters
+ */
+#define RANDOM_INDEX 1729
+
+/*
+ * Common audio utils
+ */
+void allocatePortBuffers(sp<IOmxNode> omxNode,
+ android::Vector<BufferInfo>* buffArray,
+ OMX_U32 portIndex);
+
+size_t getEmptyBufferID(android::Vector<BufferInfo>* buffArray);
+
+void dispatchInputBuffer(sp<IOmxNode> omxNode,
+ android::Vector<BufferInfo>* buffArray,
+ size_t bufferIndex, int bytesCount, uint32_t flags,
+ uint64_t timestamp);
+
+void dispatchOutputBuffer(sp<IOmxNode> omxNode,
+ android::Vector<BufferInfo>* buffArray,
+ size_t bufferIndex);
+
+Return<android::hardware::media::omx::V1_0::Status> setAudioPortFormat(
+ sp<IOmxNode> omxNode, OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE encoding);
+
+Return<android::hardware::media::omx::V1_0::Status> setRole(
+ sp<IOmxNode> omxNode, const char* role);
+
+void setupPCMPort(sp<IOmxNode> omxNode, OMX_U32 portIndex, int32_t nChannels,
+ OMX_NUMERICALDATATYPE eNumData, int32_t nBitPerSample,
+ int32_t nSamplingRate);
+
+void setupMP3Port(sp<IOmxNode> omxNode, OMX_U32 portIndex,
+ OMX_AUDIO_MP3STREAMFORMATTYPE eFormat, int32_t nChannels,
+ int32_t nBitRate, int32_t nSampleRate, bool isEncoder);
+
+void setupFLACPort(sp<IOmxNode> omxNode, OMX_U32 portIndex, int32_t nChannels,
+ int32_t nSampleRate, int32_t nCompressionLevel,
+ bool isEncoder);
+
+void setupOPUSPort(sp<IOmxNode> omxNode, OMX_U32 portIndex, int32_t nChannels,
+ int32_t nBitRate, int32_t nSampleRate, bool isEncoder);
+
+void setupAMRPort(sp<IOmxNode> omxNode, OMX_U32 portIndex, int32_t nBitRate,
+ OMX_AUDIO_AMRBANDMODETYPE eAMRBandMode, bool isEncoder);
+
+void setupVORBISPort(sp<IOmxNode> omxNode, OMX_U32 portIndex, int32_t nChannels,
+ int32_t nBitRate, int32_t nSampleRate, int32_t nQuality,
+ bool isEncoder);
+
+void setupAACPort(sp<IOmxNode> omxNode, OMX_U32 portIndex,
+ OMX_AUDIO_AACPROFILETYPE eAACProfile,
+ OMX_AUDIO_AACSTREAMFORMATTYPE eAACStreamFormat,
+ int32_t nChannels, int32_t nBitRate, int32_t nSampleRate,
+ bool isEncoder);
+
+#endif // MEDIA_AUDIO_HIDL_TEST_COMMON_H
diff --git a/media/omx/1.0/vts/functional/common/media_hidl_test_common.h b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
new file mode 100644
index 0000000..9421463
--- /dev/null
+++ b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEDIA_HIDL_TEST_COMMON_H
+#define MEDIA_HIDL_TEST_COMMON_H
+
+#include <media/stagefright/foundation/ALooper.h>
+#include <utils/Condition.h>
+#include <utils/List.h>
+#include <utils/Mutex.h>
+
+#include <media/openmax/OMX_Index.h>
+#include <media/openmax/OMX_Core.h>
+#include <media/openmax/OMX_Component.h>
+#include <media/openmax/OMX_IndexExt.h>
+#include <media/openmax/OMX_AudioExt.h>
+
+/*
+ * TODO: Borrowed from Conversion.h. This is not the ideal way to do it.
+ * Loose these definitions once you include Conversion.h
+ */
+inline uint32_t toRawIndexType(OMX_INDEXTYPE l) {
+ return static_cast<uint32_t>(l);
+}
+
+inline android::hardware::media::omx::V1_0::Status toStatus(
+ android::status_t l) {
+ return static_cast<android::hardware::media::omx::V1_0::Status>(l);
+}
+
+inline hidl_vec<uint8_t> inHidlBytes(void const* l, size_t size) {
+ hidl_vec<uint8_t> t;
+ t.setToExternal(static_cast<uint8_t*>(const_cast<void*>(l)), size, false);
+ return t;
+}
+
+inline uint32_t toRawCommandType(OMX_COMMANDTYPE l) {
+ return static_cast<uint32_t>(l);
+}
+
+/*
+ * Handle Callback functions EmptythisBuffer(), FillthisBuffer(),
+ * EventHandler()
+ */
+#define DEFAULT_TIMEOUT 40000
+
+enum bufferOwner {
+ client,
+ component,
+ unknown,
+};
+
+struct BufferInfo {
+ uint32_t id;
+ bufferOwner owner;
+ android::hardware::media::omx::V1_0::CodecBuffer omxBuffer;
+ ::android::sp<IMemory> mMemory;
+};
+
+struct CodecObserver : public IOmxObserver {
+ public:
+ Return<void> onMessages(const hidl_vec<Message>& messages) override {
+ android::Mutex::Autolock autoLock(msgLock);
+ for (hidl_vec<Message>::const_iterator it = messages.begin();
+ it != messages.end(); ++it) {
+ msgQueue.push_back(*it);
+ }
+ msgCondition.signal();
+ return Void();
+ }
+ android::hardware::media::omx::V1_0::Status dequeueMessage(
+ Message* msg, int64_t timeoutUs,
+ android::Vector<BufferInfo>* iBuffers = nullptr,
+ android::Vector<BufferInfo>* oBuffers = nullptr) {
+ int64_t finishBy = android::ALooper::GetNowUs() + timeoutUs;
+ for (;;) {
+ android::Mutex::Autolock autoLock(msgLock);
+ android::List<Message>::iterator it = msgQueue.begin();
+ while (it != msgQueue.end()) {
+ if (it->type ==
+ android::hardware::media::omx::V1_0::Message::Type::EVENT) {
+ *msg = *it;
+ msgQueue.erase(it);
+ return ::android::hardware::media::omx::V1_0::Status::OK;
+ } else if (it->type == android::hardware::media::omx::V1_0::
+ Message::Type::FILL_BUFFER_DONE) {
+ if (oBuffers) {
+ size_t i;
+ for (i = 0; i < oBuffers->size(); ++i) {
+ if ((*oBuffers)[i].id ==
+ it->data.bufferData.buffer) {
+ oBuffers->editItemAt(i).owner = client;
+ msgQueue.erase(it);
+ break;
+ }
+ }
+ EXPECT_LE(i, oBuffers->size());
+ }
+ } else if (it->type == android::hardware::media::omx::V1_0::
+ Message::Type::EMPTY_BUFFER_DONE) {
+ if (iBuffers) {
+ size_t i;
+ for (i = 0; i < iBuffers->size(); ++i) {
+ if ((*iBuffers)[i].id ==
+ it->data.bufferData.buffer) {
+ iBuffers->editItemAt(i).owner = client;
+ msgQueue.erase(it);
+ break;
+ }
+ }
+ EXPECT_LE(i, iBuffers->size());
+ }
+ }
+ ++it;
+ }
+ android::status_t err =
+ (timeoutUs < 0)
+ ? msgCondition.wait(msgLock)
+ : msgCondition.waitRelative(
+ msgLock,
+ (finishBy - android::ALooper::GetNowUs()) * 1000);
+ if (err == android::TIMED_OUT) return toStatus(err);
+ }
+ }
+
+ android::List<Message> msgQueue;
+ android::Mutex msgLock;
+ android::Condition msgCondition;
+};
+
+/*
+ * Useful Wrapper utilities
+ */
+template <class T>
+void InitOMXParams(T* params) {
+ params->nSize = sizeof(T);
+ params->nVersion.s.nVersionMajor = 1;
+ params->nVersion.s.nVersionMinor = 0;
+ params->nVersion.s.nRevision = 0;
+ params->nVersion.s.nStep = 0;
+}
+
+template <class T>
+Return<android::hardware::media::omx::V1_0::Status> getParam(
+ sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, T* params) {
+ android::hardware::media::omx::V1_0::Status status;
+ InitOMXParams(params);
+ omxNode->getParameter(
+ toRawIndexType(omxIdx), inHidlBytes(params, sizeof(*params)),
+ [&status, ¶ms](android::hardware::media::omx::V1_0::Status _s,
+ hidl_vec<uint8_t> const& outParams) {
+ status = _s;
+ std::copy(outParams.data(), outParams.data() + outParams.size(),
+ static_cast<uint8_t*>(static_cast<void*>(params)));
+ });
+ return status;
+}
+
+template <class T>
+Return<android::hardware::media::omx::V1_0::Status> setParam(
+ sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, T* params) {
+ InitOMXParams(params);
+ return omxNode->setParameter(toRawIndexType(omxIdx),
+ inHidlBytes(params, sizeof(*params)));
+}
+
+template <class T>
+Return<android::hardware::media::omx::V1_0::Status> getPortParam(
+ sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, OMX_U32 nPortIndex, T* params) {
+ android::hardware::media::omx::V1_0::Status status;
+ InitOMXParams(params);
+ params->nPortIndex = nPortIndex;
+ omxNode->getParameter(
+ toRawIndexType(omxIdx), inHidlBytes(params, sizeof(*params)),
+ [&status, ¶ms](android::hardware::media::omx::V1_0::Status _s,
+ hidl_vec<uint8_t> const& outParams) {
+ status = _s;
+ std::copy(outParams.data(), outParams.data() + outParams.size(),
+ static_cast<uint8_t*>(static_cast<void*>(params)));
+ });
+ return status;
+}
+
+template <class T>
+Return<android::hardware::media::omx::V1_0::Status> setPortParam(
+ sp<IOmxNode> omxNode, OMX_INDEXTYPE omxIdx, OMX_U32 nPortIndex, T* params) {
+ InitOMXParams(params);
+ params->nPortIndex = nPortIndex;
+ return omxNode->setParameter(toRawIndexType(omxIdx),
+ inHidlBytes(params, sizeof(*params)));
+}
+
+#endif // MEDIA_HIDL_TEST_COMMON_H
diff --git a/media/omx/1.0/vts/functional/component/Android.bp b/media/omx/1.0/vts/functional/component/Android.bp
new file mode 100644
index 0000000..02fe182
--- /dev/null
+++ b/media/omx/1.0/vts/functional/component/Android.bp
@@ -0,0 +1,45 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalMediaOmxV1_0TargetComponentTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalMediaOmxV1_0TargetComponentTest.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libnativehelper",
+ "libutils",
+ "libstagefright_foundation",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "android.hardware.media.omx@1.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+ include_dirs: [
+ "frameworks/native/include/media/openmax/",
+ "hardware/interfaces/media/omx/1.0/vts/functional/common",
+ ],
+}
+
diff --git a/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp b/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp
new file mode 100644
index 0000000..fdffd66
--- /dev/null
+++ b/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp
@@ -0,0 +1,1213 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "media_omx_hidl_component_test"
+#include <android-base/logging.h>
+
+#include <android/hardware/media/omx/1.0/IOmx.h>
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+#include <android/hardware/media/omx/1.0/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMapper.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+
+using ::android::hardware::media::omx::V1_0::IOmx;
+using ::android::hardware::media::omx::V1_0::IOmxObserver;
+using ::android::hardware::media::omx::V1_0::IOmxNode;
+using ::android::hardware::media::omx::V1_0::Message;
+using ::android::hardware::media::omx::V1_0::CodecBuffer;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::hidl::memory::V1_0::IMapper;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <getopt.h>
+#include <media_hidl_test_common.h>
+
+// A class for test environment setup
+class ComponentTestEnvironment : public ::testing::Environment {
+ public:
+ virtual void SetUp() {}
+ virtual void TearDown() {}
+
+ ComponentTestEnvironment() : instance("default") {}
+
+ void setInstance(const char* _instance) { instance = _instance; }
+
+ void setComponent(const char* _component) { component = _component; }
+
+ void setRole(const char* _role) { role = _role; }
+
+ void setQuirks(int _quirks) { quirks = _quirks; }
+
+ const hidl_string getInstance() const { return instance; }
+
+ const hidl_string getComponent() const { return component; }
+
+ const hidl_string getRole() const { return role; }
+
+ int getQuirks() const { return quirks; }
+
+ int initFromOptions(int argc, char** argv) {
+ static struct option options[] = {
+ {"instance", required_argument, 0, 'I'},
+ {"component", required_argument, 0, 'C'},
+ {"role", required_argument, 0, 'R'},
+ {"quirks", required_argument, 0, 'Q'},
+ {0, 0, 0, 0}};
+
+ while (true) {
+ int index = 0;
+ int c = getopt_long(argc, argv, "I:C:Q:R:", options, &index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'I':
+ setInstance(optarg);
+ break;
+ case 'C':
+ setComponent(optarg);
+ break;
+ case 'Q':
+ setQuirks(atoi(optarg));
+ break;
+ case 'R':
+ setRole(optarg);
+ break;
+ case '?':
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr,
+ "unrecognized option: %s\n\n"
+ "usage: %s <gtest options> <test options>\n\n"
+ "test options are:\n\n"
+ "-I, --instance: HAL instance to test\n"
+ "-C, --component: OMX component to test\n"
+ "-R, --Role: OMX component Role\n"
+ "-Q, --quirks: Component quirks\n",
+ argv[optind ?: 1], argv[0]);
+ return 2;
+ }
+ return 0;
+ }
+
+ private:
+ hidl_string instance;
+ hidl_string component;
+ hidl_string role;
+ // to be removed when IOmxNode::setQuirks is removed
+ int quirks;
+};
+
+static ComponentTestEnvironment* gEnv = nullptr;
+
+class ComponentHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ android::hardware::media::omx::V1_0::Status status;
+ omx = ::testing::VtsHalHidlTargetTestBase::getService<IOmx>(
+ gEnv->getInstance());
+ ASSERT_NE(omx, nullptr);
+ observer = new CodecObserver();
+ ASSERT_NE(observer, nullptr);
+ ASSERT_EQ(strncmp(gEnv->getComponent().c_str(), "OMX.", 4), 0)
+ << "Invalid Component Name";
+ EXPECT_TRUE(omx->allocateNode(
+ gEnv->getComponent(), observer,
+ [&](android::hardware::media::omx::V1_0::Status _s,
+ sp<IOmxNode> const& _nl) {
+ status = _s;
+ this->omxNode = _nl;
+ })
+ .isOk());
+ ASSERT_NE(omxNode, nullptr);
+ ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role";
+ struct StringToClass {
+ const char* Class;
+ standardCompClass CompClass;
+ };
+ const StringToClass kStringToClass[] = {
+ {"audio_decoder", audio_decoder},
+ {"audio_encoder", audio_encoder},
+ {"video_decoder", video_decoder},
+ {"video_encoder", video_encoder},
+ };
+ const size_t kNumStringToClass =
+ sizeof(kStringToClass) / sizeof(kStringToClass[0]);
+ const char* pch;
+ char substring[OMX_MAX_STRINGNAME_SIZE];
+ strcpy(substring, gEnv->getRole().c_str());
+ pch = strchr(substring, '.');
+ ASSERT_NE(pch, nullptr) << "Invalid Component Role";
+ substring[pch - substring] = '\0';
+ compClass = unknown_class;
+ for (size_t i = 0; i < kNumStringToClass; ++i) {
+ if (!strcasecmp(substring, kStringToClass[i].Class)) {
+ compClass = kStringToClass[i].CompClass;
+ break;
+ }
+ }
+ ASSERT_NE(compClass, unknown_class) << "Invalid Component Class";
+
+ allocator = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>(
+ "ashmem");
+ ASSERT_NE(allocator, nullptr);
+ }
+
+ virtual void TearDown() override {
+ if (omxNode != nullptr) {
+ EXPECT_TRUE((omxNode->freeNode()).isOk());
+ omxNode = nullptr;
+ }
+ }
+
+ enum standardCompClass {
+ audio_decoder,
+ audio_encoder,
+ video_decoder,
+ video_encoder,
+ unknown_class,
+ };
+
+ sp<IOmx> omx;
+ sp<CodecObserver> observer;
+ sp<IOmxNode> omxNode;
+ sp<IAllocator> allocator;
+ standardCompClass compClass;
+};
+
+#define RANDOM_INDEX 1729
+
+void allocatePortBuffers(sp<IOmxNode> omxNode, sp<IAllocator> allocator,
+ android::Vector<BufferInfo>* buffArray,
+ OMX_U32 portIndex) {
+ android::hardware::media::omx::V1_0::Status status;
+ OMX_PARAM_PORTDEFINITIONTYPE portDef;
+
+ buffArray->clear();
+
+ status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
+ &portDef);
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ for (size_t i = 0; i < portDef.nBufferCountActual; i++) {
+ BufferInfo buffer;
+ buffer.owner = client;
+ buffer.omxBuffer.type = CodecBuffer::Type::SHARED_MEM;
+ buffer.omxBuffer.attr.preset.rangeOffset = 0;
+ buffer.omxBuffer.attr.preset.rangeLength = 0;
+ bool success;
+ allocator->allocate(
+ portDef.nBufferSize,
+ [&success, &buffer](bool _s,
+ ::android::hardware::hidl_memory const& mem) {
+ success = _s;
+ buffer.omxBuffer.sharedMemory = mem;
+ });
+ ASSERT_EQ(success, true);
+
+ omxNode->useBuffer(
+ portIndex, buffer.omxBuffer,
+ [&status, &buffer](android::hardware::media::omx::V1_0::Status _s,
+ uint32_t id) {
+ status = _s;
+ buffer.id = id;
+ });
+ buffArray->push(buffer);
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ }
+}
+
+Return<android::hardware::media::omx::V1_0::Status> setVideoPortFormat(
+ sp<IOmxNode> omxNode, OMX_U32 portIndex,
+ OMX_VIDEO_CODINGTYPE compressionFormat, OMX_COLOR_FORMATTYPE colorFormat,
+ OMX_U32 frameRate) {
+ OMX_U32 index = 0;
+ OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat;
+ std::vector<OMX_COLOR_FORMATTYPE> eColorFormat;
+ std::vector<OMX_VIDEO_CODINGTYPE> eCompressionFormat;
+ android::hardware::media::omx::V1_0::Status status;
+
+ while (1) {
+ portFormat.nIndex = index;
+ status = getPortParam(omxNode, OMX_IndexParamVideoPortFormat, portIndex,
+ &portFormat);
+ if (status != ::android::hardware::media::omx::V1_0::Status::OK) break;
+ if (compressionFormat == OMX_VIDEO_CodingUnused)
+ eColorFormat.push_back(portFormat.eColorFormat);
+ else
+ eCompressionFormat.push_back(portFormat.eCompressionFormat);
+ index++;
+ if (index == 512) {
+ EXPECT_LE(index, 512U)
+ << "Expecting OMX_ErrorNoMore but not received";
+ break;
+ }
+ }
+ if (!index) return status;
+ if (compressionFormat == OMX_VIDEO_CodingUnused) {
+ for (index = 0; index < eColorFormat.size(); index++) {
+ if (eColorFormat[index] == colorFormat) {
+ portFormat.eColorFormat = eColorFormat[index];
+ break;
+ }
+ }
+ if (index == eColorFormat.size()) {
+ ALOGI("setting default color format");
+ portFormat.eColorFormat = eColorFormat[0];
+ }
+ portFormat.eCompressionFormat = OMX_VIDEO_CodingUnused;
+ } else {
+ for (index = 0; index < eCompressionFormat.size(); index++) {
+ if (eCompressionFormat[index] == compressionFormat) {
+ portFormat.eCompressionFormat = eCompressionFormat[index];
+ break;
+ }
+ }
+ if (index == eCompressionFormat.size()) {
+ ALOGI("setting default compression format");
+ portFormat.eCompressionFormat = eCompressionFormat[0];
+ }
+ portFormat.eColorFormat = OMX_COLOR_FormatUnused;
+ }
+ // In setParam call nIndex shall be ignored as per omx-il specification.
+ // see how this holds up by corrupting nIndex
+ portFormat.nIndex = RANDOM_INDEX;
+ portFormat.xFramerate = frameRate;
+ status = setPortParam(omxNode, OMX_IndexParamVideoPortFormat, portIndex,
+ &portFormat);
+ return status;
+}
+
+Return<android::hardware::media::omx::V1_0::Status> setAudioPortFormat(
+ sp<IOmxNode> omxNode, OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE encoding) {
+ OMX_U32 index = 0;
+ OMX_AUDIO_PARAM_PORTFORMATTYPE portFormat;
+ std::vector<OMX_AUDIO_CODINGTYPE> eEncoding;
+ android::hardware::media::omx::V1_0::Status status;
+
+ while (1) {
+ portFormat.nIndex = index;
+ status = getPortParam(omxNode, OMX_IndexParamAudioPortFormat, portIndex,
+ &portFormat);
+ if (status != ::android::hardware::media::omx::V1_0::Status::OK) break;
+ eEncoding.push_back(portFormat.eEncoding);
+ index++;
+ if (index == 512) {
+ EXPECT_LE(index, 512U)
+ << "Expecting OMX_ErrorNoMore but not received";
+ break;
+ }
+ }
+ if (!index) return status;
+ for (index = 0; index < eEncoding.size(); index++) {
+ if (eEncoding[index] == encoding) {
+ portFormat.eEncoding = eEncoding[index];
+ break;
+ }
+ }
+ if (index == eEncoding.size()) {
+ ALOGI("setting default Port format");
+ portFormat.eEncoding = eEncoding[0];
+ }
+ // In setParam call nIndex shall be ignored as per omx-il specification.
+ // see how this holds up by corrupting nIndex
+ portFormat.nIndex = RANDOM_INDEX;
+ status = setPortParam(omxNode, OMX_IndexParamAudioPortFormat, portIndex,
+ &portFormat);
+ return status;
+}
+
+Return<android::hardware::media::omx::V1_0::Status> setRole(
+ sp<IOmxNode> omxNode, const char* role) {
+ OMX_PARAM_COMPONENTROLETYPE params;
+ strcpy((char*)params.cRole, role);
+ return setParam(omxNode, OMX_IndexParamStandardComponentRole, ¶ms);
+}
+
+// Set Component Role
+TEST_F(ComponentHidlTest, SetRole) {
+ android::hardware::media::omx::V1_0::Status status;
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+// Get Number of Ports and their Indices for all Domains
+// (Audio/Video/Image/Other)
+TEST_F(ComponentHidlTest, GetPortIndices) {
+ android::hardware::media::omx::V1_0::Status status;
+ OMX_PORT_PARAM_TYPE params;
+
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+
+ // All standard OMX components shall support following OMX Index types
+ status = getParam(omxNode, OMX_IndexParamAudioInit, ¶ms);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ status = getParam(omxNode, OMX_IndexParamImageInit, ¶ms);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ status = getParam(omxNode, OMX_IndexParamOtherInit, ¶ms);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+}
+
+// Enumerate Port Format
+TEST_F(ComponentHidlTest, EnumeratePortFormat) {
+ android::hardware::media::omx::V1_0::Status status;
+ uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
+
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ OMX_PORT_PARAM_TYPE params;
+ if (compClass == audio_decoder || compClass == audio_encoder) {
+ status = getParam(omxNode, OMX_IndexParamAudioInit, ¶ms);
+ } else {
+ status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms);
+ }
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(params.nPorts, 2U);
+ kPortIndexInput = params.nStartPortNumber;
+ kPortIndexOutput = kPortIndexInput + 1;
+ }
+
+ OMX_COLOR_FORMATTYPE colorFormat = OMX_COLOR_FormatYUV420Planar;
+ OMX_U32 frameRate = 24 << 16;
+
+ if (compClass == audio_encoder) {
+ status =
+ setAudioPortFormat(omxNode, kPortIndexInput, OMX_AUDIO_CodingPCM);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ status = setAudioPortFormat(omxNode, kPortIndexOutput,
+ OMX_AUDIO_CodingAutoDetect);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ } else if (compClass == audio_decoder) {
+ status = setAudioPortFormat(omxNode, kPortIndexInput,
+ OMX_AUDIO_CodingAutoDetect);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ status =
+ setAudioPortFormat(omxNode, kPortIndexOutput, OMX_AUDIO_CodingPCM);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ } else if (compClass == video_encoder) {
+ status =
+ setVideoPortFormat(omxNode, kPortIndexInput, OMX_VIDEO_CodingUnused,
+ colorFormat, frameRate);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ status = setVideoPortFormat(omxNode, kPortIndexOutput,
+ OMX_VIDEO_CodingAutoDetect,
+ OMX_COLOR_FormatUnused, 0U);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ } else {
+ status = setVideoPortFormat(omxNode, kPortIndexInput,
+ OMX_VIDEO_CodingAutoDetect,
+ OMX_COLOR_FormatUnused, 0U);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ status =
+ setVideoPortFormat(omxNode, kPortIndexOutput,
+ OMX_VIDEO_CodingUnused, colorFormat, frameRate);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ }
+}
+
+// r/w default i/o port parameters
+TEST_F(ComponentHidlTest, SetDefaultPortParams) {
+ android::hardware::media::omx::V1_0::Status status;
+ uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
+
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ OMX_PORT_PARAM_TYPE params;
+ if (compClass == audio_decoder || compClass == audio_encoder) {
+ status = getParam(omxNode, OMX_IndexParamAudioInit, ¶ms);
+ } else {
+ status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms);
+ }
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(params.nPorts, 2U);
+ kPortIndexInput = params.nStartPortNumber;
+ kPortIndexOutput = kPortIndexInput + 1;
+ }
+
+ OMX_PARAM_PORTDEFINITIONTYPE iPortDef;
+ status = getPortParam(omxNode, OMX_IndexParamPortDefinition,
+ kPortIndexInput, &iPortDef);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+
+ if (status == android::hardware::media::omx::V1_0::Status::OK) {
+ EXPECT_EQ(iPortDef.eDir, OMX_DirInput);
+ EXPECT_EQ(iPortDef.bEnabled, OMX_TRUE);
+ EXPECT_EQ(iPortDef.bPopulated, 0);
+ EXPECT_GE(iPortDef.nBufferCountMin, 1U);
+ EXPECT_GE(iPortDef.nBufferCountActual, iPortDef.nBufferCountMin);
+ if (compClass == audio_encoder || compClass == audio_decoder) {
+ EXPECT_EQ(iPortDef.eDomain, OMX_PortDomainAudio);
+ if (compClass == audio_decoder) {
+ iPortDef.format.audio.bFlagErrorConcealment = OMX_TRUE;
+ status = setPortParam(omxNode, OMX_IndexParamPortDefinition,
+ kPortIndexInput, &iPortDef);
+ }
+ EXPECT_EQ(status,
+ ::android::hardware::media::omx::V1_0::Status::OK);
+ } else if (compClass == video_encoder || compClass == video_decoder) {
+ EXPECT_EQ(iPortDef.eDomain, OMX_PortDomainVideo);
+ }
+ OMX_PARAM_PORTDEFINITIONTYPE dummy = iPortDef;
+ iPortDef.nBufferCountActual = iPortDef.nBufferCountMin - 1;
+ status = setPortParam(omxNode, OMX_IndexParamPortDefinition,
+ kPortIndexInput, &iPortDef);
+ EXPECT_NE(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ // Edit Read-Only fields.
+ iPortDef.eDir = OMX_DirOutput; // Read Only field
+ iPortDef.nBufferCountActual = dummy.nBufferCountActual << 1;
+ iPortDef.nBufferCountMin = dummy.nBufferCountMin
+ << 1; // Read Only field
+ iPortDef.nBufferSize = dummy.nBufferSize << 1; // Read Only field
+ status = setPortParam(omxNode, OMX_IndexParamPortDefinition,
+ kPortIndexInput, &iPortDef);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ status = getPortParam(omxNode, OMX_IndexParamPortDefinition,
+ kPortIndexInput, &iPortDef);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ EXPECT_EQ(iPortDef.nBufferCountActual, dummy.nBufferCountActual << 1);
+ if ((iPortDef.eDir != OMX_DirInput) ||
+ (iPortDef.nBufferCountMin != dummy.nBufferCountMin) ||
+ (iPortDef.nBufferSize != dummy.nBufferSize)) {
+ ALOGI(
+ "Warning, Component does not seem to preserve Read-Only "
+ "fields");
+ printf(
+ "Warning, Component does not seem to preserve Read-Only fields "
+ "\n");
+ }
+ }
+
+ OMX_PARAM_PORTDEFINITIONTYPE oPortDef;
+ status = getPortParam(omxNode, OMX_IndexParamPortDefinition,
+ kPortIndexOutput, &oPortDef);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ EXPECT_EQ(oPortDef.eDir, OMX_DirOutput);
+ EXPECT_EQ(oPortDef.bEnabled, OMX_TRUE);
+ EXPECT_EQ(oPortDef.bPopulated, 0);
+ EXPECT_GE(oPortDef.nBufferCountMin, 1U);
+ EXPECT_GE(oPortDef.nBufferCountActual, oPortDef.nBufferCountMin);
+ if (compClass == audio_encoder || compClass == audio_decoder) {
+ EXPECT_EQ(oPortDef.eDomain, OMX_PortDomainAudio);
+ if (compClass == audio_encoder) {
+ oPortDef.format.audio.bFlagErrorConcealment = OMX_TRUE;
+ status = setPortParam(omxNode, OMX_IndexParamPortDefinition,
+ kPortIndexOutput, &oPortDef);
+ }
+ EXPECT_EQ(status,
+ ::android::hardware::media::omx::V1_0::Status::OK);
+ } else if (compClass == video_encoder || compClass == video_decoder) {
+ EXPECT_EQ(oPortDef.eDomain, OMX_PortDomainVideo);
+ }
+ OMX_PARAM_PORTDEFINITIONTYPE dummy = oPortDef;
+ oPortDef.nBufferCountActual = oPortDef.nBufferCountMin - 1;
+ status = setPortParam(omxNode, OMX_IndexParamPortDefinition,
+ kPortIndexOutput, &oPortDef);
+ EXPECT_NE(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ // Edit Read-Only fields.
+ oPortDef.eDir = OMX_DirInput; // Read Only field
+ oPortDef.nBufferCountActual = dummy.nBufferCountActual << 1;
+ oPortDef.nBufferCountMin = dummy.nBufferCountMin
+ << 1; // Read Only field
+ oPortDef.nBufferSize = dummy.nBufferSize << 1; // Read Only field
+ status = setPortParam(omxNode, OMX_IndexParamPortDefinition,
+ kPortIndexOutput, &oPortDef);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ status = getPortParam(omxNode, OMX_IndexParamPortDefinition,
+ kPortIndexOutput, &oPortDef);
+ EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ EXPECT_EQ(oPortDef.nBufferCountActual, dummy.nBufferCountActual << 1);
+ if ((oPortDef.eDir != OMX_DirOutput) ||
+ (oPortDef.nBufferCountMin != dummy.nBufferCountMin) ||
+ (oPortDef.nBufferSize != dummy.nBufferSize)) {
+ ALOGI(
+ "Warning, Component does not seem to preserve Read-Only "
+ "fields");
+ printf(
+ "Warning, Component does not seem to preserve Read-Only fields "
+ "\n");
+ }
+ }
+}
+
+// Test State Transitions & Flush
+TEST_F(ComponentHidlTest, StateTransitions_Flush) {
+ android::hardware::media::omx::V1_0::Status status;
+ uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
+ Message msg;
+
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ OMX_PORT_PARAM_TYPE params;
+ if (compClass == audio_decoder || compClass == audio_encoder) {
+ status = getParam(omxNode, OMX_IndexParamAudioInit, ¶ms);
+ } else {
+ status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms);
+ }
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(params.nPorts, 2U);
+ kPortIndexInput = params.nStartPortNumber;
+ kPortIndexOutput = kPortIndexInput + 1;
+ }
+
+ android::Vector<BufferInfo> iBuffer, oBuffer;
+
+ // set state to idle
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateIdle);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // Dont switch states until the ports got their buffers
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
+
+ // allocate buffers on input port
+ allocatePortBuffers(omxNode, allocator, &iBuffer, kPortIndexInput);
+
+ // Dont switch states until the ports got their buffers
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
+
+ // allocate buffers on output port
+ allocatePortBuffers(omxNode, allocator, &oBuffer, kPortIndexOutput);
+
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
+
+ // set state to executing
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateExecuting);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateExecuting);
+
+ CodecBuffer t;
+ t.sharedMemory = android::hardware::hidl_memory();
+ t.nativeHandle = android::hardware::hidl_handle();
+ t.type = CodecBuffer::Type::PRESET;
+ t.attr.preset.rangeOffset = 0;
+ t.attr.preset.rangeLength = 0;
+ for (size_t i = 0; i < oBuffer.size(); ++i) {
+ native_handle_t* fenceNh = native_handle_create(0, 0);
+ status = omxNode->fillBuffer(oBuffer[i].id, t, fenceNh);
+ native_handle_close(fenceNh);
+ native_handle_delete(fenceNh);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ oBuffer.editItemAt(i).owner = component;
+ }
+
+ // set state to Idle
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateIdle);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
+
+ // test if client got all its buffers back
+ for (size_t i = 0; i < oBuffer.size(); ++i) {
+ EXPECT_EQ(oBuffer[i].owner, client);
+ }
+
+ // set state to executing
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateExecuting);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateExecuting);
+
+ for (size_t i = 0; i < oBuffer.size(); i += 2) {
+ native_handle_t* fenceNh = native_handle_create(0, 0);
+ status = omxNode->fillBuffer(oBuffer[i].id, t, fenceNh);
+ native_handle_close(fenceNh);
+ native_handle_delete(fenceNh);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ oBuffer.editItemAt(i).owner = component;
+ }
+
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush),
+ kPortIndexOutput);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandFlush);
+ ASSERT_EQ(msg.data.eventData.data2, kPortIndexOutput);
+
+ // test if client got all its buffers back
+ for (size_t i = 0; i < oBuffer.size(); ++i) {
+ EXPECT_EQ(oBuffer[i].owner, client);
+ }
+
+ // set state to Idle
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateIdle);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
+
+ // set state to Loaded
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateLoaded);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // dont change state until all buffers are freed
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
+
+ for (size_t i = 0; i < iBuffer.size(); ++i) {
+ status = omxNode->freeBuffer(kPortIndexInput, iBuffer[i].id);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ }
+
+ // dont change state until all buffers are freed
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
+
+ for (size_t i = 0; i < oBuffer.size(); ++i) {
+ status = omxNode->freeBuffer(kPortIndexOutput, oBuffer[i].id);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ }
+
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateLoaded);
+}
+
+// Test State Transitions
+TEST_F(ComponentHidlTest, StateTransitions_M) {
+ android::hardware::media::omx::V1_0::Status status;
+ uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
+ Message msg;
+
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ OMX_PORT_PARAM_TYPE params;
+ if (compClass == audio_decoder || compClass == audio_encoder) {
+ status = getParam(omxNode, OMX_IndexParamAudioInit, ¶ms);
+ } else {
+ status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms);
+ }
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(params.nPorts, 2U);
+ kPortIndexInput = params.nStartPortNumber;
+ kPortIndexOutput = kPortIndexInput + 1;
+ }
+
+ android::Vector<BufferInfo> iBuffer, oBuffer;
+
+ // set state to loaded ; receive error OMX_ErrorSameState
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateLoaded);
+ EXPECT_NE(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // set state to executing ; receive error OMX_ErrorIncorrectStateTransition
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateExecuting);
+ EXPECT_NE(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // set state to idle
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateIdle);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // allocate buffers on i/o port
+ allocatePortBuffers(omxNode, allocator, &iBuffer, kPortIndexInput);
+ allocatePortBuffers(omxNode, allocator, &oBuffer, kPortIndexOutput);
+
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
+
+ // set state to idle ; receive error OMX_ErrorSameState
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateIdle);
+ EXPECT_NE(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // set state to executing
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateExecuting);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateExecuting);
+
+ // set state to executing ; receive error OMX_ErrorSameState
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateExecuting);
+ EXPECT_NE(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // set state to Loaded ; receive error OMX_ErrorIncorrectStateTransition
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateLoaded);
+ EXPECT_NE(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // set state to Idle
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateIdle);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
+
+ // set state to Loaded
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateLoaded);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ for (size_t i = 0; i < iBuffer.size(); ++i) {
+ status = omxNode->freeBuffer(kPortIndexInput, iBuffer[i].id);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ }
+ for (size_t i = 0; i < oBuffer.size(); ++i) {
+ status = omxNode->freeBuffer(kPortIndexOutput, oBuffer[i].id);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ }
+
+ status =
+ observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &iBuffer, &oBuffer);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateLoaded);
+}
+
+// Enable and Disable Input and Output ports when the component is in Loaded
+// State
+TEST_F(ComponentHidlTest, PortEnableDisable_Loaded) {
+ android::hardware::media::omx::V1_0::Status status;
+ OMX_U32 portBase = 0;
+ Message msg;
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ OMX_PORT_PARAM_TYPE params;
+ if (compClass == audio_decoder || compClass == audio_encoder) {
+ status = getParam(omxNode, OMX_IndexParamAudioInit, ¶ms);
+ } else {
+ status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms);
+ }
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(params.nPorts, 2U);
+ portBase = params.nStartPortNumber;
+ }
+
+ for (size_t i = portBase; i < portBase + 2; i++) {
+ status =
+ omxNode->sendCommand(toRawCommandType(OMX_CommandPortDisable), i);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ if (msg.data.eventData.event == OMX_EventCmdComplete) {
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortDisable);
+ ASSERT_EQ(msg.data.eventData.data2, i);
+ // If you can disable a port, then you should be able to enable it
+ // as well
+ status = omxNode->sendCommand(
+ toRawCommandType(OMX_CommandPortEnable), i);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortEnable);
+ ASSERT_EQ(msg.data.eventData.data2, i);
+ } else if (msg.data.eventData.event == OMX_EventError) {
+ ALOGI("Port %d Disabling failed with error %d", (int)i,
+ (int)msg.data.eventData.event);
+ } else {
+ // something unexpected happened
+ ASSERT_TRUE(false);
+ }
+ }
+}
+
+// Enable and Disable Input and Output ports when the component is in Idle State
+TEST_F(ComponentHidlTest, PortEnableDisable_Idle) {
+ android::hardware::media::omx::V1_0::Status status;
+ uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
+ OMX_U32 portBase = 0;
+ Message msg;
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ OMX_PORT_PARAM_TYPE params;
+ if (compClass == audio_decoder || compClass == audio_encoder) {
+ status = getParam(omxNode, OMX_IndexParamAudioInit, ¶ms);
+ } else {
+ status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms);
+ }
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(params.nPorts, 2U);
+ portBase = params.nStartPortNumber;
+ }
+ kPortIndexInput = portBase;
+ kPortIndexOutput = portBase + 1;
+
+ // Component State :: Idle
+ android::Vector<BufferInfo> pBuffer[2];
+ // set state to idle
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateIdle);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // allocate buffers on input port
+ allocatePortBuffers(omxNode, allocator, &pBuffer[0], kPortIndexInput);
+ allocatePortBuffers(omxNode, allocator, &pBuffer[1], kPortIndexOutput);
+
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &pBuffer[0],
+ &pBuffer[1]);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
+
+ for (size_t i = portBase; i < portBase + 2; i++) {
+ status =
+ omxNode->sendCommand(toRawCommandType(OMX_CommandPortDisable), i);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &pBuffer[0],
+ &pBuffer[1]);
+ if (status == android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ if (msg.data.eventData.event == OMX_EventCmdComplete) {
+ // do not disable the port until all the buffers are freed
+ ASSERT_TRUE(false);
+ } else if (msg.data.eventData.event == OMX_EventError) {
+ ALOGI("Port %d Disabling failed with error %d", (int)i,
+ (int)msg.data.eventData.event);
+ } else {
+ // something unexpected happened
+ ASSERT_TRUE(false);
+ }
+ } else if (status ==
+ android::hardware::media::omx::V1_0::Status::TIMED_OUT) {
+ for (size_t j = 0; j < pBuffer[i - portBase].size(); ++j) {
+ status = omxNode->freeBuffer(i, pBuffer[i - portBase][j].id);
+ ASSERT_EQ(status,
+ android::hardware::media::omx::V1_0::Status::OK);
+ }
+
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
+ &pBuffer[0], &pBuffer[1]);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortDisable);
+ ASSERT_EQ(msg.data.eventData.data2, i);
+
+ // If you can disable a port, then you should be able to enable it
+ // as well
+ status = omxNode->sendCommand(
+ toRawCommandType(OMX_CommandPortEnable), i);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // do not enable the port until all the buffers are supplied
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
+ &pBuffer[0], &pBuffer[1]);
+ ASSERT_EQ(status,
+ android::hardware::media::omx::V1_0::Status::TIMED_OUT);
+
+ allocatePortBuffers(omxNode, allocator, &pBuffer[i - portBase], i);
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
+ &pBuffer[0], &pBuffer[1]);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortEnable);
+ ASSERT_EQ(msg.data.eventData.data2, i);
+ } else {
+ // something unexpected happened
+ ASSERT_TRUE(false);
+ }
+ }
+}
+
+// Enable and Disable Input and Output ports when the component is in execute
+TEST_F(ComponentHidlTest, PortEnableDisable_Execute) {
+ android::hardware::media::omx::V1_0::Status status;
+ uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
+ OMX_U32 portBase = 0;
+ Message msg;
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ OMX_PORT_PARAM_TYPE params;
+ if (compClass == audio_decoder || compClass == audio_encoder) {
+ status = getParam(omxNode, OMX_IndexParamAudioInit, ¶ms);
+ } else {
+ status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms);
+ }
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(params.nPorts, 2U);
+ portBase = params.nStartPortNumber;
+ }
+ kPortIndexInput = portBase;
+ kPortIndexOutput = portBase + 1;
+
+ // Component State :: Idle
+ android::Vector<BufferInfo> pBuffer[2];
+ // set state to idle
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateIdle);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // allocate buffers on input port
+ allocatePortBuffers(omxNode, allocator, &pBuffer[0], kPortIndexInput);
+ allocatePortBuffers(omxNode, allocator, &pBuffer[1], kPortIndexOutput);
+
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &pBuffer[0],
+ &pBuffer[1]);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
+
+ // Component State :: Execute
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
+ OMX_StateExecuting);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &pBuffer[0],
+ &pBuffer[1]);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
+ ASSERT_EQ(msg.data.eventData.data2, OMX_StateExecuting);
+
+ CodecBuffer t;
+ t.sharedMemory = android::hardware::hidl_memory();
+ t.nativeHandle = android::hardware::hidl_handle();
+ t.type = CodecBuffer::Type::PRESET;
+ t.attr.preset.rangeOffset = 0;
+ t.attr.preset.rangeLength = 0;
+ for (size_t i = 0; i < pBuffer[1].size(); ++i) {
+ native_handle_t* fenceNh = native_handle_create(0, 0);
+ status = omxNode->fillBuffer(pBuffer[1][i].id, t, fenceNh);
+ native_handle_close(fenceNh);
+ native_handle_delete(fenceNh);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ pBuffer[1].editItemAt(i).owner = component;
+ }
+
+ for (size_t i = portBase; i < portBase + 2; i++) {
+ status =
+ omxNode->sendCommand(toRawCommandType(OMX_CommandPortDisable), i);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, &pBuffer[0],
+ &pBuffer[1]);
+ if (status == android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ if (msg.data.eventData.event == OMX_EventCmdComplete) {
+ // do not disable the port until all the buffers are freed
+ ASSERT_TRUE(false);
+ } else if (msg.data.eventData.event == OMX_EventError) {
+ ALOGI("Port %d Disabling failed with error %d", (int)i,
+ (int)msg.data.eventData.event);
+ } else {
+ // something unexpected happened
+ ASSERT_TRUE(false);
+ }
+ } else if (status ==
+ android::hardware::media::omx::V1_0::Status::TIMED_OUT) {
+ for (size_t j = 0; j < pBuffer[i - portBase].size(); ++j) {
+ // test if client got all its buffers back
+ EXPECT_EQ(pBuffer[i - portBase][j].owner, client);
+ // free the buffers
+ status = omxNode->freeBuffer(i, pBuffer[i - portBase][j].id);
+ ASSERT_EQ(status,
+ android::hardware::media::omx::V1_0::Status::OK);
+ }
+
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
+ &pBuffer[0], &pBuffer[1]);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortDisable);
+ ASSERT_EQ(msg.data.eventData.data2, i);
+
+ // If you can disable a port, then you should be able to enable it
+ // as well
+ status = omxNode->sendCommand(
+ toRawCommandType(OMX_CommandPortEnable), i);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // do not enable the port until all the buffers are supplied
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
+ &pBuffer[0], &pBuffer[1]);
+ ASSERT_EQ(status,
+ android::hardware::media::omx::V1_0::Status::TIMED_OUT);
+
+ allocatePortBuffers(omxNode, allocator, &pBuffer[i - portBase], i);
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
+ &pBuffer[0], &pBuffer[1]);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortEnable);
+ ASSERT_EQ(msg.data.eventData.data2, i);
+ } else {
+ // something unexpected happened
+ ASSERT_TRUE(false);
+ }
+ }
+}
+
+// Enable and Disable Input and Output ports, (in loaded state)
+TEST_F(ComponentHidlTest, PortEnableDisable_M) {
+ android::hardware::media::omx::V1_0::Status status;
+ OMX_U32 portBase = 0;
+ Message msg;
+ status = setRole(omxNode, gEnv->getRole().c_str());
+ ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
+ OMX_PORT_PARAM_TYPE params;
+ if (compClass == audio_decoder || compClass == audio_encoder) {
+ status = getParam(omxNode, OMX_IndexParamAudioInit, ¶ms);
+ } else {
+ status = getParam(omxNode, OMX_IndexParamVideoInit, ¶ms);
+ }
+ if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
+ ASSERT_EQ(params.nPorts, 2U);
+ portBase = params.nStartPortNumber;
+ }
+
+ // disable invalid port, expecting OMX_ErrorBadPortIndex
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandPortDisable),
+ RANDOM_INDEX);
+ ASSERT_NE(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // enable invalid port, expecting OMX_ErrorBadPortIndex
+ status = omxNode->sendCommand(toRawCommandType(OMX_CommandPortEnable),
+ RANDOM_INDEX);
+ ASSERT_NE(status, android::hardware::media::omx::V1_0::Status::OK);
+
+ // disable all ports
+ status =
+ omxNode->sendCommand(toRawCommandType(OMX_CommandPortDisable), OMX_ALL);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ for (size_t i = 0; i < 2; i++) {
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ if (msg.data.eventData.event == OMX_EventCmdComplete) {
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortDisable);
+ if (msg.data.eventData.data2 != portBase ||
+ msg.data.eventData.data2 != portBase + 1)
+ EXPECT_TRUE(false);
+ } else if (msg.data.eventData.event == OMX_EventError) {
+ ALOGI("Port %d Disabling failed with error %d", (int)i,
+ (int)msg.data.eventData.event);
+ } else {
+ // something unexpected happened
+ ASSERT_TRUE(false);
+ }
+ }
+
+ // enable all ports
+ status =
+ omxNode->sendCommand(toRawCommandType(OMX_CommandPortEnable), OMX_ALL);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ for (size_t i = 0; i < 2; i++) {
+ status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT);
+ ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+ ASSERT_EQ(msg.type, Message::Type::EVENT);
+ if (msg.data.eventData.event == OMX_EventCmdComplete) {
+ ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortEnable);
+ if (msg.data.eventData.data2 != portBase ||
+ msg.data.eventData.data2 != portBase + 1)
+ EXPECT_TRUE(false);
+ } else if (msg.data.eventData.event == OMX_EventError) {
+ ALOGI("Port %d Enabling failed with error %d", (int)i,
+ (int)msg.data.eventData.event);
+ } else {
+ // something unexpected happened
+ ASSERT_TRUE(false);
+ }
+ }
+}
+
+int main(int argc, char** argv) {
+ gEnv = new ComponentTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ }
+ return status;
+}
diff --git a/media/omx/1.0/vts/functional/master/Android.bp b/media/omx/1.0/vts/functional/master/Android.bp
new file mode 100644
index 0000000..6edbf4a
--- /dev/null
+++ b/media/omx/1.0/vts/functional/master/Android.bp
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalMediaOmxV1_0TargetMasterTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["VtsHalMediaOmxV1_0TargetMasterTest.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libnativehelper",
+ "libutils",
+ "android.hardware.media.omx@1.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
+
diff --git a/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp b/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp
new file mode 100644
index 0000000..65b999e
--- /dev/null
+++ b/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "media_omx_hidl_master_test"
+#include <android-base/logging.h>
+
+#include <android/hardware/media/omx/1.0/IOmx.h>
+#include <android/hardware/media/omx/1.0/types.h>
+#include <getopt.h>
+#include <log/log.h>
+#include <VtsHalHidlTargetTestBase.h>
+
+using ::android::hardware::media::omx::V1_0::IOmx;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+// A class for test environment setup
+class ComponentTestEnvironment : public ::testing::Environment {
+ public:
+ virtual void SetUp() {}
+ virtual void TearDown() {}
+
+ ComponentTestEnvironment() : instance("default") {}
+
+ void setInstance(const char* _instance) { instance = _instance; }
+
+ const hidl_string getInstance() const { return instance; }
+
+ int initFromOptions(int argc, char** argv) {
+ static struct option options[] = {
+ {"instance", required_argument, 0, 'I'}, {0, 0, 0, 0}};
+
+ while (true) {
+ int index = 0;
+ int c = getopt_long(argc, argv, "I:", options, &index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'I':
+ setInstance(optarg);
+ break;
+ case '?':
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr,
+ "unrecognized option: %s\n\n"
+ "usage: %s <gtest options> <test options>\n\n"
+ "test options are:\n\n"
+ "-I, --instance: HAL instance to test\n",
+ argv[optind ?: 1], argv[0]);
+ return 2;
+ }
+ return 0;
+ }
+
+ private:
+ hidl_string instance;
+};
+
+static ComponentTestEnvironment* gEnv = nullptr;
+
+class MasterHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ omx = ::testing::VtsHalHidlTargetTestBase::getService<IOmx>(
+ gEnv->getInstance());
+ ASSERT_NE(omx, nullptr);
+ }
+
+ virtual void TearDown() override {}
+
+ sp<IOmx> omx;
+};
+
+// enumerate list of components and roles
+TEST_F(MasterHidlTest, ListNodes) {
+ android::hardware::media::omx::V1_0::Status status;
+ hidl_vec<IOmx::ComponentInfo> nodeList;
+ EXPECT_TRUE(
+ omx->listNodes([&status, &nodeList](
+ android::hardware::media::omx::V1_0::Status _s,
+ hidl_vec<IOmx::ComponentInfo> const& _nl) {
+ status = _s;
+ nodeList = _nl;
+ })
+ .isOk());
+}
+
+int main(int argc, char** argv) {
+ gEnv = new ComponentTestEnvironment();
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ }
+ return status;
+}