]> git.vomp.tv Git - vompclient.git/blob - inputcec.cc
OSDOpenVG: Render on demand: Fix backing out of a view render race
[vompclient.git] / inputcec.cc
1  /*
2     Copyright 2004-2020 Chris Tallon; 2012 Marten Richter
3
4     This file is part of VOMP.
5
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.
10
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.
15
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/>.
18 */
19
20 #include <iostream>
21 #include <libcec/cec.h>
22 #include <libcec/cecloader.h>
23 using namespace CEC;
24
25 #include <bcm_host.h>
26
27 #include "log.h"
28 #include "vdr.h"
29 #include "woptionpane.h"
30 #include "inputcec.h"
31
32
33 //#define W_G_HCW(type,code) ((static_cast<ULLONG>(type) << 32) | code)
34
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*/
38
39
40 InputCEC* InputCEC::instance = NULL;
41
42 bool InputCEC::init()
43 {
44   InitHWCListwithDefaults();
45   InitKeymap();
46
47   // bcm_host_init(); //may be move to custom hardware init?
48   // now init cec
49   Log::getInstance()->log("InputCEC", Log::NOTICE, "Init LibCEC");
50   instance = this;
51
52   cec_config.Clear();
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);
64
65   strncpy(cec_config.strDeviceName, "vomp", sizeof(cec_config.strDeviceName));
66
67   cec_config.callbackParam = NULL; // I do not care
68   cec_config.callbacks = &cec_callbacks;
69
70   cec_adap = LibCecInitialise(&cec_config);
71   if (!cec_adap)
72   {
73     Log::getInstance()->log("InputCEC", Log::ERR, "Init LibCEC failed");
74     return false;
75   }
76
77   cec_adap->InitVideoStandalone();
78
79   cec_adapter_descriptor cec_adapter_descriptors[10];
80   int adap_num = cec_adap->DetectAdapters(cec_adapter_descriptors, 10);
81   if (adap_num < 0)
82   {
83     Log::getInstance()->log("InputCEC", Log::ERR, "CEC:Failed to find adapter");
84     return false;
85   }
86
87   if (adap_num == 0)
88   {
89     Log::getInstance()->log("InputCEC", Log::NOTICE, "CEC: No adapter found");
90     return false;
91   }
92
93   if (!cec_adap->Open(cec_adapter_descriptors[0].strComName))
94   {
95     Log::getInstance()->log("InputCEC", Log::ERR, "CEC:Failed to open adapter");
96     return false;
97   }
98
99   if (!cec_adap->SetActiveSource(cec_config.deviceTypes[0]))
100   {
101     Log::getInstance()->log("InputCEC", Log::ERR, "CEC:Failed set active source");
102     return false;
103   }
104
105   return true;
106 }
107
108 void InputCEC::shutdown()
109 {
110   if (cec_adap)
111   {
112     Log::getInstance()->log("InputCEC", Log::NOTICE, "Shutdown libcec begin");
113     cec_adap->SetInactiveView();
114     cec_adap->Close();
115     vc_cec_register_callback(NULL, NULL); //deactivate callback!
116     UnloadLibCec(cec_adap);
117     cec_adap = NULL;
118     Log::getInstance()->log("InputCEC", Log::NOTICE, "Shutdown libcec end");
119   }
120
121   instance = NULL;
122 }
123
124 void InputCEC::changePowerState(bool poweron)
125 {
126   if (cec_adap)
127   {
128     if (poweron)
129     {
130       //Log::getInstance()->log("InputCEC", Log::DEBUG, "CEC set active source");
131       cec_adap->SetActiveSource(cec_config.deviceTypes[0]);
132     }
133     else
134     {
135       //Log::getInstance()->log("InputCEC", Log::DEBUG, "CEC set inactive view");
136       cec_adap->SetInactiveView();
137     }
138   }
139 }
140
141 void InputCEC::incomingCECkey(int key)
142 {
143   sendInputKey(TranslateHWC(key));
144 }
145
146 void InputCEC::incomingPowerkey(UCHAR key)
147 {
148   sendInputKey(key);
149 }
150
151 void InputCEC::volumeUp()
152 {
153   cec_adap->VolumeUp();
154 }
155
156 void InputCEC::volumeDown()
157 {
158   cec_adap->VolumeDown();
159 }
160
161 void InputCEC::volumeMute()
162 {
163   cec_adap->AudioToggleMute();
164 }
165
166 bool InputCEC::loadOptionsFromServer(VDR* vdr)
167 {
168    // Set remote keys
169   char* name;
170   name = vdr->configLoad("InputCEC", "HandleVolume");
171
172   if (name != NULL)
173   {
174     if      (STRCASECMP(name, "Vomp") == 0) cechandlesvolume = false;
175     else if (STRCASECMP(name, "Cec") == 0) cechandlesvolume = true;
176     delete[] name;
177   }
178   return Input::loadOptionsFromServer(vdr);
179 }
180
181 bool InputCEC::saveOptionstoServer()
182 {
183   if (cechandlesvolume) VDR::getInstance()->configSave("InputCEC", "HandleVolume","Cec");
184   else VDR::getInstance()->configSave("InputCEC", "HandleVolume","Vomp");
185
186   return Input::saveOptionstoServer();
187 }
188
189 bool InputCEC::addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane)
190 {
191   //if (!Input::addOptionsToPanes(panenumber, options, pane)) return false;
192
193   Option* option;
194   if (panenumber == 2)
195   {
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);
200   }
201
202   return true;
203 }
204
205 bool InputCEC::handleOptionChanges(Option* option)
206 {
207     if (Input::handleOptionChanges(option))
208                 return true;
209         switch (option->id) {
210         case 100: {
211                 if (STRCASECMP(option->options[option->userSetChoice], "Vomp") == 0) {
212                         cechandlesvolume=false;
213                 }  else if (STRCASECMP(option->options[option->userSetChoice], "Cec")
214                                 == 0) {
215                         cechandlesvolume=true;
216                 }
217                 Log::getInstance()->log("InputCEC", Log::DEBUG, "Set volume handling to to %s %d",option->options[option->userSetChoice],cechandlesvolume);
218                 return true;
219         }
220         break;
221         };
222         return false;
223 }
224
225 // STATIC FUNCTIONS FOLLOW
226
227 void InputCEC::cecLogMessage(void* /* param */, const cec_log_message* message)
228 {
229   Log::getInstance()->log("InputCEC", Log::DEBUG, "CECLOG: %lld %d %s", message->time, message->level, message->message);
230 }
231
232 void InputCEC::cecKeyPress(void* /* param */, const cec_keypress* key)
233 {
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);
236 }
237
238 void InputCEC::cecCommand(void* /* param */, const cec_command* command)
239 {
240   Log::getInstance()->log("InputCEC", Log::DEBUG, "CECCommand: %d", command->opcode);
241   switch (command->opcode)
242   {
243     case CEC_OPCODE_STANDBY:
244     {
245       if (command->initiator==CECDEVICE_TV)
246       {
247         instance->incomingPowerkey(POWEROFF);
248       }
249       break;
250     }
251     case CEC_OPCODE_DECK_CONTROL:
252     {
253       if (command->initiator == CECDEVICE_TV && command->parameters.size == 1
254             && command->parameters[0] == CEC_DECK_CONTROL_MODE_STOP)
255       {
256         instance->incomingCECkey(CEC_USER_CONTROL_CODE_STOP);
257       }
258       break;
259     }
260     case CEC_OPCODE_PLAY:
261     {
262       if (command->initiator == CECDEVICE_TV && command->parameters.size == 1)
263       {
264         if (command->parameters[0] == CEC_PLAY_MODE_PLAY_FORWARD)
265         {
266           instance->incomingCECkey(CEC_USER_CONTROL_CODE_PLAY);
267         }
268         else if (command->parameters[0] == CEC_PLAY_MODE_PLAY_STILL)
269         {
270           instance->incomingCECkey(CEC_USER_CONTROL_CODE_PAUSE);
271         }
272       }
273       break;
274     }
275     default:
276       break;
277   }
278 }
279
280 void InputCEC::cecConfigurationChanged(void* /* param */, const libcec_configuration*)
281 {
282   Log::getInstance()->log("InputCEC", Log::DEBUG, "CECConfig:"/*,config->string()*/);
283 }
284
285 void InputCEC::cecSourceActivated(void* /* param */, const cec_logical_address address, const uint8_t activated)
286 {
287   Log::getInstance()->log("InputCEC", Log::DEBUG, "CECSourceActivated: %d %d", address, activated);
288   if (activated == 1)
289   {
290     instance->incomingPowerkey(POWERON);
291   }
292 }
293
294 void InputCEC::InitHWCListwithDefaults()
295 {
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;
308
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;
316
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;
331 }
332
333 UCHAR InputCEC::TranslateHWCFixed(int code)
334 {
335   switch (code)
336   {
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;   //?
350     default:
351       return NA_UNKNOWN;
352   }
353 }
354
355
356 #define NAMETRICK2(pre, code) cec_keymap[pre ## code]=  #code
357 static const char * cec_keymap[CEC_USER_CONTROL_CODE_MAX+1];
358
359 void InputCEC::InitKeymap()
360 {
361   for (int i=0; i < CEC_USER_CONTROL_CODE_MAX + 1; i++)
362   {
363     cec_keymap[i] = NULL;
364   }
365
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 );
447 }
448
449 const char* InputCEC::getHardCodedHardwareKeyNamesForVompKey(UCHAR /* vompKey */)
450 {
451   return ""; // FIXME
452 }
453
454 std::string InputCEC::getHardwareKeyName(int hardwareKey)
455 {
456   const char* desc = cec_keymap[hardwareKey];
457
458   std::string retval;
459
460   if (desc)
461   {
462     retval = desc;
463   }
464   else
465   {
466     char* rt = new char[10];
467     sprintf(rt, "0x%x", hardwareKey);
468     retval = rt;
469   }
470
471   return retval;
472 }
473