Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add commandHandler callback. #617

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions include/cectypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1450,6 +1450,15 @@ typedef struct ICECCallbacks
*/
void (CEC_CDECL* sourceActivated)(void* cbParam, const cec_logical_address logicalAddress, const uint8_t bActivated);

/*!
* @brief Allow the client handle a CEC command instead of libcec.
* @param cbparam Callback parameter provided when the callbacks were set up
* @param command The command to handle.
*
* @return 1 if the command has been handled and if libCEC should not take any action
*/
int (CEC_CDECL* commandHandler)(void* cbparam, const cec_command* command);

#ifdef __cplusplus
ICECCallbacks(void) { Clear(); }
~ICECCallbacks(void) { Clear(); };
Expand All @@ -1463,6 +1472,7 @@ typedef struct ICECCallbacks
alert = nullptr;
menuStateChanged = nullptr;
sourceActivated = nullptr;
commandHandler = nullptr;
}
#endif
} ICECCallbacks;
Expand Down
5 changes: 5 additions & 0 deletions src/cec-client/cec-client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,10 @@ void CecCommand(void *UNUSED(cbParam), const cec_command* UNUSED(command))
{
}

int CecCommandHandler(void *UNUSED(cbParam), const cec_command* UNUSED(command))
{
return 0;
}
void CecAlert(void *UNUSED(cbParam), const libcec_alert type, const libcec_parameter UNUSED(param))
{
switch (type)
Expand Down Expand Up @@ -1275,6 +1279,7 @@ int main (int argc, char *argv[])
g_callbacks.keyPress = &CecKeyPress;
g_callbacks.commandReceived = &CecCommand;
g_callbacks.alert = &CecAlert;
g_callbacks.commandHandler = &CecCommandHandler;
g_config.callbacks = &g_callbacks;

if (!ProcessCommandLineArguments(argc, argv))
Expand Down
3 changes: 2 additions & 1 deletion src/cecc-client/cecc-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ static ICECCallbacks g_callbacks = {
.configurationChanged = NULL,
.alert = NULL,
.menuStateChanged = NULL,
.sourceActivated = NULL
.sourceActivated = NULL,
.commandHandler = NULL
};

static libcec_configuration g_config;
Expand Down
17 changes: 16 additions & 1 deletion src/dotnetlib/CecSharpTypesUnmanaged.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,22 @@ namespace CecSharp
}

/// <summary>
/// Assign the callback methods in the g_cecCallbacks struct and return a pointer to it
/// Called by libCEC to have the client handle the command and prevent further process by libCEC
/// </summary>
/// <param name="cbParam">Pointer to the callback struct</param>
/// <param name="command">The raw CEC data</param>
/// <return>1 when handled by the client, 0 otherwise</return>
static int CecCommandHandlerCB(void* cbParam, const CEC::cec_command* command)
{
struct UnmanagedCecCallbacks* cb = static_cast<struct UnmanagedCecCallbacks*>(cbParam);
if (!!cb && !!cb->commandHandlerCB)
return cb->commandHandlerCB(command);
return 0;
}

/// <summary>
/// Assign the callback methods in the g_cecCallbacks struct and return a pointer to it
/// </summary>
static CEC::ICECCallbacks* GetLibCecCallbacks()
{
g_cecCallbacks.logMessage = CecLogMessageCB;
Expand All @@ -198,6 +212,7 @@ namespace CecSharp
g_cecCallbacks.alert = CecAlertCB;
g_cecCallbacks.menuStateChanged = CecMenuCB;
g_cecCallbacks.sourceActivated = CecSourceActivatedCB;
g_cecCallbacks.commandHandler = CecCommandHandlerCB;
return &g_cecCallbacks;
}
#pragma managed
Expand Down
37 changes: 33 additions & 4 deletions src/libcec/CECClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1604,11 +1604,12 @@ void CCECClient::QueueConfigurationChanged(const libcec_configuration& config)

int CCECClient::QueueMenuStateChanged(const cec_menu_state newState)
{
CCallbackWrap *wrapState = new CCallbackWrap(newState, true);
CCallbackWrap *wrapState = new CCallbackWrap(newState);
m_callbackCalls.Push(wrapState);
int result(wrapState->Result(1000));

delete wrapState;
if (wrapState->m_keepResult)
delete wrapState;
return result;
}

Expand All @@ -1617,13 +1618,25 @@ void CCECClient::QueueSourceActivated(bool bActivated, const cec_logical_address
m_callbackCalls.Push(new CCallbackWrap(bActivated, logicalAddress));
}

int CCECClient::QueueCommandHandler(const cec_command& command)
{
CCallbackWrap *wrapState = new CCallbackWrap(command, true);
m_callbackCalls.Push(wrapState);
int result(wrapState->Result(1000));

if (wrapState->m_keepResult)
delete wrapState;
return result;
}

void* CCECClient::Process(void)
{
CCallbackWrap* cb(NULL);
while (!IsStopped())
{
if (m_callbackCalls.Pop(cb, 500))
{
bool keepResult = cb->m_keepResult;
try
{
switch (cb->m_type)
Expand All @@ -1644,16 +1657,21 @@ void* CCECClient::Process(void)
CallbackConfigurationChanged(cb->m_config);
break;
case CCallbackWrap::CEC_CB_MENU_STATE:
cb->Report(CallbackMenuStateChanged(cb->m_menuState));
keepResult = cb->Report(CallbackMenuStateChanged(cb->m_menuState));
break;
case CCallbackWrap::CEC_CB_SOURCE_ACTIVATED:
CallbackSourceActivated(cb->m_bActivated, cb->m_logicalAddress);
break;
case CCallbackWrap::CEC_CB_COMMAND_HANDLER:
keepResult = cb->Report(CallbackCommandHandler(cb->m_command));
if (!keepResult)
LIB_CEC->AddLog(CEC_LOG_WARNING, "Command callback timeout occured !");
break;
default:
break;
}

if (!cb->m_keepResult)
if (!keepResult)
delete cb;
} catch (...)
{
Expand Down Expand Up @@ -1733,6 +1751,17 @@ int CCECClient::CallbackMenuStateChanged(const cec_menu_state newState)
return 0;
}

int CCECClient::CallbackCommandHandler(const cec_command &command)
{
CLockObject lock(m_cbMutex);
if (!!m_configuration.callbacks &&
!!m_configuration.callbacks->commandHandler)
{
return m_configuration.callbacks->commandHandler(m_configuration.callbackParam, &command);
}
return 0;
}

bool CCECClient::AudioEnable(bool enable)
{
CCECBusDevice* device = enable ? GetPrimaryDevice() : nullptr;
Expand Down
23 changes: 20 additions & 3 deletions src/libcec/CECClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,13 @@ namespace CEC
m_result(0),
m_bSucceeded(false) {}

CCallbackWrap(const cec_menu_state newState, const bool keepResult = false) :
CCallbackWrap(const cec_menu_state newState) :
m_type(CEC_CB_MENU_STATE),
m_alertType(CEC_ALERT_SERVICE_DEVICE),
m_menuState(newState),
m_bActivated(false),
m_logicalAddress(CECDEVICE_UNKNOWN),
m_keepResult(keepResult),
m_keepResult(true),
m_result(0),
m_bSucceeded(false) {}

Expand All @@ -127,23 +127,36 @@ namespace CEC
m_result(0),
m_bSucceeded(false) {}

CCallbackWrap(const cec_command& command, const bool unused) :
m_type(CEC_CB_COMMAND_HANDLER),
m_command(command),
m_alertType(CEC_ALERT_SERVICE_DEVICE),
m_menuState(CEC_MENU_STATE_ACTIVATED),
m_bActivated(false),
m_logicalAddress(CECDEVICE_UNKNOWN),
m_keepResult(true),
m_result(0),
m_bSucceeded(false) {}

int Result(uint32_t iTimeout)
{
P8PLATFORM::CLockObject lock(m_mutex);

bool bReturn = m_bSucceeded ? true : m_condition.Wait(m_mutex, m_bSucceeded, iTimeout);
if (bReturn)
return m_result;
m_keepResult = false;
return 0;
}

void Report(int result)
bool Report(int result)
{
P8PLATFORM::CLockObject lock(m_mutex);

m_result = result;
m_bSucceeded = true;
m_condition.Signal();
return m_keepResult;
}

enum callbackWrapType {
Expand All @@ -154,6 +167,7 @@ namespace CEC
CEC_CB_CONFIGURATION,
CEC_CB_MENU_STATE,
CEC_CB_SOURCE_ACTIVATED,
CEC_CB_COMMAND_HANDLER,
} m_type;

cec_command m_command;
Expand Down Expand Up @@ -314,6 +328,7 @@ namespace CEC
void QueueConfigurationChanged(const libcec_configuration& config);
int QueueMenuStateChanged(const cec_menu_state newState); //TODO
void QueueSourceActivated(bool bActivated, const cec_logical_address logicalAddress);
int QueueCommandHandler(const cec_command& command);

// callbacks
virtual void Alert(const libcec_alert type, const libcec_parameter &param) { QueueAlert(type, param); }
Expand Down Expand Up @@ -436,13 +451,15 @@ namespace CEC
virtual void SetSupportedDeviceTypes(void);

void AddCommand(const cec_command &command);
void AddCommandHandler(const cec_command &command);
void CallbackAddCommand(const cec_command& command);
void CallbackAddKey(const cec_keypress& key);
void CallbackAddLog(const cec_log_message_cpp& message);
void CallbackAlert(const libcec_alert type, const libcec_parameter& param);
void CallbackConfigurationChanged(const libcec_configuration& config);
int CallbackMenuStateChanged(const cec_menu_state newState);
void CallbackSourceActivated(bool bActivated, const cec_logical_address logicalAddress);
int CallbackCommandHandler(const cec_command &command);

uint32_t DoubleTapTimeoutMS(void);

Expand Down
12 changes: 9 additions & 3 deletions src/libcec/LibCEC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -408,23 +408,29 @@ void CLibCEC::AddLog(const cec_log_level level, const char *strFormat, ...)
va_end(argList);

// send the message to all clients
CLockObject lock(m_mutex);
for (std::vector<CECClientPtr>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
(*it)->AddLog(message);
}

void CLibCEC::AddCommand(const cec_command &command)
{
// send the command to all clients
CLockObject lock(m_mutex);
for (std::vector<CECClientPtr>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
(*it)->QueueAddCommand(command);
}

bool CLibCEC::CommandHandlerCB(const cec_command &command)
{
// send the command to all clients
for (std::vector<CECClientPtr>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
if ((*it)->QueueCommandHandler(command))
return true;
return false;
}

void CLibCEC::Alert(const libcec_alert type, const libcec_parameter &param)
{
// send the alert to all clients
CLockObject lock(m_mutex);
for (std::vector<CECClientPtr>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
(*it)->Alert(type, param);
}
Expand Down
2 changes: 1 addition & 1 deletion src/libcec/LibCEC.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ namespace CEC

void AddLog(const cec_log_level level, const char *strFormat, ...);
void AddCommand(const cec_command &command);
bool CommandHandlerCB(const cec_command &command);
uint16_t CheckKeypressTimeout(void);
void Alert(const libcec_alert type, const libcec_parameter &param);

Expand All @@ -169,7 +170,6 @@ namespace CEC

protected:
int64_t m_iStartTime;
P8PLATFORM::CMutex m_mutex;
CECClientPtr m_client;
std::vector<CECClientPtr> m_clients;
};
Expand Down
10 changes: 10 additions & 0 deletions src/libcec/SwigHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ namespace CEC
PYTHON_CB_MENU_STATE,
PYTHON_CB_SOURCE_ACTIVATED,
PYTHON_CB_CONFIGURATION,
PYTHON_CB_COMMAND_HANDLER,
NB_PYTHON_CB,
};

Expand Down Expand Up @@ -88,6 +89,7 @@ namespace CEC
m_configuration->callbacks->alert = CBCecAlert;
m_configuration->callbacks->menuStateChanged = CBCecMenuStateChanged;
m_configuration->callbacks->sourceActivated = CBCecSourceActivated;
m_configuration->callbacks->commandHandler = CBCecCommandHandler;
}

/**
Expand Down Expand Up @@ -220,6 +222,14 @@ namespace CEC
PyGILState_Release(gstate);
}

static int CBCecCommandHandler(void* param, const CEC::cec_command* command)
{
PyGILState_STATE gstate = PyGILState_Ensure();
int retval = CallPythonCallback(param, PYTHON_CB_COMMAND_HANDLER,
Py_BuildValue("(s)", CEC::CCECTypeUtils::ToString(*command).c_str()));
PyGILState_Release(gstate);
return retval;
}
PyObject* m_callbacks[NB_PYTHON_CB];
libcec_configuration* m_configuration;
};
Expand Down
3 changes: 3 additions & 0 deletions src/libcec/implementations/CECCommandHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command)

LIB_CEC->AddCommand(command);

if (LIB_CEC->CommandHandlerCB(command))
return true;

switch(command.opcode)
{
case CEC_OPCODE_REPORT_POWER_STATUS:
Expand Down
5 changes: 5 additions & 0 deletions src/libcec/libcec.i
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@
_SetCallback(self, CEC::PYTHON_CB_CONFIGURATION, pyfunc);
}

void SetCommandHandlerCallback(PyObject* pyfunc)
{
_SetCallback(self, CEC::PYTHON_CB_COMMAND_HANDLER, pyfunc);
}

void ClearCallbacks(void)
{
_ClearCallbacks(self);
Expand Down