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