After some try, it's that I can see :
The extension execution is asynchronous from dart but not C, which is blocking while the current method has not completed.
Dart_NativeFunction ResolveName(Dart_Handle name, int argc);
Dart_Handle HandleError(Dart_Handle handle);
void wrapped_method(Dart_Port dest_port_id, Dart_CObject* message) {
Dart_Port reply_port_id = message->value.as_array.values[0]->value.as_send_port;
printf("Before sleep\n");
sleep(5);
printf("Hello from c !\n");
Dart_CObject result;
result.type = Dart_CObject_kBool;
result.value.as_bool = true;
Dart_PostCObject(reply_port_id, &result);
}
DART_EXPORT Dart_Handle sample_extension_Init(Dart_Handle parent_library) {
if (Dart_IsError(parent_library)) { return parent_library; }
Dart_Handle result_code = Dart_SetNativeResolver(parent_library, ResolveName);
if (Dart_IsError(result_code)) return result_code;
return Dart_Null();
}
void sample_extension_ServicePort(Dart_NativeArguments arguments) {
Dart_EnterScope();
Dart_SetReturnValue(arguments, Dart_Null());
Dart_Port service_port = Dart_NewNativePort("sample_extension_ServicePort", wrapped_method, true);
if (service_port != ILLEGAL_PORT) {
Dart_Handle send_port = HandleError(Dart_NewSendPort(service_port));
Dart_SetReturnValue(arguments, send_port);
}
Dart_ExitScope();
}
struct FunctionLookup {
const char* name;
Dart_NativeFunction function;
};
FunctionLookup function_list[] = {
{"SampleExtension_ServicePort", sample_extension_ServicePort},
{NULL, NULL}};
Dart_NativeFunction ResolveName(Dart_Handle name, int argc) {
if (!Dart_IsString(name)) return NULL;
Dart_NativeFunction result = NULL;
Dart_EnterScope();
const char* cname;
HandleError(Dart_StringToCString(name, &cname));
for (int i=0; function_list[i].name != NULL; ++i) {
if (strcmp(function_list[i].name, cname) == 0) {
result = function_list[i].function;
break;
}
}
Dart_ExitScope();
return result;
}
Dart_Handle HandleError(Dart_Handle handle) {
if (Dart_IsError(handle)) Dart_PropagateError(handle);
return handle;
}
When I execute 3 times a method calling the service port :
Hello from Dart
Hello from Dart
Before sleep
Hello from Dart
Hello from c !
Before sleep
Hello from c !
Before sleep
Hello from c !
Until every "Hello from c!", its sleep 5 seconds.
There is a way to be also asynchronous in the C side ?
I have seen :
DART_EXPORT Dart_Port Dart_NewNativePort(const char* name,
Dart_NativeMessageHandler handler,
bool handle_concurrently);
Great ! But ...
/* TODO(turnidge): Currently handle_concurrently is ignored. */
Is there a issue about that ? (I want to vote for it to follow solutions)
While the issue is not fixed, what is the best solution ?
Running code in a C fork ?
Related
I am developing a TCP client module for Hololens 1st gen with native C++/CX.
I create a packet class which contains 1 x (uint32_t) + 7 x (float)
The server is implemented in the synchronized manner, which streams the packets to the client (Hololens) every frame.
Receiver.h
namespace HoloNet {
public ref class holoATCFrameReceiver sealed
{
public:
holoATCFrameReceiver(
_In_ Windows::Networking::Sockets::StreamSocket^ streamSocket);
Windows::Foundation::IAsyncOperation<TrackerFrame^>^ ReceiveAsync();
private:
Concurrency::task<TrackerFrame^> ReceiveTrackerFrameAsync();
private:
Windows::Networking::Sockets::StreamSocket^ _streamSocket;
Windows::Storage::Streams::DataReader^ _reader;
bool _readInProgress;
};
}
and Receiver.cpp
namespace HoloNet {
holoATCFrameReceiver::holoATCFrameReceiver(
Windows::Networking::Sockets::StreamSocket ^ streamSocket)
: _streamSocket(streamSocket)
{
_readInProgress = false;
// reader
_reader = ref new Windows::Storage::Streams::DataReader(
_streamSocket->InputStream);
_reader->UnicodeEncoding =
Windows::Storage::Streams::UnicodeEncoding::Utf8;
_reader->ByteOrder =
Windows::Storage::Streams::ByteOrder::LittleEndian;
}
Windows::Foundation::IAsyncOperation<TrackerFrame^>^ holoATCFrameReceiver::ReceiveAsync()
{
return concurrency::create_async(
[this]()
{
return ReceiveTrackerFrameAsync();
});
}
Concurrency::task<TrackerFrame^>
holoATCFrameReceiver::ReceiveTrackerFrameAsync()
{
return concurrency::create_task(
_reader->LoadAsync(TrackerFrame::TrackerFrameLength)
).then([this](Concurrency::task<unsigned int> headerBytesLoadedTaskResult)
{
headerBytesLoadedTaskResult.wait();
const size_t frameBytesLoaded = headerBytesLoadedTaskResult.get();
if (TrackerFrame::TrackerFrameLength != frameBytesLoaded)
{
throw ref new Platform::FailureException();
}
_readInProgress = true;
TrackerFrame^ header;
TrackerFrame::Read(
_reader,
&header);
dbg::trace(
L"SensorFrameReceiver::ReceiveAsync: sensor %i: t( %f, %f %f ), q( %f, %f, %f, %f)",
header->sensorID,
header->x,
header->y,
header->z,
header->qw,
header->qx,
header->qy,
header->qz);
_readInProgress = false;
return header;
});
}
}
The error throws at * _reader->LoadAsync(TrackerFrame::TrackerFrameLength) *
The receiver is called in the client class like below:
void holoTcpATCClient::OnReceiveATCframe(TrackerFrame^& header) {
std::lock_guard<std::mutex> guard(_socketMutex);
// check read in process
if (_readInProcess)
{
return;
}
_readInProcess = true;
concurrency::create_task(
_receiver->ReceiveAsync()).then(
[&](concurrency::task<TrackerFrame^> sensorFrameTask)
{
sensorFrameTask.wait();
TrackerFrame^ sensorFrame = sensorFrameTask.get()
header = sensorFrame;
});
_readInProcess = false;
}
_receiver->ReceiveAsync() is the begining of the error.
I wonder whether there is a way to pretend this happens by doing some modification on LoadAsync() of DataReader for StreamSocket under concurrency:: create_task?
Thank you very much for your help in advance!
I want to play local video file in Qt platform using ffmpeg to decode.Everything is OK except that play speed is as twice as normal.
The first thing I think about is that there must be a sampling frequency involved.But to be a new to ffmpeg,I don't know how to fix this problem.
Above is my code to read frame,is anyone can tell me what's wrong with the code ?
void VideoThread::run()
{
m_pInFmtCtx = avformat_alloc_context(); //ini struct
char path[] = "d:/test.mp4";
// open specific file
if(avformat_open_input(&m_pInFmtCtx, *path, NULL, NULL)){
{
qDebug()<<"get rtsp failed";
return;
}
else
{
qDebug()<<"get rtsp success";
}
if(avformat_find_stream_info(m_pInFmtCtx, NULL) < 0)
{
qDebug()<<"could not find stream information";
return;
}
int nVideoIndex = -1;
for(int i = 0; i < m_pInFmtCtx->nb_streams; i++)
{
if(m_pInFmtCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
nVideoIndex = i;
break;
}
}
if(nVideoIndex == -1)
{
qDebug()<<"could not find video stream";
return;
}
qDebug("---------------- File Information ---------------");
m_pCodecCtx = m_pInFmtCtx->streams[nVideoIndex]->codec;
m_pCodec = avcodec_find_decoder(m_pCodecCtx->codec_id);
if(!m_pCodec)
{
qDebug()<<"could not find codec";
return;
}
//start Decoder
if (avcodec_open2(m_pCodecCtx, m_pCodec, NULL) < 0) {
qDebug("Could not open codec.\n");
return;
}
//malloc space for stroring frame
m_pFrame = av_frame_alloc();
m_pFrameRGB = av_frame_alloc();
m_pOutBuf = (uint8_t*)av_malloc(avpicture_get_size(AV_PIX_FMT_RGB32, m_pCodecCtx->width, m_pCodecCtx->height));
avpicture_fill((AVPicture*)m_pFrameRGB, m_pOutBuf, AV_PIX_FMT_RGB32, m_pCodecCtx->width, m_pCodecCtx->height);
//for color switch,from YUV to RGB
struct SwsContext *pImgCtx = sws_getContext(m_pCodecCtx->width, m_pCodecCtx->height, m_pCodecCtx->pix_fmt,
m_pCodecCtx->width, m_pCodecCtx->height, AV_PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL);
int nSize = m_pCodecCtx->width * m_pCodecCtx->height;
m_pPacket = (AVPacket *)av_malloc(sizeof(AVPacket));
if(av_new_packet(m_pPacket, nSize) != 0)
{
qDebug()<<"new packet failed";
}
//isInterruptionRequested is a flag,determine whether the thread is over
// read each frame from specific video file
while (!isInterruptionRequested())
{
int nGotPic = 0;
if(av_read_frame(m_pInFmtCtx, m_pPacket) >= 0)
{
if(m_pPacket->stream_index == nVideoIndex)
{
//avcodec_decode_video2()transform from packet to frame
if(avcodec_decode_video2(m_pCodecCtx, m_pFrame, &nGotPic, m_pPacket) < 0)
{
qDebug()<<"decode failed";
return;
}
if(nGotPic)
{ // transform to RGB color
sws_scale(pImgCtx, (const uint8_t* const*)m_pFrame->data,
m_pFrame->linesize, 0, m_pCodecCtx->height, m_pFrameRGB->data,
m_pFrameRGB->linesize);
// save to QImage,for later use
QImage *pImage = new QImage((uchar*)m_pOutBuf, m_pCodecCtx->width, m_pCodecCtx->height, QImage::Format_RGB32);
}
}
}
av_free_packet(m_pPacket);
msleep(5);
}
exec();
}
Is there a better example on how to implement multiple async requests.
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc ListSayHello1 (HelloRequest1) returns (stream HelloReply1) {}
rpc ListSayHello2 (HelloRequest2) returns (stream HelloReply2) {}
}
// The request message containing the user's name.
message HelloRequest1 {
string name = 1;
}
message HelloRequest2 {
string name = 1;
}
// The response message containing the greetings
message HelloReply1 {
string message = 1;
}
message HelloReply2 {
string message = 1;
}
I am using below async pattern to handle SayHello1, but now I want to add support for SayHello2. What should be the approach?
new CallData(&service_, cq_.get(), *this);
void* tag; // uniquely identifies a request.
bool ok;
while (true) {
// Block waiting to read the next event from the completion queue. The
// event is uniquely identified by its tag, which in this case is the
// memory address of a CallData instance.
// The return value of Next should always be checked. This return value
// tells us whether there is any kind of event or cq_ is shutting down.
GPR_ASSERT(cq_->Next(&tag, &ok));
GPR_ASSERT(ok);
static_cast<CallData*>(tag)->Proceed();
}
In CallData, I doing this
void CallData::Proceed()
{
if (status_ == CREATE) {
status_ = PROCESS;
service_->RequestListSayHello1(&ctx_, &request_, &writer_, cq_, cq_,
this);
}
...
}
It is not necessary to create extra completion queues. We just need to know how to handle what the completion queue returns. We can solve this by making a common base class, that is able to do the necessary functions:
class CallDataBase
{
protected:
virtual void WaitForRequest() = 0;
virtual void HandleRequest() = 0;
public:
virtual void Proceed() = 0;
CallDataBase() {}
};
Each specialization of CallDataBase know how to Proceed, WaitForRequest and HandleRequest. Some of this is common for all requests, so it is convenient to use a templatized class:
template < class RequestType, class ReplyType>
class CallDataT : CallDataBase
{
protected:
enum CallStatus { CREATE, PROCESS, FINISH };
CallStatus status_;
Greeter::AsyncService* service_;
ServerCompletionQueue* completionQueue_;
RequestType request_;
ReplyType reply_;
ServerAsyncResponseWriter<ReplyType> responder_;
ServerContext serverContext_;
// When we handle a request of this type, we need to tell
// the completion queue to wait for new requests of the same type.
virtual void AddNextToCompletionQueue() = 0;
public:
CallDataT(Greeter::AsyncService* service, ServerCompletionQueue* completionQueue) :
status_(CREATE),
service_(service),
completionQueue_(completionQueue),
responder_(&serverContext_)
{
}
public:
virtual void Proceed() override
{
if (status_ == CREATE)
{
status_ = PROCESS;
WaitForRequest();
}
else if (status_ == PROCESS)
{
AddNextToCompletionQueue();
HandleRequest();
status_ = FINISH;
responder_.Finish(reply_, Status::OK, this);
}
else
{
// We're done! Self-destruct!
if (status_ != FINISH)
{
// Log some error message
}
delete this;
}
}
};
And finally, the actual implementation of the message types:
class CallDataHello : CallDataT<HelloRequest, HelloReply>
{
public:
CallDataHello(Greeter::AsyncService* service, ServerCompletionQueue* completionQueue) : CallDataT(service, completionQueue)
{
Proceed();
}
protected:
virtual void AddNextToCompletionQueue() override
{
new CallDataHello(service_, completionQueue_);
}
virtual void WaitForRequest() override
{
service_->RequestSayHello(&serverContext_, &request_, &responder_, completionQueue_, completionQueue_, this);
}
virtual void HandleRequest() override
{
reply_.set_message(std::string("Hello ") + request_.name());
}
};
class CallDataHelloAgain : CallDataT<HelloAgainRequest, HelloAgainReply>
{
public:
CallDataHelloAgain(Greeter::AsyncService* service, ServerCompletionQueue* completionQueue) : CallDataT(service, completionQueue)
{
Proceed();
}
protected:
virtual void AddNextToCompletionQueue() override
{
new CallDataHelloAgain(service_, completionQueue_);
}
virtual void WaitForRequest() override
{
service_->RequestSayHelloAgain(&serverContext_, &request_, &responder_, completionQueue_, completionQueue_, this);
}
virtual void HandleRequest() override
{
reply_.set_message(std::string("Hello again ") + request_.name());
}
};
Finally, in the GRPC server implementation, we can then handle the different requests in a unified way:
void HandleRpcs()
{
new CallDataHello(&service_, completionQueue.get());
new CallDataHelloAgain(engine_, &service_, completionQueue.get());
void* tag;
bool ok;
while (true) {
bool ret = completionQueue->Next(&tag, &ok);
if (ok == false || ret == false)
{
return;
}
static_cast<CallDataBase*>(tag)->Proceed();
}
}
This works because all the CallData we add to completionQueue, is of baseclass CallDataBase, so we can safely call Proceed() on them. This approach makes it relatively easy to add new requests. All the requests are handled by the same completion queue. However, all the requests will be handled serially, so if you are after more parallel processing, I think you have to make more than one completion queue.
I was able to figure this out.
For every protobuf function, I had to create separate completion queue.
I have been implementing the module to send the bytes in chunks, 20 bytes each onto the MCU device via BLE. When it comes to writing the bytes more than 60 bytes and so on, the last chunk of the bytes ( usually less than 20 bytes) is often missed. Hence, the MCU device cannot get the checksum and write the value. I have modified the call back to Thread.sleep(200) to change it but it sometimes works on writing 61 bytes or sometimes not. Would you please tell me are there any synchronous method to write the bytes in chunks ? The below is my working :
#Override
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
try {
Thread.sleep(300);
if (status != BluetoothGatt.GATT_SUCCESS) {
disconnect();
return;
}
if(status == BluetoothGatt.GATT_SUCCESS) {
System.out.println("ok");
broadcastUpdate(ACTION_DATA_READ, mReadCharacteristic, status);
}
else {
System.out.println("fail");
broadcastUpdate(ACTION_DATA_WRITE, characteristic, status);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public synchronized boolean writeCharacteristicData(BluetoothGattCharacteristic characteristic ,
byte [] byteResult ) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
return false;
}
boolean status = false;
characteristic.setValue(byteResult);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
status = mBluetoothGatt.writeCharacteristic(characteristic);
return status;
}
private void sendCommandData(final byte [] commandByte) {
// TODO Auto-generated method stub
if(commandByte.length > 20 ){
final List<byte[]> bytestobeSent = splitInChunks(commandByte);
for(int i = 0 ; i < bytestobeSent.size() ; i ++){
for(int k = 0 ; k < bytestobeSent.get(i).length ; k++){
System.out.println("LumChar bytes : "+ bytestobeSent.get(i)[k] );
}
BluetoothGattService LumService = mBluetoothGatt.getService(A_SERVICE);
if (LumService == null) { return; }
BluetoothGattCharacteristic LumChar = LumService.getCharacteristic(AW_CHARACTERISTIC);
if (LumChar == null) { System.out.println("LumChar"); return; }
//Thread.sleep(500);
writeCharacteristicData(LumChar , bytestobeSent.get(i));
}
}else{
....
You need to wait for the onCharacteristicWrite() callback to be invoked before sending the next write. The typical solution is to make a job queue and pop a job off the queue for each callback you get to onCharacteristicWrite(), onCharacteristicRead(), etc.
In other words, you can't do it in a for loop unfortunately, unless you want to set up some kind of lock that waits for the callback before going on to the next iteration. In my experience a job queue is a cleaner general-purpose solution though.
I have a MethodMirror and want to check if the method it's mirroring is implementing a typedef. Is this possible and how?
I couldn't find a predefined method in 'dart:mirrors' that checks if a method is an instance of typedef.
This code seems to work though (not tested throughougly)
import 'dart:mirrors';
typedef MyFunc(int a, String b);
main() {
MethodMirror mm = reflectClass(TestClass).declarations[#testFunc1];
FunctionTypeMirror tdm =(reflectType(MyFunc) as TypedefMirror).referent;
print(isOfTypeDef(mm, tdm));
mm = reflectClass(TestClass).declarations[#testFunc2];
print(isOfTypeDef(mm, tdm));
mm = reflectClass(TestClass).declarations[#testFunc3];
print(isOfTypeDef(mm, tdm));
}
class TestClass {
void testFunc1(int c, String d) {
print('$c, $d');
}
void testFunc2(var c, var d) {
print('$c, $d');
}
void testFunc3(int e, int f) {
print('$e, $f');
}
}
bool isOfTypeDef(MethodMirror mm, FunctionTypeMirror tdm) {
if((mm.returnType.isAssignableTo(tdm.returnType)) && (mm.parameters.length == tdm.parameters.length)) {
for(int i = 0; i < mm.parameters.length; i++) {
if(!mm.parameters[i].type.isAssignableTo(tdm.parameters[i].type)) {
return false;
}
};
}
return true;
}
I think this is worth a feature request at http://dartbug.com