cec: fixed potential segfault in CCECProcessor::GetDeviceByPhysicalAddress()
[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
121 if (netConfig->ServerVersion >= CecServerVersion::Version1_5_1)
122 config.bSendInactiveSource = netConfig->SendInactiveSource ? 1 : 0;
123
124 if (netConfig->ServerVersion >= CecServerVersion::Version1_6_0)
125 {
126 config.bPowerOffDevicesOnStandby = netConfig->PowerOffDevicesOnStandby ? 1 : 0;
127 config.bShutdownOnStandby = netConfig->ShutdownOnStandby ? 1 : 0;
128 }
129
130 if (netConfig->ServerVersion >= CecServerVersion::Version1_6_2)
131 _snprintf_s(config.strDeviceLanguage, 3, context->marshal_as<const char*>(netConfig->DeviceLanguage));
132
133 config.callbacks = &g_cecCallbacks;
134 }
135
136 public:
137 array<CecAdapter ^> ^ FindAdapters(String ^ path)
138 {
139 cec_adapter *devices = new cec_adapter[10];
140
141 marshal_context ^ context = gcnew marshal_context();
142 const char* strPathC = path->Length > 0 ? context->marshal_as<const char*>(path) : NULL;
143
144 uint8_t iDevicesFound = m_libCec->FindAdapters(devices, 10, NULL);
145
146 array<CecAdapter ^> ^ adapters = gcnew array<CecAdapter ^>(iDevicesFound);
147 for (unsigned int iPtr = 0; iPtr < iDevicesFound; iPtr++)
148 adapters[iPtr] = gcnew CecAdapter(gcnew String(devices[iPtr].path), gcnew String(devices[iPtr].comm));
149
150 delete devices;
151 delete context;
152 return adapters;
153 }
154
155 bool Open(String ^ strPort, int iTimeoutMs)
156 {
157 CecCallbackMethods::EnableCallbacks(m_callbacks);
158 EnableCallbacks(m_callbacks);
159 marshal_context ^ context = gcnew marshal_context();
160 const char* strPortC = context->marshal_as<const char*>(strPort);
161 bool bReturn = m_libCec->Open(strPortC, iTimeoutMs);
162 delete context;
163 return bReturn;
164 }
165
166 void Close(void)
167 {
168 DisableCallbacks();
169 m_libCec->Close();
170 }
171
172 virtual void DisableCallbacks(void) override
173 {
174 // delete the callbacks, since these might already have been destroyed in .NET
175 CecCallbackMethods::DisableCallbacks();
176 if (m_libCec)
177 m_libCec->EnableCallbacks(NULL, NULL);
178 }
179
180 virtual bool EnableCallbacks(CecCallbackMethods ^ callbacks) override
181 {
182 if (m_libCec && CecCallbackMethods::EnableCallbacks(callbacks))
183 return m_libCec->EnableCallbacks(NULL, &g_cecCallbacks);
184
185 return false;
186 }
187
188 bool PingAdapter(void)
189 {
190 return m_libCec->PingAdapter();
191 }
192
193 bool StartBootloader(void)
194 {
195 return m_libCec->StartBootloader();
196 }
197
198 int GetMinLibVersion(void)
199 {
200 return m_libCec->GetMinLibVersion();
201 }
202
203 int GetLibVersionMajor(void)
204 {
205 return m_libCec->GetLibVersionMajor();
206 }
207
208 int GetLibVersionMinor(void)
209 {
210 return m_libCec->GetLibVersionMinor();
211 }
212
213 CecLogMessage ^ GetNextLogMessage(void)
214 {
215 cec_log_message msg;
216 if (m_libCec->GetNextLogMessage(&msg))
217 {
218 return gcnew CecLogMessage(gcnew String(msg.message), (CecLogLevel)msg.level, msg.time);
219 }
220
221 return gcnew CecLogMessage();
222 }
223
224 CecKeypress ^ GetNextKeypress(void)
225 {
226 cec_keypress key;
227 if (m_libCec->GetNextKeypress(&key))
228 {
229 return gcnew CecKeypress(key.keycode, key.duration);
230 }
231
232 return gcnew CecKeypress();
233 }
234
235 CecCommand ^ GetNextCommand(void)
236 {
237 cec_command command;
238 if (m_libCec->GetNextCommand(&command))
239 {
240 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);
241 for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++)
242 retVal->Parameters->PushBack(command.parameters[iPtr]);
243 return retVal;
244 }
245
246 return gcnew CecCommand();
247 }
248
249 bool Transmit(CecCommand ^ command)
250 {
251 cec_command ccommand;
252 cec_command::Format(ccommand, (cec_logical_address)command->Initiator, (cec_logical_address)command->Destination, (cec_opcode)command->Opcode);
253 ccommand.transmit_timeout = command->TransmitTimeout;
254 ccommand.eom = command->Eom;
255 ccommand.ack = command->Ack;
256 for (unsigned int iPtr = 0; iPtr < command->Parameters->Size; iPtr++)
257 ccommand.parameters.PushBack(command->Parameters->Data[iPtr]);
258
259 return m_libCec->Transmit(ccommand);
260 }
261
262 bool SetLogicalAddress(CecLogicalAddress logicalAddress)
263 {
264 return m_libCec->SetLogicalAddress((cec_logical_address) logicalAddress);
265 }
266
267 bool SetPhysicalAddress(uint16_t physicalAddress)
268 {
269 return m_libCec->SetPhysicalAddress(physicalAddress);
270 }
271
272 bool PowerOnDevices(CecLogicalAddress logicalAddress)
273 {
274 return m_libCec->PowerOnDevices((cec_logical_address) logicalAddress);
275 }
276
277 bool StandbyDevices(CecLogicalAddress logicalAddress)
278 {
279 return m_libCec->StandbyDevices((cec_logical_address) logicalAddress);
280 }
281
282 bool PollDevice(CecLogicalAddress logicalAddress)
283 {
284 return m_libCec->PollDevice((cec_logical_address) logicalAddress);
285 }
286
287 bool SetActiveSource(CecDeviceType type)
288 {
289 return m_libCec->SetActiveSource((cec_device_type) type);
290 }
291
292 bool SetDeckControlMode(CecDeckControlMode mode, bool sendUpdate)
293 {
294 return m_libCec->SetDeckControlMode((cec_deck_control_mode) mode, sendUpdate);
295 }
296
297 bool SetDeckInfo(CecDeckInfo info, bool sendUpdate)
298 {
299 return m_libCec->SetDeckInfo((cec_deck_info) info, sendUpdate);
300 }
301
302 bool SetInactiveView(void)
303 {
304 return m_libCec->SetInactiveView();
305 }
306
307 bool SetMenuState(CecMenuState state, bool sendUpdate)
308 {
309 return m_libCec->SetMenuState((cec_menu_state) state, sendUpdate);
310 }
311
312 bool SetOSDString(CecLogicalAddress logicalAddress, CecDisplayControl duration, String ^ message)
313 {
314 marshal_context ^ context = gcnew marshal_context();
315 const char* strMessageC = context->marshal_as<const char*>(message);
316
317 bool bReturn = m_libCec->SetOSDString((cec_logical_address) logicalAddress, (cec_display_control) duration, strMessageC);
318
319 delete context;
320 return bReturn;
321 }
322
323 bool SwitchMonitoring(bool enable)
324 {
325 return m_libCec->SwitchMonitoring(enable);
326 }
327
328 CecVersion GetDeviceCecVersion(CecLogicalAddress logicalAddress)
329 {
330 return (CecVersion) m_libCec->GetDeviceCecVersion((cec_logical_address) logicalAddress);
331 }
332
333 String ^ GetDeviceMenuLanguage(CecLogicalAddress logicalAddress)
334 {
335 cec_menu_language lang;
336 if (m_libCec->GetDeviceMenuLanguage((cec_logical_address) logicalAddress, &lang))
337 {
338 return gcnew String(lang.language);
339 }
340
341 return gcnew String("");
342 }
343
344 CecVendorId GetDeviceVendorId(CecLogicalAddress logicalAddress)
345 {
346 return (CecVendorId)m_libCec->GetDeviceVendorId((cec_logical_address) logicalAddress);
347 }
348
349 CecPowerStatus GetDevicePowerStatus(CecLogicalAddress logicalAddress)
350 {
351 return (CecPowerStatus) m_libCec->GetDevicePowerStatus((cec_logical_address) logicalAddress);
352 }
353
354 void RescanActiveDevices(void)
355 {
356 m_libCec->RescanActiveDevices();
357 }
358
359 CecLogicalAddresses ^ GetActiveDevices(void)
360 {
361 CecLogicalAddresses ^ retVal = gcnew CecLogicalAddresses();
362 unsigned int iDevices = 0;
363
364 cec_logical_addresses activeDevices = m_libCec->GetActiveDevices();
365
366 for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
367 if (activeDevices[iPtr])
368 retVal->Addresses[iDevices++] = (CecLogicalAddress)iPtr;
369
370 return retVal;
371 }
372
373 bool IsActiveDevice(CecLogicalAddress logicalAddress)
374 {
375 return m_libCec->IsActiveDevice((cec_logical_address)logicalAddress);
376 }
377
378 bool IsActiveDeviceType(CecDeviceType type)
379 {
380 return m_libCec->IsActiveDeviceType((cec_device_type)type);
381 }
382
383 bool SetHDMIPort(CecLogicalAddress address, uint8_t port)
384 {
385 return m_libCec->SetHDMIPort((cec_logical_address)address, port);
386 }
387
388 uint8_t VolumeUp(bool wait)
389 {
390 return m_libCec->VolumeUp(wait);
391 }
392
393 uint8_t VolumeDown(bool wait)
394 {
395 return m_libCec->VolumeDown(wait);
396 }
397
398 uint8_t MuteAudio(bool wait)
399 {
400 return m_libCec->MuteAudio(wait);
401 }
402
403 bool SendKeypress(CecLogicalAddress destination, CecUserControlCode key, bool wait)
404 {
405 return m_libCec->SendKeypress((cec_logical_address)destination, (cec_user_control_code)key, wait);
406 }
407
408 bool SendKeyRelease(CecLogicalAddress destination, bool wait)
409 {
410 return m_libCec->SendKeyRelease((cec_logical_address)destination, wait);
411 }
412
413 String ^ GetDeviceOSDName(CecLogicalAddress logicalAddress)
414 {
415 cec_osd_name osd = m_libCec->GetDeviceOSDName((cec_logical_address) logicalAddress);
416 return gcnew String(osd.name);
417 }
418
419 CecLogicalAddress GetActiveSource()
420 {
421 return (CecLogicalAddress)m_libCec->GetActiveSource();
422 }
423
424 bool IsActiveSource(CecLogicalAddress logicalAddress)
425 {
426 return m_libCec->IsActiveSource((cec_logical_address)logicalAddress);
427 }
428
429 uint16_t GetDevicePhysicalAddress(CecLogicalAddress iAddress)
430 {
431 return m_libCec->GetDevicePhysicalAddress((cec_logical_address)iAddress);
432 }
433
434 bool SetStreamPath(CecLogicalAddress iAddress)
435 {
436 return m_libCec->SetStreamPath((cec_logical_address)iAddress);
437 }
438
439 bool SetStreamPath(uint16_t iPhysicalAddress)
440 {
441 return m_libCec->SetStreamPath(iPhysicalAddress);
442 }
443
444 CecLogicalAddresses ^GetLogicalAddresses(void)
445 {
446 CecLogicalAddresses ^addr = gcnew CecLogicalAddresses();
447 cec_logical_addresses libAddr = m_libCec->GetLogicalAddresses();
448 for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
449 addr->Addresses[iPtr] = (CecLogicalAddress)libAddr.addresses[iPtr];
450 addr->Primary = (CecLogicalAddress)libAddr.primary;
451 return addr;
452 }
453
454 bool GetCurrentConfiguration(LibCECConfiguration ^configuration)
455 {
456 libcec_configuration config;
457 config.Clear();
458
459 if (m_libCec->GetCurrentConfiguration(&config))
460 {
461 configuration->Update(config);
462 return true;
463 }
464 return false;
465 }
466
467 bool CanPersistConfiguration(void)
468 {
469 return m_libCec->CanPersistConfiguration();
470 }
471
472 bool PersistConfiguration(LibCECConfiguration ^configuration)
473 {
474 marshal_context ^ context = gcnew marshal_context();
475 libcec_configuration config;
476 ConvertConfiguration(context, configuration, config);
477
478 bool bReturn = m_libCec->PersistConfiguration(&config);
479
480 delete context;
481 return bReturn;
482 }
483
484 bool SetConfiguration(LibCECConfiguration ^configuration)
485 {
486 marshal_context ^ context = gcnew marshal_context();
487 libcec_configuration config;
488 ConvertConfiguration(context, configuration, config);
489
490 bool bReturn = m_libCec->SetConfiguration(&config);
491
492 delete context;
493 return bReturn;
494 }
495
496 bool IsLibCECActiveSource()
497 {
498 return m_libCec->IsLibCECActiveSource();
499 }
500
501 bool GetDeviceInformation(String ^ port, LibCECConfiguration ^configuration, uint32_t timeoutMs)
502 {
503 bool bReturn(false);
504 marshal_context ^ context = gcnew marshal_context();
505
506 libcec_configuration config;
507 config.Clear();
508
509 const char* strPortC = port->Length > 0 ? context->marshal_as<const char*>(port) : NULL;
510
511 if (m_libCec->GetDeviceInformation(strPortC, &config, timeoutMs))
512 {
513 configuration->Update(config);
514 bReturn = true;
515 }
516
517 delete context;
518 return bReturn;
519 }
520
521 String ^ ToString(CecLogicalAddress iAddress)
522 {
523 const char *retVal = m_libCec->ToString((cec_logical_address)iAddress);
524 return gcnew String(retVal);
525 }
526
527 String ^ ToString(CecVendorId iVendorId)
528 {
529 const char *retVal = m_libCec->ToString((cec_vendor_id)iVendorId);
530 return gcnew String(retVal);
531 }
532
533 String ^ ToString(CecVersion iVersion)
534 {
535 const char *retVal = m_libCec->ToString((cec_version)iVersion);
536 return gcnew String(retVal);
537 }
538
539 String ^ ToString(CecPowerStatus iState)
540 {
541 const char *retVal = m_libCec->ToString((cec_power_status)iState);
542 return gcnew String(retVal);
543 }
544
545 String ^ ToString(CecMenuState iState)
546 {
547 const char *retVal = m_libCec->ToString((cec_menu_state)iState);
548 return gcnew String(retVal);
549 }
550
551 String ^ ToString(CecDeckControlMode iMode)
552 {
553 const char *retVal = m_libCec->ToString((cec_deck_control_mode)iMode);
554 return gcnew String(retVal);
555 }
556
557 String ^ ToString(CecDeckInfo status)
558 {
559 const char *retVal = m_libCec->ToString((cec_deck_info)status);
560 return gcnew String(retVal);
561 }
562
563 String ^ ToString(CecOpcode opcode)
564 {
565 const char *retVal = m_libCec->ToString((cec_opcode)opcode);
566 return gcnew String(retVal);
567 }
568
569 String ^ ToString(CecSystemAudioStatus mode)
570 {
571 const char *retVal = m_libCec->ToString((cec_system_audio_status)mode);
572 return gcnew String(retVal);
573 }
574
575 String ^ ToString(CecAudioStatus status)
576 {
577 const char *retVal = m_libCec->ToString((cec_audio_status)status);
578 return gcnew String(retVal);
579 }
580
581 String ^ ToString(CecClientVersion version)
582 {
583 const char *retVal = m_libCec->ToString((cec_client_version)version);
584 return gcnew String(retVal);
585 }
586
587 String ^ ToString(CecServerVersion version)
588 {
589 const char *retVal = m_libCec->ToString((cec_server_version)version);
590 return gcnew String(retVal);
591 }
592
593 private:
594 ICECAdapter * m_libCec;
595 CecCallbackMethods ^ m_callbacks;
596 };
597 }