1 /* cec.cpp
2 *
3 * Copyright (C) 2013 Austin Hendrix <namniart@gmail.com>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /*
20 * This file provides the python cec module, which is a python wrapper
21 * around libcec
22 *
23 * Author: Austin Hendrix <namniart@gmail.com>
24 */
25
26 // request the std format macros
27 #define __STDC_FORMAT_MACROS
28
29 #include <Python.h>
30 #include <stdlib.h>
31 #include <inttypes.h>
32 #include <libcec/cec.h>
33 #include <algorithm>
34 #include <list>
35
36 #include "device.h"
37
38
39 using namespace CEC;
40
41 // Basic design/usage:
42 //
43 // ( cec.add_callback(event, handler) )
44 // ???
45 //
46 // ( cec.remove_callback(event, handler) )
47 // ???
48 //
49 // ( cec.transmit( ??? ) )
50 // call ICECAdapter::Transmit()
51 //
52 // Events:
53 // - log message
54 // message.message[1024]
55 // message.level (bitfield)
56 // message.time (int64)
57 // - key press
58 // key.keycode (int/enum)
59 // key.duration (int)
60 // - command
61 // command.initiator (logical address)
62 // command.destination (logical address)
63 // command.ack
64 // command.eom
65 // command.opcode (enum)
66 // command.parameters
67 // command.opcode_set (flag for when opcode is set; should probably use
68 // this to set opcode to None)
69 // command.transmit_timeout
70 // - cec configuration changed (adapter/library config change)
71 // - alert
72 // - menu state changed
73 // this is potentially thorny; see libcec source and CEC spec
74 // ???
75 // - source activated
76 //
77
78 #define EVENT_LOG 0x0001
79 #define EVENT_KEYPRESS 0x0002
80 #define EVENT_COMMAND 0x0004
81 #define EVENT_CONFIG_CHANGE 0x0008
82 #define EVENT_ALERT 0x0010
83 #define EVENT_MENU_CHANGED 0x0020
84 #define EVENT_ACTIVATED 0x0040
85 #define EVENT_VALID 0x007F
86 #define EVENT_ALL 0x007F
87
88 //#define DEBUG 1
89
90 #ifdef DEBUG
91 # define debug(...) printf("CEC DEBUG: " __VA_ARGS__)
92 #else
93 # define debug(...)
94 #endif
95
96 // cec_adapter_descriptor and DetectAdapters were introduced in 2.1.0
97 #if CEC_LIB_VERSION_MAJOR >= 3 || (CEC_LIB_VERSION_MAJOR >= 2 && CEC_LIB_VERSION_MINOR >= 1)
98 #define CEC_ADAPTER_TYPE cec_adapter_descriptor
99 #define CEC_FIND_ADAPTERS DetectAdapters
100 #define HAVE_CEC_ADAPTER_DESCRIPTOR 1
101 #else
102 #define CEC_ADAPTER_TYPE cec_adapter
103 #define CEC_FIND_ADAPTERS FindAdapters
104 #define HAVE_CEC_ADAPTER_DESCRIPTOR 0
105 #endif
106
parse_physical_addr(const char * addr)107 int parse_physical_addr(const char * addr) {
108 int a, b, c, d;
109 if( sscanf(addr, "%x.%x.%x.%x", &a, &b, &c, &d) == 4 ) {
110 if( a > 0xF || b > 0xF || c > 0xF || d > 0xF ) return -1;
111 if( a < 0 || b < 0 || c < 0 || d < 0 ) return -1;
112 return (a << 12) | (b << 8) | (c << 4) | d;
113 } else {
114 return -1;
115 }
116 }
117
118 #define RETURN_BOOL(arg) do { \
119 bool result; \
120 Py_BEGIN_ALLOW_THREADS \
121 result = (arg); \
122 Py_END_ALLOW_THREADS \
123 PyObject * ret = (result)?Py_True:Py_False; \
124 Py_INCREF(ret); \
125 return ret; \
126 } while(0)
127
parse_test()128 void parse_test() {
129 assert(parse_physical_addr("0.0.0.0") == 0);
130 assert(parse_physical_addr("F.0.0.0") == 0xF000);
131 assert(parse_physical_addr("0.F.0.0") == 0x0F00);
132 assert(parse_physical_addr("0.0.F.0") == 0x00F0);
133 assert(parse_physical_addr("0.0.0.F") == 0x000F);
134 assert(parse_physical_addr("-1.0.0.0") == -1);
135 assert(parse_physical_addr("0.-1.0.0") == -1);
136 assert(parse_physical_addr("0.0.-1.0") == -1);
137 assert(parse_physical_addr("0.0.0.-1") == -1);
138 assert(parse_physical_addr("foo") == -1);
139 assert(parse_physical_addr("F.F.F.F") == 0xFFFF);
140 assert(parse_physical_addr("f.f.f.f") == 0xFFFF);
141 }
142
143 ICECAdapter * CEC_adapter;
144 PyObject * Device;
145
get_adapters()146 std::list<CEC_ADAPTER_TYPE> get_adapters() {
147 std::list<CEC_ADAPTER_TYPE> res;
148 // release the Global Interpreter lock
149 Py_BEGIN_ALLOW_THREADS
150 // get adapters
151 int cec_count = 10;
152 CEC_ADAPTER_TYPE * dev_list = (CEC_ADAPTER_TYPE*)malloc(
153 cec_count * sizeof(CEC_ADAPTER_TYPE));
154 int count = CEC_adapter->CEC_FIND_ADAPTERS(dev_list, cec_count);
155 if( count > cec_count ) {
156 cec_count = count;
157 dev_list = (CEC_ADAPTER_TYPE*)realloc(dev_list,
158 cec_count * sizeof(CEC_ADAPTER_TYPE));
159 count = CEC_adapter->CEC_FIND_ADAPTERS(dev_list, cec_count);
160 count = (std::min)(count, cec_count);
161 }
162
163 for( int i=0; i<count; i++ ) {
164 res.push_back(dev_list[i]);
165 }
166
167 free(dev_list);
168 // acquire the GIL before returning to code that uses python objects
169 Py_END_ALLOW_THREADS
170 return res;
171 }
172
list_adapters(PyObject * self,PyObject * args)173 static PyObject * list_adapters(PyObject * self, PyObject * args) {
174 PyObject * result = NULL;
175
176 if( PyArg_ParseTuple(args, ":list_adapters") ) {
177 std::list<CEC_ADAPTER_TYPE> dev_list = get_adapters();
178 // set up our result list
179 result = PyList_New(0);
180
181 // populate our result list
182 std::list<CEC_ADAPTER_TYPE>::const_iterator itr;
183 for( itr = dev_list.begin(); itr != dev_list.end(); itr++ ) {
184 #if HAVE_CEC_ADAPTER_DESCRIPTOR
185 PyList_Append(result, Py_BuildValue("s", itr->strComName));
186 /* Convert all of the fields
187 PyList_Append(result, Py_BuildValue("sshhhhii",
188 itr->strComName,
189 itr->strComPath,
190 itr->iVendorId,
191 itr->iProductId,
192 itr->iFirmwareVersion,
193 itr->iPhysicalAddress,
194 itr->iFirmwareBuildDate,
195 itr->adapterType
196 ));
197 */
198 #else
199 PyList_Append(result, Py_BuildValue("s", itr->comm));
200 /* Convert all of the fields
201 PyList_Append(result, Py_BuildValue("sshhhhii",
202 itr->comm,
203 itr->strComPath,
204 itr->iVendorId,
205 itr->iProductId,
206 itr->iFirmwareVersion,
207 itr->iPhysicalAddress,
208 itr->iFirmwareBuildDate,
209 itr->adapterType
210 ));
211 */
212 #endif
213 }
214 }
215
216 return result;
217 }
218
init(PyObject * self,PyObject * args)219 static PyObject * init(PyObject * self, PyObject * args) {
220 PyObject * result = NULL;
221 const char * dev = NULL;
222
223 if( PyArg_ParseTuple(args, "|s:init", &dev) ) {
224 if( !dev ) {
225 std::list<CEC_ADAPTER_TYPE> devs = get_adapters();
226 if( devs.size() > 0 ) {
227 #if HAVE_CEC_ADAPTER_DESCRIPTOR
228 dev = devs.front().strComName;
229 #else
230 dev = devs.front().comm;
231 #endif
232 } else {
233 PyErr_SetString(PyExc_Exception, "No default adapter found");
234 }
235 }
236 }
237
238 if( dev ) {
239 bool success = false;
240 Py_BEGIN_ALLOW_THREADS
241 success = CEC_adapter->Open(dev);
242 Py_END_ALLOW_THREADS
243 if( success ) {
244 Py_INCREF(Py_None);
245 result = Py_None;
246 } else {
247 CECDestroy(CEC_adapter);
248 CEC_adapter = NULL;
249
250 char errstr[1024];
251 snprintf(errstr, 1024, "CEC failed to open %s", dev);
252 PyErr_SetString(PyExc_IOError, errstr);
253 }
254 }
255
256 return result;
257 }
258
list_devices(PyObject * self,PyObject * args)259 static PyObject * list_devices(PyObject * self, PyObject * args) {
260 PyObject * result = NULL;
261
262 if( PyArg_ParseTuple(args, ":list_devices") ) {
263 cec_logical_addresses devices;
264 Py_BEGIN_ALLOW_THREADS
265 devices = CEC_adapter->GetActiveDevices();
266 Py_END_ALLOW_THREADS
267
268 //result = PyList_New(0);
269 result = PyDict_New();
270 for( uint8_t i=0; i<32; i++ ) {
271 if( devices[i] ) {
272 PyObject * ii = Py_BuildValue("(b)", i);
273 PyObject * dev = PyObject_CallObject(Device, ii);
274 Py_DECREF(ii);
275 if( dev ) {
276 //PyList_Append(result, dev);
277 PyDict_SetItem(result, Py_BuildValue("b", i), dev);
278 } else {
279 Py_DECREF(result);
280 result = NULL;
281 break;
282 }
283 }
284 }
285 }
286
287 return result;
288 }
289
290 struct Callback {
291 public:
292 long int event;
293 PyObject * cb;
294
CallbackCallback295 Callback(long int e, PyObject * c) : event(e), cb(c) {
296 }
297 };
298
299
300 typedef std::list<Callback> cb_list;
301 cb_list callbacks;
302
add_callback(PyObject * self,PyObject * args)303 static PyObject * add_callback(PyObject * self, PyObject * args) {
304 PyObject * result = NULL;
305 PyObject * callback;
306 long int events = EVENT_ALL; // default to all events
307
308 if( PyArg_ParseTuple(args, "O|i:add_callback", &callback, &events) ) {
309 // check that event is one of the allowed events
310 if( events & ~(EVENT_VALID) ) {
311 PyErr_SetString(PyExc_TypeError, "Invalid event(s) for callback");
312 return NULL;
313 }
314 if( !PyCallable_Check(callback)) {
315 PyErr_SetString(PyExc_TypeError, "parameter must be callable");
316 return NULL;
317 }
318
319 Py_INCREF(callback);
320 Callback new_cb(events, callback);
321
322 debug("Adding callback for event %ld\n", events);
323 callbacks.push_back(new_cb);
324
325 Py_INCREF(Py_None);
326 result = Py_None;
327 }
328 return result;
329 }
330
remove_callback(PyObject * self,PyObject * args)331 static PyObject * remove_callback(PyObject * self, PyObject * args) {
332 PyObject * callback;
333 long int events = EVENT_ALL; // default to all events
334
335 if( PyArg_ParseTuple(args, "O|i:remove_callback", &callback, &events) ) {
336 for( cb_list::iterator itr = callbacks.begin();
337 itr != callbacks.end();
338 ++itr ) {
339 if( itr->cb == callback ) {
340 // clear out the given events for this callback
341 itr->event &= ~(events);
342 if( itr->event == 0 ) {
343 // if this callback has no events, remove it
344 itr = callbacks.erase(itr);
345 Py_DECREF(callback);
346 }
347 }
348 }
349
350 }
351 Py_INCREF(Py_None);
352 return Py_None;
353 }
354
make_bound_method_args(PyObject * self,PyObject * args)355 static PyObject * make_bound_method_args(PyObject * self, PyObject * args) {
356 Py_ssize_t count = 0;
357 if( PyTuple_Check(args) ) {
358 count = PyTuple_Size(args);
359 }
360 PyObject * result = PyTuple_New(count+1);
361 if( result == NULL ) {
362 return NULL;
363 }
364 assert(self != NULL);
365 Py_INCREF(self);
366 PyTuple_SetItem(result, 0, self);
367 for( int i=0; i<count; i++ ) {
368 PyObject * arg = PyTuple_GetItem(args, i);
369 if( arg == NULL ) {
370 Py_DECREF(result);
371 return NULL;
372 }
373 Py_INCREF(arg);
374 PyTuple_SetItem(result, i+1, arg);
375 }
376 return result;
377 }
378
trigger_event(long int event,PyObject * args)379 static PyObject * trigger_event(long int event, PyObject * args) {
380 assert(event & EVENT_ALL);
381 Py_INCREF(Py_None);
382 PyObject * result = Py_None;
383
384 //debug("Triggering event %ld\n", event);
385
386 int i=0;
387 for( cb_list::const_iterator itr = callbacks.begin();
388 itr != callbacks.end();
389 ++itr ) {
390 //debug("Checking callback %d with events %ld\n", i, itr->event);
391 if( itr->event & event ) {
392 //debug("Calling callback %d\n", i);
393 PyObject * callback = itr->cb;
394 PyObject * arguments = args;
395 if( PyMethod_Check(itr->cb) ) {
396 callback = PyMethod_Function(itr->cb);
397 PyObject * self = PyMethod_Self(itr->cb);
398 if( self ) {
399 // bound method, prepend self/cls to argument tuple
400 arguments = make_bound_method_args(self, args);
401 }
402 }
403 // see also: PyObject_CallFunction(...) which can take C args
404 PyObject * temp = PyObject_CallObject(callback, arguments);
405 if( arguments != args ) {
406 Py_XDECREF(arguments);
407 }
408 if( temp ) {
409 debug("Callback succeeded\n");
410 Py_DECREF(temp);
411 } else {
412 debug("Callback failed\n");
413 Py_DECREF(Py_None);
414 return NULL;
415 }
416 }
417 i++;
418 }
419
420 return result;
421 }
422
transmit(PyObject * self,PyObject * args)423 static PyObject * transmit(PyObject * self, PyObject * args) {
424 unsigned char destination;
425 unsigned char opcode;
426 const char * params = NULL;
427 int param_count = 0;
428
429 if( PyArg_ParseTuple(args, "bb|s#:transmit", &destination, &opcode,
430 ¶ms, ¶m_count) ) {
431 if( destination < 0 || destination > 15 ) {
432 PyErr_SetString(PyExc_ValueError, "Logical address must be between 0 and 15");
433 return NULL;
434 }
435 if( param_count > CEC_MAX_DATA_PACKET_SIZE ) {
436 char errstr[1024];
437 snprintf(errstr, 1024, "Too many parameters, maximum is %d",
438 CEC_MAX_DATA_PACKET_SIZE);
439 PyErr_SetString(PyExc_ValueError, errstr);
440 return NULL;
441 }
442 cec_command data;
443 bool success;
444 Py_BEGIN_ALLOW_THREADS
445 data.initiator = CEC_adapter->GetLogicalAddresses().primary;
446 data.destination = (cec_logical_address)destination;
447 data.opcode = (cec_opcode)opcode;
448 data.opcode_set = 1;
449 if( params ) {
450 for( int i=0; i<param_count; i++ ) {
451 data.PushBack(((uint8_t *)params)[i]);
452 }
453 }
454 success = CEC_adapter->Transmit(data);
455 Py_END_ALLOW_THREADS
456 RETURN_BOOL(success);
457 }
458
459 return NULL;
460 }
461
is_active_source(PyObject * self,PyObject * args)462 static PyObject * is_active_source(PyObject * self, PyObject * args) {
463 unsigned char addr;
464
465 if( PyArg_ParseTuple(args, "b:is_active_source", &addr) ) {
466 if( addr < 0 || addr > 15 ) {
467 PyErr_SetString(PyExc_ValueError, "Logical address must be between 0 and 15");
468 return NULL;
469 } else {
470 RETURN_BOOL(CEC_adapter->IsActiveSource((cec_logical_address)addr));
471 }
472 }
473 return NULL;
474 }
475
set_active_source(PyObject * self,PyObject * args)476 static PyObject * set_active_source(PyObject * self, PyObject * args) {
477 unsigned char devtype = (unsigned char)CEC_DEVICE_TYPE_RESERVED;
478
479 if( PyArg_ParseTuple(args, "|b:set_active_source", &devtype) ) {
480 if( devtype < 0 || devtype > 5 ) {
481 PyErr_SetString(PyExc_ValueError, "Device type must be between 0 and 5");
482 return NULL;
483 } else {
484 RETURN_BOOL(CEC_adapter->SetActiveSource((cec_device_type)devtype));
485 }
486 }
487 return NULL;
488 }
489
volume_up(PyObject * self,PyObject * args)490 static PyObject * volume_up(PyObject * self, PyObject * args) {
491 if( PyArg_ParseTuple(args, ":volume_up") )
492 RETURN_BOOL(CEC_adapter->VolumeUp());
493 return NULL;
494 }
495
volume_down(PyObject * self,PyObject * args)496 static PyObject * volume_down(PyObject * self, PyObject * args) {
497 if( PyArg_ParseTuple(args, ":volume_up") )
498 RETURN_BOOL(CEC_adapter->VolumeDown());
499 return NULL;
500 }
501
502 #if CEC_LIB_VERSION_MAJOR > 1
toggle_mute(PyObject * self,PyObject * args)503 static PyObject * toggle_mute(PyObject * self, PyObject * args) {
504 if( PyArg_ParseTuple(args, ":toggle_mute") )
505 RETURN_BOOL(CEC_adapter->AudioToggleMute());
506 return NULL;
507 }
508 #endif
509
set_stream_path(PyObject * self,PyObject * args)510 static PyObject * set_stream_path(PyObject * self, PyObject * args) {
511 PyObject * arg;
512
513 if( PyArg_ParseTuple(args, "O:set_stream_path", &arg) ) {
514 Py_INCREF(arg);
515 #if PY_MAJOR_VERSION >= 3
516 if(PyLong_Check(arg)) {
517 long arg_l = PyLong_AsLong(arg);
518 #else
519 if(PyInt_Check(arg)) {
520 long arg_l = PyInt_AsLong(arg);
521 #endif
522 Py_DECREF(arg);
523 if( arg_l < 0 || arg_l > 15 ) {
524 PyErr_SetString(PyExc_ValueError, "Logical address must be between 0 and 15");
525 return NULL;
526 } else {
527 RETURN_BOOL(CEC_adapter->SetStreamPath((cec_logical_address)arg_l));
528 }
529 #if PY_MAJOR_VERSION >= 3
530 } else if(PyUnicode_Check(arg)) {
531 const char * arg_s = PyUnicode_AsUTF8(arg);
532 #else
533 } else if(PyString_Check(arg)) {
534 char * arg_s = PyString_AsString(arg);
535 #endif
536 if( arg_s ) {
537 int pa = parse_physical_addr(arg_s);
538 Py_DECREF(arg);
539 if( pa < 0 ) {
540 PyErr_SetString(PyExc_ValueError, "Invalid physical address");
541 return NULL;
542 } else {
543 RETURN_BOOL(CEC_adapter->SetStreamPath((uint16_t)pa));
544 }
545 } else {
546 Py_DECREF(arg);
547 return NULL;
548 }
549 } else if(PyUnicode_Check(arg)) {
550 // Convert from Unicode to ASCII
551 PyObject* ascii_arg = PyUnicode_AsASCIIString(arg);
552 if (NULL == ascii_arg) {
553 // Means the string can't be converted to ASCII, the codec failed
554 PyErr_SetString(PyExc_ValueError,
555 "Could not convert address to ASCII");
556 return NULL;
557 }
558
559 // Get the actual bytes as a C string
560 char * arg_s = PyByteArray_AsString(ascii_arg);
561 if( arg_s ) {
562 int pa = parse_physical_addr(arg_s);
563 Py_DECREF(arg);
564 if( pa < 0 ) {
565 PyErr_SetString(PyExc_ValueError, "Invalid physical address");
566 return NULL;
567 } else {
568 RETURN_BOOL(CEC_adapter->SetStreamPath((uint16_t)pa));
569 }
570 } else {
571 Py_DECREF(arg);
572 return NULL;
573 }
574 } else {
575 PyErr_SetString(PyExc_TypeError, "parameter must be string or int");
576 return NULL;
577 }
578 }
579
580 return NULL;
581 }
582
583 PyObject * set_physical_addr(PyObject * self, PyObject * args) {
584 char * addr_s;
585 if( PyArg_ParseTuple(args, "s:set_physical_addr", &addr_s) ) {
586 int addr = parse_physical_addr(addr_s);
587 if( addr >= 0 ) {
588 RETURN_BOOL(CEC_adapter->SetPhysicalAddress((uint16_t)addr));
589 } else {
590 PyErr_SetString(PyExc_ValueError, "Invalid physical address");
591 return NULL;
592 }
593 }
594 return NULL;
595 }
596
597 PyObject * set_port(PyObject * self, PyObject * args) {
598 unsigned char dev, port;
599 if( PyArg_ParseTuple(args, "bb", &dev, &port) ) {
600 if( dev > 15 ) {
601 PyErr_SetString(PyExc_ValueError, "Invalid logical address");
602 return NULL;
603 }
604 if( port > 15 ) {
605 PyErr_SetString(PyExc_ValueError, "Invalid port");
606 return NULL;
607 }
608 RETURN_BOOL(CEC_adapter->SetHDMIPort((cec_logical_address)dev, port));
609 }
610 return NULL;
611 }
612
613 PyObject * can_persist_config(PyObject * self, PyObject * args) {
614 if( PyArg_ParseTuple(args, ":can_persist_config") ) {
615 #if CEC_LIB_VERSION_MAJOR >= 5
616 RETURN_BOOL(CEC_adapter->CanSaveConfiguration());
617 #else
618 RETURN_BOOL(CEC_adapter->CanPersistConfiguration());
619 #endif
620 }
621 return NULL;
622 }
623
624 PyObject * persist_config(PyObject * self, PyObject * args) {
625 if( PyArg_ParseTuple(args, ":persist_config") ) {
626 #if CEC_LIB_VERSION_MAJOR >= 5
627 if( ! CEC_adapter->CanSaveConfiguration() ) {
628 #else
629 if( ! CEC_adapter->CanPersistConfiguration() ) {
630 #endif
631 PyErr_SetString(PyExc_NotImplementedError,
632 "Cannot persist configuration");
633 return NULL;
634 }
635 libcec_configuration config;
636 if( ! CEC_adapter->GetCurrentConfiguration(&config) ) {
637 PyErr_SetString(PyExc_IOError, "Could not get configuration");
638 return NULL;
639 }
640 #if CEC_LIB_VERSION_MAJOR >= 5
641 RETURN_BOOL(CEC_adapter->SetConfiguration(&config));
642 #else
643 RETURN_BOOL(CEC_adapter->PersistConfiguration(&config));
644 #endif
645 }
646 return NULL;
647 }
648
649 static PyMethodDef CecMethods[] = {
650 {"list_adapters", list_adapters, METH_VARARGS, "List available adapters"},
651 {"init", init, METH_VARARGS, "Open an adapter"},
652 {"list_devices", list_devices, METH_VARARGS, "List devices"},
653 {"add_callback", add_callback, METH_VARARGS, "Add a callback"},
654 {"remove_callback", remove_callback, METH_VARARGS, "Remove a callback"},
655 {"transmit", transmit, METH_VARARGS, "Transmit a raw CEC command"},
656 {"is_active_source", is_active_source, METH_VARARGS, "Check active source"},
657 {"set_active_source", set_active_source, METH_VARARGS, "Set active source"},
658 {"volume_up", volume_up, METH_VARARGS, "Volume Up"},
659 {"volume_down", volume_down, METH_VARARGS, "Volume Down"},
660 #if CEC_LIB_VERSION_MAJOR > 1
661 {"toggle_mute", toggle_mute, METH_VARARGS, "Toggle Mute"},
662 #endif
663 {"set_stream_path", set_stream_path, METH_VARARGS, "Set HDMI stream path"},
664 {"set_physical_addr", set_physical_addr, METH_VARARGS,
665 "Set HDMI physical address"},
666 {"can_persist_config", can_persist_config, METH_VARARGS,
667 "return true if the current adapter can persist the CEC configuration"},
668 {"persist_config", persist_config, METH_VARARGS,
669 "persist CEC configuration to adapter"},
670 {"set_port", set_port, METH_VARARGS, "Set upstream HDMI port"},
671 {NULL, NULL, 0, NULL}
672 };
673
674 libcec_configuration * CEC_config;
675 ICECCallbacks * CEC_callbacks;
676
677 #if CEC_LIB_VERSION_MAJOR >= 4
678 void log_cb(void * self, const cec_log_message* message) {
679 #else
680 int log_cb(void * self, const cec_log_message message) {
681 #endif
682 debug("got log callback\n");
683 PyGILState_STATE gstate;
684 gstate = PyGILState_Ensure();
685 #if CEC_LIB_VERSION_MAJOR >= 4
686 int level = message->level;
687 long int time = message->time;
688 const char* msg = message->message;
689 #else
690 int level = message.level;
691 long int time = message.time;
692 const char* msg = message.message;
693 #endif
694 // decode message ignoring invalid characters
695 PyObject * umsg = PyUnicode_DecodeASCII(msg, strlen(msg), "ignore");
696 PyObject * args = Py_BuildValue("(iilO)", EVENT_LOG,
697 level,
698 time,
699 umsg);
700 if( args ) {
701 trigger_event(EVENT_LOG, args);
702 Py_DECREF(args);
703 }
704 Py_XDECREF(umsg);
705 PyGILState_Release(gstate);
706 #if CEC_LIB_VERSION_MAJOR >= 4
707 return;
708 #else
709 return 1;
710 #endif
711 }
712
713 #if CEC_LIB_VERSION_MAJOR >= 4
714 void keypress_cb(void * self, const cec_keypress* key) {
715 #else
716 int keypress_cb(void * self, const cec_keypress key) {
717 #endif
718 debug("got keypress callback\n");
719 PyGILState_STATE gstate;
720 gstate = PyGILState_Ensure();
721 #if CEC_LIB_VERSION_MAJOR >= 4
722 cec_user_control_code keycode = key->keycode;
723 unsigned int duration = key->duration;
724 #else
725 cec_user_control_code keycode = key.keycode;
726 unsigned int duration = key.duration;
727 #endif
728 PyObject * args = Py_BuildValue("(iBI)", EVENT_KEYPRESS,
729 keycode,
730 duration);
731 if( args ) {
732 trigger_event(EVENT_KEYPRESS, args);
733 Py_DECREF(args);
734 }
735 PyGILState_Release(gstate);
736 #if CEC_LIB_VERSION_MAJOR >= 4
737 return;
738 #else
739 return 1;
740 #endif
741 }
742
743 static PyObject * convert_cmd(const cec_command* cmd) {
744 #if PY_MAJOR_VERSION >= 3
745 return Py_BuildValue("{sBsBsOsOsBsy#sOsi}",
746 #else
747 return Py_BuildValue("{sBsBsOsOsBss#sOsi}",
748 #endif
749 "initiator", cmd->initiator,
750 "destination", cmd->destination,
751 "ack", cmd->ack ? Py_True : Py_False,
752 "eom", cmd->eom ? Py_True : Py_False,
753 "opcode", cmd->opcode,
754 "parameters", cmd->parameters.data, cmd->parameters.size,
755 "opcode_set", cmd->opcode_set ? Py_True : Py_False,
756 "transmit_timeout", cmd->transmit_timeout);
757 }
758
759 #if CEC_LIB_VERSION_MAJOR >= 4
760 void command_cb(void * self, const cec_command* command) {
761 #else
762 int command_cb(void * self, const cec_command command) {
763 #endif
764 debug("got command callback\n");
765 PyGILState_STATE gstate;
766 gstate = PyGILState_Ensure();
767 #if CEC_LIB_VERSION_MAJOR >= 4
768 const cec_command * cmd = command;
769 #else
770 const cec_command * cmd = &command;
771 #endif
772 PyObject * args = Py_BuildValue("(iO&)", EVENT_COMMAND, convert_cmd, cmd);
773 if( args ) {
774 trigger_event(EVENT_COMMAND, args);
775 Py_DECREF(args);
776 }
777 PyGILState_Release(gstate);
778 #if CEC_LIB_VERSION_MAJOR >= 4
779 return;
780 #else
781 return 1;
782 #endif
783 }
784
785 #if CEC_LIB_VERSION_MAJOR >= 4
786 void config_cb(void * self, const libcec_configuration*) {
787 #else
788 int config_cb(void * self, const libcec_configuration) {
789 #endif
790 debug("got config callback\n");
791 PyGILState_STATE gstate;
792 gstate = PyGILState_Ensure();
793 // TODO: figure out how to pass these as parameters
794 // yeah... right.
795 // we'll probably have to come up with some functions for converting the
796 // libcec_configuration class into a python Object
797 // this will probably be _lots_ of work and should probably wait until
798 // a later release, or when it becomes necessary.
799 PyObject * args = Py_BuildValue("(i)", EVENT_CONFIG_CHANGE);
800 if( args ) {
801 // don't bother triggering an event until we can actually pass arguments
802 //trigger_event(EVENT_CONFIG_CHANGE, args);
803 Py_DECREF(args);
804 }
805 PyGILState_Release(gstate);
806 #if CEC_LIB_VERSION_MAJOR >= 4
807 return;
808 #else
809 return 1;
810 #endif
811 }
812
813 #if CEC_LIB_VERSION_MAJOR >= 4
814 void alert_cb(void * self, const libcec_alert alert, const libcec_parameter p) {
815 #else
816 int alert_cb(void * self, const libcec_alert alert, const libcec_parameter p) {
817 #endif
818 debug("got alert callback\n");
819 PyGILState_STATE gstate;
820 gstate = PyGILState_Ensure();
821 PyObject * param = Py_None;
822 if( p.paramType == CEC_PARAMETER_TYPE_STRING ) {
823 param = Py_BuildValue("s", p.paramData);
824 } else {
825 Py_INCREF(param);
826 }
827 PyObject * args = Py_BuildValue("(iiN)", EVENT_ALERT, alert, param);
828 if( args ) {
829 trigger_event(EVENT_ALERT, args);
830 Py_DECREF(args);
831 }
832 PyGILState_Release(gstate);
833 #if CEC_LIB_VERSION_MAJOR >= 4
834 return;
835 #else
836 return 1;
837 #endif
838 }
839
840 int menu_cb(void * self, const cec_menu_state menu) {
841 debug("got menu callback\n");
842 PyGILState_STATE gstate;
843 gstate = PyGILState_Ensure();
844 PyObject * args = Py_BuildValue("(ii)", EVENT_MENU_CHANGED, menu);
845 if( args ) {
846 trigger_event(EVENT_MENU_CHANGED, args);
847 Py_DECREF(args);
848 }
849 PyGILState_Release(gstate);
850 return 1;
851 }
852
853 void activated_cb(void * self, const cec_logical_address logical_address,
854 const uint8_t state) {
855 debug("got activated callback\n");
856 PyGILState_STATE gstate;
857 gstate = PyGILState_Ensure();
858 PyObject * active = (state == 1) ? Py_True : Py_False;
859 PyObject * args = Py_BuildValue("(iOi)", EVENT_ACTIVATED, active,
860 logical_address);
861 if( args ) {
862 trigger_event(EVENT_ACTIVATED, args);
863 Py_DECREF(args);
864 }
865 PyGILState_Release(gstate);
866 return;
867 }
868
869 #if PY_MAJOR_VERSION >= 3
870 static struct PyModuleDef moduledef = {
871 PyModuleDef_HEAD_INIT,
872 "cec",
873 NULL,
874 -1,
875 CecMethods,
876 NULL,
877 NULL,
878 NULL,
879 NULL
880 };
881 #endif
882
883 #if PY_MAJOR_VERSION >= 3
884 #define INITERROR return NULL
885 #else
886 #define INITERROR return
887 #endif
888
889 #if PY_MAJOR_VERSION >= 3
890 PyMODINIT_FUNC PyInit_cec(void) {
891 #else
892 PyMODINIT_FUNC initcec(void) {
893 #endif
894 // Make sure threads are enabled in the python interpreter
895 // this also acquires the global interpreter lock
896 PyEval_InitThreads();
897
898 // set up libcec
899 // libcec config
900 CEC_config = new libcec_configuration();
901 CEC_config->Clear();
902
903 snprintf(CEC_config->strDeviceName, 13, "python-cec");
904 // CEC_CLIENT_VERSION_CURRENT was introduced in 2.0.4
905 // just use 2.1.0 because the conditional is simpler
906 #if CEC_LIB_VERSION_MAJOR >= 3
907 CEC_config->clientVersion = LIBCEC_VERSION_CURRENT;
908 #elif CEC_LIB_VERSION_MAJOR >= 2 && CEC_LIB_VERSION_MINOR >= 1
909 CEC_config->clientVersion = CEC_CLIENT_VERSION_CURRENT;
910 #else
911 // fall back to 1.6.0 since it's the lowest common denominator shipped with
912 // Ubuntu
913 CEC_config->clientVersion = CEC_CLIENT_VERSION_1_6_0;
914 #endif
915 CEC_config->bActivateSource = 0;
916 CEC_config->deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
917
918
919 // libcec callbacks
920 CEC_callbacks = new ICECCallbacks();
921 #if CEC_LIB_VERSION_MAJOR > 1 || ( CEC_LIB_VERSION_MAJOR == 1 && CEC_LIB_VERSION_MINOR >= 7 )
922 CEC_callbacks->Clear();
923 #endif
924 #if CEC_LIB_VERSION_MAJOR >= 4
925 CEC_callbacks->logMessage = log_cb;
926 CEC_callbacks->keyPress = keypress_cb;
927 CEC_callbacks->commandReceived = command_cb;
928 CEC_callbacks->configurationChanged = config_cb;
929 CEC_callbacks->alert = alert_cb;
930 CEC_callbacks->menuStateChanged = menu_cb;
931 CEC_callbacks->sourceActivated = activated_cb;
932 #else
933 CEC_callbacks->CBCecLogMessage = log_cb;
934 CEC_callbacks->CBCecKeyPress = keypress_cb;
935 CEC_callbacks->CBCecCommand = command_cb;
936 CEC_callbacks->CBCecConfigurationChanged = config_cb;
937 CEC_callbacks->CBCecAlert = alert_cb;
938 CEC_callbacks->CBCecMenuStateChanged = menu_cb;
939 CEC_callbacks->CBCecSourceActivated = activated_cb;
940 #endif
941
942 CEC_config->callbacks = CEC_callbacks;
943
944 CEC_adapter = (ICECAdapter*)CECInitialise(CEC_config);
945
946 if( !CEC_adapter ) {
947 PyErr_SetString(PyExc_IOError, "Failed to initialize libcec");
948 INITERROR;
949 }
950
951 #if CEC_LIB_VERSION_MAJOR > 1 || ( CEC_LIB_VERSION_MAJOR == 1 && CEC_LIB_VERSION_MINOR >= 8 )
952 CEC_adapter->InitVideoStandalone();
953 #endif
954
955 // set up python module
956 PyTypeObject * dev = DeviceTypeInit(CEC_adapter);
957 Device = (PyObject*)dev;
958 if(PyType_Ready(dev) < 0 ) INITERROR;
959
960 #if PY_MAJOR_VERSION >= 3
961 PyObject * m = PyModule_Create(&moduledef);
962 #else
963 PyObject * m = Py_InitModule("cec", CecMethods);
964 #endif
965
966 if( m == NULL ) INITERROR;
967
968 Py_INCREF(dev);
969 PyModule_AddObject(m, "Device", (PyObject*)dev);
970
971 // constants for event types
972 PyModule_AddIntMacro(m, EVENT_LOG);
973 PyModule_AddIntMacro(m, EVENT_KEYPRESS);
974 PyModule_AddIntMacro(m, EVENT_COMMAND);
975 PyModule_AddIntMacro(m, EVENT_CONFIG_CHANGE);
976 PyModule_AddIntMacro(m, EVENT_ALERT);
977 PyModule_AddIntMacro(m, EVENT_MENU_CHANGED);
978 PyModule_AddIntMacro(m, EVENT_ACTIVATED);
979 PyModule_AddIntMacro(m, EVENT_ALL);
980
981 // constants for alert types
982 PyModule_AddIntConstant(m, "CEC_ALERT_SERVICE_DEVICE",
983 CEC_ALERT_SERVICE_DEVICE);
984 PyModule_AddIntConstant(m, "CEC_ALERT_CONNECTION_LOST",
985 CEC_ALERT_CONNECTION_LOST);
986 PyModule_AddIntConstant(m, "CEC_ALERT_PERMISSION_ERROR",
987 CEC_ALERT_PERMISSION_ERROR);
988 PyModule_AddIntConstant(m, "CEC_ALERT_PORT_BUSY",
989 CEC_ALERT_PORT_BUSY);
990 PyModule_AddIntConstant(m, "CEC_ALERT_PHYSICAL_ADDRESS_ERROR",
991 CEC_ALERT_PHYSICAL_ADDRESS_ERROR);
992 PyModule_AddIntConstant(m, "CEC_ALERT_TV_POLL_FAILED",
993 CEC_ALERT_TV_POLL_FAILED);
994
995 // constants for menu events
996 PyModule_AddIntConstant(m, "CEC_MENU_STATE_ACTIVATED",
997 CEC_MENU_STATE_ACTIVATED);
998 PyModule_AddIntConstant(m, "CEC_MENU_STATE_DEACTIVATED",
999 CEC_MENU_STATE_DEACTIVATED);
1000
1001 // constants for device types
1002 PyModule_AddIntConstant(m, "CEC_DEVICE_TYPE_TV",
1003 CEC_DEVICE_TYPE_TV);
1004 PyModule_AddIntConstant(m, "CEC_DEVICE_TYPE_RECORDING_DEVICE",
1005 CEC_DEVICE_TYPE_RECORDING_DEVICE);
1006 PyModule_AddIntConstant(m, "CEC_DEVICE_TYPE_RESERVED",
1007 CEC_DEVICE_TYPE_RESERVED);
1008 PyModule_AddIntConstant(m, "CEC_DEVICE_TYPE_TUNER",
1009 CEC_DEVICE_TYPE_TUNER);
1010 PyModule_AddIntConstant(m, "CEC_DEVICE_TYPE_PLAYBACK_DEVICE",
1011 CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
1012 PyModule_AddIntConstant(m, "CEC_DEVICE_TYPE_AUDIO_SYSTEM",
1013 CEC_DEVICE_TYPE_AUDIO_SYSTEM);
1014
1015 // constants for logical addresses
1016 PyModule_AddIntConstant(m, "CECDEVICE_UNKNOWN",
1017 CECDEVICE_UNKNOWN);
1018 PyModule_AddIntConstant(m, "CECDEVICE_TV",
1019 CECDEVICE_TV);
1020 PyModule_AddIntConstant(m, "CECDEVICE_RECORDINGDEVICE1",
1021 CECDEVICE_RECORDINGDEVICE1);
1022 PyModule_AddIntConstant(m, "CECDEVICE_RECORDINGDEVICE2",
1023 CECDEVICE_RECORDINGDEVICE2);
1024 PyModule_AddIntConstant(m, "CECDEVICE_TUNER1",
1025 CECDEVICE_TUNER1);
1026 PyModule_AddIntConstant(m, "CECDEVICE_PLAYBACKDEVICE1",
1027 CECDEVICE_PLAYBACKDEVICE1);
1028 PyModule_AddIntConstant(m, "CECDEVICE_AUDIOSYSTEM",
1029 CECDEVICE_AUDIOSYSTEM);
1030 PyModule_AddIntConstant(m, "CECDEVICE_TUNER2",
1031 CECDEVICE_TUNER2);
1032 PyModule_AddIntConstant(m, "CECDEVICE_TUNER3",
1033 CECDEVICE_TUNER3);
1034 PyModule_AddIntConstant(m, "CECDEVICE_PLAYBACKDEVICE2",
1035 CECDEVICE_PLAYBACKDEVICE2);
1036 PyModule_AddIntConstant(m, "CECDEVICE_RECORDINGDEVICE3",
1037 CECDEVICE_RECORDINGDEVICE3);
1038 PyModule_AddIntConstant(m, "CECDEVICE_TUNER4",
1039 CECDEVICE_TUNER4);
1040 PyModule_AddIntConstant(m, "CECDEVICE_PLAYBACKDEVICE3",
1041 CECDEVICE_PLAYBACKDEVICE3);
1042 PyModule_AddIntConstant(m, "CECDEVICE_RESERVED1",
1043 CECDEVICE_RESERVED1);
1044 PyModule_AddIntConstant(m, "CECDEVICE_RESERVED2",
1045 CECDEVICE_RESERVED2);
1046 PyModule_AddIntConstant(m, "CECDEVICE_FREEUSE",
1047 CECDEVICE_FREEUSE);
1048 PyModule_AddIntConstant(m, "CECDEVICE_UNREGISTERED",
1049 CECDEVICE_UNREGISTERED);
1050 PyModule_AddIntConstant(m, "CECDEVICE_BROADCAST",
1051 CECDEVICE_BROADCAST);
1052
1053 // constants for opcodes
1054 PyModule_AddIntConstant(m, "CEC_OPCODE_ACTIVE_SOURCE",
1055 CEC_OPCODE_ACTIVE_SOURCE);
1056 PyModule_AddIntConstant(m, "CEC_OPCODE_IMAGE_VIEW_ON",
1057 CEC_OPCODE_IMAGE_VIEW_ON);
1058 PyModule_AddIntConstant(m, "CEC_OPCODE_TEXT_VIEW_ON",
1059 CEC_OPCODE_TEXT_VIEW_ON);
1060 PyModule_AddIntConstant(m, "CEC_OPCODE_INACTIVE_SOURCE",
1061 CEC_OPCODE_INACTIVE_SOURCE);
1062 PyModule_AddIntConstant(m, "CEC_OPCODE_REQUEST_ACTIVE_SOURCE",
1063 CEC_OPCODE_REQUEST_ACTIVE_SOURCE);
1064 PyModule_AddIntConstant(m, "CEC_OPCODE_ROUTING_CHANGE",
1065 CEC_OPCODE_ROUTING_CHANGE);
1066 PyModule_AddIntConstant(m, "CEC_OPCODE_ROUTING_INFORMATION",
1067 CEC_OPCODE_ROUTING_INFORMATION);
1068 PyModule_AddIntConstant(m, "CEC_OPCODE_SET_STREAM_PATH",
1069 CEC_OPCODE_SET_STREAM_PATH);
1070 PyModule_AddIntConstant(m, "CEC_OPCODE_STANDBY",
1071 CEC_OPCODE_STANDBY);
1072 PyModule_AddIntConstant(m, "CEC_OPCODE_RECORD_OFF",
1073 CEC_OPCODE_RECORD_OFF);
1074 PyModule_AddIntConstant(m, "CEC_OPCODE_RECORD_ON",
1075 CEC_OPCODE_RECORD_ON);
1076 PyModule_AddIntConstant(m, "CEC_OPCODE_RECORD_STATUS",
1077 CEC_OPCODE_RECORD_STATUS);
1078 PyModule_AddIntConstant(m, "CEC_OPCODE_RECORD_TV_SCREEN",
1079 CEC_OPCODE_RECORD_TV_SCREEN);
1080 PyModule_AddIntConstant(m, "CEC_OPCODE_CLEAR_ANALOGUE_TIMER",
1081 CEC_OPCODE_CLEAR_ANALOGUE_TIMER);
1082 PyModule_AddIntConstant(m, "CEC_OPCODE_CLEAR_DIGITAL_TIMER",
1083 CEC_OPCODE_CLEAR_DIGITAL_TIMER);
1084 PyModule_AddIntConstant(m, "CEC_OPCODE_CLEAR_EXTERNAL_TIMER",
1085 CEC_OPCODE_CLEAR_EXTERNAL_TIMER);
1086 PyModule_AddIntConstant(m, "CEC_OPCODE_SET_ANALOGUE_TIMER",
1087 CEC_OPCODE_SET_ANALOGUE_TIMER);
1088 PyModule_AddIntConstant(m, "CEC_OPCODE_SET_DIGITAL_TIMER",
1089 CEC_OPCODE_SET_DIGITAL_TIMER);
1090 PyModule_AddIntConstant(m, "CEC_OPCODE_SET_EXTERNAL_TIMER",
1091 CEC_OPCODE_SET_EXTERNAL_TIMER);
1092 PyModule_AddIntConstant(m, "CEC_OPCODE_SET_TIMER_PROGRAM_TITLE",
1093 CEC_OPCODE_SET_TIMER_PROGRAM_TITLE);
1094 PyModule_AddIntConstant(m, "CEC_OPCODE_TIMER_CLEARED_STATUS",
1095 CEC_OPCODE_TIMER_CLEARED_STATUS);
1096 PyModule_AddIntConstant(m, "CEC_OPCODE_TIMER_STATUS",
1097 CEC_OPCODE_TIMER_STATUS);
1098 PyModule_AddIntConstant(m, "CEC_OPCODE_CEC_VERSION",
1099 CEC_OPCODE_CEC_VERSION);
1100 PyModule_AddIntConstant(m, "CEC_OPCODE_GET_CEC_VERSION",
1101 CEC_OPCODE_GET_CEC_VERSION);
1102 PyModule_AddIntConstant(m, "CEC_OPCODE_GIVE_PHYSICAL_ADDRESS",
1103 CEC_OPCODE_GIVE_PHYSICAL_ADDRESS);
1104 PyModule_AddIntConstant(m, "CEC_OPCODE_GET_MENU_LANGUAGE",
1105 CEC_OPCODE_GET_MENU_LANGUAGE);
1106 PyModule_AddIntConstant(m, "CEC_OPCODE_REPORT_PHYSICAL_ADDRESS",
1107 CEC_OPCODE_REPORT_PHYSICAL_ADDRESS);
1108 PyModule_AddIntConstant(m, "CEC_OPCODE_SET_MENU_LANGUAGE",
1109 CEC_OPCODE_SET_MENU_LANGUAGE);
1110 PyModule_AddIntConstant(m, "CEC_OPCODE_DECK_CONTROL",
1111 CEC_OPCODE_DECK_CONTROL);
1112 PyModule_AddIntConstant(m, "CEC_OPCODE_DECK_STATUS",
1113 CEC_OPCODE_DECK_STATUS);
1114 PyModule_AddIntConstant(m, "CEC_OPCODE_GIVE_DECK_STATUS",
1115 CEC_OPCODE_GIVE_DECK_STATUS);
1116 PyModule_AddIntConstant(m, "CEC_OPCODE_PLAY",
1117 CEC_OPCODE_PLAY);
1118 PyModule_AddIntConstant(m, "CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS",
1119 CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS);
1120 PyModule_AddIntConstant(m, "CEC_OPCODE_SELECT_ANALOGUE_SERVICE",
1121 CEC_OPCODE_SELECT_ANALOGUE_SERVICE);
1122 PyModule_AddIntConstant(m, "CEC_OPCODE_SELECT_DIGITAL_SERVICE",
1123 CEC_OPCODE_SELECT_DIGITAL_SERVICE);
1124 PyModule_AddIntConstant(m, "CEC_OPCODE_TUNER_DEVICE_STATUS",
1125 CEC_OPCODE_TUNER_DEVICE_STATUS);
1126 PyModule_AddIntConstant(m, "CEC_OPCODE_TUNER_STEP_DECREMENT",
1127 CEC_OPCODE_TUNER_STEP_DECREMENT);
1128 PyModule_AddIntConstant(m, "CEC_OPCODE_TUNER_STEP_INCREMENT",
1129 CEC_OPCODE_TUNER_STEP_INCREMENT);
1130 PyModule_AddIntConstant(m, "CEC_OPCODE_DEVICE_VENDOR_ID",
1131 CEC_OPCODE_DEVICE_VENDOR_ID);
1132 PyModule_AddIntConstant(m, "CEC_OPCODE_GIVE_DEVICE_VENDOR_ID",
1133 CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
1134 PyModule_AddIntConstant(m, "CEC_OPCODE_VENDOR_COMMAND",
1135 CEC_OPCODE_VENDOR_COMMAND);
1136 PyModule_AddIntConstant(m, "CEC_OPCODE_VENDOR_COMMAND_WITH_ID",
1137 CEC_OPCODE_VENDOR_COMMAND_WITH_ID);
1138 PyModule_AddIntConstant(m, "CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN",
1139 CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN);
1140 PyModule_AddIntConstant(m, "CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP",
1141 CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP);
1142 PyModule_AddIntConstant(m, "CEC_OPCODE_SET_OSD_STRING",
1143 CEC_OPCODE_SET_OSD_STRING);
1144 PyModule_AddIntConstant(m, "CEC_OPCODE_GIVE_OSD_NAME",
1145 CEC_OPCODE_GIVE_OSD_NAME);
1146 PyModule_AddIntConstant(m, "CEC_OPCODE_SET_OSD_NAME",
1147 CEC_OPCODE_SET_OSD_NAME);
1148 PyModule_AddIntConstant(m, "CEC_OPCODE_MENU_REQUEST",
1149 CEC_OPCODE_MENU_REQUEST);
1150 PyModule_AddIntConstant(m, "CEC_OPCODE_MENU_STATUS",
1151 CEC_OPCODE_MENU_STATUS);
1152 PyModule_AddIntConstant(m, "CEC_OPCODE_USER_CONTROL_PRESSED",
1153 CEC_OPCODE_USER_CONTROL_PRESSED);
1154 PyModule_AddIntConstant(m, "CEC_OPCODE_USER_CONTROL_RELEASE",
1155 CEC_OPCODE_USER_CONTROL_RELEASE);
1156 PyModule_AddIntConstant(m, "CEC_OPCODE_GIVE_DEVICE_POWER_STATUS",
1157 CEC_OPCODE_GIVE_DEVICE_POWER_STATUS);
1158 PyModule_AddIntConstant(m, "CEC_OPCODE_REPORT_POWER_STATUS",
1159 CEC_OPCODE_REPORT_POWER_STATUS);
1160 PyModule_AddIntConstant(m, "CEC_OPCODE_FEATURE_ABORT",
1161 CEC_OPCODE_FEATURE_ABORT);
1162 PyModule_AddIntConstant(m, "CEC_OPCODE_ABORT",
1163 CEC_OPCODE_ABORT);
1164 PyModule_AddIntConstant(m, "CEC_OPCODE_GIVE_AUDIO_STATUS",
1165 CEC_OPCODE_GIVE_AUDIO_STATUS);
1166 PyModule_AddIntConstant(m, "CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS",
1167 CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS);
1168 PyModule_AddIntConstant(m, "CEC_OPCODE_REPORT_AUDIO_STATUS",
1169 CEC_OPCODE_REPORT_AUDIO_STATUS);
1170 PyModule_AddIntConstant(m, "CEC_OPCODE_SET_SYSTEM_AUDIO_MODE",
1171 CEC_OPCODE_SET_SYSTEM_AUDIO_MODE);
1172 PyModule_AddIntConstant(m, "CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST",
1173 CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST);
1174 PyModule_AddIntConstant(m, "CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS",
1175 CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS);
1176 PyModule_AddIntConstant(m, "CEC_OPCODE_SET_AUDIO_RATE",
1177 CEC_OPCODE_SET_AUDIO_RATE);
1178 PyModule_AddIntConstant(m, "CEC_OPCODE_START_ARC",
1179 CEC_OPCODE_START_ARC);
1180 PyModule_AddIntConstant(m, "CEC_OPCODE_REPORT_ARC_STARTED",
1181 CEC_OPCODE_REPORT_ARC_STARTED);
1182 PyModule_AddIntConstant(m, "CEC_OPCODE_REPORT_ARC_ENDED",
1183 CEC_OPCODE_REPORT_ARC_ENDED);
1184 PyModule_AddIntConstant(m, "CEC_OPCODE_REQUEST_ARC_START",
1185 CEC_OPCODE_REQUEST_ARC_START);
1186 PyModule_AddIntConstant(m, "CEC_OPCODE_REQUEST_ARC_END",
1187 CEC_OPCODE_REQUEST_ARC_END);
1188 PyModule_AddIntConstant(m, "CEC_OPCODE_END_ARC",
1189 CEC_OPCODE_END_ARC);
1190 PyModule_AddIntConstant(m, "CEC_OPCODE_CDC",
1191 CEC_OPCODE_CDC);
1192 PyModule_AddIntConstant(m, "CEC_OPCODE_NONE",
1193 CEC_OPCODE_NONE);
1194
1195 // expose whether or not we're using the new cec_adapter_descriptor API
1196 // this should help debugging by exposing which version was detected and
1197 // which adapter detection API was used at compile time
1198 PyModule_AddIntMacro(m, HAVE_CEC_ADAPTER_DESCRIPTOR);
1199
1200 #if PY_MAJOR_VERSION >= 3
1201 return m;
1202 #endif
1203 }
1204