libwebsockets write to all active connections after receive - libwebsockets

I am toying around with a libwebsockets tutorial trying to make it such that, after it receives a message from a connection over a given protocol, it sends a response to all active connections implementing that protocol. I have used the function libwebsocket_callback_all_protocol but it is not doing what I think it should do from its name (I'm not quite sure what it does from the documentation).
The goal is to have two webpages open and, when info is sent from one, the result will be relayed to both. Below is my code - you'll see that libwebsocket_callback_all_protocol is called in main (which currently does nothing, I think....) :
#include <stdio.h>
#include <stdlib.h>
#include <libwebsockets.h>
#include <string.h>
static int callback_http(struct libwebsocket_context * this,
struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason, void *user,
void *in, size_t len)
{
return 0;
}
static int callback_dumb_increment(struct libwebsocket_context * this,
struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason,
void *user, void *in, size_t len)
{
switch (reason) {
case LWS_CALLBACK_ESTABLISHED: // just log message that someone is connecting
printf("connection established\n");
break;
case LWS_CALLBACK_RECEIVE: { // the funny part
// create a buffer to hold our response
// it has to have some pre and post padding. You don't need to care
// what comes there, libwebsockets will do everything for you. For more info see
// http://git.warmcat.com/cgi-bin/cgit/libwebsockets/tree/lib/libwebsockets.h#n597
unsigned char *buf = (unsigned char*) malloc(LWS_SEND_BUFFER_PRE_PADDING + len +
LWS_SEND_BUFFER_POST_PADDING);
int i;
// pointer to `void *in` holds the incomming request
// we're just going to put it in reverse order and put it in `buf` with
// correct offset. `len` holds length of the request.
for (i=0; i < len; i++) {
buf[LWS_SEND_BUFFER_PRE_PADDING + (len - 1) - i ] = ((char *) in)[i];
}
// log what we recieved and what we're going to send as a response.
// that disco syntax `%.*s` is used to print just a part of our buffer
// http://stackoverflow.com/questions/5189071/print-part-of-char-array
printf("received data: %s, replying: %.*s\n", (char *) in, (int) len,
buf + LWS_SEND_BUFFER_PRE_PADDING);
// send response
// just notice that we have to tell where exactly our response starts. That's
// why there's `buf[LWS_SEND_BUFFER_PRE_PADDING]` and how long it is.
// we know that our response has the same length as request because
// it's the same message in reverse order.
libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], len, LWS_WRITE_TEXT);
// release memory back into the wild
free(buf);
break;
}
default:
break;
}
return 0;
}
static struct libwebsocket_protocols protocols[] = {
/* first protocol must always be HTTP handler */
{
"http-only", // name
callback_http, // callback
0, // per_session_data_size
0
},
{
"dumb-increment-protocol", // protocol name - very important!
callback_dumb_increment, // callback
0, // we don't use any per session data
0
},
{
NULL, NULL, 0, 0 /* End of list */
}
};
int main(void) {
// server url will be http://localhost:9000
int port = 9000;
const char *interface = NULL;
struct libwebsocket_context *context;
// we're not using ssl
const char *cert_path = NULL;
const char *key_path = NULL;
// no special options
int opts = 0;
// create libwebsocket context representing this server
struct lws_context_creation_info info;
memset(&info, 0, sizeof info);
info.port = port;
info.iface = interface;
info.protocols = protocols;
info.extensions = libwebsocket_get_internal_extensions();
info.ssl_cert_filepath = cert_path;
info.ssl_private_key_filepath = key_path;
info.gid = -1;
info.uid = -1;
info.options = opts;
info.user = NULL;
info.ka_time = 0;
info.ka_probes = 0;
info.ka_interval = 0;
/*context = libwebsocket_create_context(port, interface, protocols,
libwebsocket_get_internal_extensions,
cert_path, key_path, -1, -1, opts);
*/
context = libwebsocket_create_context(&info);
if (context == NULL) {
fprintf(stderr, "libwebsocket init failed\n");
return -1;
}
libwebsocket_callback_all_protocol(&protocols[1], LWS_CALLBACK_RECEIVE);
printf("starting server...\n");
// infinite loop, to end this server send SIGTERM. (CTRL+C)
while (1) {
libwebsocket_service(context, 50);
// libwebsocket_service will process all waiting events with their
// callback functions and then wait 50 ms.
// (this is a single threaded webserver and this will keep our server
// from generating load while there are not requests to process)
}
libwebsocket_context_destroy(context);
return 0;
}

I had the same problem, the libwebsocket_write on LWS_CALLBACK_ESTABLISHED generate some random segfault so using the mail list the libwebsockets developer Andy Green instructed me the correct way is to use libwebsocket_callback_on_writable_all_protocol, the file test-server/test-server.c in library source code shows sample of use.
libwebsocket_callback_on_writable_all_protocol(libwebsockets_get_protocol(wsi))
It worked very well to notify all instances, but it only call the write method in all connected instances, it do not define the data to send. You need to manage the data yourself. The sample source file test-server.c show a sample ring buffer to do it.
http://ml.libwebsockets.org/pipermail/libwebsockets/2015-January/001580.html
Hope it helps.

From what I can quickly grab from the documentation, in order to send a message to all clients, what you should do is store somewhere (in a vector, a hashmap, an array, whatever) the struct libwebsocket * wsi that you have access when your clients connect.
Then when you receive a message and want to broadcast it, simply call libwebsocket_write on all wsi * instances.
That's what I'd do, anyway.

Related

Sending a string to UART gives garbage with printf

I'm trying to format data sent over a USB UART with printf and it's giving me garbage. I can send a simple string and that works but anything I try to format gives junk. Looking through the code I think it has to do with my string not being in program space but I'm not sure.
Here is my main:
void main(void) {
CPU_PRESCALE(CPU_16MHz);
init_uart();
int degree = 0;
char buffer[50];
while(1) {
degree = (degree + 1) % 360;
send_str(PSTR("\n\nHello!!!\n\n"));
memset(buffer, 0, 50);
sprintf_P(buffer, PSTR("%d degrees\n"), degree);
send_str(buffer);
_delay_ms(20);
}
}
The output looks like this:
Hello!!!
����/�������(/����#Q��������
Hello!!!
����/�������(/����#Q��������
The USB UART code I found in a tutorial. The relevant parts look like this:
void send_str(const char *s)
{
char c;
while (1) {
c = pgm_read_byte(s++);
if (!c) break;
usb_serial_putchar(c);
}
}
int8_t usb_serial_putchar(uint8_t c)
{
uint8_t timeout, intr_state;
// if we're not online (enumerated and configured), error
if (!usb_configuration) return -1;
// interrupts are disabled so these functions can be
// used from the main program or interrupt context,
// even both in the same program!
intr_state = SREG;
cli();
UENUM = CDC_TX_ENDPOINT;
// if we gave up due to timeout before, don't wait again
if (transmit_previous_timeout) {
if (!(UEINTX & (1<<RWAL))) {
SREG = intr_state;
return -1;
}
transmit_previous_timeout = 0;
}
// wait for the FIFO to be ready to accept data
timeout = UDFNUML + TRANSMIT_TIMEOUT;
while (1) {
// are we ready to transmit?
if (UEINTX & (1<<RWAL)) break;
SREG = intr_state;
// have we waited too long? This happens if the user
// is not running an application that is listening
if (UDFNUML == timeout) {
transmit_previous_timeout = 1;
return -1;
}
// has the USB gone offline?
if (!usb_configuration) return -1;
// get ready to try checking again
intr_state = SREG;
cli();
UENUM = CDC_TX_ENDPOINT;
}
// actually write the byte into the FIFO
UEDATX = c;
// if this completed a packet, transmit it now!
if (!(UEINTX & (1<<RWAL))) UEINTX = 0x3A;
transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT;
SREG = intr_state;
return 0;
}

NKE. Can't handle file uploads and other high load connections

I got a problem when using a kernel extension that filters network traffic.
My code was written according to Apple's tcplognke example.
Everything goes OK but when I attempt to upload a file bigger than 500 kb - connection drops.
Here is simplified kext code:
errno_t tl_data_fn(void *cookie, socket_t so, const struct sockaddr *addr, mbuf_t *data, mbuf_t *control, sflt_data_flag_t flags, FilterSocketDataDirection direction) {
errno_t result = 0;
if (check_tag(data, gidtag, FILTER_TAG_TYPE, direction == FilterSocketDataDirectionIn ? IN_DONE : OUT_DONE)) {
return result;
}
if (!cookie) return result;
filter_cookie *f_cookie = get_filter_cookie(cookie);
uint32_t data_size = (uint32_t)mbuf_pkthdr_len(*data);
uint32_t offset = 0;
printf("tl_data_ft: %d", data_size);
while (offset < data_size) {
FilterNotification notification;
if (direction == FilterSocketDataDirectionIn) {
notification.event = FilterEventDataIn;
} else {
notification.event = FilterEventDataOut;
}
notification.socketId = (uint64_t)so;
notification.inputoutput.dataSize = min(data_size - offset, sizeof(notification.inputoutput.data));
mbuf_copydata(*data, offset, notification.inputoutput.dataSize, notification.inputoutput.data);
offset += notification.inputoutput.dataSize;
send_notification(f_cookie, &notification);
}
result = EJUSTRETURN;
if (result == EJUSTRETURN) {
mbuf_freem(*data);
if (control != NULL && *control != NULL)
mbuf_freem(*control);
}
return result;
}
errno_t tl_data_in_fn(void *cookie, socket_t so, const struct sockaddr *from, mbuf_t *data, mbuf_t *control, sflt_data_flag_t flags) {
return tl_data_fn(cookie, so, from, data, control, flags, FilterSocketDataDirectionIn);
}
errno_t tl_data_out_fn(void *cookie, socket_t so, const struct sockaddr *to, mbuf_t *data, mbuf_t *control, sflt_data_flag_t flags) {
return tl_data_fn(cookie, so, to, data, control, flags, FilterSocketDataDirectionOut);
}
And the user space code:
int s = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
//connect to driver
FilterNotification notification;
while (recv(s, &notification, sizeof(FilterNotification), 0) == sizeof(FilterNotification)) {
FilterClientResponse response;
response.socketId = notification.socketId;
response.direction = (notification.event == FilterEventDataIn) ? FilterSocketDataDirectionIn : FilterSocketDataDirectionOut;
response.dataSize = notification.inputoutput.dataSize;
memcpy(response.data, notification.inputoutput.data, notification.inputoutput.dataSize);
send(s, &response, sizeof(response), 0);
}
When I asked on apple develper forum, the developer said "I don’t see any attempt to handle send-side flow control here. Without that a file upload can easily eat up all of the available mbufs, and things will go badly from there" but there is not examples at all. Can someone help me? thanks.
The problem was in socket buffer. When I inject a lot of data very quickly, the buffer becomes full and inject_data_in/inject_data_out functions returns error.
The workaround is to store pending packets in kernel space (You can use TAILQ for example) and then, when socket becomes available for writing (To get this event you can use kqueue on OS X) continue injection

USN NFTS change notification event interrupt

I'm trying to find a way to let the system tell me whenever there's a new entry in the USN Change Journal to track modifications made to files and directories on an NTFS volume (Server 2008/2012).
This way I don't have to constantly poll the journal and can just let my thread sleep until I get notified when there's a new change-event.
However, is there even such an interrupt?
The FSCTL_QUERY_USN_JOURNAL function doesn't specifically mention interrupts (events, notifications), nor have I been able to find another way to achieve this with less intensive poll-and-compare techniques.
I'm not a hard-core programmer so there may be simpler ways to tie these functions to interrupts that I'm not aware of.
Could I perhaps find out where the USN Change Journal is stored and watch that file with another process that can generate and interrupt on change?
https://msdn.microsoft.com/en-us/library/aa365729(v=vs.85).aspx
The code posted here blocks the executing thread till the new USN record is created in the Journal. When new records arrive, the thread awakens and you can process changes and/or notify listeners via a callback that filesystem has changed (in the example it just prints message to the console). Then the thread blocks again. This example uses one thread per volume (so for each volume, separate NTFSChangesWatcher class instance needed).
It is not specified which tools or language you use, so I will write as I did it. To run this code, create a Visual Studio C++ Win32 Console Application.
Create NTFSChangesWatcher class. Paste this code in NTFSChangesWatcher.h file (replacing auto-generated one):
#pragma once
#include <windows.h>
#include <memory>
class NTFSChangesWatcher
{
public:
NTFSChangesWatcher(char drive_letter);
~NTFSChangesWatcher() = default;
// Method which runs an infinite loop and waits for new update sequence number in a journal.
// The thread is blocked till the new USN record created in the journal.
void WatchChanges();
private:
HANDLE OpenVolume(char drive_letter);
bool CreateJournal(HANDLE volume);
bool LoadJournal(HANDLE volume, USN_JOURNAL_DATA* journal_data);
bool NTFSChangesWatcher::WaitForNextUsn(PREAD_USN_JOURNAL_DATA read_journal_data) const;
std::unique_ptr<READ_USN_JOURNAL_DATA> GetWaitForNextUsnQuery(USN start_usn);
bool NTFSChangesWatcher::ReadJournalRecords(PREAD_USN_JOURNAL_DATA journal_query, LPVOID buffer,
DWORD& byte_count) const;
std::unique_ptr<READ_USN_JOURNAL_DATA> NTFSChangesWatcher::GetReadJournalQuery(USN low_usn);
char drive_letter_;
HANDLE volume_;
std::unique_ptr<USN_JOURNAL_DATA> journal_;
DWORDLONG journal_id_;
USN last_usn_;
// Flags, which indicate which types of changes you want to listen.
static const int FILE_CHANGE_BITMASK;
static const int kBufferSize;
};
and this code in NTFSChangesWatcher.cpp file:
#include "NTFSChangesWatcher.h"
#include <iostream>
using namespace std;
const int NTFSChangesWatcher::kBufferSize = 1024 * 1024 / 2;
const int NTFSChangesWatcher::FILE_CHANGE_BITMASK =
USN_REASON_RENAME_NEW_NAME | USN_REASON_SECURITY_CHANGE | USN_REASON_BASIC_INFO_CHANGE | USN_REASON_DATA_OVERWRITE |
USN_REASON_DATA_TRUNCATION | USN_REASON_DATA_EXTEND | USN_REASON_CLOSE;
NTFSChangesWatcher::NTFSChangesWatcher(char drive_letter) :
drive_letter_(drive_letter)
{
volume_ = OpenVolume(drive_letter_);
journal_ = make_unique<USN_JOURNAL_DATA>();
bool res = LoadJournal(volume_, journal_.get());
if (!res) {
cout << "Failed to load journal" << endl;
return;
}
journal_id_ = journal_->UsnJournalID;
last_usn_ = journal_->NextUsn;
}
HANDLE NTFSChangesWatcher::OpenVolume(char drive_letter) {
wchar_t pattern[10] = L"\\\\?\\a:";
pattern[4] = static_cast<wchar_t>(drive_letter);
HANDLE volume = nullptr;
volume = CreateFile(
pattern, // lpFileName
// also could be | FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, // dwDesiredAccess
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, // share mode
NULL, // default security attributes
OPEN_EXISTING, // disposition
// It is always set, no matter whether you explicitly specify it or not. This means, that access
// must be aligned with sector size so we can only read a number of bytes that is a multiple of the sector size.
FILE_FLAG_NO_BUFFERING, // file attributes
NULL // do not copy file attributes
);
if (volume == INVALID_HANDLE_VALUE) {
// An error occurred!
cout << "Failed to open volume" << endl;
return nullptr;
}
return volume;
}
bool NTFSChangesWatcher::CreateJournal(HANDLE volume) {
DWORD byte_count;
CREATE_USN_JOURNAL_DATA create_journal_data;
bool ok = DeviceIoControl(volume, // handle to volume
FSCTL_CREATE_USN_JOURNAL, // dwIoControlCode
&create_journal_data, // input buffer
sizeof(create_journal_data), // size of input buffer
NULL, // lpOutBuffer
0, // nOutBufferSize
&byte_count, // number of bytes returned
NULL) != 0; // OVERLAPPED structure
if (!ok) {
// An error occurred!
}
return ok;
}
bool NTFSChangesWatcher::LoadJournal(HANDLE volume, USN_JOURNAL_DATA* journal_data) {
DWORD byte_count;
// Try to open journal.
if (!DeviceIoControl(volume, FSCTL_QUERY_USN_JOURNAL, NULL, 0, journal_data, sizeof(*journal_data), &byte_count,
NULL)) {
// If failed (for example, in case journaling is disabled), create journal and retry.
if (CreateJournal(volume)) {
return LoadJournal(volume, journal_data);
}
return false;
}
return true;
}
void NTFSChangesWatcher::WatchChanges() {
auto u_buffer = make_unique<char[]>(kBufferSize);
auto read_journal_query = GetWaitForNextUsnQuery(last_usn_);
while (true) {
// This function does not return until new USN record created.
WaitForNextUsn(read_journal_query.get());
cout << "New entry created in the journal!" << endl;
auto journal_query = GetReadJournalQuery(read_journal_query->StartUsn);
DWORD byte_count;
if (!ReadJournalRecords(journal_query.get(), u_buffer.get(), byte_count)) {
// An error occurred.
cout << "Failed to read journal records" << endl;
}
last_usn_ = *(USN*)u_buffer.get();
read_journal_query->StartUsn = last_usn_;
// If you need here you can:
// Read and parse Journal records from the buffer.
// Notify an NTFSChangeObservers about journal changes.
}
}
bool NTFSChangesWatcher::WaitForNextUsn(PREAD_USN_JOURNAL_DATA read_journal_data) const {
DWORD bytes_read;
bool ok = true;
// This function does not return until new USN record created.
ok = DeviceIoControl(volume_, FSCTL_READ_USN_JOURNAL, read_journal_data, sizeof(*read_journal_data),
&read_journal_data->StartUsn, sizeof(read_journal_data->StartUsn), &bytes_read,
nullptr) != 0;
return ok;
}
unique_ptr<READ_USN_JOURNAL_DATA> NTFSChangesWatcher::GetWaitForNextUsnQuery(USN start_usn) {
auto query = make_unique<READ_USN_JOURNAL_DATA>();
query->StartUsn = start_usn;
query->ReasonMask = 0xFFFFFFFF; // All bits.
query->ReturnOnlyOnClose = FALSE; // All entries.
query->Timeout = 0; // No timeout.
query->BytesToWaitFor = 1; // Wait for this.
query->UsnJournalID = journal_id_; // The journal.
query->MinMajorVersion = 2;
query->MaxMajorVersion = 2;
return query;
}
bool NTFSChangesWatcher::ReadJournalRecords(PREAD_USN_JOURNAL_DATA journal_query, LPVOID buffer,
DWORD& byte_count) const {
return DeviceIoControl(volume_, FSCTL_READ_USN_JOURNAL, journal_query, sizeof(*journal_query), buffer, kBufferSize,
&byte_count, nullptr) != 0;
}
unique_ptr<READ_USN_JOURNAL_DATA> NTFSChangesWatcher::GetReadJournalQuery(USN low_usn) {
auto query = make_unique<READ_USN_JOURNAL_DATA>();
query->StartUsn = low_usn;
query->ReasonMask = 0xFFFFFFFF; // All bits.
query->ReturnOnlyOnClose = FALSE;
query->Timeout = 0; // No timeout.
query->BytesToWaitFor = 0;
query->UsnJournalID = journal_id_;
query->MinMajorVersion = 2;
query->MaxMajorVersion = 2;
return query;
}
Now you can use it (for example in the main function for testing):
#include "NTFSChangesWatcher.h"
int _tmain(int argc, _TCHAR* argv[])
{
auto watcher = new NTFSChangesWatcher('z');
watcher->WatchChanges();
return 0;
}
And console output should be like this on every change in the filesystem:
This code was slightly reworked to remove unrelated details and is a part of the Indexer++ project. So for more details, you can refer to the original code.
You can use Journal, but in this case I'd use easier method via registering a directory notification by calling the FindFirstChangeNotification or ReadDirectoryChangesW functions, see https://msdn.microsoft.com/en-us/library/aa364417.aspx
If you'd prefer to use Journal, this is - I think - the best introductory article with many examples. It is written for W2K, but those concepts are still valid: https://www.microsoft.com/msj/0999/journal/journal.aspx

CoreMIDI: midiReadProc only receives the first packet of 3 packets with the same timestamp

I am working on a small program to monitor midi output from NI Maschine 2. (Idea is to add program change messages to some Parts in NI Machine and use them to trigger VJ-efects and some other stuff)
The following test case gives the problem. the test Part in NI Machine has one note and two program change messages on the first beat and a second note a 16th later.
When i hit start and capture the output with a MIDI Monitor tool i see:
This is correct. Exactly what Maschine is sending.
- notice the two Control Changes and the next Note On packets have the same timestamp.
When i do the same with my simple virtual client (see code below) i get this:
as you can see the second Control Change and the Note On packets are missing!
notice also the second an third line (Song Position and Continue) also have the same timestamp and are in both cases received.
If you took the trouble to read until this point you will understand the problem.
I know the big difference between my simpel virtual client and the MIDI Monitor program is the use of a CoreMidi Service plugin for 'spying' the midi output.
Is this just a limitation of CoreMidi or am i missing something?
Below the code for the virtual client:
It is stripped down to the basic needs to receive something from NI Mashine.
The init sets up the virtual client, destination and sets the UniqueID.
The readproc is producing the NSLOG messages with the missing packets as shown above.
Any suggestions are very appreciated
//
// VirtualClient.m
// testMidiReadProc
//
// Created by Rob Keeris on 02/06/15.
// Copyright (c) 2015 Connector. All rights reserved.
//
#import "VirtualClient.h"
#implementation VirtualClient
SInt32 virtualinUniqueId = 1234567893;
MIDIClientRef client;
MIDIEndpointRef virtualIn;
NSString * midiTypeName(Byte midiType){
switch (midiType) {
case 0x80: return #"Note Off";
case 0x90: return #"Note On";
case 0xB0: return #"ControlChange";
case 0xC0: return #"ProgramChange";
case 0xF2: return #"SongPosition";
case 0xF8: return #"Clock";
case 0xFA: return #"Start";
case 0xFB: return #"Continue";
case 0xFC: return #"Stop";
case 0x00: return #"InvalidType";
default: return [NSString stringWithFormat:#"Unlisted midiType 0x%02x",midiType];
}
}
void midiReadProc (const MIDIPacketList *list, void *procRef, void *srcRef) {
const MIDIPacket *packet = &list->packet[0]; // ?defined as const to avoid compiler warnings?
for (int i = 0; i < list->numPackets; i++) {
if (packet->data[0] != 0xF8){ // filter out Clock messages
NSLog(#"%llu packet(%i of %i) %#(0x%02x) 0x%02x 0x%02x",
packet->timeStamp,i+1,list->numPackets,midiTypeName(packet->data[0]),packet->data[0],packet->data[1],packet->data[2]);
}
packet = MIDIPacketNext (packet);
}
}
- (id)init{
OSStatus result;
self = [super init];
if (self) {
// Create the client
result = MIDIClientCreate(CFSTR("myVirtualClient"), NULL, NULL, &client);
if (result !=0) NSLog(#"MIDIClientCreate error %i",result);
// create the destination
result = MIDIDestinationCreate(client, CFSTR("myVirtualDestination"), midiReadProc,(__bridge void *)(self),&virtualIn);
if (result !=0) NSLog(#"MIDIClientCreate error %i",result);
// set the UniqueId so i dont have to toggele the output in NI Maschine
result = MIDIObjectSetIntegerProperty(virtualIn, kMIDIPropertyUniqueID, virtualinUniqueId);
if (result !=0) NSLog(#"MIDIClientCreate error %i",result);
}
return self;
}
#end
Extra info
Put in this extra test in response to the hints of Gene to see what happens when
removing the 0xF8 filter and using a printf instead of NSLog();
Output from MIDI Monitor:
Output form my code:
No solution but now a clock is received with the same timestamp.
Tempo in this test was set to 50 BPM (so one clock every 50 ms)
I checked to see if there are missing clock pulses but this isn't the case. All clocks are received with approx the expected timestamp.
Minor comment here.
Since you're doing this:
const MIDIPacket *packet = &list->packet[0]; // ?defined as const to avoid compiler warnings?
This
for (int i = 0; i < list->numPackets; i++) {
should be
for (int i = 0; i < list->numPackets; ++i) {
But that doesn't fix your problem.
What happens when you remove the filtering "if" (besides getting lots of F8s)?
Shot in the dark: try printf to see if NSLog is up to no good.
I think i found out wat the problem is.
The packets are not missing but put together in the data[0] of the first package.
Another post (proper-use-of-midipacketlistadd-coremidi) put me on the right track.
for this test i put a chord of 3 notes and 2 control change messages on the first bar and a single not on the sixteenth and a singe control change .
Well, its clear the control change holds the 2 control change's and the 3 NoteOn messages. The NoteOf message holds the 3 NoteOf's.
Is this a bug in Coremidi or bad behavieur of the programmer on the other side?
EDIT
This is solved.
As Kurt pointed out its just normal and you have to be prepared for multiple messages in one packet. So you have to do something like below.
Thanks for all input.
#import "VirtualClient.h"
#implementation VirtualClient
SInt32 virtualinUniqueId = 1234567893;
MIDIClientRef client;
MIDIEndpointRef virtualIn;
MIDITimeStamp previousTimeStamp;
struct MIDIMessage
{
char* description;
int messageLength;
};
typedef struct MIDIMessage MIDIMessage;
// incomplete list of possible messages but suffucient for this test
const MIDIMessage x00 = {"Error! or Unlisted",0};
const MIDIMessage x80 = {"Note Off",3};
const MIDIMessage x90 = {"Note On",3};
const MIDIMessage xB0 = {"ControlChange",3};
const MIDIMessage xC0 = {"ProgramChange",2};
const MIDIMessage xF2 = {"SongPosition",3};
const MIDIMessage xF8 = {"Clock",1};
const MIDIMessage xFA = {"Start",1};
const MIDIMessage xFB = {"Continue",1};
const MIDIMessage xFC = {"Stop",1};
MIDIMessage midiType(Byte midiType){
switch (midiType) {
case 0x80: return x80;
case 0x90: return x90;
case 0xB0: return xB0;
case 0xC0: return xC0;
case 0xF2: return xF2;
case 0xF8: return xF8;
case 0xFA: return xFA;
case 0xFB: return xFB;
case 0xFC: return xFC;
default: return x00;
}
}
void midiReadProc (const MIDIPacketList *list, void *procRef, void *srcRef) {
int index;
int messageLength;
const MIDIPacket *packet = &list->packet[0];
// handle packets
for (int i =0;i< list->numPackets;++i){
// handle messages in each packet
index = 0;
while (index < packet->length){
messageLength = midiType(packet->data[index]).messageLength;
if (messageLength){
printf("%llu packet(%i of %i) %s", packet->timeStamp,i+1,list->numPackets,midiType(packet->data[index]).description);
for (int x =1; x< messageLength;x++)
printf(" data[%i]:0x%02x",x,packet->data[index+x]);
printf("\n");
index+=messageLength;
}
else{
printf("Unlisted comand! printing rest of bytes");
for (int i =index; i < packet->length;i++)
printf("0x%02x ",packet->data[i]);
printf("\n");
break;
}
}
packet = MIDIPacketNext (packet);
}
}
- (id)init{
OSStatus result;
self = [super init];
if (self) {
// Create the client
result = MIDIClientCreate(CFSTR("myVirtualClient"), NULL, NULL, &client);
if (result !=0) NSLog(#"MIDIClientCreate error %i",result);
// create the destination
result = MIDIDestinationCreate(client, CFSTR("myVirtualDestination"), midiReadProc,(__bridge void *)(self),&virtualIn);
if (result !=0) NSLog(#"MIDIClientCreate error %i",result);
// set the UniqueId so i dont have to toggele the output in NI Maschine
result = MIDIObjectSetIntegerProperty(virtualIn, kMIDIPropertyUniqueID, virtualinUniqueId);
if (result !=0) NSLog(#"MIDIClientCreate error %i",result);
}
return self;
}
#end

Parsing events in real time ETW consumer on Windows

We are working on ETW real time consumer application by referring to https://msdn.microsoft.com/en-us/library/windows/desktop/aa364157(v=vs.85).aspx sample.
We have been successful getting callback and print "ParentGuid" of EVENT_TRACE structure within callback. However we are getting MofData pointer as always NULL and MofLength as always 0 (zero).
On the other hand if we use non real time ETW consumer method i.e. file mode; reading from .etl file we are able to get valid MofData pointer.
We are trying to consume Kernel events such as CPU usage, DISK IO details from Events in real time.
So does it mean we cannot consume Kernel events in real time? Can some one suggest why we are not getting valid pointer/MofData?
// ConsoleApplication5.cpp : Defines the entry point for the console application.
//
//Turns the DEFINE_GUID for EventTraceGuid into a const.
#define INITGUID
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <evntrace.h>
#define LOGSESSION_NAME L"power"
// Used to calculate CPU usage
ULONG g_TimerResolution = 0;
void WINAPI ProcessEvent(PEVENT_TRACE pEvent);
void wmain(void)
{
ULONG status = ERROR_SUCCESS;
EVENT_TRACE_LOGFILE trace;
TRACE_LOGFILE_HEADER* pHeader = &trace.LogfileHeader;
TRACEHANDLE hTrace = 0;
HRESULT hr = S_OK;
// Identify the log file from which you want to consume events
// and the callbacks used to process the events and buffers.
ZeroMemory(&trace, sizeof(EVENT_TRACE_LOGFILE));
trace.LoggerName = (LPWSTR)LOGSESSION_NAME;
trace.CurrentTime = 0;
trace.BuffersRead = 0;
trace.BufferSize = 0;
trace.Filled = 0;
trace.EventsLost = 0;
trace.Context = NULL;
trace.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD;
trace.EventCallback = (PEVENT_CALLBACK)(ProcessEvent);
trace.BufferCallback = (PEVENT_TRACE_BUFFER_CALLBACK)(ProcessBuffer);
hTrace = OpenTrace(&trace);
if ((TRACEHANDLE)INVALID_HANDLE_VALUE == hTrace)
{
wprintf(L"OpenTrace failed with %lu\n", GetLastError());
goto cleanup;
}
if (pHeader->TimerResolution > 0)
{
g_TimerResolution = pHeader->TimerResolution / 10000;
}
wprintf(L"Number of events lost: %lu\n", pHeader->EventsLost);
// Use pHeader to access all fields prior to LoggerName.
// Adjust pHeader based on the pointer size to access
// all fields after LogFileName. This is required only if
// you are consuming events on an architecture that is
// different from architecture used to write the events.
if (pHeader->PointerSize != sizeof(PVOID))
{
pHeader = (PTRACE_LOGFILE_HEADER)((PUCHAR)pHeader +
2 * (pHeader->PointerSize - sizeof(PVOID)));
}
wprintf(L"Number of buffers lost: %lu\n\n", pHeader->BuffersLost);
status = ProcessTrace(&hTrace, 1, 0, 0);
if (status != ERROR_SUCCESS && status != ERROR_CANCELLED)
{
wprintf(L"ProcessTrace failed with %lu\n", status);
goto cleanup;
}
cleanup:
if ((TRACEHANDLE)INVALID_HANDLE_VALUE != hTrace)
{
status = CloseTrace(hTrace);
}
}
VOID WINAPI ProcessEvent(PEVENT_TRACE pEvent)
{
PBYTE pEventData = NULL;
pEventData = (PBYTE)(pEvent->MofData);
printf("\n hi%d", pEventData);
printf("\n length %d", pEvent->MofLength);
}

Resources