Merge "Remove libhwbinder/libhidltransport deps"
diff --git a/tv/cec/1.0/default/HdmiCecMock.cpp b/tv/cec/1.0/default/HdmiCecMock.cpp
index eba8f95..219be86 100644
--- a/tv/cec/1.0/default/HdmiCecMock.cpp
+++ b/tv/cec/1.0/default/HdmiCecMock.cpp
@@ -77,6 +77,7 @@
if (message.body.size() == 0) {
return SendMessageResult::NACK;
}
+ sendMessageToFifo(message);
return SendMessageResult::SUCCESS;
}
@@ -88,6 +89,11 @@
if (callback != nullptr) {
mCallback = callback;
mCallback->linkToDeath(this, 0 /*cookie*/);
+
+ mInputFile = open(CEC_MSG_IN_FIFO, O_RDWR);
+ mOutputFile = open(CEC_MSG_OUT_FIFO, O_RDWR);
+ pthread_create(&mThreadId, NULL, __threadLoop, this);
+ pthread_setname_np(mThreadId, "hdmi_cec_loop");
}
return Void();
}
@@ -102,17 +108,8 @@
}
Return<void> HdmiCecMock::getPortInfo(getPortInfo_cb _hidl_cb) {
- vector<HdmiPortInfo> portInfos;
// TODO ready port info from device specific config
- portInfos.resize(mTotalPorts);
- for (int i = 0; i < mTotalPorts; ++i) {
- portInfos[i] = {.type = HdmiPortType::INPUT,
- .portId = static_cast<uint32_t>(i),
- .cecSupported = true,
- .arcSupported = (i == 0),
- .physicalAddress = static_cast<uint16_t>(i << 12)};
- }
- _hidl_cb(portInfos);
+ _hidl_cb(mPortInfo);
return Void();
}
@@ -140,13 +137,177 @@
return Void();
}
-Return<bool> HdmiCecMock::isConnected(int32_t portId __unused) {
+Return<bool> HdmiCecMock::isConnected(int32_t portId) {
// maintain port connection status and update on hotplug event
+ if (portId < mTotalPorts && portId >= 0) {
+ return mPortConnectionStatus[portId];
+ }
return false;
}
+void* HdmiCecMock::__threadLoop(void* user) {
+ HdmiCecMock* const self = static_cast<HdmiCecMock*>(user);
+ self->threadLoop();
+ return 0;
+}
+
+int HdmiCecMock::readMessageFromFifo(unsigned char* buf, int msgCount) {
+ if (msgCount <= 0 || !buf) {
+ return 0;
+ }
+
+ int ret = -1;
+ /* maybe blocked at driver */
+ ret = read(mInputFile, buf, msgCount);
+ if (ret < 0) {
+ ALOGE("[halimp] read :%s failed, ret:%d\n", CEC_MSG_IN_FIFO, ret);
+ return -1;
+ }
+
+ return ret;
+}
+
+int HdmiCecMock::sendMessageToFifo(const CecMessage& message) {
+ unsigned char msgBuf[CEC_MESSAGE_BODY_MAX_LENGTH];
+ int ret = -1;
+
+ memset(msgBuf, 0, sizeof(msgBuf));
+ msgBuf[0] = ((static_cast<uint8_t>(message.initiator) & 0xf) << 4) |
+ (static_cast<uint8_t>(message.destination) & 0xf);
+
+ size_t length = std::min(static_cast<size_t>(message.body.size()),
+ static_cast<size_t>(MaxLength::MESSAGE_BODY));
+ for (size_t i = 0; i < length; ++i) {
+ msgBuf[i + 1] = static_cast<unsigned char>(message.body[i]);
+ }
+
+ // open the output pipe for writing outgoing cec message
+ mOutputFile = open(CEC_MSG_OUT_FIFO, O_WRONLY);
+ if (mOutputFile < 0) {
+ ALOGD("[halimp] file open failed for writing");
+ return -1;
+ }
+
+ // write message into the output pipe
+ ret = write(mOutputFile, msgBuf, length + 1);
+ close(mOutputFile);
+ if (ret < 0) {
+ ALOGE("[halimp] write :%s failed, ret:%d\n", CEC_MSG_OUT_FIFO, ret);
+ return -1;
+ }
+ return ret;
+}
+
+void HdmiCecMock::printCecMsgBuf(const char* msg_buf, int len) {
+ char buf[64] = {};
+ int i, size = 0;
+ memset(buf, 0, sizeof(buf));
+ for (i = 0; i < len; i++) {
+ size += sprintf(buf + size, " %02x", msg_buf[i]);
+ }
+ ALOGD("[halimp] %s, msg:%s", __FUNCTION__, buf);
+}
+
+void HdmiCecMock::handleHotplugMessage(unsigned char* msgBuf) {
+ HotplugEvent hotplugEvent{.connected = ((msgBuf[3]) & 0xf) > 0,
+ .portId = static_cast<uint32_t>(msgBuf[0] & 0xf)};
+
+ if (hotplugEvent.portId >= mPortInfo.size()) {
+ ALOGD("[halimp] ignore hot plug message, id %x does not exist", hotplugEvent.portId);
+ return;
+ }
+
+ ALOGD("[halimp] hot plug port id %x, is connected %x", (msgBuf[0] & 0xf), (msgBuf[3] & 0xf));
+ if (mPortInfo[hotplugEvent.portId].type == HdmiPortType::OUTPUT) {
+ mPhysicalAddress =
+ ((hotplugEvent.connected == 0) ? 0xffff : ((msgBuf[1] << 8) | (msgBuf[2])));
+ mPortInfo[hotplugEvent.portId].physicalAddress = mPhysicalAddress;
+ ALOGD("[halimp] hot plug physical address %x", mPhysicalAddress);
+ }
+
+ // todo update connection status
+
+ if (mCallback != nullptr) {
+ mCallback->onHotplugEvent(hotplugEvent);
+ }
+}
+
+void HdmiCecMock::handleCecMessage(unsigned char* msgBuf, int megSize) {
+ CecMessage message;
+ size_t length = std::min(static_cast<size_t>(megSize - 1),
+ static_cast<size_t>(MaxLength::MESSAGE_BODY));
+ message.body.resize(length);
+
+ for (size_t i = 0; i < length; ++i) {
+ message.body[i] = static_cast<uint8_t>(msgBuf[i + 1]);
+ ALOGD("[halimp] msg body %x", message.body[i]);
+ }
+
+ message.initiator = static_cast<CecLogicalAddress>((msgBuf[0] >> 4) & 0xf);
+ ALOGD("[halimp] msg init %x", message.initiator);
+ message.destination = static_cast<CecLogicalAddress>((msgBuf[0] >> 0) & 0xf);
+ ALOGD("[halimp] msg dest %x", message.destination);
+
+ // messageValidateAndHandle(&event);
+
+ if (mCallback != nullptr) {
+ mCallback->onCecMessage(message);
+ }
+}
+
+void HdmiCecMock::threadLoop() {
+ ALOGD("[halimp] threadLoop start.");
+ unsigned char msgBuf[CEC_MESSAGE_BODY_MAX_LENGTH];
+ int r = -1;
+
+ // open the input pipe
+ while (mInputFile < 0) {
+ usleep(1000 * 1000);
+ mInputFile = open(CEC_MSG_IN_FIFO, O_RDONLY);
+ }
+ ALOGD("[halimp] file open ok, fd = %d.", mInputFile);
+
+ while (mCecThreadRun) {
+ if (!mOptionSystemCecControl) {
+ usleep(1000 * 1000);
+ continue;
+ }
+
+ memset(msgBuf, 0, sizeof(msgBuf));
+ // try to get a message from dev.
+ // echo -n -e '\x04\x83' >> /dev/cec
+ r = readMessageFromFifo(msgBuf, CEC_MESSAGE_BODY_MAX_LENGTH);
+ if (r <= 1) {
+ // ignore received ping messages
+ continue;
+ }
+
+ printCecMsgBuf((const char*)msgBuf, r);
+
+ if (((msgBuf[0] >> 4) & 0xf) == 0xf) {
+ // the message is a hotplug event
+ handleHotplugMessage(msgBuf);
+ continue;
+ }
+
+ handleCecMessage(msgBuf, r);
+ }
+
+ ALOGD("[halimp] thread end.");
+ // mCecDevice.mExited = true;
+}
+
HdmiCecMock::HdmiCecMock() {
- ALOGE("Opening a virtual HAL for testing and virtual machine.");
+ ALOGE("[halimp] Opening a virtual HAL for testing and virtual machine.");
+ mCallback = nullptr;
+ mPortInfo.resize(mTotalPorts);
+ mPortConnectionStatus.resize(mTotalPorts);
+ mPortInfo[0] = {.type = HdmiPortType::OUTPUT,
+ .portId = static_cast<uint32_t>(0),
+ .cecSupported = true,
+ .arcSupported = false,
+ .physicalAddress = mPhysicalAddress};
+ mPortConnectionStatus[0] = false;
}
} // namespace implementation
diff --git a/tv/cec/1.0/default/HdmiCecMock.h b/tv/cec/1.0/default/HdmiCecMock.h
index b2f1113..0a708fa 100644
--- a/tv/cec/1.0/default/HdmiCecMock.h
+++ b/tv/cec/1.0/default/HdmiCecMock.h
@@ -49,6 +49,9 @@
using ::android::hardware::tv::cec::V1_0::Result;
using ::android::hardware::tv::cec::V1_0::SendMessageResult;
+#define CEC_MSG_IN_FIFO "/dev/cec_in_pipe"
+#define CEC_MSG_OUT_FIFO "/dev/cec_out_pipe"
+
struct HdmiCecMock : public IHdmiCec, public hidl_death_recipient {
HdmiCecMock();
// Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow.
@@ -71,21 +74,43 @@
}
void cec_set_option(int flag, int value);
+ void printCecMsgBuf(const char* msg_buf, int len);
+
+ private:
+ static void* __threadLoop(void* data);
+ void threadLoop();
+ int readMessageFromFifo(unsigned char* buf, int msgCount);
+ int sendMessageToFifo(const CecMessage& message);
+ void handleHotplugMessage(unsigned char* msgBuf);
+ void handleCecMessage(unsigned char* msgBuf, int length);
private:
sp<IHdmiCecCallback> mCallback;
+
// Variables for the virtual cec hal impl
uint16_t mPhysicalAddress = 0xFFFF;
vector<CecLogicalAddress> mLogicalAddresses;
int32_t mCecVersion = 0;
uint32_t mCecVendorId = 0;
+
// Port configuration
- int mTotalPorts = 4;
+ int mTotalPorts = 1;
+ hidl_vec<HdmiPortInfo> mPortInfo;
+ hidl_vec<bool> mPortConnectionStatus;
+
// CEC Option value
int mOptionWakeUp = 0;
int mOptionEnableCec = 0;
int mOptionSystemCecControl = 0;
int mOptionLanguage = 0;
+
+ // Testing variables
+ // Input file descriptor
+ int mInputFile;
+ // Output file descriptor
+ int mOutputFile;
+ bool mCecThreadRun = true;
+ pthread_t mThreadId = 0;
};
} // namespace implementation
} // namespace V1_0
diff --git a/tv/tuner/1.0/Android.bp b/tv/tuner/1.0/Android.bp
index b54413d..986518b 100644
--- a/tv/tuner/1.0/Android.bp
+++ b/tv/tuner/1.0/Android.bp
@@ -8,6 +8,9 @@
},
srcs: [
"types.hal",
+ "IDemux.hal",
+ "IDemuxCallback.hal",
+ "IDescrambler.hal",
"IFrontend.hal",
"IFrontendCallback.hal",
"ITuner.hal",
diff --git a/tv/tuner/1.0/IDemux.hal b/tv/tuner/1.0/IDemux.hal
new file mode 100644
index 0000000..938bc44
--- /dev/null
+++ b/tv/tuner/1.0/IDemux.hal
@@ -0,0 +1,37 @@
+package android.hardware.tv.tuner@1.0;
+
+import IDemuxCallback;
+
+/**
+ * Demultiplexer(Demux) takes a single multiplexed input and splits it into
+ * one or more output.
+ *
+ */
+interface IDemux {
+
+ /**
+ * Set a frontend resource as data input of the demux
+ *
+ * It is used by the client to specify a hardware frontend as data source of
+ * this demux instance. A demux instance can have only one data source.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * INVALID_STATE if failed for wrong state.
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ setFrontendDataSource(FrontendId frontendId) generates (Result result);
+
+ /**
+ * Close the Demux instance
+ *
+ * It is used by the client to release the demux instance. HAL clear
+ * underneath resource. client mustn't access the instance any more.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ close() generates (Result result);
+};
+
diff --git a/tv/tuner/1.0/IDemuxCallback.hal b/tv/tuner/1.0/IDemuxCallback.hal
new file mode 100644
index 0000000..c67c5f2
--- /dev/null
+++ b/tv/tuner/1.0/IDemuxCallback.hal
@@ -0,0 +1,11 @@
+package android.hardware.tv.tuner@1.0;
+
+interface IDemuxCallback {
+ /**
+ * Notify the client that a new filter event happened.
+ *
+ * @param filterEvent a demux filter event.
+ */
+ oneway onFilterEvent(DemuxFilterEvent filterEvent);
+};
+
diff --git a/tv/tuner/1.0/IDescrambler.hal b/tv/tuner/1.0/IDescrambler.hal
new file mode 100644
index 0000000..4d6cf3c
--- /dev/null
+++ b/tv/tuner/1.0/IDescrambler.hal
@@ -0,0 +1,35 @@
+package android.hardware.tv.tuner@1.0;
+
+/**
+ * Descrambler is used to descramble input data.
+ *
+ */
+interface IDescrambler {
+
+ /**
+ * Set a demux as source of the descrambler
+ *
+ * It is used by the client to specify a demux as source of this
+ * descrambler. A descrambler instance can have only one source, and
+ * this method can be only called once.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * INVALID_STATE if failed for wrong state.
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ setDemuxSource(DemuxId demuxId) generates (Result result);
+
+ /**
+ * Release the descrambler instance
+ *
+ * It is used by the client to release the descrambler instance. HAL clear
+ * underneath resource. client mustn't access the instance any more.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ close() generates (Result result);
+};
+
diff --git a/tv/tuner/1.0/ITuner.hal b/tv/tuner/1.0/ITuner.hal
index 5a5f547..61a9d63 100644
--- a/tv/tuner/1.0/ITuner.hal
+++ b/tv/tuner/1.0/ITuner.hal
@@ -16,6 +16,8 @@
package android.hardware.tv.tuner@1.0;
+import IDemux;
+import IDescrambler;
import IFrontend;
/**
@@ -48,5 +50,30 @@
openFrontendById(FrontendId frontendId)
generates (Result result, IFrontend frontend);
-};
+ /**
+ * Create a new instance of Demux.
+ *
+ * It is used by the client to create a Demux instance.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * UNKNOWN_ERROR if creation failed for other reasons.
+ * @return demuxId newly created demux id.
+ * @return demux the newly created demux interface.
+ */
+ openDemux()
+ generates (Result result, DemuxId demuxId, IDemux demux);
+ /**
+ * Create a new instance of Descrambler.
+ *
+ * It is used by the client to create a Descrambler instance.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * UNKNOWN_ERROR if creation failed for other reasons.
+ * @return descrambler the newly created descrambler interface.
+ */
+ openDescrambler()
+ generates (Result result, IDescrambler descrambler);
+};
diff --git a/tv/tuner/1.0/default/OWNERS b/tv/tuner/1.0/default/OWNERS
new file mode 100644
index 0000000..1b3d095
--- /dev/null
+++ b/tv/tuner/1.0/default/OWNERS
@@ -0,0 +1,4 @@
+nchalko@google.com
+amyjojo@google.com
+shubang@google.com
+quxiangfang@google.com
diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
index 67ec754..6bb7aa9 100644
--- a/tv/tuner/1.0/default/Tuner.cpp
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -28,6 +28,8 @@
namespace V1_0 {
namespace implementation {
+using ::android::hardware::tv::tuner::V1_0::DemuxId;
+
Tuner::Tuner() {
// Static Frontends array to maintain local frontends information
// Array index matches their FrontendId in the default impl
@@ -71,6 +73,25 @@
return Void();
}
+Return<void> Tuner::openDemux(openDemux_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ sp<IDemux> demux;
+ DemuxId demuxId = 0;
+
+ _hidl_cb(Result::SUCCESS, demuxId, demux);
+ return Void();
+}
+
+Return<void> Tuner::openDescrambler(openDescrambler_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ sp<IDescrambler> descrambler;
+
+ _hidl_cb(Result::SUCCESS, descrambler);
+ return Void();
+}
+
} // namespace implementation
} // namespace V1_0
} // namespace tuner
diff --git a/tv/tuner/1.0/default/Tuner.h b/tv/tuner/1.0/default/Tuner.h
index 2152c89..1ca7671 100644
--- a/tv/tuner/1.0/default/Tuner.h
+++ b/tv/tuner/1.0/default/Tuner.h
@@ -37,6 +37,10 @@
virtual Return<void> openFrontendById(uint32_t frontendId,
openFrontendById_cb _hidl_cb) override;
+ virtual Return<void> openDemux(openDemux_cb _hidl_cb) override;
+
+ virtual Return<void> openDescrambler(openDescrambler_cb _hidl_cb) override;
+
private:
virtual ~Tuner();
// Static mFrontends array to maintain local frontends information
diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal
index 1ca7fda..3fa9641 100644
--- a/tv/tuner/1.0/types.hal
+++ b/tv/tuner/1.0/types.hal
@@ -137,3 +137,53 @@
*/
LOST_LOCK,
};
+
+/* Demux ID is used to associate with a hardware demux resource. */
+typedef uint32_t DemuxId;
+
+/* Filter ID is used to associate with a hardware filter resource. */
+typedef uint32_t DemuxFilterId;
+
+/**
+ * Filter Type according to ISO/IEC 13818-1
+ */
+@export
+enum DemuxFilterType : uint32_t {
+ /**
+ * A filter to filter section data out from input stream.
+ */
+ SECTION,
+ /**
+ * A filter to filter PES data out from input stream.
+ */
+ PES,
+ /**
+ * A filter to filter TS payload out from input stream.
+ */
+ TS,
+ /**
+ * A filter to filter Audio Metadata out from input stream.
+ */
+ AUDIO,
+ /**
+ * A filter to filter Vidoe Metadata out from input stream.
+ */
+ VIDEO,
+ /**
+ * A filter to set PCR channel from input stream.
+ */
+ PCR,
+ /**
+ * A filter to filter data directly to output buffer for record.
+ */
+ RECORD,
+};
+
+/**
+ * Filter Event.
+ */
+struct DemuxFilterEvent {
+ DemuxFilterId filterId;
+ DemuxFilterType filterType;
+};
+
diff --git a/tv/tuner/1.0/vts/OWNERS b/tv/tuner/1.0/vts/OWNERS
new file mode 100644
index 0000000..1b3d095
--- /dev/null
+++ b/tv/tuner/1.0/vts/OWNERS
@@ -0,0 +1,4 @@
+nchalko@google.com
+amyjojo@google.com
+shubang@google.com
+quxiangfang@google.com