mirror of
https://github.com/tuxbox-fork-migrations/recycled-ni-libstb-hal.git
synced 2025-08-26 23:12:44 +02:00
libarmbox: move hdmi_cec to own class, add basic cec-remote support
cec-remote will print received commands in log for now
Origin commit data
------------------
Branch: master
Commit: eca390a574
Author: TangoCash <eric@loxat.de>
Date: 2018-10-07 (Sun, 07 Oct 2018)
------------------
This commit was generated by Migit
This commit is contained in:
@@ -20,7 +20,8 @@ libarmbox_la_SOURCES = \
|
||||
video.cpp \
|
||||
audio.cpp \
|
||||
init.cpp \
|
||||
record.cpp
|
||||
record.cpp \
|
||||
hdmi_cec.cpp
|
||||
|
||||
if ENABLE_GSTREAMER_10
|
||||
libarmbox_la_SOURCES += \
|
||||
|
495
libarmbox/hdmi_cec.cpp
Normal file
495
libarmbox/hdmi_cec.cpp
Normal file
@@ -0,0 +1,495 @@
|
||||
/*
|
||||
Copyright (C) 2018 TangoCash
|
||||
|
||||
License: GPLv2
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation;
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <utime.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "linux-uapi-cec.h"
|
||||
#include "hdmi_cec.h"
|
||||
#include "lt_debug.h"
|
||||
|
||||
#define lt_debug(args...) _lt_debug(TRIPLE_DEBUG_VIDEO, this, args)
|
||||
#define lt_info(args...) _lt_info(TRIPLE_DEBUG_VIDEO, this, args)
|
||||
#define lt_debug_c(args...) _lt_debug(TRIPLE_DEBUG_VIDEO, NULL, args)
|
||||
#define lt_info_c(args...) _lt_info(TRIPLE_DEBUG_VIDEO, NULL, args)
|
||||
|
||||
#define fop(cmd, args...) ({ \
|
||||
int _r; \
|
||||
if (fd >= 0) { \
|
||||
if ((_r = ::cmd(fd, args)) < 0) \
|
||||
lt_info(#cmd"(fd, "#args")\n"); \
|
||||
else \
|
||||
lt_debug(#cmd"(fd, "#args")\n");\
|
||||
} \
|
||||
else { _r = fd; } \
|
||||
_r; \
|
||||
})
|
||||
|
||||
#define CEC_DEVICE "/dev/cec0"
|
||||
|
||||
hdmi_cec * hdmi_cec::hdmi_cec_instance = NULL;
|
||||
|
||||
hdmi_cec::hdmi_cec()
|
||||
{
|
||||
standby_cec_activ = autoview_cec_activ = false;
|
||||
hdmiFd = -1;
|
||||
if (hdmiFd == -1)
|
||||
hdmiFd = open(CEC_DEVICE, O_RDWR | O_CLOEXEC);
|
||||
Start();
|
||||
}
|
||||
|
||||
hdmi_cec::~hdmi_cec()
|
||||
{
|
||||
if (hdmiFd >= 0)
|
||||
{
|
||||
close(hdmiFd);
|
||||
hdmiFd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
hdmi_cec* hdmi_cec::getInstance()
|
||||
{
|
||||
if (hdmi_cec_instance == NULL)
|
||||
hdmi_cec_instance = new hdmi_cec();
|
||||
return hdmi_cec_instance;
|
||||
}
|
||||
|
||||
bool hdmi_cec::SetCECMode(VIDEO_HDMI_CEC_MODE _deviceType)
|
||||
{
|
||||
physicalAddress[0] = 0x10;
|
||||
physicalAddress[1] = 0x00;
|
||||
logicalAddress = 1;
|
||||
|
||||
if (_deviceType == VIDEO_HDMI_CEC_MODE_OFF)
|
||||
{
|
||||
if (hdmiFd >= 0)
|
||||
{
|
||||
close(hdmiFd);
|
||||
hdmiFd = -1;
|
||||
Stop();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
deviceType = _deviceType;
|
||||
|
||||
if (hdmiFd == -1)
|
||||
{
|
||||
hdmiFd = open(CEC_DEVICE, O_RDWR | O_CLOEXEC);
|
||||
Start();
|
||||
}
|
||||
|
||||
if (hdmiFd >= 0)
|
||||
{
|
||||
__u32 monitor = CEC_MODE_INITIATOR | CEC_MODE_FOLLOWER;
|
||||
struct cec_caps caps = {};
|
||||
|
||||
if (ioctl(hdmiFd, CEC_ADAP_G_CAPS, &caps) < 0)
|
||||
lt_info("%s: CEC get caps failed (%m)\n", __func__);
|
||||
|
||||
if (caps.capabilities & CEC_CAP_LOG_ADDRS)
|
||||
{
|
||||
struct cec_log_addrs laddrs = {};
|
||||
|
||||
if (ioctl(hdmiFd, CEC_ADAP_S_LOG_ADDRS, &laddrs) < 0)
|
||||
lt_info("%s: CEC reset log addr failed (%m)\n", __func__);
|
||||
|
||||
memset(&laddrs, 0, sizeof(laddrs));
|
||||
|
||||
/*
|
||||
* NOTE: cec_version, osd_name and deviceType should be made configurable,
|
||||
* CEC_ADAP_S_LOG_ADDRS delayed till the desired values are available
|
||||
* (saves us some startup speed as well, polling for a free logical address
|
||||
* takes some time)
|
||||
*/
|
||||
laddrs.cec_version = CEC_OP_CEC_VERSION_2_0;
|
||||
strcpy(laddrs.osd_name, "neutrino");
|
||||
laddrs.vendor_id = CEC_VENDOR_ID_NONE;
|
||||
|
||||
switch (deviceType)
|
||||
{
|
||||
case CEC_LOG_ADDR_TV:
|
||||
laddrs.log_addr_type[laddrs.num_log_addrs] = CEC_LOG_ADDR_TYPE_TV;
|
||||
laddrs.all_device_types[laddrs.num_log_addrs] = CEC_OP_ALL_DEVTYPE_TV;
|
||||
laddrs.primary_device_type[laddrs.num_log_addrs] = CEC_OP_PRIM_DEVTYPE_TV;
|
||||
break;
|
||||
case CEC_LOG_ADDR_RECORD_1:
|
||||
laddrs.log_addr_type[laddrs.num_log_addrs] = CEC_LOG_ADDR_TYPE_RECORD;
|
||||
laddrs.all_device_types[laddrs.num_log_addrs] = CEC_OP_ALL_DEVTYPE_RECORD;
|
||||
laddrs.primary_device_type[laddrs.num_log_addrs] = CEC_OP_PRIM_DEVTYPE_RECORD;
|
||||
break;
|
||||
case CEC_LOG_ADDR_TUNER_1:
|
||||
laddrs.log_addr_type[laddrs.num_log_addrs] = CEC_LOG_ADDR_TYPE_TUNER;
|
||||
laddrs.all_device_types[laddrs.num_log_addrs] = CEC_OP_ALL_DEVTYPE_TUNER;
|
||||
laddrs.primary_device_type[laddrs.num_log_addrs] = CEC_OP_PRIM_DEVTYPE_TUNER;
|
||||
break;
|
||||
case CEC_LOG_ADDR_PLAYBACK_1:
|
||||
laddrs.log_addr_type[laddrs.num_log_addrs] = CEC_LOG_ADDR_TYPE_PLAYBACK;
|
||||
laddrs.all_device_types[laddrs.num_log_addrs] = CEC_OP_ALL_DEVTYPE_PLAYBACK;
|
||||
laddrs.primary_device_type[laddrs.num_log_addrs] = CEC_OP_PRIM_DEVTYPE_PLAYBACK;
|
||||
break;
|
||||
case CEC_LOG_ADDR_AUDIOSYSTEM:
|
||||
laddrs.log_addr_type[laddrs.num_log_addrs] = CEC_LOG_ADDR_TYPE_AUDIOSYSTEM;
|
||||
laddrs.all_device_types[laddrs.num_log_addrs] = CEC_OP_ALL_DEVTYPE_AUDIOSYSTEM;
|
||||
laddrs.primary_device_type[laddrs.num_log_addrs] = CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM;
|
||||
break;
|
||||
default:
|
||||
laddrs.log_addr_type[laddrs.num_log_addrs] = CEC_LOG_ADDR_TYPE_UNREGISTERED;
|
||||
laddrs.all_device_types[laddrs.num_log_addrs] = CEC_OP_ALL_DEVTYPE_SWITCH;
|
||||
laddrs.primary_device_type[laddrs.num_log_addrs] = CEC_OP_PRIM_DEVTYPE_SWITCH;
|
||||
break;
|
||||
}
|
||||
laddrs.num_log_addrs++;
|
||||
|
||||
if (ioctl(hdmiFd, CEC_ADAP_S_LOG_ADDRS, &laddrs) < 0)
|
||||
lt_info("%s: CEC set log addr failed (%m)\n", __func__);
|
||||
}
|
||||
|
||||
if (ioctl(hdmiFd, CEC_S_MODE, &monitor) < 0)
|
||||
lt_info("%s: CEC monitor failed (%m)\n", __func__);
|
||||
|
||||
GetCECAddressInfo();
|
||||
|
||||
if(autoview_cec_activ)
|
||||
SetCECState(false);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void hdmi_cec::GetCECAddressInfo()
|
||||
{
|
||||
if (hdmiFd >= 0)
|
||||
{
|
||||
struct addressinfo addressinfo;
|
||||
|
||||
__u16 phys_addr;
|
||||
struct cec_log_addrs laddrs = {};
|
||||
|
||||
::ioctl(hdmiFd, CEC_ADAP_G_PHYS_ADDR, &phys_addr);
|
||||
addressinfo.physical[0] = (phys_addr >> 8) & 0xff;
|
||||
addressinfo.physical[1] = phys_addr & 0xff;
|
||||
|
||||
::ioctl(hdmiFd, CEC_ADAP_G_LOG_ADDRS, &laddrs);
|
||||
addressinfo.logical = laddrs.log_addr[0];
|
||||
|
||||
switch (laddrs.log_addr_type[0])
|
||||
{
|
||||
case CEC_LOG_ADDR_TYPE_TV:
|
||||
addressinfo.type = CEC_LOG_ADDR_TV;
|
||||
break;
|
||||
case CEC_LOG_ADDR_TYPE_RECORD:
|
||||
addressinfo.type = CEC_LOG_ADDR_RECORD_1;
|
||||
break;
|
||||
case CEC_LOG_ADDR_TYPE_TUNER:
|
||||
addressinfo.type = CEC_LOG_ADDR_TUNER_1;
|
||||
break;
|
||||
case CEC_LOG_ADDR_TYPE_PLAYBACK:
|
||||
addressinfo.type = CEC_LOG_ADDR_PLAYBACK_1;
|
||||
break;
|
||||
case CEC_LOG_ADDR_TYPE_AUDIOSYSTEM:
|
||||
addressinfo.type = CEC_LOG_ADDR_AUDIOSYSTEM;
|
||||
break;
|
||||
case CEC_LOG_ADDR_TYPE_UNREGISTERED:
|
||||
default:
|
||||
addressinfo.type = CEC_LOG_ADDR_UNREGISTERED;
|
||||
break;
|
||||
}
|
||||
|
||||
deviceType = addressinfo.type;
|
||||
logicalAddress = addressinfo.logical;
|
||||
if (memcmp(physicalAddress, addressinfo.physical, sizeof(physicalAddress)))
|
||||
{
|
||||
lt_info("%s: detected physical address change: %02X%02X --> %02X%02X\n", __func__, physicalAddress[0], physicalAddress[1], addressinfo.physical[0], addressinfo.physical[1]);
|
||||
memcpy(physicalAddress, addressinfo.physical, sizeof(physicalAddress));
|
||||
ReportPhysicalAddress();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hdmi_cec::ReportPhysicalAddress()
|
||||
{
|
||||
struct cec_message txmessage;
|
||||
txmessage.address = 0x0f; /* broadcast */
|
||||
txmessage.data[0] = CEC_MSG_REPORT_PHYSICAL_ADDR;
|
||||
txmessage.data[1] = physicalAddress[0];
|
||||
txmessage.data[2] = physicalAddress[1];
|
||||
txmessage.data[3] = deviceType;
|
||||
txmessage.length = 4;
|
||||
SendCECMessage(txmessage);
|
||||
}
|
||||
|
||||
void hdmi_cec::SendCECMessage(struct cec_message &txmessage)
|
||||
{
|
||||
if (hdmiFd >= 0)
|
||||
{
|
||||
char str[txmessage.length*6];
|
||||
for (int i = 0; i < txmessage.length; i++)
|
||||
{
|
||||
sprintf(str+(i*6),"(0x%02X)", txmessage.data[i]);
|
||||
}
|
||||
lt_info("[CEC] send message %s\n",str);
|
||||
struct cec_msg msg;
|
||||
cec_msg_init(&msg, logicalAddress, txmessage.address);
|
||||
memcpy(&msg.msg[1], txmessage.data, txmessage.length);
|
||||
msg.len = txmessage.length + 1;
|
||||
ioctl(hdmiFd, CEC_TRANSMIT, &msg);
|
||||
}
|
||||
}
|
||||
|
||||
void hdmi_cec::SetCECAutoStandby(bool state)
|
||||
{
|
||||
standby_cec_activ = state;
|
||||
}
|
||||
|
||||
void hdmi_cec::SetCECAutoView(bool state)
|
||||
{
|
||||
autoview_cec_activ = state;
|
||||
}
|
||||
|
||||
void hdmi_cec::SetCECState(bool state)
|
||||
{
|
||||
struct cec_message message;
|
||||
|
||||
if ((standby_cec_activ) && state)
|
||||
{
|
||||
message.address = CEC_OP_PRIM_DEVTYPE_TV;
|
||||
message.data[0] = CEC_MSG_STANDBY;
|
||||
message.length = 1;
|
||||
SendCECMessage(message);
|
||||
}
|
||||
|
||||
if ((autoview_cec_activ) && !state)
|
||||
{
|
||||
message.address = CEC_OP_PRIM_DEVTYPE_TV;
|
||||
message.data[0] = CEC_MSG_IMAGE_VIEW_ON;
|
||||
message.length = 1;
|
||||
SendCECMessage(message);
|
||||
usleep(10000);
|
||||
message.address = 0x0f; /* broadcast */
|
||||
message.data[0] = CEC_MSG_ACTIVE_SOURCE;
|
||||
message.data[1] = physicalAddress[0];
|
||||
message.data[2] = physicalAddress[1];
|
||||
message.length = 3;
|
||||
SendCECMessage(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
long hdmi_cec::translateKey(unsigned char code)
|
||||
{
|
||||
long key = 0;
|
||||
switch (code)
|
||||
{
|
||||
case 0x32:
|
||||
key = 0x8b;
|
||||
break;
|
||||
case 0x20:
|
||||
key = 0x0b;
|
||||
break;
|
||||
case 0x21:
|
||||
key = 0x02;
|
||||
break;
|
||||
case 0x22:
|
||||
key = 0x03;
|
||||
break;
|
||||
case 0x23:
|
||||
key = 0x04;
|
||||
break;
|
||||
case 0x24:
|
||||
key = 0x05;
|
||||
break;
|
||||
case 0x25:
|
||||
key = 0x06;
|
||||
break;
|
||||
case 0x26:
|
||||
key = 0x07;
|
||||
break;
|
||||
case 0x27:
|
||||
key = 0x08;
|
||||
break;
|
||||
case 0x28:
|
||||
key = 0x09;
|
||||
break;
|
||||
case 0x29:
|
||||
key = 0x0a;
|
||||
break;
|
||||
case 0x30:
|
||||
key = 0x192;
|
||||
break;
|
||||
case 0x31:
|
||||
key = 0x193;
|
||||
break;
|
||||
case 0x44:
|
||||
key = 0xcf;
|
||||
break;
|
||||
case 0x45:
|
||||
key = 0x80;
|
||||
break;
|
||||
case 0x46:
|
||||
key = 0x77;
|
||||
break;
|
||||
case 0x47:
|
||||
key = 0xa7;
|
||||
break;
|
||||
case 0x48:
|
||||
key = 0xa8;
|
||||
break;
|
||||
case 0x49:
|
||||
key = 0xd0;
|
||||
break;
|
||||
case 0x53:
|
||||
key = 0x166;
|
||||
break;
|
||||
case 0x54:
|
||||
key = 0x16a;
|
||||
break;
|
||||
case 0x60:
|
||||
key = 0xcf;
|
||||
break;
|
||||
case 0x61:
|
||||
key = 0xa4;
|
||||
break;
|
||||
case 0x62:
|
||||
key = 0xa7;
|
||||
break;
|
||||
case 0x64:
|
||||
key = 0x80;
|
||||
break;
|
||||
case 0x00:
|
||||
key = 0x160;
|
||||
break;
|
||||
case 0x03:
|
||||
key = 0x69;
|
||||
break;
|
||||
case 0x04:
|
||||
key = 0x6a;
|
||||
break;
|
||||
case 0x01:
|
||||
key = 0x67;
|
||||
break;
|
||||
case 0x02:
|
||||
key = 0x6c;
|
||||
break;
|
||||
case 0x0d:
|
||||
key = 0xae;
|
||||
break;
|
||||
case 0x72:
|
||||
key = 0x18e;
|
||||
break;
|
||||
case 0x71:
|
||||
key = 0x191;
|
||||
break;
|
||||
case 0x73:
|
||||
key = 0x18f;
|
||||
break;
|
||||
case 0x74:
|
||||
key = 0x190;
|
||||
break;
|
||||
default:
|
||||
key = 0x8b;
|
||||
break;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
bool hdmi_cec::Start()
|
||||
{
|
||||
if (running)
|
||||
return false;
|
||||
|
||||
if (hdmiFd == -1)
|
||||
return false;
|
||||
|
||||
running = true;
|
||||
return (OpenThreads::Thread::start() == 0);
|
||||
}
|
||||
|
||||
bool hdmi_cec::Stop()
|
||||
{
|
||||
if (!running)
|
||||
return false;
|
||||
|
||||
running = false;
|
||||
|
||||
return (OpenThreads::Thread::join() == 0);
|
||||
}
|
||||
|
||||
void hdmi_cec::run()
|
||||
{
|
||||
while (running)
|
||||
{
|
||||
Receive();
|
||||
}
|
||||
}
|
||||
|
||||
void hdmi_cec::Receive()
|
||||
{
|
||||
bool hasdata = false;
|
||||
struct cec_message rxmessage;
|
||||
|
||||
struct cec_msg msg;
|
||||
if (::ioctl(hdmiFd, CEC_RECEIVE, &msg) >= 0)
|
||||
{
|
||||
rxmessage.length = msg.len - 1;
|
||||
memcpy(&rxmessage.data, &msg.msg[1], rxmessage.length);
|
||||
hasdata = true;
|
||||
}
|
||||
|
||||
if (hasdata)
|
||||
{
|
||||
bool keypressed = false;
|
||||
static unsigned char pressedkey = 0;
|
||||
|
||||
char str[rxmessage.length*6];
|
||||
for (int i = 0; i < rxmessage.length; i++)
|
||||
{
|
||||
sprintf(str+(i*6),"(0x%02X)", rxmessage.data[i]);
|
||||
}
|
||||
lt_info("[CEC] received message %s\n", str);
|
||||
|
||||
switch (rxmessage.data[0])
|
||||
{
|
||||
case 0x44: /* key pressed */
|
||||
keypressed = true;
|
||||
pressedkey = rxmessage.data[1];
|
||||
case 0x45: /* key released */
|
||||
{
|
||||
long code = translateKey(pressedkey);
|
||||
if (keypressed)
|
||||
code |= 0x80000000;
|
||||
lt_info("[CEC] received key %ld\n",code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
66
libarmbox/hdmi_cec.h
Normal file
66
libarmbox/hdmi_cec.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
Copyright (C) 2018 TangoCash
|
||||
|
||||
License: GPLv2
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation;
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <OpenThreads/Thread>
|
||||
#include <OpenThreads/Condition>
|
||||
|
||||
#include "video_lib.h"
|
||||
|
||||
struct cec_message
|
||||
{
|
||||
unsigned char address;
|
||||
unsigned char length;
|
||||
unsigned char data[256];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct addressinfo
|
||||
{
|
||||
unsigned char logical;
|
||||
unsigned char physical[2];
|
||||
unsigned char type;
|
||||
};
|
||||
|
||||
class hdmi_cec : public OpenThreads::Thread
|
||||
{
|
||||
private:
|
||||
hdmi_cec();
|
||||
static hdmi_cec *hdmi_cec_instance;
|
||||
void run();
|
||||
bool Start();
|
||||
bool Stop();
|
||||
void Receive();
|
||||
unsigned char physicalAddress[2];
|
||||
bool autoview_cec_activ;
|
||||
unsigned char deviceType, logicalAddress;
|
||||
int hdmiFd;
|
||||
long translateKey(unsigned char code);
|
||||
protected:
|
||||
bool running;
|
||||
public:
|
||||
~hdmi_cec();
|
||||
static hdmi_cec* getInstance();
|
||||
bool SetCECMode(VIDEO_HDMI_CEC_MODE);
|
||||
void SetCECAutoView(bool);
|
||||
void SetCECAutoStandby(bool);
|
||||
void GetCECAddressInfo();
|
||||
void SendCECMessage(struct cec_message &message);
|
||||
void SetCECState(bool state);
|
||||
void ReportPhysicalAddress();
|
||||
bool standby_cec_activ;
|
||||
};
|
@@ -36,7 +36,7 @@
|
||||
#include <linux/fb.h>
|
||||
#include "video_lib.h"
|
||||
#include "lt_debug.h"
|
||||
#include "linux-uapi-cec.h"
|
||||
#include "hdmi_cec.h"
|
||||
|
||||
#include <proc_tools.h>
|
||||
|
||||
@@ -326,8 +326,6 @@ cVideo::cVideo(int, void *, void *, unsigned int unit)
|
||||
} else
|
||||
devnum = unit;
|
||||
fd = -1;
|
||||
hdmiFd = -1;
|
||||
standby_cec_activ = autoview_cec_activ = false;
|
||||
openDevice();
|
||||
setAVInput(ENCODER);
|
||||
}
|
||||
@@ -336,8 +334,8 @@ cVideo::~cVideo(void)
|
||||
{
|
||||
if(fd >= 0)
|
||||
setAVInput(AUX);
|
||||
if (standby_cec_activ && fd >= 0)
|
||||
SetCECState(true);
|
||||
if (hdmi_cec::getInstance()->standby_cec_activ && fd >= 0)
|
||||
hdmi_cec::getInstance()->SetCECState(true);
|
||||
|
||||
closeDevice();
|
||||
}
|
||||
@@ -640,7 +638,7 @@ void cVideo::Standby(unsigned int bOn)
|
||||
setAVInput(ENCODER);
|
||||
}
|
||||
video_standby = bOn;
|
||||
SetCECState(video_standby);
|
||||
hdmi_cec::getInstance()->SetCECState(video_standby);
|
||||
}
|
||||
|
||||
int cVideo::getBlank(void)
|
||||
@@ -1171,220 +1169,15 @@ bool cVideo::GetScreenImage(unsigned char * &out_data, int &xres, int &yres, boo
|
||||
|
||||
bool cVideo::SetCECMode(VIDEO_HDMI_CEC_MODE _deviceType)
|
||||
{
|
||||
physicalAddress[0] = 0x10;
|
||||
physicalAddress[1] = 0x00;
|
||||
logicalAddress = 1;
|
||||
|
||||
if (_deviceType == VIDEO_HDMI_CEC_MODE_OFF)
|
||||
{
|
||||
if (hdmiFd >= 0) {
|
||||
close(hdmiFd);
|
||||
hdmiFd = -1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
deviceType = _deviceType;
|
||||
|
||||
if (hdmiFd == -1)
|
||||
hdmiFd = open("/dev/cec0", O_RDWR | O_CLOEXEC);
|
||||
|
||||
if (hdmiFd >= 0)
|
||||
{
|
||||
__u32 monitor = CEC_MODE_INITIATOR | CEC_MODE_FOLLOWER;
|
||||
struct cec_caps caps = {};
|
||||
|
||||
if (ioctl(hdmiFd, CEC_ADAP_G_CAPS, &caps) < 0)
|
||||
lt_info("%s: CEC get caps failed (%m)\n", __func__);
|
||||
|
||||
if (caps.capabilities & CEC_CAP_LOG_ADDRS)
|
||||
{
|
||||
struct cec_log_addrs laddrs = {};
|
||||
|
||||
if (ioctl(hdmiFd, CEC_ADAP_S_LOG_ADDRS, &laddrs) < 0)
|
||||
lt_info("%s: CEC reset log addr failed (%m)\n", __func__);
|
||||
|
||||
memset(&laddrs, 0, sizeof(laddrs));
|
||||
|
||||
/*
|
||||
* NOTE: cec_version, osd_name and deviceType should be made configurable,
|
||||
* CEC_ADAP_S_LOG_ADDRS delayed till the desired values are available
|
||||
* (saves us some startup speed as well, polling for a free logical address
|
||||
* takes some time)
|
||||
*/
|
||||
laddrs.cec_version = CEC_OP_CEC_VERSION_2_0;
|
||||
strcpy(laddrs.osd_name, "neutrino");
|
||||
laddrs.vendor_id = CEC_VENDOR_ID_NONE;
|
||||
|
||||
switch (deviceType)
|
||||
{
|
||||
case CEC_LOG_ADDR_TV:
|
||||
laddrs.log_addr_type[laddrs.num_log_addrs] = CEC_LOG_ADDR_TYPE_TV;
|
||||
laddrs.all_device_types[laddrs.num_log_addrs] = CEC_OP_ALL_DEVTYPE_TV;
|
||||
laddrs.primary_device_type[laddrs.num_log_addrs] = CEC_OP_PRIM_DEVTYPE_TV;
|
||||
break;
|
||||
case CEC_LOG_ADDR_RECORD_1:
|
||||
laddrs.log_addr_type[laddrs.num_log_addrs] = CEC_LOG_ADDR_TYPE_RECORD;
|
||||
laddrs.all_device_types[laddrs.num_log_addrs] = CEC_OP_ALL_DEVTYPE_RECORD;
|
||||
laddrs.primary_device_type[laddrs.num_log_addrs] = CEC_OP_PRIM_DEVTYPE_RECORD;
|
||||
break;
|
||||
case CEC_LOG_ADDR_TUNER_1:
|
||||
laddrs.log_addr_type[laddrs.num_log_addrs] = CEC_LOG_ADDR_TYPE_TUNER;
|
||||
laddrs.all_device_types[laddrs.num_log_addrs] = CEC_OP_ALL_DEVTYPE_TUNER;
|
||||
laddrs.primary_device_type[laddrs.num_log_addrs] = CEC_OP_PRIM_DEVTYPE_TUNER;
|
||||
break;
|
||||
case CEC_LOG_ADDR_PLAYBACK_1:
|
||||
laddrs.log_addr_type[laddrs.num_log_addrs] = CEC_LOG_ADDR_TYPE_PLAYBACK;
|
||||
laddrs.all_device_types[laddrs.num_log_addrs] = CEC_OP_ALL_DEVTYPE_PLAYBACK;
|
||||
laddrs.primary_device_type[laddrs.num_log_addrs] = CEC_OP_PRIM_DEVTYPE_PLAYBACK;
|
||||
break;
|
||||
case CEC_LOG_ADDR_AUDIOSYSTEM:
|
||||
laddrs.log_addr_type[laddrs.num_log_addrs] = CEC_LOG_ADDR_TYPE_AUDIOSYSTEM;
|
||||
laddrs.all_device_types[laddrs.num_log_addrs] = CEC_OP_ALL_DEVTYPE_AUDIOSYSTEM;
|
||||
laddrs.primary_device_type[laddrs.num_log_addrs] = CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM;
|
||||
break;
|
||||
default:
|
||||
laddrs.log_addr_type[laddrs.num_log_addrs] = CEC_LOG_ADDR_TYPE_UNREGISTERED;
|
||||
laddrs.all_device_types[laddrs.num_log_addrs] = CEC_OP_ALL_DEVTYPE_SWITCH;
|
||||
laddrs.primary_device_type[laddrs.num_log_addrs] = CEC_OP_PRIM_DEVTYPE_SWITCH;
|
||||
break;
|
||||
}
|
||||
laddrs.num_log_addrs++;
|
||||
|
||||
if (ioctl(hdmiFd, CEC_ADAP_S_LOG_ADDRS, &laddrs) < 0)
|
||||
lt_info("%s: CEC set log addr failed (%m)\n", __func__);
|
||||
}
|
||||
|
||||
if (ioctl(hdmiFd, CEC_S_MODE, &monitor) < 0)
|
||||
lt_info("%s: CEC monitor failed (%m)\n", __func__);
|
||||
|
||||
GetCECAddressInfo();
|
||||
|
||||
if(autoview_cec_activ)
|
||||
SetCECState(false);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void cVideo::GetCECAddressInfo()
|
||||
{
|
||||
if (hdmiFd >= 0)
|
||||
{
|
||||
struct addressinfo addressinfo;
|
||||
|
||||
__u16 phys_addr;
|
||||
struct cec_log_addrs laddrs = {};
|
||||
|
||||
::ioctl(hdmiFd, CEC_ADAP_G_PHYS_ADDR, &phys_addr);
|
||||
addressinfo.physical[0] = (phys_addr >> 8) & 0xff;
|
||||
addressinfo.physical[1] = phys_addr & 0xff;
|
||||
|
||||
::ioctl(hdmiFd, CEC_ADAP_G_LOG_ADDRS, &laddrs);
|
||||
addressinfo.logical = laddrs.log_addr[0];
|
||||
|
||||
switch (laddrs.log_addr_type[0])
|
||||
{
|
||||
case CEC_LOG_ADDR_TYPE_TV:
|
||||
addressinfo.type = CEC_LOG_ADDR_TV;
|
||||
break;
|
||||
case CEC_LOG_ADDR_TYPE_RECORD:
|
||||
addressinfo.type = CEC_LOG_ADDR_RECORD_1;
|
||||
break;
|
||||
case CEC_LOG_ADDR_TYPE_TUNER:
|
||||
addressinfo.type = CEC_LOG_ADDR_TUNER_1;
|
||||
break;
|
||||
case CEC_LOG_ADDR_TYPE_PLAYBACK:
|
||||
addressinfo.type = CEC_LOG_ADDR_PLAYBACK_1;
|
||||
break;
|
||||
case CEC_LOG_ADDR_TYPE_AUDIOSYSTEM:
|
||||
addressinfo.type = CEC_LOG_ADDR_AUDIOSYSTEM;
|
||||
break;
|
||||
case CEC_LOG_ADDR_TYPE_UNREGISTERED:
|
||||
default:
|
||||
addressinfo.type = CEC_LOG_ADDR_UNREGISTERED;
|
||||
break;
|
||||
}
|
||||
|
||||
deviceType = addressinfo.type;
|
||||
logicalAddress = addressinfo.logical;
|
||||
if (memcmp(physicalAddress, addressinfo.physical, sizeof(physicalAddress)))
|
||||
{
|
||||
lt_info("%s: detected physical address change: %02X%02X --> %02X%02X", __func__, physicalAddress[0], physicalAddress[1], addressinfo.physical[0], addressinfo.physical[1]);
|
||||
memcpy(physicalAddress, addressinfo.physical, sizeof(physicalAddress));
|
||||
ReportPhysicalAddress();
|
||||
// addressChanged((physicalAddress[0] << 8) | physicalAddress[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cVideo::ReportPhysicalAddress()
|
||||
{
|
||||
struct cec_message txmessage;
|
||||
txmessage.address = 0x0f; /* broadcast */
|
||||
txmessage.data[0] = CEC_MSG_REPORT_PHYSICAL_ADDR;
|
||||
txmessage.data[1] = physicalAddress[0];
|
||||
txmessage.data[2] = physicalAddress[1];
|
||||
txmessage.data[3] = deviceType;
|
||||
txmessage.length = 4;
|
||||
SendCECMessage(txmessage);
|
||||
}
|
||||
|
||||
void cVideo::SendCECMessage(struct cec_message &message)
|
||||
{
|
||||
if (hdmiFd >= 0)
|
||||
{
|
||||
lt_info("[CEC] send message");
|
||||
for (int i = 0; i < message.length; i++)
|
||||
{
|
||||
lt_info(" %02X", message.data[i]);
|
||||
}
|
||||
lt_info("\n");
|
||||
struct cec_msg msg;
|
||||
cec_msg_init(&msg, logicalAddress, message.address);
|
||||
memcpy(&msg.msg[1], message.data, message.length);
|
||||
msg.len = message.length + 1;
|
||||
ioctl(hdmiFd, CEC_TRANSMIT, &msg);
|
||||
}
|
||||
return hdmi_cec::getInstance()->SetCECMode(_deviceType);
|
||||
}
|
||||
|
||||
void cVideo::SetCECAutoStandby(bool state)
|
||||
{
|
||||
standby_cec_activ = state;
|
||||
hdmi_cec::getInstance()->SetCECAutoStandby(state);
|
||||
}
|
||||
|
||||
void cVideo::SetCECAutoView(bool state)
|
||||
{
|
||||
autoview_cec_activ = state;
|
||||
}
|
||||
|
||||
void cVideo::SetCECState(bool state)
|
||||
{
|
||||
struct cec_message message;
|
||||
|
||||
if ((standby_cec_activ) && state){
|
||||
message.address = CEC_OP_PRIM_DEVTYPE_TV;
|
||||
message.data[0] = CEC_MSG_STANDBY;
|
||||
message.length = 1;
|
||||
SendCECMessage(message);
|
||||
}
|
||||
|
||||
if ((autoview_cec_activ) && !state){
|
||||
message.address = CEC_OP_PRIM_DEVTYPE_TV;
|
||||
message.data[0] = CEC_MSG_IMAGE_VIEW_ON;
|
||||
message.length = 1;
|
||||
SendCECMessage(message);
|
||||
usleep(10000);
|
||||
message.address = 0x0f; /* broadcast */
|
||||
message.data[0] = CEC_MSG_ACTIVE_SOURCE;
|
||||
//message.data[1] = ((((int)physicalAddress >> 12) & 0xf) << 4) + (((int)physicalAddress >> 8) & 0xf);
|
||||
//message.data[2] = ((((int)physicalAddress >> 4) & 0xf) << 4) + (((int)physicalAddress >> 0) & 0xf);
|
||||
message.data[1] = physicalAddress[0];
|
||||
message.data[2] = physicalAddress[1];
|
||||
message.length = 3;
|
||||
SendCECMessage(message);
|
||||
}
|
||||
|
||||
hdmi_cec::getInstance()->SetCECAutoView(state);
|
||||
}
|
||||
|
@@ -144,20 +144,6 @@ typedef enum
|
||||
VIDEO_CONTROL_MAX = VIDEO_CONTROL_SHARPNESS
|
||||
} VIDEO_CONTROL;
|
||||
|
||||
struct cec_message
|
||||
{
|
||||
unsigned char address;
|
||||
unsigned char length;
|
||||
unsigned char data[256];
|
||||
}__attribute__((packed));
|
||||
#define cec_rx_message cec_message
|
||||
struct addressinfo
|
||||
{
|
||||
unsigned char logical;
|
||||
unsigned char physical[2];
|
||||
unsigned char type;
|
||||
};
|
||||
|
||||
class cDemux;
|
||||
class cPlayback;
|
||||
|
||||
@@ -201,11 +187,6 @@ class cVideo
|
||||
/* used internally by dmx */
|
||||
int64_t GetPTS(void);
|
||||
|
||||
unsigned char physicalAddress[2];
|
||||
bool standby_cec_activ,autoview_cec_activ;
|
||||
unsigned char deviceType, logicalAddress;
|
||||
int hdmiFd;
|
||||
|
||||
public:
|
||||
/* constructor & destructor */
|
||||
cVideo(int mode, void *, void *, unsigned int unit = 0);
|
||||
@@ -250,10 +231,6 @@ class cVideo
|
||||
bool SetCECMode(VIDEO_HDMI_CEC_MODE);
|
||||
void SetCECAutoView(bool);
|
||||
void SetCECAutoStandby(bool);
|
||||
void GetCECAddressInfo();
|
||||
void SendCECMessage(struct cec_message &message);
|
||||
void SetCECState(bool state);
|
||||
void ReportPhysicalAddress();
|
||||
void ShowPicture(const char * fname);
|
||||
void StopPicture();
|
||||
void Standby(unsigned int bOn);
|
||||
|
Reference in New Issue
Block a user