#pragma once
#define SWIG_FILE_WITH_INIT
#define SWIG_PYTHON_THREADS
#define SWIG_PYTHON_USE_GIL
#define LIBCEC_SWIG_EXPORTS
#include "env.h"
#include "cectypes.h"
#include "cec.h"
#include "CECTypeUtils.h"
#include "p8-platform/threads/mutex.h"
#ifndef Py_PYTHON_H
#include <python2.7/Python.h>
#include <assert.h>
#endif
namespace CEC
{
enum libcecSwigCallback {
PYTHON_CB_LOG_MESSAGE,
PYTHON_CB_KEY_PRESS,
PYTHON_CB_COMMAND,
PYTHON_CB_ALERT,
PYTHON_CB_MENU_STATE,
PYTHON_CB_SOURCE_ACTIVATED,
PYTHON_CB_CONFIGURATION,
PYTHON_CB_COMMAND_HANDLER,
NB_PYTHON_CB,
};
class CCecPythonCallbacks
{
public:
CCecPythonCallbacks(libcec_configuration* config) :
m_configuration(config)
{
assert(!!config);
assert(!!m_configuration);
config->callbacks = new ICECCallbacks;
if (!config->callbacks)
throw std::bad_alloc();
for (size_t ptr = 0; ptr < NB_PYTHON_CB; ++ptr)
m_callbacks[ptr] = NULL;
m_configuration->callbacks->logMessage = CBCecLogMessage;
m_configuration->callbacks->keyPress = CBCecKeyPress;
m_configuration->callbacks->commandReceived = CBCecCommand;
m_configuration->callbacks->configurationChanged = CBCecConfigurationChanged;
m_configuration->callbacks->alert = CBCecAlert;
m_configuration->callbacks->menuStateChanged = CBCecMenuStateChanged;
m_configuration->callbacks->sourceActivated = CBCecSourceActivated;
m_configuration->callbacks->commandHandler = CBCecCommandHandler;
}
virtual ~CCecPythonCallbacks(void)
{
for (size_t ptr = 0; ptr < NB_PYTHON_CB; ++ptr)
if (m_callbacks[ptr])
Py_XDECREF(m_callbacks[ptr]);
delete m_configuration->callbacks;
m_configuration->callbacks = nullptr;
}
int CallPythonCallback(enum libcecSwigCallback callback, PyObject* arglist)
{
int retval = 0;
if (callback >= NB_PYTHON_CB || !m_callbacks[callback])
return retval;
PyObject* result = nullptr;
if (!!m_callbacks[callback])
{
#if (PY_MAJOR_VERSION < 3)
result = PyEval_CallObject(m_callbacks[callback], arglist);
#else
result = PyObject_CallObject(m_callbacks[callback], arglist);
#endif
if (!!arglist)
Py_DECREF(arglist);
if (!!result)
{
if (PyInt_Check(result))
retval = (int)PyInt_AsLong(result);
Py_XDECREF(result);
}
}
return retval;
}
void SetCallback(size_t cb, PyObject* pyfunc)
{
assert(cb < NB_PYTHON_CB);
assert(PyCallable_Check(pyfunc));
if (!!m_callbacks[cb])
Py_XDECREF(m_callbacks[cb]);
m_callbacks[cb] = pyfunc;
Py_XINCREF(pyfunc);
}
private:
static inline int CallPythonCallback(void* param, enum libcecSwigCallback callback, PyObject* arglist)
{
CCecPythonCallbacks* pCallbacks = static_cast<CCecPythonCallbacks*>(param);
return !!pCallbacks ?
pCallbacks->CallPythonCallback(callback, arglist) :
0;
}
static void CBCecLogMessage(void* param, const CEC::cec_log_message* message)
{
PyGILState_STATE gstate = PyGILState_Ensure();
PyObject* arglist = Py_BuildValue("(I,I,s)", message->level, (long)message->time, message->message);
CallPythonCallback(param, PYTHON_CB_LOG_MESSAGE, arglist);
PyGILState_Release(gstate);
}
static void CBCecKeyPress(void* param, const CEC::cec_keypress* key)
{
PyGILState_STATE gstate = PyGILState_Ensure();
CallPythonCallback(param, PYTHON_CB_KEY_PRESS,
Py_BuildValue("(I,I)", (long)key->keycode, (long)key->duration));
PyGILState_Release(gstate);
}
static void CBCecCommand(void* param, const CEC::cec_command* command)
{
PyGILState_STATE gstate = PyGILState_Ensure();
CallPythonCallback(param, PYTHON_CB_COMMAND,
Py_BuildValue("(s)", CEC::CCECTypeUtils::ToString(*command).c_str()));
PyGILState_Release(gstate);
}
static int CBCecMenuStateChanged(void* param, const CEC::cec_menu_state state)
{
PyGILState_STATE gstate = PyGILState_Ensure();
int retval = CallPythonCallback(param, PYTHON_CB_MENU_STATE,
Py_BuildValue("(I)", state));
PyGILState_Release(gstate);
return retval;
}
static void CBCecSourceActivated(void* param, const CEC::cec_logical_address logicalAddress, const uint8_t activated)
{
PyGILState_STATE gstate = PyGILState_Ensure();
CallPythonCallback(param, PYTHON_CB_SOURCE_ACTIVATED,
Py_BuildValue("(I,I)", logicalAddress, activated));
PyGILState_Release(gstate);
}
static void CBCecAlert(void* param, const libcec_alert alert, const libcec_parameter cbparam)
{
PyGILState_STATE gstate = PyGILState_Ensure();
CallPythonCallback(param, PYTHON_CB_ALERT,
Py_BuildValue("(I,I)", alert, cbparam));
PyGILState_Release(gstate);
}
static void CBCecConfigurationChanged(void* param, const libcec_configuration* configuration)
{
PyGILState_STATE gstate = PyGILState_Ensure();
CallPythonCallback(param, PYTHON_CB_CONFIGURATION,
Py_BuildValue("(I)", configuration));
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;
};
static CCecPythonCallbacks* _GetCallbacks(CEC::libcec_configuration* self)
{
if (!self->callbackParam)
self->callbackParam = new CCecPythonCallbacks(self);
if (!self->callbackParam)
throw std::bad_alloc();
return static_cast<CCecPythonCallbacks*>(self->callbackParam);
}
}
static void _SetCallback(CEC::libcec_configuration* self, size_t cb, PyObject* pyfunc)
{
assert(!!self);
CEC::CCecPythonCallbacks* pCallbacks = CEC::_GetCallbacks(self);
if (!!pCallbacks)
pCallbacks->SetCallback(cb, pyfunc);
else
throw std::bad_alloc();
}
void _ClearCallbacks(CEC::libcec_configuration* self)
{
assert(!!self);
CEC::CCecPythonCallbacks* pCallbacks = static_cast<CEC::CCecPythonCallbacks*>(self->callbackParam);
if (!!pCallbacks)
delete pCallbacks;
self->callbackParam = NULL;
}