@@ -1,5 +1,6 @@
#include <chrono>
#include <iostream>
#include <sstream>
#include <thread>
#include <GL/glfw.h>

@@ -14,6 +15,7 @@ using std::chrono::milliseconds;
using std::lock_guard;
using std::mutex;
using std::shared_ptr;
using std::stringstream;
using std::this_thread::sleep_for;

InteractionHandler::InteractionHandler() {
@@ -22,11 +24,12 @@ InteractionHandler::InteractionHandler() {
void InteractionHandler::operator()() {
milliseconds stime(20);
shared_ptr<MessageSlot> keySlot = this->getMessageDriver()->getSlot("keys");
bool scriptInput = false;
stringstream script;

while(!this->shouldShutdown()) {
while(keySlot->hasMessages()) {
shared_ptr<Message> m(keySlot->get());

shared_ptr<Message> m;
while((m = keySlot->get()).get() != nullptr) {
// check type
if (m->isType("int")) {
IntMessage* m2 = dynamic_cast<IntMessage*>(m.get());
@@ -47,6 +50,29 @@ void InteractionHandler::operator()() {
if (keyCode == GLFW_KEY_ESC) {
this->getMessageDriver()->getSlot("userEvents")->emit(IntMessage(UserEventTable::EXIT));
}

if ((keyCode == GLFW_KEY_F12) && pressed) {
if (scriptInput) {
scriptInput = false;
} else {
scriptInput = true;
script.str("");
}
}

if ((keyCode == GLFW_KEY_ENTER) && pressed && scriptInput) {
this->getMessageDriver()->getSlot("exec")->emit(StringMessage(script.str()));
script.str("");
}
}
} else if (m->isType("string")) {
StringMessage* m2 = dynamic_cast<StringMessage*>(m.get());

// security check
if (m2 != nullptr) {
if (scriptInput) {
script << m2->getData();
}
}
}
}
@@ -62,6 +88,8 @@ void InteractionHandler::setupMessageDriver(shared_ptr<MessageDriver> messageDri
this->getMessageDriver()->createSlot("keys");
this->getMessageDriver()->createSlot("log");
this->getMessageDriver()->createSlot("userEvents");
this->getMessageDriver()->createSlot("chars");
this->getMessageDriver()->createSlot("exec");
}
}

@@ -28,10 +28,10 @@ using std::this_thread::sleep_for;
void Logger::operator()() {
milliseconds stime(20);
shared_ptr<MessageSlot> defaultSlot = this->getMessageDriver()->getSlot("defaultLog");
shared_ptr<Message> m;

while(!this->shouldShutdown() || defaultSlot->hasMessages()) {
while(defaultSlot->hasMessages()) {
shared_ptr<Message> m = defaultSlot->get();
while(!this->shouldShutdown() || ((m = defaultSlot->get()).get() != nullptr)) {
while((m = defaultSlot->get()).get() != nullptr) {
string msg("unkown message");

// check type
@@ -1,5 +1,7 @@
#include <chrono>
#include <iostream>
#include <stdexcept>
#include <thread>

/// \warning we have to include lua before luabridge
#include <lua.hpp>
@@ -12,9 +14,10 @@
using namespace ProjectMaya;
using namespace luabridge;

using std::chrono::milliseconds;
using std::runtime_error;
using std::shared_ptr;

using std::this_thread::sleep_for;

Interpreter::Interpreter() {
}
@@ -34,15 +37,35 @@ void Interpreter::operator()() {

this->getMessageDriver()->getSlot("log")->emit(StringMessage("Lua engine successfully initialized"));

// do the test call
luaL_dostring(luaState, "Interpreter:reportSuccess()");
// listen to events
shared_ptr<MessageSlot> execSlot = this->getMessageDriver()->getSlot("exec");
milliseconds stime(200);
while (!this->shouldShutdown()) {
shared_ptr<Message> m;
while ((m = execSlot->get()).get() != nullptr) {

// check type
if (m->isType("string")) {
StringMessage* m2 = dynamic_cast<StringMessage*>(m.get());

// security check
if (m2 != nullptr) {
this->getMessageDriver()->getSlot("log")->emit(StringMessage(m2->getData()));
luaL_dostring(luaState, m2->getData().c_str());
}
}
}

sleep_for(stime);
}
}

void Interpreter::setupMessageDriver(shared_ptr<MessageDriver> messageDriver, bool firstTime) {
ModulePayload::setupMessageDriver(messageDriver, firstTime);

if (firstTime) {
this->getMessageDriver()->createSlot("log");
this->getMessageDriver()->createSlot("exec");
}
}

@@ -54,7 +77,7 @@ void Interpreter::exposeToState(lua_State* luaState) {
// Register
getGlobalNamespace(luaState)
.beginClass<Interpreter>("Interpreter")
.addMethod("reportSuccess", &Interpreter::reportSuccess)
.addFunction("reportSuccess", &Interpreter::reportSuccess)
.endClass();

//Push concrete objects over
@@ -1,5 +1,7 @@
#include <chrono>
#include <sstream>
#include <stdexcept>
#include <thread>

#include <AL/alc.h>
#include <AL/al.h>
@@ -11,99 +13,164 @@

using namespace ProjectMaya;

using std::chrono::milliseconds;
using std::noskipws;
using std::runtime_error;
using std::shared_ptr;
using std::string;
using std::stringstream;
using std::this_thread::sleep_for;


SoundHandler::SoundHandler() {
device = alcOpenDevice(NULL);
context = alcCreateContext(device, NULL);
alcMakeContextCurrent(context);
checkForErrors();
}

void SoundHandler::operator()() {
device = alcOpenDevice(NULL);
context = alcCreateContext(device, NULL);
alcMakeContextCurrent(context);
checkForErrors();

printALCInfo();
checkForErrors();
SoundHandler::~SoundHandler() {
alcMakeContextCurrent(NULL);
alcDestroyContext(context);
alcCloseDevice(device);
}

alcMakeContextCurrent(NULL);
alcDestroyContext(context);
alcCloseDevice(device);
void SoundHandler::operator()() {
printALCInfo();
checkForErrors();
playDummySound();
}

void SoundHandler::setupMessageDriver(shared_ptr<MessageDriver> messageDriver, bool firstTime) {
ModulePayload::setupMessageDriver(messageDriver, firstTime);
ModulePayload::setupMessageDriver(messageDriver, firstTime);

if (firstTime) {
this->getMessageDriver()->createSlot("log");
}
if (firstTime) {
this->getMessageDriver()->createSlot("log");
}
}

void SoundHandler::checkForErrors() {
{
ALCenum error = alcGetError(device);
{
ALCenum error = alcGetError(device);

if(error != ALC_NO_ERROR)
throw new runtime_error("ALC error occured" /* , (const char*)alcGetString(device, error) */);
}
if(error != ALC_NO_ERROR)
this->getMessageDriver()->getSlot("log")->emit(StringMessage("ALC error occured"));
// throw new runtime_error("ALC error occured" /* , (const char*)alcGetString(device, error) */);
}

{
ALenum error = alGetError();
{
ALenum error = alGetError();

if(error != AL_NO_ERROR)
throw new runtime_error("AL error occured" /* , (const char*)alGetString(error) */);
}
if(error != AL_NO_ERROR)
this->getMessageDriver()->getSlot("log")->emit(StringMessage("AL error occured"));
// throw new runtime_error("AL error occured" /* , (const char*)alGetString(error) */);
}
}

void SoundHandler::printDevices(ALCenum which, const string& kind) {
const char *s = alcGetString(NULL, which);
checkForErrors();
const char *s = alcGetString(NULL, which);
checkForErrors();

stringstream stream;
stream << noskipws << "Available " << kind << "devices: ";
stringstream stream;
stream << noskipws << "Available " << kind << "devices: ";

while(*s != '\0') {
stream << s << " ";
while(*s != '\0') {
stream << s << " ";

while(*s++ != '\0')
;
}
while(*s++ != '\0')
;
}

this->getMessageDriver()->getSlot("log")->emit(StringMessage(stream.str()));
this->getMessageDriver()->getSlot("log")->emit(StringMessage(stream.str()));
}

void SoundHandler::printALCInfo() {
ALCint major, minor;

stringstream stream;
stream << noskipws;

if(alcIsExtensionPresent(NULL, (const ALCchar*)"ALC_ENUMERATION_EXT") == AL_TRUE) {
if(alcIsExtensionPresent(NULL, (const ALCchar*)"ALC_ENUMERATE_ALL_EXT") == AL_TRUE) {
printDevices(ALC_ALL_DEVICES_SPECIFIER, "playback ");
} else {
printDevices(ALC_DEVICE_SPECIFIER, "playback ");
}
} else {
stream << "No device enumeration available";
this->getMessageDriver()->getSlot("log")->emit(StringMessage(stream.str()));
stream << "";
}

stream << "Default device: " << alcGetString(device, ALC_DEFAULT_DEVICE_SPECIFIER);
this->getMessageDriver()->getSlot("log")->emit(StringMessage(stream.str()));
stream << "";


alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major);
alcGetIntegerv(device, ALC_MINOR_VERSION, 1, &minor);
checkForErrors();

stream << "ALC version: " << (int)major << "." << (int)minor;
this->getMessageDriver()->getSlot("log")->emit(StringMessage(stream.str()));
ALCint major, minor;

stringstream stream;
stream << noskipws;

if(alcIsExtensionPresent(NULL, (const ALCchar*)"ALC_ENUMERATION_EXT") == AL_TRUE) {
if(alcIsExtensionPresent(NULL, (const ALCchar*)"ALC_ENUMERATE_ALL_EXT") == AL_TRUE) {
printDevices(ALC_ALL_DEVICES_SPECIFIER, "playback ");
} else {
printDevices(ALC_DEVICE_SPECIFIER, "playback ");
}
} else {
stream << "No device enumeration available";
this->getMessageDriver()->getSlot("log")->emit(StringMessage(stream.str()));
stream << "";
}

stream << "Default device: " << alcGetString(device, ALC_DEFAULT_DEVICE_SPECIFIER);
this->getMessageDriver()->getSlot("log")->emit(StringMessage(stream.str()));
stream << "";


alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major);
alcGetIntegerv(device, ALC_MINOR_VERSION, 1, &minor);
checkForErrors();

stream << "ALC version: " << (int)major << "." << (int)minor;
this->getMessageDriver()->getSlot("log")->emit(StringMessage(stream.str()));
}

void SoundHandler::playDummySound() {
/* create default listener */
alListener3f(AL_POSITION, 0, 0, 0);
alListener3f(AL_VELOCITY, 0, 0, 0);
// alListener3f(AL_ORIENTATION, 0, 0, -1); /// TODO: forward then up vector
checkForErrors();

/* create default source */
ALuint source;
alGenSources(1, &source);
checkForErrors();

alSourcef(source, AL_PITCH, 1);
alSourcef(source, AL_GAIN, 1);
alSource3f(source, AL_POSITION, 0, 0, 0);
alSource3f(source, AL_VELOCITY, 0, 0, 0);
alSourcei(source, AL_LOOPING, AL_TRUE);
checkForErrors();

/* create buffer for source */
ALuint buffer;
alGenBuffers(1, &buffer);
checkForErrors();



/* fill buffer */
int sampleRate = 44100;
int seconds = 10;
int frames = seconds * sampleRate;
int frequency = 1800;
ALbyte data[frames];

for(int i = 0; i < frames; ++i)
data[i] = 25;

alBufferData(buffer, AL_FORMAT_MONO8, &data, sizeof(data), frequency);



/* attach and play */
alSourcei(source, AL_BUFFER, buffer);
alSourcePlay(source);



this->getMessageDriver()->getSlot("log")->emit(StringMessage("playing noise"));
milliseconds stime(2000);
sleep_for(stime);
this->getMessageDriver()->getSlot("log")->emit(StringMessage("stopping noise"));



/* stop and cleanup */
alDeleteSources(1, &source);
alDeleteBuffers(1, &buffer);
checkForErrors();
}

@@ -15,6 +15,7 @@ namespace ProjectMaya {
class SoundHandler : public ModulePayload {
public:
explicit SoundHandler();
~SoundHandler();

void operator()() override;
void setupMessageDriver(std::shared_ptr<MessageDriver> messageDriver, bool firstTime) override;
@@ -26,6 +27,7 @@ namespace ProjectMaya {
void checkForErrors();
void printDevices(ALCenum which, const std::string& kind);
void printALCInfo();
void playDummySound();
};

}
@@ -35,20 +35,11 @@ void MessageSlot::addTarget(MessagePublicSlot target) {
}

void MessageSlot::drop(shared_ptr<Message> message) {
lock_guard<mutex> queueGuard(this->queueMutex);
this->messages.push(message);
}

bool MessageSlot::hasMessages() {
lock_guard<mutex> queueGuard(this->queueMutex);
return !this->messages.empty();
this->messages.enqueue(message);
}

shared_ptr<Message> MessageSlot::get() {
lock_guard<mutex> queueGuard(this->queueMutex);
shared_ptr<Message> m = this->messages.front();
this->messages.pop();
return m;
return this->messages.dequeue();
}

string MessageSlot::getId() {
@@ -4,7 +4,8 @@
#include <forward_list>
#include <memory>
#include <string>
#include <queue>

#include "Thread/LockFreeQueue.hpp"

#include "Message.hpp"
#include "MessagePublicSlot.hpp"
@@ -28,9 +29,6 @@ namespace ProjectMaya {
/// Enqueue a new message
void drop(std::shared_ptr<Message> message);

/// Ask if queue holds messages, that should be processed
bool hasMessages();

/// Get first message from queue
std::shared_ptr<Message> get();

@@ -53,12 +51,11 @@ namespace ProjectMaya {

private:
std::mutex targetsMutex;
std::mutex queueMutex;

std::string id;
std::shared_ptr<MessagePublicSlot::Alive> alive;
std::forward_list<MessagePublicSlot> targets;
std::queue<std::shared_ptr<Message>> messages;
LockFreeQueue<Message> messages;
};

}
@@ -0,0 +1,137 @@
#ifndef LOCKFREEQUEUE_HPP
#define LOCKFREEQUEUE_HPP

#include <atomic>
#include <memory>

namespace ProjectMaya {

/**
* A lock free, high performance queue
*
* See following paper for more details:
* http://people.csail.mit.edu/edya/publications/OptimisticFIFOQueue-journal.pdf
*/
template <typename T>
class LockFreeQueue {
public:
LockFreeQueue() {
Node* nd = new Node;
nd->next = {nullptr, 0};

this->tail.store(new Pointer({nd, 0}));
this->head.store(new Pointer({nd, 0}));
}

~LockFreeQueue() {
// dequeue all elements
std::shared_ptr<T> val;
do {
val = this->dequeue();
} while (val.get() != nullptr);

// delete helper
delete this->tail.load()->ptr;
delete this->tail.load();
delete this->head.load();
}

/// Adds new element to the queue
void enqueue(std::shared_ptr<T> val) {
Pointer* tail;
Node* nd = new Node;
nd->value = val;

while (true) {
tail = this->tail.load();
nd->next = {tail->ptr, tail->tag + 1};

// CAS
Pointer* expected = tail;
Pointer* new_val = new Pointer({nd, tail->tag + 1});
if (this->tail.compare_exchange_weak(expected, new_val)) {
tail->ptr->prev = {nd, tail->tag};
delete tail;
break;
} else {
delete new_val;
}
}
}

/// Get element from queue, returns shared_ptr to nullptr if queue is empty
std::shared_ptr<T> dequeue() {
Pointer* tail;
Pointer* head;
Pointer firstNodePrev;
std::shared_ptr<T> val;

while (true) {
head = this->head.load();
tail = this->tail.load();
firstNodePrev = head->ptr->prev;
if (head == this->head.load()) {
if (*tail != *head) {
if (firstNodePrev.tag != head->tag) {
this->fixList(tail, head);
continue;
}
val = firstNodePrev.ptr->value;

// CAS
Pointer* expected = head;
Pointer* new_value = new Pointer({firstNodePrev.ptr, head->tag + 1});
if (this->head.compare_exchange_weak(expected, new_value)) {
delete head->ptr;
delete head;
return val;
} else {
delete new_value;
}
} else {
return nullptr;
}
}
}
}

private:
struct Node;
struct Pointer {
Node* ptr;
unsigned int tag;

bool operator==(const Pointer& obj) {
return ((this->ptr == obj.ptr) && (this->tag == obj.tag));
}

bool operator!=(const Pointer& obj) {
return ((this->ptr != obj.ptr) || (this->tag != obj.tag));
}
};

struct Node {
std::shared_ptr<T> value;
Pointer next;
Pointer prev;
};

std::atomic<Pointer*> head;
std::atomic<Pointer*> tail;

void fixList(Pointer* tail, Pointer* head) {
Pointer curNode;
Pointer curNodeNext;
curNode = *tail;
while((*head == *this->head.load()) && (curNode != *head)) {
curNodeNext = curNode.ptr->next;
curNodeNext.ptr->prev = {curNode.ptr, curNode.tag + 1};
curNode = {curNodeNext.ptr, curNode.tag - 1};
}
}
};

}

#endif