libCEC 8.1.0
C / C++ API — control CEC-capable HDMI devices
Loading...
Searching...
No Matches
libCEC — C / C++ API

libCEC lets applications control CEC-capable HDMI hardware — power a TV on or to standby, become the active source, send remote-control keys, read device state — and receive everything happening on the CEC bus. It works over Pulse-Eight's USB-CEC adapter (the cross-platform default) and SoC-native CEC on Linux and Raspberry Pi.

This is the reference for the native interface. Everything else — the .NET, Node.js and Python bindings — is a thin wrapper over the same engine, so the concepts documented here (logical and physical addresses, device types, opcodes, power states) carry across all of them.

There are two native surfaces:

  • C++ — the CEC::ICECAdapter interface in cec.h, the object you send commands through. Events arrive via the CEC::ICECCallbacks function pointers in cectypes.h.
  • C — the flat libcec_* functions in cecc.h, the same surface the .NET and Node.js bindings bind. Prefer this for FFI.

Requirements

  • A Pulse-Eight USB-CEC adapter (or a supported SoC-native CEC backend).
  • libCEC and its development files (headers + the cec shared library).
  • A C++11 compiler.

Installing

Debian / Ubuntu

# development headers + the shared library, plus the cec-client tools
sudo apt-get install libcec-dev cec-utils

On Pulse-Eight's own package feed the development package is named after the SONAME (libcec8-dev); distribution repositories ship it as libcec-dev.

Build from source (Linux / macOS / BSD / Raspberry Pi)

git clone https://github.com/Pulse-Eight/libcec.git
mkdir libcec/build && cd libcec/build
cmake ..
make -j4
sudo make install && sudo ldconfig

Platform-native CEC backends are off by default and enabled with cmake flags (e.g. -DHAVE_LINUX_API=1, -DHAVE_RPI_API=1); without one, only the Pulse-Eight USB adapter backend is built. See the platform notes for Linux, macOS and Raspberry Pi.

Windows

Install the USB-CEC Adapter software from Pulse-Eight (it ships cec.dll, the import library cec.lib and the headers), or build the library and installer from source with python windows\create-installer.py (see the Windows build notes). Compile against the flat headers and link cec.lib; at runtime keep cec.dll on the DLL search path.

Using the C++ API

The lifecycle is: describe yourself in a CEC::libcec_configuration, register callbacks, create the instance with LibCecInitialise() (from cecloader.h, which loads the shared library for you), open a connection, then send commands. Tear down with Close() + UnloadLibCec().

#include <iostream>
#include <libcec/cec.h>
#include <libcec/cecloader.h>
using namespace CEC;
// --- event callbacks (fired from libCEC's own worker thread) --------------
void onLog(void*, const cec_log_message* m) {
std::cout << "log: " << m->message << std::endl;
}
void onKey(void*, const cec_keypress* k) {
std::cout << "key: " << static_cast<int>(k->keycode) << std::endl;
}
void onCommand(void*, const cec_command* c) {
std::cout << "command: " << static_cast<int>(c->opcode) << std::endl;
}
int main() {
// 1. describe this client
config.Clear();
snprintf(config.strDeviceName, sizeof(config.strDeviceName), "CppApp");
config.bActivateSource = 0; // don't steal focus on open
config.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
// 2. wire up the callbacks
ICECCallbacks callbacks;
callbacks.Clear();
callbacks.logMessage = &onLog;
callbacks.keyPress = &onKey;
callbacks.commandReceived = &onCommand;
config.callbacks = &callbacks;
// 3. create the libCEC instance (loads cec.dll / libcec.so)
ICECAdapter* adapter = LibCecInitialise(&config);
if (!adapter) {
std::cerr << "could not load libCEC" << std::endl;
return 1;
}
// 4. find an adapter and open it
int8_t found = adapter->DetectAdapters(devices, 10, nullptr, true);
if (found <= 0 || !adapter->Open(devices[0].strComName)) {
std::cerr << "no CEC adapter, or could not open it" << std::endl;
UnloadLibCec(adapter);
return 1;
}
// 5. control the bus
adapter->PowerOnDevices(CECDEVICE_TV);
for (uint8_t la = CECDEVICE_TV; la <= CECDEVICE_BROADCAST; ++la) {
if (actives[la])
std::cout << adapter->GetDeviceOSDName((cec_logical_address)la).c_str()
<< std::endl;
}
// 6. clean up (Close() stops the worker thread before UnloadLibCec())
adapter->Close();
UnloadLibCec(adapter);
return 0;
}
CEC::ICECAdapter * LibCecInitialise(CEC::libcec_configuration *configuration, const char *strLib=NULL)
Create a new libCEC instance.
Definition cecloader.h:117
void UnloadLibCec(CEC::ICECAdapter *device)
Destroy an instance of libCEC.
Definition cecloader.h:148
To create a new libCEC instance, call CECInitialise() and pass the configuration as argument.
Definition cec.h:54
virtual int8_t DetectAdapters(cec_adapter_descriptor *deviceList, uint8_t iBufSize, const char *strDevicePath=nullptr, bool bQuickScan=false)=0
Try to find all connected CEC adapters.
virtual std::string GetDeviceOSDName(cec_logical_address iAddress)=0
Get the OSD name of a device on the CEC bus.
virtual void Close(void)=0
Close the connection to the CEC adapter.
virtual cec_logical_addresses GetActiveDevices(void)=0
virtual bool PowerOnDevices(cec_logical_address address=CECDEVICE_TV)=0
Power on the given CEC capable devices.
Definition cec.h:41
@ LIBCEC_VERSION_CURRENT
Definition cectypes.h:933
cec_logical_address
Definition cectypes.h:764
@ CECDEVICE_BROADCAST
Definition cectypes.h:782
uint32_t clientVersion
the version of the client that is connecting
Definition cectypes.h:1563
ICECCallbacks * callbacks
the callback methods to use.
Definition cectypes.h:1582
cec_device_type_list deviceTypes
the device type(s) to use on the CEC bus for libCEC
Definition cectypes.h:1565
void Clear(void)
Reset this configution struct to the default values.
Definition cectypes.h:1658
char strDeviceName[(15)]
the device name to use on the CEC bus, name + 0 terminator
Definition cectypes.h:1564
uint8_t bActivateSource
make libCEC the active source on the bus when starting the player application
Definition cectypes.h:1578
void Clear(void)
Definition cectypes.h:1541
void(* commandReceived)(void *cbparam, const cec_command *command)
Transfer a CEC command from libCEC to the client.
Definition cectypes.h:1490
void(* logMessage)(void *cbparam, const cec_log_message *message)
Transfer a log message from libCEC to the client.
Definition cectypes.h:1476
void(* keyPress)(void *cbparam, const cec_keypress *key)
Transfer a keypress from libCEC to the client.
Definition cectypes.h:1483
cec_opcode opcode
the opcode of this message
Definition cectypes.h:1098
void Add(const cec_device_type type)
Add a type to this list.
Definition cectypes.h:1282
cec_user_control_code keycode
the keycode
Definition cectypes.h:948
const char * message
the actual message, valid until returning from the log callback
Definition cectypes.h:941

Build it against the installed library with pkg-config:

g++ -std=c++11 example.cpp -o example $(pkg-config --cflags --libs libcec)

Receiving events

Every CEC::ICECCallbacks member is optional — set only the ones you need and leave the rest null (that is what Clear() does). libCEC invokes them from its own worker thread, so treat the payloads as read-only and hand work off to your own thread if it is expensive. The menuStateChanged and commandHandler callbacks additionally return an int telling libCEC whether you handled the event; the others are notifications.

The C API

For FFI or C code, use cecc.h instead: libcec_initialise(), libcec_open(), libcec_power_on_devices(), libcec_close(), libcec_destroy(), and so on — the same operations as ICECAdapter, taking a libcec_connection_t handle as the first argument. ceccloader.h provides the matching dynamic loader.

Where to go next


libCEC is Copyright © Pulse-Eight Limited, dual-licensed (GPL-2.0-or-later or commercial). See the project on GitHub.