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"
33 //#define W_G_HCW(type,code) ((static_cast<ULLONG>(type) << 32) | code)
35 //#define W_HCW_KC 1 /* key code as defined by kernel for keyboard and remotes through /dev/input */
36 //#define W_HCW_CEC 2 /* HDMI_CEC */
37 //#define W_HCW_LIRC 3 /* remote control LIRC*/
40 InputCEC* InputCEC::instance = NULL;
44 InitHWCListwithDefaults();
47 // bcm_host_init(); //may be move to custom hardware init?
49 Log::getInstance()->log("InputCEC", Log::NOTICE, "Init LibCEC");
53 cec_callbacks.Clear();
54 cec_callbacks.logMessage = cecLogMessage;
55 cec_callbacks.keyPress = cecKeyPress;
56 cec_callbacks.commandReceived = cecCommand;
57 cec_callbacks.configurationChanged = cecConfigurationChanged;
58 cec_callbacks.sourceActivated = cecSourceActivated;
59 cec_config.clientVersion = LIBCEC_VERSION_CURRENT;
60 cec_config.bActivateSource = 1;
61 //cec_config.deviceTypes.Add(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
62 cec_config.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
63 //cec_config.deviceTypes.Add(CEC_DEVICE_TYPE_TUNER);
65 strncpy(cec_config.strDeviceName, "vomp", sizeof(cec_config.strDeviceName));
67 cec_config.callbackParam = NULL; // I do not care
68 cec_config.callbacks = &cec_callbacks;
70 cec_adap = LibCecInitialise(&cec_config);
73 Log::getInstance()->log("InputCEC", Log::ERR, "Init LibCEC failed");
77 cec_adap->InitVideoStandalone();
79 cec_adapter_descriptor cec_adapter_descriptors[10];
80 int adap_num = cec_adap->DetectAdapters(cec_adapter_descriptors, 10);
83 Log::getInstance()->log("InputCEC", Log::ERR, "CEC:Failed to find adapter");
89 Log::getInstance()->log("InputCEC", Log::NOTICE, "CEC: No adapter found");
93 if (!cec_adap->Open(cec_adapter_descriptors[0].strComName))
95 Log::getInstance()->log("InputCEC", Log::ERR, "CEC:Failed to open adapter");
99 if (!cec_adap->SetActiveSource(cec_config.deviceTypes[0]))
101 Log::getInstance()->log("InputCEC", Log::ERR, "CEC:Failed set active source");
108 void InputCEC::shutdown()
112 Log::getInstance()->log("InputCEC", Log::NOTICE, "Shutdown libcec begin");
113 cec_adap->SetInactiveView();
115 vc_cec_register_callback(NULL, NULL); //deactivate callback!
116 UnloadLibCec(cec_adap);
118 Log::getInstance()->log("InputCEC", Log::NOTICE, "Shutdown libcec end");
124 void InputCEC::changePowerState(bool poweron)
130 //Log::getInstance()->log("InputCEC", Log::DEBUG, "CEC set active source");
131 cec_adap->SetActiveSource(cec_config.deviceTypes[0]);
135 //Log::getInstance()->log("InputCEC", Log::DEBUG, "CEC set inactive view");
136 cec_adap->SetInactiveView();
141 void InputCEC::incomingCECkey(int key)
143 sendInputKey(TranslateHWC(key));
146 void InputCEC::incomingPowerkey(UCHAR key)
151 void InputCEC::volumeUp()
153 cec_adap->VolumeUp();
156 void InputCEC::volumeDown()
158 cec_adap->VolumeDown();
161 void InputCEC::volumeMute()
163 cec_adap->AudioToggleMute();
166 bool InputCEC::loadOptionsFromServer(VDR* vdr)
170 name = vdr->configLoad("InputCEC", "HandleVolume");
174 if (STRCASECMP(name, "Vomp") == 0) cechandlesvolume = false;
175 else if (STRCASECMP(name, "Cec") == 0) cechandlesvolume = true;
178 return Input::loadOptionsFromServer(vdr);
181 bool InputCEC::saveOptionstoServer()
183 if (cechandlesvolume) VDR::getInstance()->configSave("InputCEC", "HandleVolume","Cec");
184 else VDR::getInstance()->configSave("InputCEC", "HandleVolume","Vomp");
186 return Input::saveOptionstoServer();
189 bool InputCEC::addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane)
191 //if (!Input::addOptionsToPanes(panenumber, options, pane)) return false;
196 static const char* volumeopts[]={"Vomp","Cec"};
197 option = new Option(100,tr("Volume handled by"), "InputCEC","HandleVolume",Option::TYPE_TEXT,/*4,2*/2,0,0,volumeopts,NULL,false,this);
198 options->push_back(option);
199 pane->addOptionLine(option);
205 bool InputCEC::handleOptionChanges(Option* option)
207 if (Input::handleOptionChanges(option))
209 switch (option->id) {
211 if (STRCASECMP(option->options[option->userSetChoice], "Vomp") == 0) {
212 cechandlesvolume=false;
213 } else if (STRCASECMP(option->options[option->userSetChoice], "Cec")
215 cechandlesvolume=true;
217 Log::getInstance()->log("InputCEC", Log::DEBUG, "Set volume handling to to %s %d",option->options[option->userSetChoice],cechandlesvolume);
225 // STATIC FUNCTIONS FOLLOW
227 void InputCEC::cecLogMessage(void* /* param */, const cec_log_message* message)
229 Log::getInstance()->log("InputCEC", Log::DEBUG, "CECLOG: %lld %d %s", message->time, message->level, message->message);
232 void InputCEC::cecKeyPress(void* /* param */, const cec_keypress* key)
234 //Log::getInstance()->log("InputCEC", Log::DEBUG, "Incoming cec key %d %d", key->keycode,key->duration);
235 if (key->duration == 0) instance->incomingCECkey(key->keycode);
238 void InputCEC::cecCommand(void* /* param */, const cec_command* command)
240 Log::getInstance()->log("InputCEC", Log::DEBUG, "CECCommand: %d", command->opcode);
241 switch (command->opcode)
243 case CEC_OPCODE_STANDBY:
245 if (command->initiator==CECDEVICE_TV)
247 instance->incomingPowerkey(POWEROFF);
251 case CEC_OPCODE_DECK_CONTROL:
253 if (command->initiator == CECDEVICE_TV && command->parameters.size == 1
254 && command->parameters[0] == CEC_DECK_CONTROL_MODE_STOP)
256 instance->incomingCECkey(CEC_USER_CONTROL_CODE_STOP);
260 case CEC_OPCODE_PLAY:
262 if (command->initiator == CECDEVICE_TV && command->parameters.size == 1)
264 if (command->parameters[0] == CEC_PLAY_MODE_PLAY_FORWARD)
266 instance->incomingCECkey(CEC_USER_CONTROL_CODE_PLAY);
268 else if (command->parameters[0] == CEC_PLAY_MODE_PLAY_STILL)
270 instance->incomingCECkey(CEC_USER_CONTROL_CODE_PAUSE);
280 void InputCEC::cecConfigurationChanged(void* /* param */, const libcec_configuration*)
282 Log::getInstance()->log("InputCEC", Log::DEBUG, "CECConfig:"/*,config->string()*/);
285 void InputCEC::cecSourceActivated(void* /* param */, const cec_logical_address address, const uint8_t activated)
287 Log::getInstance()->log("InputCEC", Log::DEBUG, "CECSourceActivated: %d %d", address, activated);
290 instance->incomingPowerkey(POWERON);
294 void InputCEC::InitHWCListwithDefaults()
296 //Processing CEC_Messages
297 translist[CEC_USER_CONTROL_CODE_NUMBER9] = NINE;
298 translist[CEC_USER_CONTROL_CODE_NUMBER8] = EIGHT;
299 translist[CEC_USER_CONTROL_CODE_NUMBER7] = SEVEN;
300 translist[CEC_USER_CONTROL_CODE_NUMBER6] = SIX;
301 translist[CEC_USER_CONTROL_CODE_NUMBER5] = FIVE;
302 translist[CEC_USER_CONTROL_CODE_NUMBER4] = FOUR;
303 translist[CEC_USER_CONTROL_CODE_NUMBER3] = THREE;
304 translist[CEC_USER_CONTROL_CODE_NUMBER2] = TWO;
305 translist[CEC_USER_CONTROL_CODE_NUMBER1] = ONE;
306 translist[CEC_USER_CONTROL_CODE_NUMBER0] = ZERO;
307 //translist[KEY_KPDOT] = STAR;
309 //translist[KEY_J] = GO; //j for JUMP TO instead of go to
310 translist[CEC_USER_CONTROL_CODE_F2_RED] = RED;
311 translist[CEC_USER_CONTROL_CODE_F3_GREEN] = GREEN;
312 translist[CEC_USER_CONTROL_CODE_F4_YELLOW] = YELLOW;
313 translist[CEC_USER_CONTROL_CODE_F1_BLUE] = BLUE;
314 //Processing Remote Style Messages
315 translist[CEC_USER_CONTROL_CODE_FAVORITE_MENU] = MENU;
317 translist[CEC_USER_CONTROL_CODE_RECORD] = RECORD;
318 translist[CEC_USER_CONTROL_CODE_PLAY] = PLAY; //Playback Televison
319 translist[CEC_USER_CONTROL_CODE_PAUSE] = PAUSE;
320 translist[CEC_USER_CONTROL_CODE_STOP] = STOP;
321 translist[CEC_USER_CONTROL_CODE_PAUSE_PLAY_FUNCTION] = PLAYPAUSE;
322 translist[CEC_USER_CONTROL_CODE_FORWARD] = SKIPFORWARD;
323 translist[CEC_USER_CONTROL_CODE_BACKWARD] = SKIPBACK;
324 translist[CEC_USER_CONTROL_CODE_FAST_FORWARD ] = FORWARD;
325 translist[CEC_USER_CONTROL_CODE_REWIND] = REVERSE;
326 translist[CEC_USER_CONTROL_CODE_MUTE] = MUTE;
327 translist[CEC_USER_CONTROL_CODE_VOLUME_UP] = VOLUMEUP;
328 translist[CEC_USER_CONTROL_CODE_VOLUME_DOWN] = VOLUMEDOWN;
329 translist[CEC_USER_CONTROL_CODE_CHANNEL_UP ] = CHANNELUP;
330 translist[CEC_USER_CONTROL_CODE_CHANNEL_DOWN] = CHANNELDOWN;
333 UCHAR InputCEC::TranslateHWCFixed(int code)
337 case CEC_USER_CONTROL_CODE_DOWN: return DOWN;
338 case CEC_USER_CONTROL_CODE_UP: return UP;
339 case CEC_USER_CONTROL_CODE_LEFT: return LEFT;
340 case CEC_USER_CONTROL_CODE_RIGHT: return RIGHT;
341 case CEC_USER_CONTROL_CODE_ROOT_MENU:
342 case CEC_USER_CONTROL_CODE_CONTENTS_MENU:
343 case CEC_USER_CONTROL_CODE_SETUP_MENU: return MENU;
344 case CEC_USER_CONTROL_CODE_EXIT: return BACK;
345 case CEC_USER_CONTROL_CODE_ENTER:
346 case CEC_USER_CONTROL_CODE_SELECT:
347 case CEC_USER_CONTROL_CODE_AN_RETURN: return OK;
348 case CEC_USER_CONTROL_CODE_POWER:
349 case POWER: return POWER; //?
356 #define NAMETRICK2(pre, code) cec_keymap[pre ## code]= #code
357 static const char * cec_keymap[CEC_USER_CONTROL_CODE_MAX+1];
359 void InputCEC::InitKeymap()
361 for (int i=0; i < CEC_USER_CONTROL_CODE_MAX + 1; i++)
363 cec_keymap[i] = NULL;
366 NAMETRICK2(CEC_USER_CONTROL_CODE_,SELECT);
367 NAMETRICK2(CEC_USER_CONTROL_CODE_,UP);
368 NAMETRICK2(CEC_USER_CONTROL_CODE_,DOWN);
369 NAMETRICK2(CEC_USER_CONTROL_CODE_,LEFT);
370 NAMETRICK2(CEC_USER_CONTROL_CODE_,RIGHT);
371 NAMETRICK2(CEC_USER_CONTROL_CODE_,RIGHT_UP);
372 NAMETRICK2(CEC_USER_CONTROL_CODE_,RIGHT_DOWN);
373 NAMETRICK2(CEC_USER_CONTROL_CODE_,LEFT_UP);
374 NAMETRICK2(CEC_USER_CONTROL_CODE_,LEFT_DOWN);
375 NAMETRICK2(CEC_USER_CONTROL_CODE_,ROOT_MENU);
376 NAMETRICK2(CEC_USER_CONTROL_CODE_,SETUP_MENU);
377 NAMETRICK2(CEC_USER_CONTROL_CODE_,CONTENTS_MENU);
378 NAMETRICK2(CEC_USER_CONTROL_CODE_,FAVORITE_MENU);
379 NAMETRICK2(CEC_USER_CONTROL_CODE_,EXIT);
380 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER0);
381 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER1);
382 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER2);
383 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER3);
384 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER4);
385 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER5);
386 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER6);
387 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER7);
388 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER8);
389 NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER9);
390 NAMETRICK2(CEC_USER_CONTROL_CODE_,DOT);
391 NAMETRICK2(CEC_USER_CONTROL_CODE_,ENTER);
392 NAMETRICK2(CEC_USER_CONTROL_CODE_,CLEAR);
393 NAMETRICK2(CEC_USER_CONTROL_CODE_,NEXT_FAVORITE);
394 NAMETRICK2(CEC_USER_CONTROL_CODE_,CHANNEL_UP);
395 NAMETRICK2(CEC_USER_CONTROL_CODE_,CHANNEL_DOWN);
396 NAMETRICK2(CEC_USER_CONTROL_CODE_,PREVIOUS_CHANNEL);
397 NAMETRICK2(CEC_USER_CONTROL_CODE_,SOUND_SELECT);
398 NAMETRICK2(CEC_USER_CONTROL_CODE_,INPUT_SELECT);
399 NAMETRICK2(CEC_USER_CONTROL_CODE_,DISPLAY_INFORMATION);
400 NAMETRICK2(CEC_USER_CONTROL_CODE_,HELP);
401 NAMETRICK2(CEC_USER_CONTROL_CODE_,PAGE_UP);
402 NAMETRICK2(CEC_USER_CONTROL_CODE_,PAGE_DOWN);
403 NAMETRICK2(CEC_USER_CONTROL_CODE_,POWER );
404 NAMETRICK2(CEC_USER_CONTROL_CODE_,VOLUME_UP );
405 NAMETRICK2(CEC_USER_CONTROL_CODE_,VOLUME_DOWN );
406 NAMETRICK2(CEC_USER_CONTROL_CODE_,MUTE );
407 NAMETRICK2(CEC_USER_CONTROL_CODE_,PLAY );
408 NAMETRICK2(CEC_USER_CONTROL_CODE_,STOP );
409 NAMETRICK2(CEC_USER_CONTROL_CODE_,PAUSE );
410 NAMETRICK2(CEC_USER_CONTROL_CODE_,RECORD );
411 NAMETRICK2(CEC_USER_CONTROL_CODE_,REWIND );
412 NAMETRICK2(CEC_USER_CONTROL_CODE_,FAST_FORWARD );
413 NAMETRICK2(CEC_USER_CONTROL_CODE_,EJECT );
414 NAMETRICK2(CEC_USER_CONTROL_CODE_,FORWARD );
415 NAMETRICK2(CEC_USER_CONTROL_CODE_,BACKWARD );
416 NAMETRICK2(CEC_USER_CONTROL_CODE_,STOP_RECORD );
417 NAMETRICK2(CEC_USER_CONTROL_CODE_,PAUSE_RECORD );
418 NAMETRICK2(CEC_USER_CONTROL_CODE_,ANGLE );
419 NAMETRICK2(CEC_USER_CONTROL_CODE_,SUB_PICTURE );
420 NAMETRICK2(CEC_USER_CONTROL_CODE_,VIDEO_ON_DEMAND );
421 NAMETRICK2(CEC_USER_CONTROL_CODE_,ELECTRONIC_PROGRAM_GUIDE );
422 NAMETRICK2(CEC_USER_CONTROL_CODE_,TIMER_PROGRAMMING );
423 NAMETRICK2(CEC_USER_CONTROL_CODE_,INITIAL_CONFIGURATION );
424 NAMETRICK2(CEC_USER_CONTROL_CODE_,PLAY_FUNCTION );
425 NAMETRICK2(CEC_USER_CONTROL_CODE_,PAUSE_PLAY_FUNCTION );
426 NAMETRICK2(CEC_USER_CONTROL_CODE_,RECORD_FUNCTION );
427 NAMETRICK2(CEC_USER_CONTROL_CODE_,PAUSE_RECORD_FUNCTION );
428 NAMETRICK2(CEC_USER_CONTROL_CODE_,STOP_FUNCTION );
429 NAMETRICK2(CEC_USER_CONTROL_CODE_,MUTE_FUNCTION );
430 NAMETRICK2(CEC_USER_CONTROL_CODE_,RESTORE_VOLUME_FUNCTION );
431 NAMETRICK2(CEC_USER_CONTROL_CODE_,TUNE_FUNCTION );
432 NAMETRICK2(CEC_USER_CONTROL_CODE_,SELECT_MEDIA_FUNCTION );
433 NAMETRICK2(CEC_USER_CONTROL_CODE_,SELECT_AV_INPUT_FUNCTION );
434 NAMETRICK2(CEC_USER_CONTROL_CODE_,SELECT_AUDIO_INPUT_FUNCTION );
435 NAMETRICK2(CEC_USER_CONTROL_CODE_,POWER_TOGGLE_FUNCTION );
436 NAMETRICK2(CEC_USER_CONTROL_CODE_,POWER_OFF_FUNCTION );
437 NAMETRICK2(CEC_USER_CONTROL_CODE_,POWER_ON_FUNCTION );
438 NAMETRICK2(CEC_USER_CONTROL_CODE_,F1_BLUE );
439 NAMETRICK2(CEC_USER_CONTROL_CODE_,F2_RED );
440 NAMETRICK2(CEC_USER_CONTROL_CODE_,F3_GREEN );
441 NAMETRICK2(CEC_USER_CONTROL_CODE_,F4_YELLOW );
442 NAMETRICK2(CEC_USER_CONTROL_CODE_,F5 );
443 NAMETRICK2(CEC_USER_CONTROL_CODE_,DATA );
444 NAMETRICK2(CEC_USER_CONTROL_CODE_,AN_RETURN );
445 NAMETRICK2(CEC_USER_CONTROL_CODE_,AN_CHANNELS_LIST );
446 NAMETRICK2(CEC_USER_CONTROL_CODE_,MAX );
449 const char* InputCEC::getHardCodedHardwareKeyNamesForVompKey(UCHAR /* vompKey */)
454 std::string InputCEC::getHardwareKeyName(int hardwareKey)
456 const char* desc = cec_keymap[hardwareKey];
466 char* rt = new char[10];
467 sprintf(rt, "0x%x", hardwareKey);