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