LibCecSharp: recreate the delegates properly when (re)connecting to LibCecSharp
[deb_libcec.git] / src / LibCecSharp / LibCecSharp.cpp
1 /*
2 * This file is part of the libCEC(R) library.
3 *
4 * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved.
5 * libCEC(R) is an original work, containing original code.
6 *
7 * libCEC(R) is a trademark of Pulse-Eight Limited.
8 *
9 * This program is dual-licensed; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 *
23 *
24 * Alternatively, you can license this library under a commercial license,
25 * please contact Pulse-Eight Licensing for more information.
26 *
27 * For more information contact:
28 * Pulse-Eight Licensing <license@pulse-eight.com>
29 * http://www.pulse-eight.com/
30 * http://www.pulse-eight.net/
31 */
32
33 #include "CecSharpTypes.h"
34 #using <System.dll>
35
36 using namespace System;
37 using namespace System::Runtime::InteropServices;
38 using namespace CEC;
39 using namespace msclr::interop;
40
41 namespace CecSharp
42 {
43 public ref class LibCecSharp : public CecCallbackMethods
44 {
45 public:
46 LibCecSharp(LibCECConfiguration ^config)
47 {
48 m_callbacks = config->Callbacks;
49 CecCallbackMethods::EnableCallbacks(m_callbacks);
50 if (!InitialiseLibCec(config))
51 throw gcnew Exception("Could not initialise LibCecSharp");
52 }
53
54 LibCecSharp(String ^ strDeviceName, CecDeviceTypeList ^ deviceTypes)
55 {
56 m_callbacks = gcnew CecCallbackMethods();
57 LibCECConfiguration ^config = gcnew LibCECConfiguration();
58 config->SetCallbacks(this);
59 config->DeviceName = strDeviceName;
60 config->DeviceTypes = deviceTypes;
61 if (!InitialiseLibCec(config))
62 throw gcnew Exception("Could not initialise LibCecSharp");
63 }
64
65 ~LibCecSharp(void)
66 {
67 Close();
68 m_libCec = NULL;
69 }
70
71 private:
72 !LibCecSharp(void)
73 {
74 Close();
75 m_libCec = NULL;
76 }
77
78 bool InitialiseLibCec(LibCECConfiguration ^config)
79 {
80 marshal_context ^ context = gcnew marshal_context();
81 libcec_configuration libCecConfig;
82 ConvertConfiguration(context, config, libCecConfig);
83
84 m_libCec = (ICECAdapter *) CECInitialise(&libCecConfig);
85
86 delete context;
87 return m_libCec != NULL;
88 }
89
90 void ConvertConfiguration(marshal_context ^context, LibCECConfiguration ^netConfig, CEC::libcec_configuration &config)
91 {
92 config.Clear();
93
94 _snprintf_s(config.strDeviceName, 13, context->marshal_as<const char*>(netConfig->DeviceName));
95 for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
96 config.deviceTypes.types[iPtr] = (cec_device_type)netConfig->DeviceTypes->Types[iPtr];
97
98 config.bAutodetectAddress = netConfig->AutodetectAddress ? 1 : 0;
99 config.iPhysicalAddress = netConfig->PhysicalAddress;
100 config.baseDevice = (cec_logical_address)netConfig->BaseDevice;
101 config.iHDMIPort = netConfig->HDMIPort;
102 config.clientVersion = (cec_client_version)netConfig->ClientVersion;
103 config.bGetSettingsFromROM = netConfig->GetSettingsFromROM ? 1 : 0;
104 config.bActivateSource = netConfig->ActivateSource ? 1 : 0;
105 config.tvVendor = (cec_vendor_id)netConfig->TvVendor;
106 config.wakeDevices.Clear();
107 for (int iPtr = 0; iPtr < 16; iPtr++)
108 {
109 if (netConfig->WakeDevices->IsSet((CecLogicalAddress)iPtr))
110 config.wakeDevices.Set((cec_logical_address)iPtr);
111 }
112 config.powerOffDevices.Clear();
113 for (int iPtr = 0; iPtr < 16; iPtr++)
114 {
115 if (netConfig->PowerOffDevices->IsSet((CecLogicalAddress)iPtr))
116 config.powerOffDevices.Set((cec_logical_address)iPtr);
117 }
118 config.bPowerOffScreensaver = netConfig->PowerOffScreensaver ? 1 : 0;
119 config.bPowerOffOnStandby = netConfig->PowerOffOnStandby ? 1 : 0;
120 config.callbacks = &g_cecCallbacks;
121 }
122
123 public:
124 array<CecAdapter ^> ^ FindAdapters(String ^ path)
125 {
126 cec_adapter *devices = new cec_adapter[10];
127
128 marshal_context ^ context = gcnew marshal_context();
129 const char* strPathC = path->Length > 0 ? context->marshal_as<const char*>(path) : NULL;
130
131 uint8_t iDevicesFound = m_libCec->FindAdapters(devices, 10, NULL);
132
133 array<CecAdapter ^> ^ adapters = gcnew array<CecAdapter ^>(iDevicesFound);
134 for (unsigned int iPtr = 0; iPtr < iDevicesFound; iPtr++)
135 adapters[iPtr] = gcnew CecAdapter(gcnew String(devices[iPtr].path), gcnew String(devices[iPtr].comm));
136
137 delete devices;
138 delete context;
139 return adapters;
140 }
141
142 bool Open(String ^ strPort, int iTimeoutMs)
143 {
144 CecCallbackMethods::EnableCallbacks(m_callbacks);
145 EnableCallbacks(m_callbacks);
146 marshal_context ^ context = gcnew marshal_context();
147 const char* strPortC = context->marshal_as<const char*>(strPort);
148 bool bReturn = m_libCec->Open(strPortC, iTimeoutMs);
149 delete context;
150 return bReturn;
151 }
152
153 void Close(void)
154 {
155 DisableCallbacks();
156 m_libCec->Close();
157 }
158
159 virtual void DisableCallbacks(void) override
160 {
161 // delete the callbacks, since these might already have been destroyed in .NET
162 CecCallbackMethods::DisableCallbacks();
163 if (m_libCec)
164 m_libCec->EnableCallbacks(NULL, NULL);
165 }
166
167 virtual bool EnableCallbacks(CecCallbackMethods ^ callbacks) override
168 {
169 if (m_libCec && CecCallbackMethods::EnableCallbacks(callbacks))
170 return m_libCec->EnableCallbacks(NULL, &g_cecCallbacks);
171
172 return false;
173 }
174
175 bool PingAdapter(void)
176 {
177 return m_libCec->PingAdapter();
178 }
179
180 bool StartBootloader(void)
181 {
182 return m_libCec->StartBootloader();
183 }
184
185 int GetMinLibVersion(void)
186 {
187 return m_libCec->GetMinLibVersion();
188 }
189
190 int GetLibVersionMajor(void)
191 {
192 return m_libCec->GetLibVersionMajor();
193 }
194
195 int GetLibVersionMinor(void)
196 {
197 return m_libCec->GetLibVersionMinor();
198 }
199
200 CecLogMessage ^ GetNextLogMessage(void)
201 {
202 cec_log_message msg;
203 if (m_libCec->GetNextLogMessage(&msg))
204 {
205 return gcnew CecLogMessage(gcnew String(msg.message), (CecLogLevel)msg.level, msg.time);
206 }
207
208 return gcnew CecLogMessage();
209 }
210
211 CecKeypress ^ GetNextKeypress(void)
212 {
213 cec_keypress key;
214 if (m_libCec->GetNextKeypress(&key))
215 {
216 return gcnew CecKeypress(key.keycode, key.duration);
217 }
218
219 return gcnew CecKeypress();
220 }
221
222 CecCommand ^ GetNextCommand(void)
223 {
224 cec_command command;
225 if (m_libCec->GetNextCommand(&command))
226 {
227 CecCommand ^ retVal = gcnew CecCommand((CecLogicalAddress)command.initiator, (CecLogicalAddress)command.destination, command.ack == 1 ? true : false, command.eom == 1 ? true : false, (CecOpcode)command.opcode, command.transmit_timeout);
228 for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++)
229 retVal->Parameters->PushBack(command.parameters[iPtr]);
230 return retVal;
231 }
232
233 return gcnew CecCommand();
234 }
235
236 bool Transmit(CecCommand ^ command)
237 {
238 cec_command ccommand;
239 cec_command::Format(ccommand, (cec_logical_address)command->Initiator, (cec_logical_address)command->Destination, (cec_opcode)command->Opcode);
240 ccommand.transmit_timeout = command->TransmitTimeout;
241 ccommand.eom = command->Eom;
242 ccommand.ack = command->Ack;
243 for (unsigned int iPtr = 0; iPtr < command->Parameters->Size; iPtr++)
244 ccommand.parameters.PushBack(command->Parameters->Data[iPtr]);
245
246 return m_libCec->Transmit(ccommand);
247 }
248
249 bool SetLogicalAddress(CecLogicalAddress logicalAddress)
250 {
251 return m_libCec->SetLogicalAddress((cec_logical_address) logicalAddress);
252 }
253
254 bool SetPhysicalAddress(uint16_t physicalAddress)
255 {
256 return m_libCec->SetPhysicalAddress(physicalAddress);
257 }
258
259 bool PowerOnDevices(CecLogicalAddress logicalAddress)
260 {
261 return m_libCec->PowerOnDevices((cec_logical_address) logicalAddress);
262 }
263
264 bool StandbyDevices(CecLogicalAddress logicalAddress)
265 {
266 return m_libCec->StandbyDevices((cec_logical_address) logicalAddress);
267 }
268
269 bool PollDevice(CecLogicalAddress logicalAddress)
270 {
271 return m_libCec->PollDevice((cec_logical_address) logicalAddress);
272 }
273
274 bool SetActiveSource(CecDeviceType type)
275 {
276 return m_libCec->SetActiveSource((cec_device_type) type);
277 }
278
279 bool SetDeckControlMode(CecDeckControlMode mode, bool sendUpdate)
280 {
281 return m_libCec->SetDeckControlMode((cec_deck_control_mode) mode, sendUpdate);
282 }
283
284 bool SetDeckInfo(CecDeckInfo info, bool sendUpdate)
285 {
286 return m_libCec->SetDeckInfo((cec_deck_info) info, sendUpdate);
287 }
288
289 bool SetInactiveView(void)
290 {
291 return m_libCec->SetInactiveView();
292 }
293
294 bool SetMenuState(CecMenuState state, bool sendUpdate)
295 {
296 return m_libCec->SetMenuState((cec_menu_state) state, sendUpdate);
297 }
298
299 bool SetOSDString(CecLogicalAddress logicalAddress, CecDisplayControl duration, String ^ message)
300 {
301 marshal_context ^ context = gcnew marshal_context();
302 const char* strMessageC = context->marshal_as<const char*>(message);
303
304 bool bReturn = m_libCec->SetOSDString((cec_logical_address) logicalAddress, (cec_display_control) duration, strMessageC);
305
306 delete context;
307 return bReturn;
308 }
309
310 bool SwitchMonitoring(bool enable)
311 {
312 return m_libCec->SwitchMonitoring(enable);
313 }
314
315 CecVersion GetDeviceCecVersion(CecLogicalAddress logicalAddress)
316 {
317 return (CecVersion) m_libCec->GetDeviceCecVersion((cec_logical_address) logicalAddress);
318 }
319
320 String ^ GetDeviceMenuLanguage(CecLogicalAddress logicalAddress)
321 {
322 cec_menu_language lang;
323 if (m_libCec->GetDeviceMenuLanguage((cec_logical_address) logicalAddress, &lang))
324 {
325 return gcnew String(lang.language);
326 }
327
328 return gcnew String("");
329 }
330
331 CecVendorId GetDeviceVendorId(CecLogicalAddress logicalAddress)
332 {
333 return (CecVendorId)m_libCec->GetDeviceVendorId((cec_logical_address) logicalAddress);
334 }
335
336 CecPowerStatus GetDevicePowerStatus(CecLogicalAddress logicalAddress)
337 {
338 return (CecPowerStatus) m_libCec->GetDevicePowerStatus((cec_logical_address) logicalAddress);
339 }
340
341 void RescanActiveDevices(void)
342 {
343 m_libCec->RescanActiveDevices();
344 }
345
346 CecLogicalAddresses ^ GetActiveDevices(void)
347 {
348 CecLogicalAddresses ^ retVal = gcnew CecLogicalAddresses();
349 unsigned int iDevices = 0;
350
351 cec_logical_addresses activeDevices = m_libCec->GetActiveDevices();
352
353 for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
354 if (activeDevices[iPtr])
355 retVal->Addresses[iDevices++] = (CecLogicalAddress)iPtr;
356
357 return retVal;
358 }
359
360 bool IsActiveDevice(CecLogicalAddress logicalAddress)
361 {
362 return m_libCec->IsActiveDevice((cec_logical_address)logicalAddress);
363 }
364
365 bool IsActiveDeviceType(CecDeviceType type)
366 {
367 return m_libCec->IsActiveDeviceType((cec_device_type)type);
368 }
369
370 bool SetHDMIPort(CecLogicalAddress address, uint8_t port)
371 {
372 return m_libCec->SetHDMIPort((cec_logical_address)address, port);
373 }
374
375 uint8_t VolumeUp(bool wait)
376 {
377 return m_libCec->VolumeUp(wait);
378 }
379
380 uint8_t VolumeDown(bool wait)
381 {
382 return m_libCec->VolumeDown(wait);
383 }
384
385 uint8_t MuteAudio(bool wait)
386 {
387 return m_libCec->MuteAudio(wait);
388 }
389
390 bool SendKeypress(CecLogicalAddress destination, CecUserControlCode key, bool wait)
391 {
392 return m_libCec->SendKeypress((cec_logical_address)destination, (cec_user_control_code)key, wait);
393 }
394
395 bool SendKeyRelease(CecLogicalAddress destination, bool wait)
396 {
397 return m_libCec->SendKeyRelease((cec_logical_address)destination, wait);
398 }
399
400 String ^ GetDeviceOSDName(CecLogicalAddress logicalAddress)
401 {
402 cec_osd_name osd = m_libCec->GetDeviceOSDName((cec_logical_address) logicalAddress);
403 return gcnew String(osd.name);
404 }
405
406 CecLogicalAddress GetActiveSource()
407 {
408 return (CecLogicalAddress)m_libCec->GetActiveSource();
409 }
410
411 bool IsActiveSource(CecLogicalAddress logicalAddress)
412 {
413 return m_libCec->IsActiveSource((cec_logical_address)logicalAddress);
414 }
415
416 uint16_t GetDevicePhysicalAddress(CecLogicalAddress iAddress)
417 {
418 return m_libCec->GetDevicePhysicalAddress((cec_logical_address)iAddress);
419 }
420
421 bool SetStreamPath(CecLogicalAddress iAddress)
422 {
423 return m_libCec->SetStreamPath((cec_logical_address)iAddress);
424 }
425
426 bool SetStreamPath(uint16_t iPhysicalAddress)
427 {
428 return m_libCec->SetStreamPath(iPhysicalAddress);
429 }
430
431 CecLogicalAddresses ^GetLogicalAddresses(void)
432 {
433 CecLogicalAddresses ^addr = gcnew CecLogicalAddresses();
434 cec_logical_addresses libAddr = m_libCec->GetLogicalAddresses();
435 for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
436 addr->Addresses[iPtr] = (CecLogicalAddress)libAddr.addresses[iPtr];
437 addr->Primary = (CecLogicalAddress)libAddr.primary;
438 return addr;
439 }
440
441 bool GetCurrentConfiguration(LibCECConfiguration ^configuration)
442 {
443 libcec_configuration config;
444 config.Clear();
445
446 if (m_libCec->GetCurrentConfiguration(&config))
447 {
448 configuration->Update(config);
449 return true;
450 }
451 return false;
452 }
453
454 bool CanPersistConfiguration(void)
455 {
456 return m_libCec->CanPersistConfiguration();
457 }
458
459 bool PersistConfiguration(LibCECConfiguration ^configuration)
460 {
461 marshal_context ^ context = gcnew marshal_context();
462 libcec_configuration config;
463 ConvertConfiguration(context, configuration, config);
464
465 bool bReturn = m_libCec->PersistConfiguration(&config);
466
467 delete context;
468 return bReturn;
469 }
470
471 bool SetConfiguration(LibCECConfiguration ^configuration)
472 {
473 marshal_context ^ context = gcnew marshal_context();
474 libcec_configuration config;
475 ConvertConfiguration(context, configuration, config);
476
477 bool bReturn = m_libCec->SetConfiguration(&config);
478
479 delete context;
480 return bReturn;
481 }
482
483 String ^ ToString(CecLogicalAddress iAddress)
484 {
485 const char *retVal = m_libCec->ToString((cec_logical_address)iAddress);
486 return gcnew String(retVal);
487 }
488
489 String ^ ToString(CecVendorId iVendorId)
490 {
491 const char *retVal = m_libCec->ToString((cec_vendor_id)iVendorId);
492 return gcnew String(retVal);
493 }
494
495 String ^ ToString(CecVersion iVersion)
496 {
497 const char *retVal = m_libCec->ToString((cec_version)iVersion);
498 return gcnew String(retVal);
499 }
500
501 String ^ ToString(CecPowerStatus iState)
502 {
503 const char *retVal = m_libCec->ToString((cec_power_status)iState);
504 return gcnew String(retVal);
505 }
506
507 String ^ ToString(CecMenuState iState)
508 {
509 const char *retVal = m_libCec->ToString((cec_menu_state)iState);
510 return gcnew String(retVal);
511 }
512
513 String ^ ToString(CecDeckControlMode iMode)
514 {
515 const char *retVal = m_libCec->ToString((cec_deck_control_mode)iMode);
516 return gcnew String(retVal);
517 }
518
519 String ^ ToString(CecDeckInfo status)
520 {
521 const char *retVal = m_libCec->ToString((cec_deck_info)status);
522 return gcnew String(retVal);
523 }
524
525 String ^ ToString(CecOpcode opcode)
526 {
527 const char *retVal = m_libCec->ToString((cec_opcode)opcode);
528 return gcnew String(retVal);
529 }
530
531 String ^ ToString(CecSystemAudioStatus mode)
532 {
533 const char *retVal = m_libCec->ToString((cec_system_audio_status)mode);
534 return gcnew String(retVal);
535 }
536
537 String ^ ToString(CecAudioStatus status)
538 {
539 const char *retVal = m_libCec->ToString((cec_audio_status)status);
540 return gcnew String(retVal);
541 }
542
543 String ^ ToString(CecClientVersion version)
544 {
545 const char *retVal = m_libCec->ToString((cec_client_version)version);
546 return gcnew String(retVal);
547 }
548
549 String ^ ToString(CecServerVersion version)
550 {
551 const char *retVal = m_libCec->ToString((cec_server_version)version);
552 return gcnew String(retVal);
553 }
554
555 private:
556 ICECAdapter * m_libCec;
557 CecCallbackMethods ^ m_callbacks;
558 };
559 }