* http://www.pulse-eight.net/
*/
+#include "env.h"
#include "CECBusDevice.h"
-#include "../CECProcessor.h"
-#include "../implementations/ANCommandHandler.h"
-#include "../implementations/CECCommandHandler.h"
-#include "../implementations/SLCommandHandler.h"
-#include "../implementations/VLCommandHandler.h"
-#include "../LibCEC.h"
-#include "../platform/util/timeutils.h"
+
+#include "lib/CECProcessor.h"
+#include "lib/CECClient.h"
+#include "lib/implementations/ANCommandHandler.h"
+#include "lib/implementations/CECCommandHandler.h"
+#include "lib/implementations/SLCommandHandler.h"
+#include "lib/implementations/VLCommandHandler.h"
+#include "lib/LibCEC.h"
+#include "lib/CECTypeUtils.h"
+#include "lib/platform/util/timeutils.h"
+#include "lib/platform/util/util.h"
#include "CECAudioSystem.h"
#include "CECPlaybackDevice.h"
using namespace PLATFORM;
#define LIB_CEC m_processor->GetLib()
-#define ToString(p) LIB_CEC->ToString(p)
+#define ToString(p) CCECTypeUtils::ToString(p)
CCECBusDevice::CCECBusDevice(CCECProcessor *processor, cec_logical_address iLogicalAddress, uint16_t iPhysicalAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */) :
m_type (CEC_DEVICE_TYPE_RESERVED),
m_deviceStatus (CEC_DEVICE_STATUS_UNKNOWN),
m_iHandlerUseCount (0),
m_bAwaitingReceiveFailed(false),
- m_bVendorIdRequested (false)
+ m_bVendorIdRequested (false),
+ m_waitForResponse (new CWaitForResponse)
{
m_handler = new CCECCommandHandler(this);
CCECBusDevice::~CCECBusDevice(void)
{
- delete m_handler;
+ DELETE_AND_NULL(m_handler);
+ DELETE_AND_NULL(m_waitForResponse);
}
bool CCECBusDevice::ReplaceHandler(bool bActivateSource /* = true */)
{
+ if (m_iLogicalAddress == CECDEVICE_BROADCAST)
+ return false;
+
bool bInitHandler(false);
{
- CTryLockObject lock(m_mutex);
- if (!lock.IsLocked())
- return false;
-
+ CLockObject lock(m_mutex);
CLockObject handlerLock(m_handlerMutex);
if (m_iHandlerUseCount > 0)
return false;
if (CCECCommandHandler::HasSpecificHandler(m_vendor))
{
LIB_CEC->AddLog(CEC_LOG_DEBUG, "replacing the command handler for device '%s' (%x)", GetLogicalAddressName(), GetLogicalAddress());
- delete m_handler;
+
+ int32_t iTransmitTimeout = m_handler->m_iTransmitTimeout;
+ int32_t iTransmitWait = m_handler->m_iTransmitWait;
+ int8_t iTransmitRetries = m_handler->m_iTransmitRetries;
+ int64_t iActiveSourcePending = m_handler->m_iActiveSourcePending;
+
+ DELETE_AND_NULL(m_handler);
switch (m_vendor)
{
case CEC_VENDOR_SAMSUNG:
- m_handler = new CANCommandHandler(this);
+ m_handler = new CANCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
break;
case CEC_VENDOR_LG:
- m_handler = new CSLCommandHandler(this);
+ m_handler = new CSLCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
break;
case CEC_VENDOR_PANASONIC:
- m_handler = new CVLCommandHandler(this);
+ m_handler = new CVLCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
break;
default:
- m_handler = new CCECCommandHandler(this);
+ m_handler = new CCECCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
break;
}
if (bInitHandler)
{
- m_handler->InitHandler();
+ CCECBusDevice *primary = GetProcessor()->GetPrimaryDevice();
+ if (primary->GetLogicalAddress() != CECDEVICE_UNREGISTERED)
+ {
+ m_handler->InitHandler();
- if (bActivateSource && IsHandledByLibCEC() && IsActiveSource())
- m_handler->ActivateSource();
+ if (bActivateSource && IsHandledByLibCEC() && IsActiveSource())
+ m_handler->ActivateSource();
+ }
}
MarkReady();
return true;
}
+CCECCommandHandler *CCECBusDevice::GetHandler(void)
+{
+ ReplaceHandler(false);
+ MarkBusy();
+ return m_handler;
+}
+
bool CCECBusDevice::HandleCommand(const cec_command &command)
{
bool bHandled(false);
// signal threads that are waiting for a reponse
MarkBusy();
- m_handler->SignalOpcode(cec_command::GetResponseOpcode(opcode));
+ SignalOpcode(cec_command::GetResponseOpcode(opcode));
MarkReady();
}
return bReturn;
}
-bool CCECBusDevice::TransmitCECVersion(const cec_logical_address destination)
+bool CCECBusDevice::TransmitCECVersion(const cec_logical_address destination, bool bIsReply)
{
cec_version version;
{
}
MarkBusy();
- bool bReturn = m_handler->TransmitCECVersion(m_iLogicalAddress, destination, version);
+ bool bReturn = m_handler->TransmitCECVersion(m_iLogicalAddress, destination, version, bIsReply);
MarkReady();
return bReturn;
}
return bReturn;
}
-bool CCECBusDevice::TransmitSetMenuLanguage(const cec_logical_address destination)
+bool CCECBusDevice::TransmitSetMenuLanguage(const cec_logical_address destination, bool bIsReply)
{
bool bReturn(false);
cec_menu_language language;
else
{
LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): Menu language '%s'", GetLogicalAddressName(), m_iLogicalAddress, lang);
- bReturn = m_handler->TransmitSetMenuLanguage(m_iLogicalAddress, lang);
+ bReturn = m_handler->TransmitSetMenuLanguage(m_iLogicalAddress, lang, bIsReply);
}
MarkReady();
return bReturn;
}
-bool CCECBusDevice::TransmitOSDString(const cec_logical_address destination, cec_display_control duration, const char *strMessage)
+bool CCECBusDevice::TransmitOSDString(const cec_logical_address destination, cec_display_control duration, const char *strMessage, bool bIsReply)
{
bool bReturn(false);
if (!m_processor->GetDevice(destination)->IsUnsupportedFeature(CEC_OPCODE_SET_OSD_STRING))
{
LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): display OSD message '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, strMessage);
MarkBusy();
- bReturn = m_handler->TransmitOSDString(m_iLogicalAddress, destination, duration, strMessage);
+ bReturn = m_handler->TransmitOSDString(m_iLogicalAddress, destination, duration, strMessage, bIsReply);
MarkReady();
}
return bReturn;
return bReturn;
}
-bool CCECBusDevice::TransmitOSDName(const cec_logical_address destination)
+bool CCECBusDevice::TransmitOSDName(const cec_logical_address destination, bool bIsReply)
{
CStdString strDeviceName;
{
}
MarkBusy();
- bool bReturn = m_handler->TransmitOSDName(m_iLogicalAddress, destination, strDeviceName);
+ bool bReturn = m_handler->TransmitOSDName(m_iLogicalAddress, destination, strDeviceName, bIsReply);
MarkReady();
return bReturn;
}
return bReturn;
}
-bool CCECBusDevice::TransmitPhysicalAddress(void)
+bool CCECBusDevice::TransmitPhysicalAddress(bool bIsReply)
{
uint16_t iPhysicalAddress;
cec_device_type type;
}
MarkBusy();
- bool bReturn = m_handler->TransmitPhysicalAddress(m_iLogicalAddress, iPhysicalAddress, type);
+ bool bReturn = m_handler->TransmitPhysicalAddress(m_iLogicalAddress, iPhysicalAddress, type, bIsReply);
MarkReady();
return bReturn;
}
return bReturn;
}
-bool CCECBusDevice::TransmitPowerState(const cec_logical_address destination)
+bool CCECBusDevice::TransmitPowerState(const cec_logical_address destination, bool bIsReply)
{
cec_power_status state;
{
}
MarkBusy();
- bool bReturn = m_handler->TransmitPowerState(m_iLogicalAddress, destination, state);
+ bool bReturn = m_handler->TransmitPowerState(m_iLogicalAddress, destination, state, bIsReply);
MarkReady();
return bReturn;
}
return bReturn;
}
-bool CCECBusDevice::TransmitVendorID(const cec_logical_address destination, bool bSendAbort /* = true */)
+bool CCECBusDevice::TransmitVendorID(const cec_logical_address destination, bool bSendAbort, bool bIsReply)
{
bool bReturn(false);
uint64_t iVendorId;
else
{
LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): vendor id %s (%x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, ToString((cec_vendor_id)iVendorId), iVendorId);
- bReturn = m_handler->TransmitVendorID(m_iLogicalAddress, iVendorId);
+ bReturn = m_handler->TransmitVendorID(m_iLogicalAddress, iVendorId, bIsReply);
}
MarkReady();
return bReturn;
return status;
}
-void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus)
+void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus, cec_version libCECSpecVersion /* = CEC_VERSION_1_4 */)
{
{
CLockObject lock(m_mutex);
switch (newStatus)
{
- case CEC_DEVICE_STATUS_UNKNOWN:
- if (m_deviceStatus != newStatus)
- LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'unknown'", ToString(m_iLogicalAddress));
- ResetDeviceStatus();
- m_deviceStatus = newStatus;
- break;
case CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC:
if (m_deviceStatus != newStatus)
- LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'handled by libCEC'", ToString(m_iLogicalAddress));
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'handled by libCEC'", GetLogicalAddressName(), m_iLogicalAddress);
SetPowerStatus (CEC_POWER_STATUS_ON);
SetVendorId (CEC_VENDOR_UNKNOWN);
SetMenuState (CEC_MENU_STATE_ACTIVATED);
- SetCecVersion (CEC_VERSION_1_3A);
+ SetCecVersion (libCECSpecVersion);
SetStreamPath (CEC_INVALID_PHYSICAL_ADDRESS);
MarkAsInactiveSource();
m_iLastActive = 0;
break;
case CEC_DEVICE_STATUS_PRESENT:
if (m_deviceStatus != newStatus)
- LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'present'", ToString(m_iLogicalAddress));
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'present'", GetLogicalAddressName(), m_iLogicalAddress);
m_deviceStatus = newStatus;
break;
case CEC_DEVICE_STATUS_NOT_PRESENT:
if (m_deviceStatus != newStatus)
{
- LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'not present'", ToString(m_iLogicalAddress));
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'not present'", GetLogicalAddressName(), m_iLogicalAddress);
ResetDeviceStatus();
m_deviceStatus = newStatus;
}
break;
+ default:
+ ResetDeviceStatus();
+ break;
}
}
}
SetStreamPath (CEC_INVALID_PHYSICAL_ADDRESS);
SetOSDName (ToString(m_iLogicalAddress));
MarkAsInactiveSource();
+
m_iLastActive = 0;
m_bVendorIdRequested = false;
m_unsupportedFeatures.clear();
+ m_waitForResponse->Clear();
+
+ if (m_deviceStatus != CEC_DEVICE_STATUS_UNKNOWN)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'unknown'", GetLogicalAddressName(), m_iLogicalAddress);
+ m_deviceStatus = CEC_DEVICE_STATUS_UNKNOWN;
}
-bool CCECBusDevice::TransmitPoll(const cec_logical_address dest)
+bool CCECBusDevice::TransmitPoll(const cec_logical_address dest, bool bIsReply)
{
bool bReturn(false);
cec_logical_address destination(dest);
MarkBusy();
LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): POLL", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest);
- bReturn = m_handler->TransmitPoll(m_iLogicalAddress, destination);
+ bReturn = m_handler->TransmitPoll(m_iLogicalAddress, destination, bIsReply);
LIB_CEC->AddLog(CEC_LOG_DEBUG, bReturn ? ">> POLL sent" : ">> POLL not sent");
CLockObject lock(m_mutex);
}
}
-bool CCECBusDevice::TransmitMenuState(const cec_logical_address dest)
+bool CCECBusDevice::TransmitMenuState(const cec_logical_address dest, bool bIsReply)
{
cec_menu_state menuState;
{
}
MarkBusy();
- bool bReturn = m_handler->TransmitMenuState(m_iLogicalAddress, dest, menuState);
+ bool bReturn = m_handler->TransmitMenuState(m_iLogicalAddress, dest, menuState, bIsReply);
MarkReady();
return bReturn;
}
-bool CCECBusDevice::ActivateSource(void)
+bool CCECBusDevice::ActivateSource(uint64_t iDelay /* = 0 */)
{
MarkAsActiveSource();
- LIB_CEC->AddLog(CEC_LOG_DEBUG, "activating source '%s'", ToString(m_iLogicalAddress));
MarkBusy();
- bool bReturn = m_handler->ActivateSource();
+ bool bReturn(true);
+ if (iDelay == 0)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending active source message for '%s'", ToString(m_iLogicalAddress));
+ bReturn = m_handler->ActivateSource();
+ }
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "scheduling active source message for '%s'", ToString(m_iLogicalAddress));
+ m_handler->ScheduleActivateSource(iDelay);
+ }
MarkReady();
return bReturn;
}
void CCECBusDevice::MarkAsActiveSource(void)
{
- CLockObject lock(m_mutex);
- if (!m_bActiveSource)
- LIB_CEC->AddLog(CEC_LOG_DEBUG, "making %s (%x) the active source", GetLogicalAddressName(), m_iLogicalAddress);
- else
- LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%x) was already marked as active source", GetLogicalAddressName(), m_iLogicalAddress);
+ bool bWasActivated(false);
+
+ // set the power status to powered on
+ SetPowerStatus(CEC_POWER_STATUS_ON);
+
+ // mark this device as active source
+ {
+ CLockObject lock(m_mutex);
+ if (!m_bActiveSource)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "making %s (%x) the active source", GetLogicalAddressName(), m_iLogicalAddress);
+ bWasActivated = true;
+ }
+ else
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%x) was already marked as active source", GetLogicalAddressName(), m_iLogicalAddress);
+
+ m_bActiveSource = true;
+ }
+ // mark other devices as inactive sources
CECDEVICEVEC devices;
m_processor->GetDevices()->Get(devices);
for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
if ((*it)->GetLogicalAddress() != m_iLogicalAddress)
(*it)->MarkAsInactiveSource();
- m_bActiveSource = true;
- SetPowerStatus(CEC_POWER_STATUS_ON);
+ if (bWasActivated)
+ {
+ CCECClient *client = GetClient();
+ if (client)
+ client->SourceActivated(m_iLogicalAddress);
+ }
}
void CCECBusDevice::MarkAsInactiveSource(void)
{
+ bool bWasDeactivated(false);
{
CLockObject lock(m_mutex);
if (m_bActiveSource)
+ {
LIB_CEC->AddLog(CEC_LOG_DEBUG, "marking %s (%X) as inactive source", GetLogicalAddressName(), m_iLogicalAddress);
+ bWasDeactivated = true;
+ }
m_bActiveSource = false;
}
+
+ if (bWasDeactivated)
+ {
+ CCECClient *client = GetClient();
+ if (client)
+ client->SourceDeactivated(m_iLogicalAddress);
+ }
}
-bool CCECBusDevice::TransmitActiveSource(void)
+bool CCECBusDevice::TransmitActiveSource(bool bIsReply)
{
bool bSendActiveSource(false);
+ uint16_t iPhysicalAddress(CEC_INVALID_PHYSICAL_ADDRESS);
{
CLockObject lock(m_mutex);
+ if (!HasValidPhysicalAddress())
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X) has an invalid physical address (%04x), not sending active source commands", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
+ return false;
+ }
+
+ iPhysicalAddress = m_iPhysicalAddress;
+
if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
else if (m_bActiveSource)
LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not the active source", GetLogicalAddressName(), m_iLogicalAddress);
}
+ bool bActiveSourceSent(false);
if (bSendActiveSource)
{
MarkBusy();
- m_handler->TransmitActiveSource(m_iLogicalAddress, m_iPhysicalAddress);
+ bActiveSourceSent = m_handler->TransmitActiveSource(m_iLogicalAddress, iPhysicalAddress, bIsReply);
MarkReady();
- return true;
}
- return false;
+ return bActiveSourceSent;
}
bool CCECBusDevice::TransmitImageViewOn(void)
}
}
+ bool bImageViewOnSent(false);
MarkBusy();
- m_handler->TransmitImageViewOn(m_iLogicalAddress, CECDEVICE_TV);
+ bImageViewOnSent = m_handler->TransmitImageViewOn(m_iLogicalAddress, CECDEVICE_TV);
MarkReady();
- return true;
+ return bImageViewOnSent;
}
bool CCECBusDevice::TransmitInactiveSource(void)
bool CCECBusDevice::TransmitPendingActiveSourceCommands(void)
{
MarkBusy();
- bool bReturn = m_handler->TransmitPendingActiveSourceCommands();
+ bool bReturn = m_handler->ActivateSource(true);
MarkReady();
return bReturn;
}
{
// if a device is found with the new physical address, mark it as active, which will automatically mark all other devices as inactive
device->MarkAsActiveSource();
+
+ // respond with an active source message if this device is handled by libCEC
+ if (device->IsHandledByLibCEC())
+ device->TransmitActiveSource(true);
}
else
{
--m_iHandlerUseCount;
}
-bool CCECBusDevice::TryLogicalAddress(void)
+bool CCECBusDevice::TryLogicalAddress(cec_version libCECSpecVersion /* = CEC_VERSION_1_4 */)
{
LIB_CEC->AddLog(CEC_LOG_DEBUG, "trying logical address '%s'", GetLogicalAddressName());
- if (!TransmitPoll(m_iLogicalAddress))
+ if (!TransmitPoll(m_iLogicalAddress, false))
{
LIB_CEC->AddLog(CEC_LOG_NOTICE, "using logical address '%s'", GetLogicalAddressName());
- SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
+ SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC, libCECSpecVersion);
return true;
}
{
return m_processor->GetClient(m_iLogicalAddress);
}
+
+void CCECBusDevice::SignalOpcode(cec_opcode opcode)
+{
+ m_waitForResponse->Received(opcode);
+}
+
+bool CCECBusDevice::WaitForOpcode(cec_opcode opcode)
+{
+ return m_waitForResponse->Wait(opcode);
+}