Is there a working example of COM event handling in C++ Builder? - c++

I am trying to connect a C++ Builder app with a .NET service app, and would like the .NET service app to be able to send events back to the C++ Builder app.
Is there a working example of a C++ Builder app which can handle COM events?

There was an error in the DocWiki regarding handling COM Events. I was able to collect some examples from various places, and put them together here for reference.
The .NET application has the following:
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace IPractLib01
{
//
// GUID's to use for the COM objects.
[Guid("ACD03FE3-E506-4D87-BF8B-CC1F52E1FF0C")]
public interface IManagedInterface
{
int SendMessage(
string message
);
}
// Source interface with "event handlers" for COM objects to implement
[Guid("1ACAB463-55A3-4B3F-BE10-6252CDD93CE8")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] // use InterfaceIsDual to get callbacks by other than InvokeEvent()
public interface IIntelliPractEvents
{
[DispId(1)] void MessageReceived();
[DispId(2)] void MessageTextReceived(string message);
}
// Delegates for the events
public delegate void MessageReceivedEventHandler();
public delegate void MessageTextReceivedEventHandler(string message);
[Guid("1F4A7EDA-EE2A-4EA3-B213-A1911C5F766E")]
[ComSourceInterfaces(typeof(IIntelliPractEvents))]
public class IPractLib01Class : IManagedInterface
{
public event MessageReceivedEventHandler MessageReceived;
public event MessageTextReceivedEventHandler MessageTextReceived;
public int SendMessage(string message)
{
if (MessageReceived != null)
{
MessageReceived();
}
if (MessageTextReceived != null)
{
int len = message.Length;
string newMessage = "The message is '" + message + "', and the length of the message is " + len;
MessageTextReceived(newMessage);
}
return 0;
}
}
}
The C++ Builder application contains:
#include "Unit1.h"
#include "IPractLib01_TLB.h" // created with Component/Import Component/Import a Type Library
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// to register the assembly dll:
// regasm IPractLib01.dll /tlb /verbose
// Need to run regasm as administrator, due to need to modify registry. If a regular user login was used to map drives, the mappings are not normally seen by the administrator login. Use "net use" in the administrator login to map them for the administrator
static TCOM_IPractLib01Class iplClass;
// The DocWiki does not take the address of the DIID_, but that does not compile
class MyEventSinkClass : public TEventDispatcher<MyEventSinkClass, &DIID_IIntelliPractEvents>
{
public:
MyEventSinkClass(IUnknown* sourceClass);
~MyEventSinkClass();
// declare the methods of DIID_IIntelliPractEvents here
void __fastcall MessageReceived();
void __fastcall MessageTextReceived(BSTR message/*[in]*/);
virtual HRESULT InvokeEvent(DISPID id, TVariant* params = 0);
IUnknown* theSource_;
};
static MyEventSinkClass* theEventSink = NULL;
static void ConnectNetHandler(void)
{
if (!iplClass)
iplClass = CoIPractLib01Class::Create();
if (!theEventSink) {
theEventSink = new MyEventSinkClass(iplClass);
}
}
// All of the events come through InvokeEvent -- change the interface to InterfaceIsDual if you want events through the other routines
HRESULT MyEventSinkClass::InvokeEvent(DISPID id, TVariant* params)
{
ShowMessage("got InvokeEvent with DISPID " + String(id));
// params would need better handling in a real app
if (params) {
String st = params->operator WideString();
ShowMessage("String is " + st);
}
return 0;
}
MyEventSinkClass::MyEventSinkClass(IUnknown* sourceClass)
{
theSource_ = sourceClass;
ConnectEvents(sourceClass);
}
MyEventSinkClass::~MyEventSinkClass()
{
DisconnectEvents(theSource_);
}
// These two routines do not get called with InterfaceIsDispatch; change that to InterfaceIsDual for these routines to be called.
void __fastcall MyEventSinkClass::MessageReceived()
{
ShowMessage("Message handler received");
}
void __fastcall MyEventSinkClass::MessageTextReceived(BSTR message/*[in]*/)
{
ShowMessage(String("Message handler received with message: ") + message);
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ConnectNetHandler();
long result = -1;
TCOMIManagedInterface mif = iplClass;
if (!mif) {
ShowMessage("Unable to connect to interface");
return;
}
String theMessage = "the message";
mif->SendMessage(WideString(theMessage).c_bstr(), &result);
// check the IErrorInfo
// (Microsoft: Making a COM call that goes through a proxy-stub will clear any existing error object for the calling thread)
IErrorInfo *pperrinfo = NULL;
HRESULT hr = GetErrorInfo(0, &pperrinfo);
if (SUCCEEDED(hr) && pperrinfo) {
WideString wideStringMessage, wideStringDescription; // WideString is a wrapper for BSTR
pperrinfo->GetSource(&wideStringMessage);
pperrinfo->GetDescription(&wideStringDescription);
ShowMessage("Got error from " + String(wideStringMessage) + "; error description: " + String(wideStringDescription));
}
The DLL created by the .NET code must be registered with regasm /tlb to generate the type library, to allow C++ Builder to create the unit to implement COM. However, once the application has been created, regasm does not need to be called on the systems where this is deployed.

Related

Boost Message queue Not receiving across two processes

I wrote a small test app to use the Boos Message_Queue to send data between two processes. That all worked correctly and I was able to print the data that I sent.
I moved my test code into my main project and now the main project is not waking from the Receives. The main project runs as systems so I tracked down one error and saw that the message_queue was not checking the same memory location for some reason. I defined BOOST_INTERPROCESS_SHARED_DIR_PATH and then the main project was able to open the queue created by the test app. But when the test app sends the main project never woke from its receive. The main project should be running as system and the test app as a user. But I figured since it is sharing the memory location it should work correctly?
If I open the queue in the test app again it wakes and receives all of the messages right away. Am I missing something or is this a limitation on BOOST message_queue?
The code from the test app:
MessageQueue::MessageQueue(int, boost::interprocess::permissions perm) :
mq(boost::interprocess::create_only, "TestChannel", 100, sizeof(QueueData), perm)
{
}
MessageQueue::MessageQueue(bool) :
mq(boost::interprocess::open_only, "TestChannel")
{
}
MessageQueue::~MessageQueue()
{
int num = mq.get_num_msg();
wprintf(_T("sent: %d\n"), num);
boost::interprocess::message_queue::remove("TestChannel");
}
void MessageQueue::SetCommand(int i)
{
QueueData qd;
qd.fakeInfo = i;
qd.exit = false;
CoCreateGuid(&qd.msgGuid);
mq.send(&qd, sizeof(qd), 0);
OLECHAR* uidOleStr;
if (StringFromCLSID(qd.msgGuid, &uidOleStr) != S_OK)
throw std::runtime_error("Unknown error occurred when trying to convert a GUID to string!");
// Copy the ole str into a CString and then free it immediately, so we don't have to worry about it.
CString guidString(uidOleStr);
CoTaskMemFree(uidOleStr);
wprintf(_T("sent: %d, %s\n"), qd.fakeInfo, guidString);
}
void MessageQueue::WaitForCommand()
{
while(true)
{
QueueData qd;
size_t size, pri;
mq.receive(&qd, sizeof(qd), size, pri);
if (qd.fakeInfo == 2)
sendExit();
OLECHAR* uidOleStr;
if (StringFromCLSID(qd.msgGuid, &uidOleStr) != S_OK)
throw std::runtime_error("Unknown error occurred when trying to convert a GUID to string!");
// Copy the ole str into a CString and then free it immediately, so we don't have to worry about it.
CString guidString(uidOleStr);
CoTaskMemFree(uidOleStr);
wprintf(_T("Recieved: %d, %s\n"), qd.fakeInfo, guidString);
if (qd.exit)
break;
}
}
void MessageQueue::sendExit()
{
QueueData qd;
qd.exit = true;
mq.send(&qd, sizeof(qd), 0);
wprintf(_T("Sent Exit"));
}
.h file:
#pragma once
#define BOOST_INTERPROCESS_SHARED_DIR_PATH "C:\\Program Files (x86)\\Users"
#include <boost/interprocess/ipc/message_queue.hpp>
#include <boost/interprocess/permissions.hpp>
class QueueData
{
public:
int fakeInfo;
GUID msgGuid;
bool exit;
};
class MessageQueue
{
public:
MessageQueue(int, boost::interprocess::permissions perm);
MessageQueue(bool);
~MessageQueue();
boost::interprocess::message_queue mq;
void SetCommand(int);
void WaitForCommand();
void sendExit();
};
test app running code: (I have been using breakpoints)
void waiter()
{
MessageQueue mq(true);
mq.WaitForCommand();
}
void sender()
{
boost::interprocess::permissions perm;
perm.set_unrestricted();
try
{
boost::interprocess::message_queue::remove("TestChannel");
MessageQueue mq(2, perm);
mq.SetCommand(1);
mq.SetCommand(1);
mq.SetCommand(2);
}
catch (boost::interprocess::interprocess_exception e)
{
}
}
int main() {
waiter();
sender();
}
The code from the main project: (To test I did have it use the wait of the above code and still nothing)
void MemoryChannel::WaitForCmd( const std::function< void ( MemoryChannelCmd cmd, const char *pData, TCHAR *tempPath, GUID msgGuid ) > func )
{
QueueData mcObject;
size_t size, pri;
while (true)
{
pMCD->dataQueue.timed_receive(&mcObject, sizeof(mcObject), size, pri, boost::posix_time::microsec_clock::universal_time() + boost::posix_time::milliseconds(30000));
size_t num = pMCD->dataQueue.get_num_msg();
//func(MemoryChannelCmd::MEMORY_CHANNEL_RUN_SQL_SELECT, "", _T(""), mcObject.msgGuid);
}
}
Doesn't seem to be a code issue since it works in the test app but not in the main project even sharing code.
I am at a loss.
For inter-process communication the higher privilege process must start first. Only then can lower privilege processes can connect.
In your example system process should start the queue, test app connects and then they can communicate. This is why it works when restarting the test app.
It's designed this way to prevent lower privilege users to access higher privilege user memory without permission.

Memory leak with ActiveX in C++ Builder

I'm encountering a memory leak while using an activeX component in my project.
I'm working with Embarcadero Rad Studio 10.2 and developing a C++ industrial program that needs to communicate with a Codesys soft PLC on the same machine.
So, i have a ActiveX component that can handle the communication part between my program and the soft PLC.
I imported the ActiveX and everything seemed OK but i've found a memory leak that fills about 20MB per hour...
To import the library i followed the official guide:
http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Registering_a_COM_Object
I made lot of tests and I realized that the memory leak happens every time I work with ActiveX methods with variants involved. Looks like the program is not able to free some kind of temporary variants used by the component.
I've tested Visual Studio examples and everything works fine, so i think that the problems is generated by the type library that Rad Studio generates when I import the activeX component.
Also the ActiveX developer claims that everything works with Visual Studio.
I used also Dr. Memory and other tools that confirm the presence of the leak but can't provide details because i think the ActiveX is not compiled for debug.
Any idea about the reason for a behaviour like that?
There is some possibile incompatibility for an ActiveX in RAD studio?
Thanks in advance
Edit
An example that shows the ActiveX usage.
Unit1.cpp
#include <vcl.h>
#pragma hdrstop
#pragma package(smart_init)
#pragma resource "*.dfm"
#include <System.IOUtils.hpp>
#include "Unit1.h"
TForm1 *Form1;
// ---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
counter = 0;
// Setting the path for communication setting files required for later connection
if (TFile::Exists("PLCHandler.ini"))
{
iniPath = (wchar_t*)L"PLCHandler.ini";
logPath = (wchar_t*)L"Log.txt";
}
iResult = PLCHandler->MCreate(&iHandle);
try
{
// Creating the component and retrieving the handle for other methods
iResult = PLCHandler->MCreate(&iHandle);
if (iResult == 0)
{
iResult = PLCHandler->MConnect(iHandle, 0, iniPath, logPath);
if (iResult == 0)
{
connected = true;
LabeledEdit1->Text = "CONNECTED";
long int numeroSimboli = 0;
PLCHandler->MGetNumberOfSymbols(iHandle, &numeroSimboli);
LabeledEdit2->Text = numeroSimboli;
PLCHandler->MGetPlcStatus(iHandle, &iPLCStatus);
LabeledEdit3->Text = iPLCStatus;
}
}
else
{
LabeledEdit2->Text = "ERROR: " + (String)iResult;
}
}
catch (...)
{
LabeledEdit2->Text = "ERROR";
}
}
// ---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
// Timers for testing purposes, they launch the next method every ms. Changing timing only delays the problem
Timer1->Enabled = !Timer1->Enabled;
Timer2->Enabled = !Timer2->Enabled;
}
// ---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
// Asking to the PLC Handler the value of a PLC variable, identified by name
Variant varReceived;
BSTR name = SysAllocString(L"Test.GVL.Test_INT");
try
{
counter++;
LabeledEdit1->Text = counter;
// This is where i suppose the memory leak happens; the problem vanishes commenting the next line
varReceived = PLCHandler->MSyncReadVarFromPlc(iHandle, &iResult, name, 2);
LabeledEdit3->Text = varReceived.GetElement(0);
SysFreeString(name);
VarClear(varReceived);
}
catch (...)
{
VarClear(varReceived);
SysFreeString(name);
}
}
// ---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
Timer1Timer(this);
}
// ---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
// Other test: destroy the component and recreates it: the memory usages remains the same, no deallocation happens
try
{
PLCHandler->MDelete(&iHandle);
iResult = PLCHandler->MCreate(&iHandle);
if (iResult == 0)
{
iResult = PLCHandler->MConnect(iHandle, 0, iniPath, logPath);
if (iResult == 0)
{
connected = true;
LabeledEdit1->Text = "CONNECTED";
long int numeroSimboli = 0;
PLCHandler->MGetNumberOfSymbols(iHandle, &numeroSimboli);
LabeledEdit2->Text = numeroSimboli;
PLCHandler->MGetPlcStatus(iHandle, &iPLCStatus);
LabeledEdit3->Text = iPLCStatus;
}
}
else
{
LabeledEdit2->Text = "ERROR: " + (String)iResult;
}
}
catch (...)
{
LabeledEdit2->Text = "ERROR";
}
}
// ---------------------------------------------------------------------------
Unit1.h
#ifndef Unit1H
#define Unit1H
// ---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.ExtCtrls.hpp>
#include <Vcl.OleCtrls.hpp>
#include "PLCHANDLERXLib_OCX.h"
// ---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TTimer * Timer1;
TButton * Button1;
TLabeledEdit *LabeledEdit1;
TTimer * Timer2;
TLabeledEdit *LabeledEdit2;
TButton * Button3;
TPLCHandlerX *PLCHandler;
TLabeledEdit *LabeledEdit3;
void __fastcall Button1Click(TObject *Sender);
void __fastcall Timer1Timer(TObject *Sender);
void __fastcall Button2Click(TObject *Sender);
void __fastcall Button3Click(TObject *Sender);
private:
// User declarations
public: // User declarations
long int counter;
wchar_t* iniPath;
wchar_t* logPath;
long int iPLCStatus;
long int iHandle;
long int readSize;
long int writeSize;
long int iResult;
Byte unbyte;
bool connected;
__fastcall TForm1(TComponent* Owner);
};
// ---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
// ---------------------------------------------------------------------------
#endif
And as requested the TLB generated by RAD Studio while importing the ActiveX
.cpp File
// ************************************************************************ //
// WARNING
// -------
// The types declared in this file were generated from data read from a
// Type Library. If this type library is explicitly or indirectly (via
// another type library referring to this type library) re-imported, or the
// 'Refresh' command of the Type Library Editor activated while editing the
// Type Library, the contents of this file will be regenerated and all
// manual modifications will be lost.
// ************************************************************************ //
// $Rev: 87174 $
// File generated on 14/03/2018 11:22:13 from Type Library described below.
// ************************************************************************ //
// Type Lib: C:\PLCHandler_SDK_Windows_v16\bin\Windows\PLCHandlerX.ocx (1)
// LIBID: {BB4C0C2B-D94B-4F5C-A774-4DF59A2227FF}
// LCID: 0
// Helpfile: C:\PLCHandler_SDK_Windows_v16\bin\Windows\PLCHandlerX.hlp
// HelpString: PLCHandlerX ActiveX Control module
// DepndLst:
// (1) v2.0 stdole, (C:\Windows\SysWOW64\stdole2.tlb)
// SYS_KIND: SYS_WIN32
// ************************************************************************ //
#include <vcl.h>
#pragma hdrstop
#include "PLCHANDLERXLib_TLB.h"
#if !defined(__PRAGMA_PACKAGE_SMART_INIT)
#define __PRAGMA_PACKAGE_SMART_INIT
#pragma package(smart_init)
#endif
namespace Plchandlerxlib_tlb
{
// *********************************************************************//
// GUIDS declared in the TypeLibrary
// *********************************************************************//
const GUID LIBID_PLCHANDLERXLib = {0xBB4C0C2B, 0xD94B, 0x4F5C,{ 0xA7, 0x74, 0x4D,0xF5, 0x9A, 0x22,0x27, 0xFF} };
const GUID DIID__DPLCHandlerX = {0xA51B6208, 0x4C76, 0x4E79,{ 0xAC, 0x93, 0xB4,0x15, 0x7D, 0x6D,0x97, 0xC5} };
const GUID DIID__DPLCHandlerXEvents = {0xF2CC045D, 0x93E1, 0x4FE1,{ 0xA1, 0x5F, 0xE6,0x48, 0x18, 0x85,0x35, 0x5A} };
const GUID CLSID_PLCHandlerX = {0x99036BDD, 0x9A94, 0x4ED2,{ 0x89, 0x61, 0x42,0x0C, 0x74, 0xDD,0x51, 0xCE} };
};
.h File is too long for the question body (Full code here), but the MSyncReadVarsFromPlc method is
VARIANT __fastcall MSyncReadVarsFromPlc(long lHandle, long* plResult, BSTR pszSymbols, VARIANT SizeList, long lNumOfVars)
{
_TDispID _dispid(/* MSyncReadVarsFromPlc */ DISPID(45));
TAutoArgs<5> _args;
_args[1] = lHandle /*[VT_I4:0]*/;
_args[2] = plResult /*[VT_I4:1]*/;
_args[3] = pszSymbols /*[VT_BSTR:0]*/;
_args[4] = SizeList /*[VT_VARIANT:0]*/;
_args[5] = lNumOfVars /*[VT_I4:0]*/;
OleFunction(_dispid, _args);
return _args.GetRetVariant();
}
As you can see in the TLB, the MSyncReadVars method returns a VARIANT that actually contains an array of bytes with the requested variables values.
The Variant varReceived stores the returned VARIANT but is deallocated with VarClear when finished.
Any idea of what can generate the memory leak?
My feeling is that the returned VARIANT from MSyncReadVarsFromPlc is not deallocated after the method execution. But I can't see any way to solve this issue, also because same usage in a Visual Studio example works fine.
Can an ActiveX work fine in Visual Studio and not in RAD Studio?
You have a memory leak when calling MSyncReadVarFromPlc(). It returns an OLE VARIANT, which you are assigning to an RTL Variant. That assignment copies the data, and then the leak occurs because you are not calling VariantClear() on the original VARIANT.
A VARIANT is just a struct with data fields. Assigning a VARIANT directly to another VARIANT without using VariantCopy() just copies the field values as-is. Dynamically allocated data, like strings and arrays, are not re-allocated, the pointers are copied as-is.
A Variant, on the other hand, is a class wrapper that has copy semantics. Assigning a VARIANT (or another Variant) to a Variant allocates a new copy of dynamic data, preserving the original. The original and copy need to be cleared separately. You are leaking because you are not clearing the original VARIANT, only the copied Variant.
Change your call to MSyncReadVarFromPlc() to save the return value to a VARIANT instead of a Variant, and then call VariantClear() when you are done using it:
VARIANT varReceived;
...
varReceived = PLCHandler->MSyncReadVarFromPlc(iHandle, &iResult, name, 2);
...
VariantClear(&varReceived);

In webRTC no frame transmitted to browser from C++ code after calling onFrame in the capturer

I am trying to make my app up to date with webrtc. This is basically a desktop streaming application with a C++ application video streaming to a browser using webRTC.
My implementation used to use a bunch of deprecated stuff like SignalFrameCaptured and cricket::CapturedFrame.
Looking at webRTC right now it seems those classes/signals are not available.
Here is my capturer:
class Capturer
: public cricket::VideoCapturer,
public webrtc::DesktopCapturer::Callback
{
public:
sigslot::signal1<Capturer*> SignalDestroyed;
Capturer();
~Capturer();
void ResetSupportedFormats(const std::vector<cricket::VideoFormat>& formats);
bool CaptureFrame();
cricket::CaptureState Start(const cricket::VideoFormat& format) override;
void Stop() override;
bool IsRunning() override;
bool IsScreencast() const override;
bool GetPreferredFourccs(std::vector<uint32_t>* fourccs) override;
virtual void OnCaptureResult(webrtc::DesktopCapturer::Result result,
std::unique_ptr<webrtc::DesktopFrame> desktop_frame) override;
private:
bool running_;
int64_t initial_timestamp_;
int64_t next_timestamp_;
std::unique_ptr<webrtc::DesktopCapturer> _capturer;
};
Capturer::CaptureFrame() is called periodically from another thread and Capturer::OnCaptureResult is called as expected with a DesktopFrame as parameter.
Now looking at the implementation of OnCaptureResult:
void Capturer::OnCaptureResult(webrtc::DesktopCapturer::Result result,
std::unique_ptr<webrtc::DesktopFrame> desktopFrame)
{
if (result != webrtc::DesktopCapturer::Result::SUCCESS)
{
return; // Never called. Which leads me to conclude thedesktop capturer works
}
int width = desktopFrame->size().width();
int height = desktopFrame->size().height();
rtc::scoped_refptr<webrtc::I420Buffer> res_i420_frame = webrtc::I420Buffer::Create(width, height);
webrtc::ConvertToI420(webrtc::VideoType::kABGR,
desktopFrame->data(),
0, 0,
width, height,
0,
webrtc::kVideoRotation_0,
res_i420_frame);
webrtc::VideoFrame frame = webrtc::VideoFrame(res_i420_frame, webrtc::kVideoRotation_0, next_timestamp_ / rtc::kNumNanosecsPerMicrosec);
this->OnFrame(frame, width, height);
}
No frame are ever transmitted to the connected browser, as seen from chrome::webrtc-internals.
Back to the code, here is how I create the peerConnection:
void Conductor::connectToPeer() {
this->_peerConnectionFactory = webrtc::CreatePeerConnectionFactory();
if (!this->_peerConnectionFactory.get())
{
std::cerr << "Failed to initialize PeerConnectionFactory" << std::endl;
throw new std::runtime_error("Cannot initialize PeerConnectionFactory");
}
webrtc::PeerConnectionInterface::RTCConfiguration config;
webrtc::PeerConnectionInterface::IceServer server;
server.uri = "stun:stun.l.google.com:19302";
config.servers.push_back(server);
webrtc::FakeConstraints constraints;constraints.AddOptional(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp, "true");
this->_peerConnection = this->_peerConnectionFactory->CreatePeerConnection(config, &constraints, NULL, NULL, this);
if (!this->_peerConnection.get())
{
std::cerr << "Failed to initialize PeerConnection" << std::endl;
throw new std::runtime_error("Cannot initialize PeerConnection");
}
auto capturer = new Capturer();
CapturerThread *capturerThread = new CapturerThread(capturer); // This thread sole functionis to call CaptureFrameperiodically
rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> videoSource = this->_peerConnectionFactory->CreateVideoSource(capturer, NULL);
rtc::scoped_refptr<webrtc::VideoTrackInterface> videoTrack(this->_peerConnectionFactory->CreateVideoTrack("video_label", videoSource));
rtc::scoped_refptr<webrtc::MediaStreamInterface> stream = this->_peerConnectionFactory->CreateLocalMediaStream("stream_label");
stream->AddTrack(videoTrack);
if (!this->_peerConnection->AddStream(stream))
{
std::cerr << "Adding stream to PeerConnection failed" << std::endl;
throw new std::runtime_error("Cannot add stream");
}
typedef std::pair<std::string,rtc::scoped_refptr<webrtc::MediaStreamInterface>> MediaStreamPair;
this->_activeStreams.insert(MediaStreamPair(stream->label(), stream));
webrtc::SdpParseError error;
webrtc::SessionDescriptionInterface* sessionDescription(webrtc::CreateSessionDescription("offer", this->_offer, &error));
if (!sessionDescription)
{
std::cerr << "Cannot initialize session description." << std::endl;
throw new std::runtime_error("Cannot set session description");
}
this->_peerConnection->SetRemoteDescription(DummySetSessionDescriptionObserver::Create(), sessionDescription);
this->_peerConnection->CreateAnswer(this, NULL);
}
My problem is no video frames are even transmitted to the browser client even though both the capturer and the peer connection are in place as expected. Is there something I'm missing ?
I got to the bottom of this. The local description was simply not set after creating the answer.
Calling createAnswer will hopefully trigger the OnSuccess callback in the CreateSessionDescriptionObserver (in my case Conductor).
There I failed to save the answer as the local description. Here is how the OnSuccess method should be implemented:
void Conductor::OnSuccess(webrtc::SessionDescriptionInterface *desc)
{
this->_peerConnection->SetLocalDescription(DummySetSessionDescriptionObserver::Create(), desc);
}
Doing this will ultimately trigger OnIceGatheringChange with kIceGatheringComplete as parameter, meaning both sides are ready.
According with google group discuss-webrtc thread
you should implement VideoTrackSourceInterface. In my case, I used the base class AdaptedVideoTrackSource and I created a method FrameCaptured it's is called from my thread. In the method FrameCaptured I call the base method OnFrame. It's work fine !!!
class StreamSource : public rtc::AdaptedVideoTrackSource
{
void OnFrameCaptured(const webrtc::VideoFrame& frame);
}
void StreamSource::OnFrameCaptured(const webrtc::VideoFrame& frame)
{
OnFrame(frame);
}

avr-gcc: No such file or directory

I have been following the TinyOS tutorial at this link: http://www.cse.wustl.edu/~lu/cse521s/Slides/tutorial.pdf. I cannot get the final project code to compile in tinyos. I'm using windows xp with cygwin and all the latest rpms. When I try to compile the code with "make micaz" I get and error stating "avr gcc: no file or directory found". Here is the code. thanks in advance.
Makefile:
COMPONENT=DemoAppC
include $(MAKERULES)
DemoMessage.h
#ifndef __DEMOMESSAGE_H
#define __DEMOMESSAGE_H
enum
{
AM_DEMO_MSG = 231,
};
typedef nx_struct demo_msg
{
nx_uint16_t lastReading;
} demo_msg_t;
#endif
DemoP.nc
module DemoP
{
uses interface Boot;
uses interface Leds;
uses interface Read<uint16_t>;
uses interface SplitControl as RadioControl;
uses interface AMSend;
uses interface Receive;
uses interface Packet;
uses interface Timer<TMilli>;
}
implementation
{
message_t buf;
task void readSensor();
task void sendBuffer();
event void Boot.booted()
{
if(call RadioControl.start() != SUCCESS)
call Leds.led0On();
}
event void RadioControl.startDone(error_t err)
{
if(err != SUCCESS)
call Leds.led0On();
if(TOS_NODE_ID == 0)
call Timer.startPeriodic(64);
}
event void Timer.fired()
{
post readSensor();
}
task void readSensor()
{
if(call Read.read() != SUCCESS)
post readSensor();
}
event void Read.readDone(error_t err, uint16_t val)
{
demo_msg_t * payload = (demo_msg_t *)call Packet.getPayload(&buf, sizeof(d
payload->lastReading = val;
post sendBuffer();
}
task void sendBuffer()
{
if(call AMSend.send(AM_BROADCAST_ADDR,
&buf, sizeof(demo_msg_t)) != SUCCESS)
post sendBuffer();
}
event void AMSend.sendDone(message_t * jkdsakljads, error_t err)
{
if(err != SUCCESS)
post sendBuffer();
}
event message_t * Receive.receive(message_t * m,void * payload,uint8_t size)
{
demo_msg_t * dpayload = (demo_msg_t *)payload;
call Leds.set(dpayload->lastReading / 200);
return m;
}
event void RadioControl.stopDone(error_t err) {}
DemoAppC.nc
#include "DemoMessage.h"
configuration DemoAppC{}
implementation{
components DemoP, MainC;
DemoP.Boot -> MainC.Boot;
components LedsC;
DemoP.Leds -> LedsC;
components new HamamatsuS10871TsrC() as PhotoSensor;
DemoP.Read -> PhotoSensor;
components ActiveMessageC;
DemoP.RadioControl -> ActiveMessageC;
components new AMSenderC(AM_DEMO_MSG),
new AMReceiverC(AM_DEMO_MSG);
DemoP.AMSend -> AMSenderC;
DemoP.Receive -> AMReceiverC;
DemoP.Packet -> AMSenderC;
components new TimerMilliC();
DemoP.Timer -> TimerMilliC;
}
I had the same issue. Had to install avr-gcc from https://github.com/osx-cross/homebrew-avr
avr-gcc must not be installed correctly. Make sure you have all of the RPMs from http://docs.tinyos.net/tinywiki/index.php/Manual_installation_using_RPM_packages under the avr section installed.
If rpm -ivh avr-gcc-4.1.2-1.cygwin.i386.rpm returns that the package is already installed then you need to add/usr/bin to your $PATH.

How soon will Windows OS be able to wake from a wake timer?

I'm writing a program using C++ and Win APIs. I employed SetSuspendState() API to send the system into a sleep mode (with a possibility to wake on a wake timer, 'DisableWakeEvent' set to FALSE.) I then use CreateWaitableTimer and SetWaitableTimer API to set the actual timer. The issue is that sometimes the system does not wake up if I set the wake timer too soon after the system enters the sleep mode.
So I was curious if there's a minimum time that has to pass since the system is sent into a sleep mode before it can be woken up with a wake timer programmatically?
Right now. Your PC can wake up using a timer:
Schedule machine to wake up
C# Article if you dont mind : http://www.codeproject.com/Articles/49798/Wake-the-PC-from-standby-or-hibernation
using System;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using System.ComponentModel;
using System.Threading;
namespace WakeUPTimer
{
class WakeUP
{
[DllImport("kernel32.dll")]
public static extern SafeWaitHandle CreateWaitableTimer(IntPtr lpTimerAttributes,
bool bManualReset,
string lpTimerName);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWaitableTimer(SafeWaitHandle hTimer,
[In] ref long pDueTime,
int lPeriod,
IntPtr pfnCompletionRoutine,
IntPtr lpArgToCompletionRoutine,
bool fResume);
public event EventHandler Woken;
private BackgroundWorker bgWorker = new BackgroundWorker();
public WakeUP()
{
bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
bgWorker.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted);
}
public void SetWakeUpTime(DateTime time)
{
bgWorker.RunWorkerAsync(time.ToFileTime());
}
void bgWorker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
if (Woken != null)
{
Woken(this, new EventArgs());
}
}
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
long waketime = (long)e.Argument;
using (SafeWaitHandle handle =
CreateWaitableTimer(IntPtr.Zero, true,
this.GetType().Assembly.GetName().Name.ToString() + "Timer"))
{
if (SetWaitableTimer(handle, ref waketime, 0,
IntPtr.Zero, IntPtr.Zero, true))
{
using (EventWaitHandle wh = new EventWaitHandle(false,
EventResetMode.AutoReset))
{
wh.SafeWaitHandle = handle;
wh.WaitOne();
}
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
}
}
}
Or from the control panel : http://www.anuko.com/content/world_clock/faq/enable_wake_timers.htm