2 Copyright 2004-2020 Chris Tallon; 2012 Marten Richter
4 This file is part of VOMP.
6 VOMP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 VOMP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with VOMP. If not, see <https://www.gnu.org/licenses/>.
21 #include <libcec/cec.h>
22 #include <libcec/cecloader.h>
29 #include "woptionpane.h"
32 static const char* TAG = "InputCEC";
35 //#define W_G_HCW(type,code) ((static_cast<u8>(type) << 32) | code)
37 //#define W_HCW_KC 1 /* key code as defined by kernel for keyboard and remotes through /dev/input */
38 //#define W_HCW_CEC 2 /* HDMI_CEC */
39 //#define W_HCW_LIRC 3 /* remote control LIRC*/
42 InputCEC* InputCEC::instance = NULL;
46 InitHWCListwithDefaults();
49 // bcm_host_init(); //may be move to custom hardware init?
51 LogNT::getInstance()->info(TAG, "Init LibCEC");
55 cec_callbacks.Clear();
56 cec_callbacks.logMessage = cecLogMessage;
57 cec_callbacks.keyPress = cecKeyPress;
58 cec_callbacks.commandReceived = cecCommand;
59 cec_callbacks.configurationChanged = cecConfigurationChanged;
60 cec_callbacks.sourceActivated = cecSourceActivated;
61 cec_config.clientVersion = LIBCEC_VERSION_CURRENT;
62 cec_config.bActivateSource = 1;
63 //cec_config.deviceTypes.Add(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
64 cec_config.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
65 //cec_config.deviceTypes.Add(CEC_DEVICE_TYPE_TUNER);
67 strncpy(cec_config.strDeviceName, "vomp", sizeof(cec_config.strDeviceName));
69 cec_config.callbackParam = NULL; // I do not care
70 cec_config.callbacks = &cec_callbacks;
72 cec_adap = LibCecInitialise(&cec_config);
75 LogNT::getInstance()->error(TAG, "Init LibCEC failed");
79 cec_adap->InitVideoStandalone();
81 cec_adapter_descriptor cec_adapter_descriptors[10];
82 int adap_num = cec_adap->DetectAdapters(cec_adapter_descriptors, 10);
85 LogNT::getInstance()->error(TAG, "CEC:Failed to find adapter");
91 LogNT::getInstance()->info(TAG, "CEC: No adapter found");
95 if (!cec_adap->Open(cec_adapter_descriptors[0].strComName))
97 LogNT::getInstance()->error(TAG, "CEC:Failed to open adapter");
101 if (!cec_adap->SetActiveSource(cec_config.deviceTypes[0]))
103 LogNT::getInstance()->error(TAG, "CEC:Failed set active source");
110 void InputCEC::shutdown()
114 LogNT::getInstance()->info(TAG, "Shutdown libcec begin");
115 cec_adap->SetInactiveView();
117 vc_cec_register_callback(NULL, NULL); //deactivate callback!
118 UnloadLibCec(cec_adap);
120 LogNT::getInstance()->info(TAG, "Shutdown libcec end");
126 void InputCEC::changePowerState(bool poweron)
132 //Log::getInstance()->log("InputCEC", Log::DEBUG, "CEC set active source");
133 cec_adap->SetActiveSource(cec_config.deviceTypes[0]);
137 //Log::getInstance()->log("InputCEC", Log::DEBUG, "CEC set inactive view");
138 cec_adap->SetInactiveView();
143 void InputCEC::incomingCECkey(int key)
145 sendInputKey(TranslateHWC(key));
148 void InputCEC::incomingPowerkey(u1 key)
153 void InputCEC::volumeUp()
155 cec_adap->VolumeUp();
158 void InputCEC::volumeDown()
160 cec_adap->VolumeDown();
163 void InputCEC::volumeMute()
165 cec_adap->AudioToggleMute();
168 bool InputCEC::loadOptionsFromServer(VDR* vdr)
172 name = vdr->configLoad("InputCEC", "HandleVolume");
176 if (STRCASECMP(name, "Vomp") == 0) cechandlesvolume = false;
177 else if (STRCASECMP(name, "Cec") == 0) cechandlesvolume = true;
180 return Input::loadOptionsFromServer(vdr);
183 bool InputCEC::saveOptionstoServer()
185 if (cechandlesvolume) VDR::getInstance()->configSave("InputCEC", "HandleVolume","Cec");
186 else VDR::getInstance()->configSave("InputCEC", "HandleVolume","Vomp");
188 return Input::saveOptionstoServer();
191 bool InputCEC::addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane)
193 //if (!Input::addOptionsToPanes(panenumber, options, pane)) return false;
198 static const char* volumeopts[]={"Vomp","Cec"};
199 option = new Option(100,tr("Volume handled by"), "InputCEC","HandleVolume",Option::TYPE_TEXT,/*4,2*/2,0,0,volumeopts,NULL,false,this);
200 options->push_back(option);
201 pane->addOptionLine(option);
207 bool InputCEC::handleOptionChanges(Option* option)
209 if (Input::handleOptionChanges(option))
211 switch (option->id) {
213 if (STRCASECMP(option->options[option->userSetChoice], "Vomp") == 0) {
214 cechandlesvolume=false;
215 } else if (STRCASECMP(option->options[option->userSetChoice], "Cec")
217 cechandlesvolume=true;
219 LogNT::getInstance()->debug(TAG, "Set volume handling to to {} {}",option->options[option->userSetChoice],cechandlesvolume);
227 // STATIC FUNCTIONS FOLLOW
229 void InputCEC::cecLogMessage(void* /* param */, const cec_log_message* message)
231 LogNT::getInstance()->debug(TAG, "CECLOG: {} {} {}", message->time, message->level, message->message);
234 void InputCEC::cecKeyPress(void* /* param */, const cec_keypress* key)
236 //Log::getInstance()->log("InputCEC", Log::DEBUG, "Incoming cec key %d %d", key->keycode,key->duration);
237 if (key->duration == 0) instance->incomingCECkey(key->keycode);
240 void InputCEC::cecCommand(void* /* param */, const cec_command* command)
242 LogNT::getInstance()->debug(TAG, "CECCommand: {}", command->opcode);
243 switch (command->opcode)
245 case CEC_OPCODE_STANDBY:
247 if (command->initiator==CECDEVICE_TV)
249 instance->incomingPowerkey(POWEROFF);
253 case CEC_OPCODE_DECK_CONTROL:
255 if (command->initiator == CECDEVICE_TV && command->parameters.size == 1
256 && command->parameters[0] == CEC_DECK_CONTROL_MODE_STOP)
258 instance->incomingCECkey(CEC_USER_CONTROL_CODE_STOP);
262 case CEC_OPCODE_PLAY:
264 if (command->initiator == CECDEVICE_TV && command->parameters.size == 1)
266 if (command->parameters[0] == CEC_PLAY_MODE_PLAY_FORWARD)
268 instance->incomingCECkey(CEC_USER_CONTROL_CODE_PLAY);
270 else if (command->parameters[0] == CEC_PLAY_MODE_PLAY_STILL)
272 instance->incomingCECkey(CEC_USER_CONTROL_CODE_PAUSE);
282 void InputCEC::cecConfigurationChanged(void* /* param */, const libcec_configuration*)
284 LogNT::getInstance()->debug(TAG, "CECConfig:"/*,config->string()*/);
287 void InputCEC::cecSourceActivated(void* /* param */, const cec_logical_address address, const uint8_t activated)
289 LogNT::getInstance()->debug(TAG, "CECSourceActivated: {} {}", address, activated);
292 instance->incomingPowerkey(POWERON);
296 void InputCEC::InitHWCListwithDefaults()
298 //Processing CEC_Messages
299 translist[CEC_USER_CONTROL_CODE_NUMBER9] = NINE;
300 translist[CEC_USER_CONTROL_CODE_NUMBER8] = EIGHT;
301 translist[CEC_USER_CONTROL_CODE_NUMBER7] = SEVEN;
302 translist[CEC_USER_CONTROL_CODE_NUMBER6] = SIX;
303 translist[CEC_USER_CONTROL_CODE_NUMBER5] = FIVE;
304 translist[CEC_USER_CONTROL_CODE_NUMBER4] = FOUR;
305 translist[CEC_USER_CONTROL_CODE_NUMBER3] = THREE;
306 translist[CEC_USER_CONTROL_CODE_NUMBER2] = TWO;
307 translist[CEC_USER_CONTROL_CODE_NUMBER1] = ONE;
308 translist[CEC_USER_CONTROL_CODE_NUMBER0] = ZERO;
309 //translist[KEY_KPDOT] = STAR;
311 //translist[KEY_J] = GO; //j for JUMP TO instead of go to
312 translist[CEC_USER_CONTROL_CODE_F2_RED] = RED;
313 translist[CEC_USER_CONTROL_CODE_F3_GREEN] = GREEN;
314 translist[CEC_USER_CONTROL_CODE_F4_YELLOW] = YELLOW;
315 translist[CEC_USER_CONTROL_CODE_F1_BLUE] = BLUE;
316 //Processing Remote Style Messages
317 translist[CEC_USER_CONTROL_CODE_FAVORITE_MENU] = MENU;
319 translist[CEC_USER_CONTROL_CODE_RECORD] = RECORD;
320 translist[CEC_USER_CONTROL_CODE_PLAY] = PLAY; //Playback Televison
321 translist[CEC_USER_CONTROL_CODE_PAUSE] = PAUSE;
322 translist[CEC_USER_CONTROL_CODE_STOP] = STOP;
323 translist[CEC_USER_CONTROL_CODE_PAUSE_PLAY_FUNCTION] = PLAYPAUSE;
324 translist[CEC_USER_CONTROL_CODE_FORWARD] = SKIPFORWARD;
325 translist[CEC_USER_CONTROL_CODE_BACKWARD] = SKIPBACK;
326 translist[CEC_USER_CONTROL_CODE_FAST_FORWARD ] = FORWARD;
327 translist[CEC_USER_CONTROL_CODE_REWIND] = REVERSE;
328 translist[CEC_USER_CONTROL_CODE_MUTE] = MUTE;
329 translist[CEC_USER_CONTROL_CODE_VOLUME_UP] = VOLUMEUP;
330 translist[CEC_USER_CONTROL_CODE_VOLUME_DOWN] = VOLUMEDOWN;
331 translist[CEC_USER_CONTROL_CODE_CHANNEL_UP ] = CHANNELUP;
332 translist[CEC_USER_CONTROL_CODE_CHANNEL_DOWN] = CHANNELDOWN;
335 u1 InputCEC::TranslateHWCFixed(u8 code)
339 case CEC_USER_CONTROL_CODE_DOWN: return DOWN;
340 case CEC_USER_CONTROL_CODE_UP: return UP;
341 case CEC_USER_CONTROL_CODE_LEFT: return LEFT;
342 case CEC_USER_CONTROL_CODE_RIGHT: return RIGHT;
343 case CEC_USER_CONTROL_CODE_ROOT_MENU:
344 case CEC_USER_CONTROL_CODE_CONTENTS_MENU:
345 case CEC_USER_CONTROL_CODE_SETUP_MENU: return MENU;
346 case CEC_USER_CONTROL_CODE_EXIT: return BACK;
347 case CEC_USER_CONTROL_CODE_ENTER:
348 case CEC_USER_CONTROL_CODE_SELECT:
349 case CEC_USER_CONTROL_CODE_AN_RETURN: return OK;
350 case CEC_USER_CONTROL_CODE_POWER:
351 case POWER: return POWER; //?
358 #define NAMETRICK2(pre, code) cec_keymap[pre ## code]= #code
359 static const char * cec_keymap[CEC_USER_CONTROL_CODE_MAX+1];
361 void InputCEC::InitKeymap()
363 for (int i=0; i < CEC_USER_CONTROL_CODE_MAX + 1; i++)
365 cec_keymap[i] = NULL;
368 NAMETRICK2(CEC_USER_CONTROL_CODE_,SELECT);
369 NAMETRICK2(CEC_USER_CONTROL_CODE_,UP);
370 NAMETRICK2(CEC_USER_CONTROL_CODE_,DOWN);
371 NAMETRICK2(CEC_USER_CONTROL_CODE_,LEFT);
372 NAMETRICK2(CEC_USER_CONTROL_CODE_,RIGHT);
373 NAMETRICK2(CEC_USER_CONTROL_CODE_,RIGHT_UP);
374 NAMETRICK2(CEC_USER_CONTROL_CODE_,RIGHT_DOWN);
375 NAMETRICK2(CEC_USER_CONTROL_CODE_,LEFT_UP);
376 NAMETRICK2(CEC_USER_CONTROL_CODE_,LEFT_DOWN);
377 NAMETRICK2(CEC_USER_CONTROL_CODE_,ROOT_MENU);
378 NAMETRICK2(CEC_USER_CONTROL_CODE_,SETUP_MENU);
379 NAMETRICK2(CEC_USER_CONTROL_CODE_,CONTENTS_MENU);
380 NAMETRICK2(CEC_USER_CONTROL_CODE_,FAVORITE_MENU);
381 NAMETRICK2(CEC_USER_CONTROL_CODE_,EXIT);
382 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER0);
383 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER1);
384 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER2);
385 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER3);
386 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER4);
387 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER5);
388 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER6);
389 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER7);
390 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER8);
391 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER9);
392 NAMETRICK2(CEC_USER_CONTROL_CODE_,DOT);
393 NAMETRICK2(CEC_USER_CONTROL_CODE_,ENTER);
394 NAMETRICK2(CEC_USER_CONTROL_CODE_,CLEAR);
395 NAMETRICK2(CEC_USER_CONTROL_CODE_,NEXT_FAVORITE);
396 NAMETRICK2(CEC_USER_CONTROL_CODE_,CHANNEL_UP);
397 NAMETRICK2(CEC_USER_CONTROL_CODE_,CHANNEL_DOWN);
398 NAMETRICK2(CEC_USER_CONTROL_CODE_,PREVIOUS_CHANNEL);
399 NAMETRICK2(CEC_USER_CONTROL_CODE_,SOUND_SELECT);
400 NAMETRICK2(CEC_USER_CONTROL_CODE_,INPUT_SELECT);
401 NAMETRICK2(CEC_USER_CONTROL_CODE_,DISPLAY_INFORMATION);
402 NAMETRICK2(CEC_USER_CONTROL_CODE_,HELP);
403 NAMETRICK2(CEC_USER_CONTROL_CODE_,PAGE_UP);
404 NAMETRICK2(CEC_USER_CONTROL_CODE_,PAGE_DOWN);
405 NAMETRICK2(CEC_USER_CONTROL_CODE_,POWER );
406 NAMETRICK2(CEC_USER_CONTROL_CODE_,VOLUME_UP );
407 NAMETRICK2(CEC_USER_CONTROL_CODE_,VOLUME_DOWN );
408 NAMETRICK2(CEC_USER_CONTROL_CODE_,MUTE );
409 NAMETRICK2(CEC_USER_CONTROL_CODE_,PLAY );
410 NAMETRICK2(CEC_USER_CONTROL_CODE_,STOP );
411 NAMETRICK2(CEC_USER_CONTROL_CODE_,PAUSE );
412 NAMETRICK2(CEC_USER_CONTROL_CODE_,RECORD );
413 NAMETRICK2(CEC_USER_CONTROL_CODE_,REWIND );
414 NAMETRICK2(CEC_USER_CONTROL_CODE_,FAST_FORWARD );
415 NAMETRICK2(CEC_USER_CONTROL_CODE_,EJECT );
416 NAMETRICK2(CEC_USER_CONTROL_CODE_,FORWARD );
417 NAMETRICK2(CEC_USER_CONTROL_CODE_,BACKWARD );
418 NAMETRICK2(CEC_USER_CONTROL_CODE_,STOP_RECORD );
419 NAMETRICK2(CEC_USER_CONTROL_CODE_,PAUSE_RECORD );
420 NAMETRICK2(CEC_USER_CONTROL_CODE_,ANGLE );
421 NAMETRICK2(CEC_USER_CONTROL_CODE_,SUB_PICTURE );
422 NAMETRICK2(CEC_USER_CONTROL_CODE_,VIDEO_ON_DEMAND );
423 NAMETRICK2(CEC_USER_CONTROL_CODE_,ELECTRONIC_PROGRAM_GUIDE );
424 NAMETRICK2(CEC_USER_CONTROL_CODE_,TIMER_PROGRAMMING );
425 NAMETRICK2(CEC_USER_CONTROL_CODE_,INITIAL_CONFIGURATION );
426 NAMETRICK2(CEC_USER_CONTROL_CODE_,PLAY_FUNCTION );
427 NAMETRICK2(CEC_USER_CONTROL_CODE_,PAUSE_PLAY_FUNCTION );
428 NAMETRICK2(CEC_USER_CONTROL_CODE_,RECORD_FUNCTION );
429 NAMETRICK2(CEC_USER_CONTROL_CODE_,PAUSE_RECORD_FUNCTION );
430 NAMETRICK2(CEC_USER_CONTROL_CODE_,STOP_FUNCTION );
431 NAMETRICK2(CEC_USER_CONTROL_CODE_,MUTE_FUNCTION );
432 NAMETRICK2(CEC_USER_CONTROL_CODE_,RESTORE_VOLUME_FUNCTION );
433 NAMETRICK2(CEC_USER_CONTROL_CODE_,TUNE_FUNCTION );
434 NAMETRICK2(CEC_USER_CONTROL_CODE_,SELECT_MEDIA_FUNCTION );
435 NAMETRICK2(CEC_USER_CONTROL_CODE_,SELECT_AV_INPUT_FUNCTION );
436 NAMETRICK2(CEC_USER_CONTROL_CODE_,SELECT_AUDIO_INPUT_FUNCTION );
437 NAMETRICK2(CEC_USER_CONTROL_CODE_,POWER_TOGGLE_FUNCTION );
438 NAMETRICK2(CEC_USER_CONTROL_CODE_,POWER_OFF_FUNCTION );
439 NAMETRICK2(CEC_USER_CONTROL_CODE_,POWER_ON_FUNCTION );
440 NAMETRICK2(CEC_USER_CONTROL_CODE_,F1_BLUE );
441 NAMETRICK2(CEC_USER_CONTROL_CODE_,F2_RED );
442 NAMETRICK2(CEC_USER_CONTROL_CODE_,F3_GREEN );
443 NAMETRICK2(CEC_USER_CONTROL_CODE_,F4_YELLOW );
444 NAMETRICK2(CEC_USER_CONTROL_CODE_,F5 );
445 NAMETRICK2(CEC_USER_CONTROL_CODE_,DATA );
446 NAMETRICK2(CEC_USER_CONTROL_CODE_,AN_RETURN );
447 NAMETRICK2(CEC_USER_CONTROL_CODE_,AN_CHANNELS_LIST );
448 NAMETRICK2(CEC_USER_CONTROL_CODE_,MAX );
451 const char* InputCEC::getHardCodedHardwareKeyNamesForVompKey(u1 /* vompKey */)
456 std::string InputCEC::getHardwareKeyName(u8 hardwareKey)
459 if (hardwareKey > CEC_USER_CONTROL_CODE_MAX) return retval;
461 const char* desc = cec_keymap[hardwareKey];
468 char* rt = new char[10];
469 sprintf(rt, "0x%llx", hardwareKey);