]> git.vomp.tv Git - vompclient.git/blob - inputcec.cc
WIP [broken]
[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 "message.h"
29 #include "messagequeue.h"
30 #include "vdr.h"
31 #include "woptionpane.h"
32 #include "inputcec.h"
33
34
35 //#define W_G_HCW(type,code) ((static_cast<ULLONG>(type) << 32) | code)
36
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*/
40
41
42 InputCEC* InputCEC::instance = NULL;
43
44 int InputCEC::init()
45 {
46   InitHWCListwithDefaults();
47   InitKeymap();
48
49   // bcm_host_init(); //may be move to custom hardware init?
50   // now init cec
51   Log::getInstance()->log("InputCEC", Log::NOTICE, "Init LibCEC");
52   instance = this;
53
54   cec_config.Clear();
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);
66
67   strncpy(cec_config.strDeviceName, "vomp", sizeof(cec_config.strDeviceName));
68
69   cec_config.callbackParam = NULL; // I do not care
70   cec_config.callbacks = &cec_callbacks;
71
72   cec_adap = LibCecInitialise(&cec_config);
73   if (!cec_adap)
74   {
75     Log::getInstance()->log("InputCEC", Log::ERR, "Init LibCEC failed");
76     return 1;
77   }
78
79   cec_adap->InitVideoStandalone();
80
81   cec_adapter_descriptor cec_adapter_descriptors[10];
82   int adap_num = cec_adap->DetectAdapters(cec_adapter_descriptors, 10);
83   if (adap_num < 0)
84   {
85     Log::getInstance()->log("InputCEC", Log::ERR, "CEC:Failed to find adapter");
86     return 1;
87   }
88
89   if (adap_num == 0)
90   {
91     Log::getInstance()->log("InputCEC", Log::NOTICE, "CEC: No adapter found");
92     return 1;
93   }
94
95   if (!cec_adap->Open(cec_adapter_descriptors[0].strComName))
96   {
97     Log::getInstance()->log("InputCEC", Log::ERR, "CEC:Failed to open adapter");
98     return 1;
99   }
100
101   if (!cec_adap->SetActiveSource(cec_config.deviceTypes[0]))
102   {
103     Log::getInstance()->log("InputCEC", Log::ERR, "CEC:Failed set active source");
104     return 1;
105   }
106
107   return 1;
108 }
109
110 void InputCEC::shutdown()
111 {
112   if (cec_adap)
113   {
114     Log::getInstance()->log("InputCEC", Log::NOTICE, "Shutdown libcec begin");
115     cec_adap->SetInactiveView();
116     cec_adap->Close();
117     vc_cec_register_callback(NULL, NULL); //deactivate callback!
118     UnloadLibCec(cec_adap);
119     cec_adap = NULL;
120     Log::getInstance()->log("InputCEC", Log::NOTICE, "Shutdown libcec end");
121   }
122
123   instance = NULL;
124 }
125
126 void InputCEC::changePowerState(bool poweron)
127 {
128   if (cec_adap)
129   {
130     if (poweron)
131     {
132       //Log::getInstance()->log("InputCEC", Log::DEBUG, "CEC set active source");
133       cec_adap->SetActiveSource(cec_config.deviceTypes[0]);
134     }
135     else
136     {
137       //Log::getInstance()->log("InputCEC", Log::DEBUG, "CEC set inactive view");
138       cec_adap->SetInactiveView();
139     }
140   }
141 }
142
143 void InputCEC::incomingCECkey(int keys)
144 {
145   // Send INPUT message
146   Message* m = new Message();
147   m->message = Message::INPUT_EVENT;
148   m->to = Command::getInstance();
149   m->from = this;
150   m->parameter = TranslateHWC(keys);
151   MessageQueue::getInstance()->postMessage(m);
152 }
153
154 void InputCEC::incomingPowerkey(UCHAR key)
155 {
156   // Send INPUT message
157   Message* m = new Message();
158   m->message = Message::INPUT_EVENT;
159   m->to = Command::getInstance();
160   m->from = this;
161   m->parameter = key;
162   MessageQueue::getInstance()->postMessage(m);
163 }
164
165 void InputCEC::volumeUp()
166 {
167   cec_adap->VolumeUp();
168 }
169
170 void InputCEC::volumeDown()
171 {
172   cec_adap->VolumeDown();
173 }
174
175 void InputCEC::volumeMute()
176 {
177   cec_adap->AudioToggleMute();
178 }
179
180 bool InputCEC::loadOptionsfromServer(VDR* vdr)
181 {
182    // Set remote keys
183   char* name;
184   name = vdr->configLoad("InputCEC", "HandleVolume");
185
186   if (name != NULL)
187   {
188     if      (STRCASECMP(name, "Vomp") == 0) cechandlesvolume = false;
189     else if (STRCASECMP(name, "Cec") == 0) cechandlesvolume = true;
190     delete[] name;
191   }
192   return Input::loadOptionsfromServer(vdr);
193 }
194
195 bool InputCEC::saveOptionstoServer()
196 {
197   if (cechandlesvolume) VDR::getInstance()->configSave("InputCEC", "HandleVolume","Cec");
198   else VDR::getInstance()->configSave("InputCEC", "HandleVolume","Vomp");
199
200   return Input::saveOptionstoServer();
201 }
202
203 bool InputCEC::addOptionsToPanes(int panenumber,Options *options,WOptionPane* pane)
204 {
205   //if (!Input::addOptionsToPanes(panenumber, options, pane)) return false;
206
207   Option* option;
208   if (panenumber == 2)
209   {
210     static const char* volumeopts[]={"Vomp","Cec"};
211     option = new Option(100,tr("Volume handled by"), "InputCEC","HandleVolume",Option::TYPE_TEXT,/*4,2*/2,0,0,volumeopts,NULL,false,this);
212     options->push_back(option);
213     pane->addOptionLine(option);
214   }
215
216   return true;
217 }
218
219 bool InputCEC::handleOptionChanges(Option* option)
220 {
221     if (Input::handleOptionChanges(option))
222                 return true;
223         switch (option->id) {
224         case 100: {
225                 if (STRCASECMP(option->options[option->userSetChoice], "Vomp") == 0) {
226                         cechandlesvolume=false;
227                 }  else if (STRCASECMP(option->options[option->userSetChoice], "Cec")
228                                 == 0) {
229                         cechandlesvolume=true;
230                 }
231                 Log::getInstance()->log("InputCEC", Log::DEBUG, "Set volume handling to to %s %d",option->options[option->userSetChoice],cechandlesvolume);
232                 return true;
233         }
234         break;
235         };
236         return false;
237 }
238
239 // STATIC FUNCTIONS FOLLOW
240
241 void InputCEC::cecLogMessage(void* /* param */, const cec_log_message* message)
242 {
243   Log::getInstance()->log("InputCEC", Log::DEBUG, "CECLOG: %lld %d %s", message->time, message->level, message->message);
244 }
245
246 void InputCEC::cecKeyPress(void* /* param */, const cec_keypress* key)
247 {
248   //Log::getInstance()->log("InputCEC", Log::DEBUG, "Incoming cec key %d %d", key->keycode,key->duration);
249   if (key->duration == 0) instance->incomingCECkey(key->keycode);
250 }
251
252 void InputCEC::cecCommand(void* /* param */, const cec_command* command)
253 {
254   Log::getInstance()->log("InputCEC", Log::DEBUG, "CECCommand: %d", command->opcode);
255   switch (command->opcode)
256   {
257     case CEC_OPCODE_STANDBY:
258     {
259       if (command->initiator==CECDEVICE_TV)
260       {
261         instance->incomingPowerkey(POWEROFF);
262       }
263       break;
264     }
265     case CEC_OPCODE_DECK_CONTROL:
266     {
267       if (command->initiator == CECDEVICE_TV && command->parameters.size == 1
268             && command->parameters[0] == CEC_DECK_CONTROL_MODE_STOP)
269       {
270         instance->incomingCECkey(CEC_USER_CONTROL_CODE_STOP);
271       }
272       break;
273     }
274     case CEC_OPCODE_PLAY:
275     {
276       if (command->initiator == CECDEVICE_TV && command->parameters.size == 1)
277       {
278         if (command->parameters[0] == CEC_PLAY_MODE_PLAY_FORWARD)
279         {
280           instance->incomingCECkey(CEC_USER_CONTROL_CODE_PLAY);
281         }
282         else if (command->parameters[0] == CEC_PLAY_MODE_PLAY_STILL)
283         {
284           instance->incomingCECkey(CEC_USER_CONTROL_CODE_PAUSE);
285         }
286       }
287       break;
288     }
289     default:
290       break;
291   }
292 }
293
294 void InputCEC::cecConfigurationChanged(void* /* param */, const libcec_configuration*)
295 {
296   Log::getInstance()->log("InputCEC", Log::DEBUG, "CECConfig:"/*,config->string()*/);
297 }
298
299 void InputCEC::cecSourceActivated(void* /* param */, const cec_logical_address address, const uint8_t activated)
300 {
301   Log::getInstance()->log("InputCEC", Log::DEBUG, "CECSourceActivated: %d %d", address, activated);
302   if (activated == 1)
303   {
304     instance->incomingPowerkey(POWERON);
305   }
306 }
307
308 void InputCEC::InitHWCListwithDefaults()
309 {
310   //Processing CEC_Messages
311   translist[CEC_USER_CONTROL_CODE_NUMBER9] = NINE;
312   translist[CEC_USER_CONTROL_CODE_NUMBER8] = EIGHT;
313   translist[CEC_USER_CONTROL_CODE_NUMBER7] = SEVEN;
314   translist[CEC_USER_CONTROL_CODE_NUMBER6] = SIX;
315   translist[CEC_USER_CONTROL_CODE_NUMBER5] = FIVE;
316   translist[CEC_USER_CONTROL_CODE_NUMBER4] = FOUR;
317   translist[CEC_USER_CONTROL_CODE_NUMBER3] = THREE;
318   translist[CEC_USER_CONTROL_CODE_NUMBER2] = TWO;
319   translist[CEC_USER_CONTROL_CODE_NUMBER1] = ONE;
320   translist[CEC_USER_CONTROL_CODE_NUMBER0] = ZERO;
321   //translist[KEY_KPDOT] = STAR;
322
323   //translist[KEY_J] = GO; //j for JUMP TO instead of go to
324   translist[CEC_USER_CONTROL_CODE_F2_RED] = RED;
325   translist[CEC_USER_CONTROL_CODE_F3_GREEN] = GREEN;
326   translist[CEC_USER_CONTROL_CODE_F4_YELLOW] = YELLOW;
327   translist[CEC_USER_CONTROL_CODE_F1_BLUE] = BLUE;
328   //Processing Remote Style Messages
329   translist[CEC_USER_CONTROL_CODE_FAVORITE_MENU] = MENU;
330
331   translist[CEC_USER_CONTROL_CODE_RECORD] = RECORD;
332   translist[CEC_USER_CONTROL_CODE_PLAY] = PLAY; //Playback Televison
333   translist[CEC_USER_CONTROL_CODE_PAUSE] = PAUSE;
334   translist[CEC_USER_CONTROL_CODE_STOP] = STOP;
335   translist[CEC_USER_CONTROL_CODE_PAUSE_PLAY_FUNCTION] = PLAYPAUSE;
336   translist[CEC_USER_CONTROL_CODE_FORWARD] = SKIPFORWARD;
337   translist[CEC_USER_CONTROL_CODE_BACKWARD] = SKIPBACK;
338   translist[CEC_USER_CONTROL_CODE_FAST_FORWARD ] = FORWARD;
339   translist[CEC_USER_CONTROL_CODE_REWIND] = REVERSE;
340   translist[CEC_USER_CONTROL_CODE_MUTE] = MUTE;
341   translist[CEC_USER_CONTROL_CODE_VOLUME_UP] = VOLUMEUP;
342   translist[CEC_USER_CONTROL_CODE_VOLUME_DOWN] = VOLUMEDOWN;
343   translist[CEC_USER_CONTROL_CODE_CHANNEL_UP ] = CHANNELUP;
344   translist[CEC_USER_CONTROL_CODE_CHANNEL_DOWN] = CHANNELDOWN;
345 }
346
347 UCHAR InputCEC::TranslateHWCFixed(int code)
348 {
349   switch (code)
350   {
351     case CEC_USER_CONTROL_CODE_DOWN:            return DOWN;
352     case CEC_USER_CONTROL_CODE_UP:              return UP;
353     case CEC_USER_CONTROL_CODE_LEFT:            return LEFT;
354     case CEC_USER_CONTROL_CODE_RIGHT:           return RIGHT;
355     case CEC_USER_CONTROL_CODE_ROOT_MENU:
356     case CEC_USER_CONTROL_CODE_CONTENTS_MENU:
357     case CEC_USER_CONTROL_CODE_SETUP_MENU:      return MENU;
358     case CEC_USER_CONTROL_CODE_EXIT:            return BACK;
359     case CEC_USER_CONTROL_CODE_ENTER:
360     case CEC_USER_CONTROL_CODE_SELECT:
361     case CEC_USER_CONTROL_CODE_AN_RETURN:       return OK;
362     case CEC_USER_CONTROL_CODE_POWER:
363     case POWER:                                 return POWER;   //?
364     default:
365       return NA_UNKNOWN;
366   }
367 }
368
369
370 #define NAMETRICK2(pre, code) cec_keymap[pre ## code]=  #code
371 static const char * cec_keymap[CEC_USER_CONTROL_CODE_MAX+1];
372
373 void InputCEC::InitKeymap()
374 {
375   for (int i=0; i < CEC_USER_CONTROL_CODE_MAX + 1; i++)
376   {
377     cec_keymap[i] = NULL;
378   }
379
380   NAMETRICK2(CEC_USER_CONTROL_CODE_,SELECT);
381   NAMETRICK2(CEC_USER_CONTROL_CODE_,UP);
382   NAMETRICK2(CEC_USER_CONTROL_CODE_,DOWN);
383   NAMETRICK2(CEC_USER_CONTROL_CODE_,LEFT);
384   NAMETRICK2(CEC_USER_CONTROL_CODE_,RIGHT);
385   NAMETRICK2(CEC_USER_CONTROL_CODE_,RIGHT_UP);
386   NAMETRICK2(CEC_USER_CONTROL_CODE_,RIGHT_DOWN);
387   NAMETRICK2(CEC_USER_CONTROL_CODE_,LEFT_UP);
388   NAMETRICK2(CEC_USER_CONTROL_CODE_,LEFT_DOWN);
389   NAMETRICK2(CEC_USER_CONTROL_CODE_,ROOT_MENU);
390   NAMETRICK2(CEC_USER_CONTROL_CODE_,SETUP_MENU);
391   NAMETRICK2(CEC_USER_CONTROL_CODE_,CONTENTS_MENU);
392   NAMETRICK2(CEC_USER_CONTROL_CODE_,FAVORITE_MENU);
393   NAMETRICK2(CEC_USER_CONTROL_CODE_,EXIT);
394   NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER0);
395   NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER1);
396   NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER2);
397   NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER3);
398   NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER4);
399   NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER5);
400   NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER6);
401   NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER7);
402   NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER8);
403   NAMETRICK2(CEC_USER_CONTROL_CODE_,NUMBER9);
404   NAMETRICK2(CEC_USER_CONTROL_CODE_,DOT);
405   NAMETRICK2(CEC_USER_CONTROL_CODE_,ENTER);
406   NAMETRICK2(CEC_USER_CONTROL_CODE_,CLEAR);
407   NAMETRICK2(CEC_USER_CONTROL_CODE_,NEXT_FAVORITE);
408   NAMETRICK2(CEC_USER_CONTROL_CODE_,CHANNEL_UP);
409   NAMETRICK2(CEC_USER_CONTROL_CODE_,CHANNEL_DOWN);
410   NAMETRICK2(CEC_USER_CONTROL_CODE_,PREVIOUS_CHANNEL);
411   NAMETRICK2(CEC_USER_CONTROL_CODE_,SOUND_SELECT);
412   NAMETRICK2(CEC_USER_CONTROL_CODE_,INPUT_SELECT);
413   NAMETRICK2(CEC_USER_CONTROL_CODE_,DISPLAY_INFORMATION);
414   NAMETRICK2(CEC_USER_CONTROL_CODE_,HELP);
415   NAMETRICK2(CEC_USER_CONTROL_CODE_,PAGE_UP);
416   NAMETRICK2(CEC_USER_CONTROL_CODE_,PAGE_DOWN);
417   NAMETRICK2(CEC_USER_CONTROL_CODE_,POWER );
418   NAMETRICK2(CEC_USER_CONTROL_CODE_,VOLUME_UP );
419   NAMETRICK2(CEC_USER_CONTROL_CODE_,VOLUME_DOWN );
420   NAMETRICK2(CEC_USER_CONTROL_CODE_,MUTE );
421   NAMETRICK2(CEC_USER_CONTROL_CODE_,PLAY );
422   NAMETRICK2(CEC_USER_CONTROL_CODE_,STOP );
423   NAMETRICK2(CEC_USER_CONTROL_CODE_,PAUSE );
424   NAMETRICK2(CEC_USER_CONTROL_CODE_,RECORD );
425   NAMETRICK2(CEC_USER_CONTROL_CODE_,REWIND );
426   NAMETRICK2(CEC_USER_CONTROL_CODE_,FAST_FORWARD );
427   NAMETRICK2(CEC_USER_CONTROL_CODE_,EJECT );
428   NAMETRICK2(CEC_USER_CONTROL_CODE_,FORWARD );
429   NAMETRICK2(CEC_USER_CONTROL_CODE_,BACKWARD );
430   NAMETRICK2(CEC_USER_CONTROL_CODE_,STOP_RECORD );
431   NAMETRICK2(CEC_USER_CONTROL_CODE_,PAUSE_RECORD );
432   NAMETRICK2(CEC_USER_CONTROL_CODE_,ANGLE );
433   NAMETRICK2(CEC_USER_CONTROL_CODE_,SUB_PICTURE );
434   NAMETRICK2(CEC_USER_CONTROL_CODE_,VIDEO_ON_DEMAND );
435   NAMETRICK2(CEC_USER_CONTROL_CODE_,ELECTRONIC_PROGRAM_GUIDE );
436   NAMETRICK2(CEC_USER_CONTROL_CODE_,TIMER_PROGRAMMING );
437   NAMETRICK2(CEC_USER_CONTROL_CODE_,INITIAL_CONFIGURATION );
438   NAMETRICK2(CEC_USER_CONTROL_CODE_,PLAY_FUNCTION );
439   NAMETRICK2(CEC_USER_CONTROL_CODE_,PAUSE_PLAY_FUNCTION );
440   NAMETRICK2(CEC_USER_CONTROL_CODE_,RECORD_FUNCTION );
441   NAMETRICK2(CEC_USER_CONTROL_CODE_,PAUSE_RECORD_FUNCTION );
442   NAMETRICK2(CEC_USER_CONTROL_CODE_,STOP_FUNCTION );
443   NAMETRICK2(CEC_USER_CONTROL_CODE_,MUTE_FUNCTION );
444   NAMETRICK2(CEC_USER_CONTROL_CODE_,RESTORE_VOLUME_FUNCTION );
445   NAMETRICK2(CEC_USER_CONTROL_CODE_,TUNE_FUNCTION );
446   NAMETRICK2(CEC_USER_CONTROL_CODE_,SELECT_MEDIA_FUNCTION );
447   NAMETRICK2(CEC_USER_CONTROL_CODE_,SELECT_AV_INPUT_FUNCTION );
448   NAMETRICK2(CEC_USER_CONTROL_CODE_,SELECT_AUDIO_INPUT_FUNCTION );
449   NAMETRICK2(CEC_USER_CONTROL_CODE_,POWER_TOGGLE_FUNCTION );
450   NAMETRICK2(CEC_USER_CONTROL_CODE_,POWER_OFF_FUNCTION );
451   NAMETRICK2(CEC_USER_CONTROL_CODE_,POWER_ON_FUNCTION );
452   NAMETRICK2(CEC_USER_CONTROL_CODE_,F1_BLUE );
453   NAMETRICK2(CEC_USER_CONTROL_CODE_,F2_RED );
454   NAMETRICK2(CEC_USER_CONTROL_CODE_,F3_GREEN );
455   NAMETRICK2(CEC_USER_CONTROL_CODE_,F4_YELLOW );
456   NAMETRICK2(CEC_USER_CONTROL_CODE_,F5 );
457   NAMETRICK2(CEC_USER_CONTROL_CODE_,DATA );
458   NAMETRICK2(CEC_USER_CONTROL_CODE_,AN_RETURN );
459   NAMETRICK2(CEC_USER_CONTROL_CODE_,AN_CHANNELS_LIST );
460   NAMETRICK2(CEC_USER_CONTROL_CODE_,MAX );
461 }