From a07b673f69e5684f379db990a2ae87ff6643de7f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 3 Oct 2013 11:41:45 -0700 Subject: [PATCH 1/7] beginning of hook of AudioInjector into JS --- assignment-client/src/Agent.cpp | 46 ++++++++++++++++++++++++++--- assignment-client/src/Agent.h | 9 ++++++ assignment-client/src/main.cpp | 4 ++- libraries/audio/src/AudioInjector.h | 9 +++++- 4 files changed, 62 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 2906233d78..d0f36402b5 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -8,8 +8,6 @@ #include -#include - #include #include #include @@ -17,11 +15,13 @@ #include "Agent.h" #include "voxels/VoxelScriptingInterface.h" +Agent* Agent::_staticInstance = NULL; + Agent::Agent(const unsigned char* dataBuffer, int numBytes) : Assignment(dataBuffer, numBytes), _shouldStop(false) { - + setStaticInstance(this); } void Agent::stop() { @@ -40,10 +40,40 @@ static size_t writeScriptDataToString(void *contents, size_t size, size_t nmemb, return realSize; } +void Agent::setStaticInstance(Agent* staticInstance) { + _staticInstance = staticInstance; +} + +QScriptValue Agent::AudioInjectorConstructor(QScriptContext *context, QScriptEngine *engine) { + AudioInjector* injector = new AudioInjector(BUFFER_LENGTH_SAMPLES_PER_CHANNEL); + + // add this injector to the vector of audio injectors so we know we have to tell it to send its audio during loop + _staticInstance->_audioInjectors.push_back(injector); + + return engine->newQObject(injector, QScriptEngine::ScriptOwnership); +} + +QScriptValue vec3toScriptValue(QScriptEngine *engine, const glm::vec3 &vec3) { + QScriptValue obj = engine->newObject(); + obj.setProperty("x", vec3.x); + obj.setProperty("y", vec3.y); + obj.setProperty("z", vec3.z); + return obj; +} + +void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3) { + vec3.x = object.property("x").toVariant().toFloat(); + vec3.y = object.property("y").toVariant().toFloat(); + vec3.z = object.property("z").toVariant().toFloat(); +} + void Agent::run() { NodeList* nodeList = NodeList::getInstance(); nodeList->setOwnerType(NODE_TYPE_AGENT); - nodeList->setNodeTypesOfInterest(&NODE_TYPE_VOXEL_SERVER, 1); + + const char AGENT_NODE_TYPES_OF_INTEREST[2] = { NODE_TYPE_VOXEL_SERVER, NODE_TYPE_AUDIO_MIXER }; + + nodeList->setNodeTypesOfInterest(AGENT_NODE_TYPES_OF_INTEREST, sizeof(AGENT_NODE_TYPES_OF_INTEREST)); nodeList->getNodeSocket()->setBlocking(false); @@ -83,6 +113,9 @@ void Agent::run() { QScriptEngine engine; + // register meta-type for glm::vec3 conversions + qScriptRegisterMetaType(&engine, vec3toScriptValue, vec3FromScriptValue); + QScriptValue agentValue = engine.newQObject(this); engine.globalObject().setProperty("Agent", agentValue); @@ -101,6 +134,11 @@ void Agent::run() { QScriptValue visualSendIntervalValue = engine.newVariant((QVariant(VISUAL_DATA_SEND_INTERVAL_USECS / 1000))); engine.globalObject().setProperty("VISUAL_DATA_SEND_INTERVAL_MS", visualSendIntervalValue); + // hook in a constructor for audio injectorss + QScriptValue audioInjectorConstructor = engine.newFunction(AudioInjectorConstructor); + QScriptValue audioMetaObject = engine.newQMetaObject(&AudioInjector::staticMetaObject, audioInjectorConstructor); + engine.globalObject().setProperty("AudioInjector", audioMetaObject); + qDebug() << "Downloaded script:" << scriptContents << "\n"; QScriptValue result = engine.evaluate(scriptContents); qDebug() << "Evaluated script.\n"; diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 0490238d3f..84e8e11269 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -9,9 +9,13 @@ #ifndef __hifi__Agent__ #define __hifi__Agent__ +#include + +#include #include #include +#include #include class Agent : public Assignment { @@ -25,7 +29,12 @@ public slots: signals: void willSendVisualDataCallback(); private: + static void setStaticInstance(Agent* staticInstance); + static Agent* _staticInstance; + static QScriptValue AudioInjectorConstructor(QScriptContext *context, QScriptEngine *engine); + bool volatile _shouldStop; + std::vector _audioInjectors; }; #endif /* defined(__hifi__Operative__) */ diff --git a/assignment-client/src/main.cpp b/assignment-client/src/main.cpp index 75c8a00343..03578c4e8a 100644 --- a/assignment-client/src/main.cpp +++ b/assignment-client/src/main.cpp @@ -66,11 +66,13 @@ void childClient() { // create a request assignment, accept assignments defined by the overidden type Assignment requestAssignment(Assignment::RequestCommand, ::overiddenAssignmentType); + qDebug() << "Waiting for assignment -" << requestAssignment << "\n"; + while (true) { if (usecTimestampNow() - usecTimestamp(&lastRequest) >= ASSIGNMENT_REQUEST_INTERVAL_USECS) { gettimeofday(&lastRequest, NULL); + // if we're here we have no assignment, so send a request - qDebug() << "Sending an assignment request -" << requestAssignment << "\n"; nodeList->sendAssignment(requestAssignment); } diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index b102d58e19..b8e6cb823d 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -12,6 +12,8 @@ #include #include +#include + #include #include "AudioRingBuffer.h" @@ -22,7 +24,12 @@ const int MAX_INJECTOR_VOLUME = 0xFF; const int INJECT_INTERVAL_USECS = floorf((BUFFER_LENGTH_SAMPLES_PER_CHANNEL / SAMPLE_RATE) * 1000000); -class AudioInjector { +Q_DECLARE_METATYPE(glm::vec3) + +class AudioInjector : public QObject { + Q_OBJECT + + Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) public: AudioInjector(const char* filename); AudioInjector(int maxNumSamples); From e977d28fe338e431c8d0ee98baab648f34ee022c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 3 Oct 2013 11:55:30 -0700 Subject: [PATCH 2/7] replace QVariantMap glm::vec3 setters with conversions for QScriptValue --- libraries/audio/src/AudioInjector.h | 3 +- libraries/avatars/src/AvatarData.cpp | 32 ---------------------- libraries/avatars/src/AvatarData.h | 15 ++++------ libraries/shared/src/RegisteredMetaTypes.h | 16 +++++++++++ 4 files changed, 23 insertions(+), 43 deletions(-) create mode 100644 libraries/shared/src/RegisteredMetaTypes.h diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index b8e6cb823d..5824086eb0 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -14,6 +14,7 @@ #include +#include #include #include "AudioRingBuffer.h" @@ -24,8 +25,6 @@ const int MAX_INJECTOR_VOLUME = 0xFF; const int INJECT_INTERVAL_USECS = floorf((BUFFER_LENGTH_SAMPLES_PER_CHANNEL / SAMPLE_RATE) * 1000000); -Q_DECLARE_METATYPE(glm::vec3) - class AudioInjector : public QObject { Q_OBJECT diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index edc76bedca..66c33d4713 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -52,38 +52,6 @@ AvatarData::~AvatarData() { delete _handData; } -void AvatarData::setPositionFromVariantMap(QVariantMap positionMap) { - _position = glm::vec3(positionMap.value("x").toFloat(), - positionMap.value("y").toFloat(), - positionMap.value("z").toFloat()); -} - -QVariantMap AvatarData::getPositionVariantMap() { - QVariantMap positionMap; - - positionMap.insert("x", _position.x); - positionMap.insert("y", _position.y); - positionMap.insert("z", _position.z); - - return positionMap; -} - -void AvatarData::setHandPositionFromVariantMap(QVariantMap handPositionMap) { - _handPosition = glm::vec3(handPositionMap.value("x").toFloat(), - handPositionMap.value("y").toFloat(), - handPositionMap.value("z").toFloat()); -} - -QVariantMap AvatarData::getHandPositionVariantMap() { - QVariantMap positionMap; - - positionMap.insert("x", _handPosition.x); - positionMap.insert("y", _handPosition.y); - positionMap.insert("z", _handPosition.z); - - return positionMap; -} - void AvatarData::sendData() { // called from Agent visual loop to send data diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 82ef0d671a..0b1181f8f2 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -19,6 +19,8 @@ #include #include +#include + #include #include "HeadData.h" #include "HandData.h" @@ -48,8 +50,8 @@ class JointData; class AvatarData : public NodeData { Q_OBJECT - Q_PROPERTY(QVariantMap position READ getPositionVariantMap WRITE setPositionFromVariantMap) - Q_PROPERTY(QVariantMap handPosition READ getHandPositionVariantMap WRITE setHandPositionFromVariantMap) + Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) + Q_PROPERTY(glm::vec3 handPosition READ getHandPosition WRITE setHandPosition) Q_PROPERTY(float bodyYaw READ getBodyYaw WRITE setBodyYaw) Q_PROPERTY(float bodyPitch READ getBodyPitch WRITE setBodyPitch) Q_PROPERTY(float bodyRoll READ getBodyRoll WRITE setBodyRoll) @@ -59,16 +61,11 @@ public: ~AvatarData(); const glm::vec3& getPosition() const { return _position; } - void setPosition(const glm::vec3 position) { _position = position; } + + const glm::vec3& getHandPosition() const { return _handPosition; } void setHandPosition(const glm::vec3 handPosition) { _handPosition = handPosition; } - void setPositionFromVariantMap(QVariantMap positionMap); - QVariantMap getPositionVariantMap(); - - void setHandPositionFromVariantMap(QVariantMap handPositionMap); - QVariantMap getHandPositionVariantMap(); - int getBroadcastData(unsigned char* destinationBuffer); int parseData(unsigned char* sourceBuffer, int numBytes); diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h new file mode 100644 index 0000000000..e15e053ebb --- /dev/null +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -0,0 +1,16 @@ +// +// RegisteredMetaTypes.h +// hifi +// +// Created by Stephen Birarda on 10/3/13. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// +// Used to register meta-types with Qt so that they can be used as properties for objects exposed to our +// Agent scripting. + +#ifndef hifi_RegisteredMetaTypes_h +#define hifi_RegisteredMetaTypes_h + +Q_DECLARE_METATYPE(glm::vec3) + +#endif From 0477ad79ddf781bcce0eaf3fb90d59337af25132 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 3 Oct 2013 13:22:02 -0700 Subject: [PATCH 3/7] add methods to set/get samples and volume --- libraries/audio/src/AudioInjector.cpp | 12 ++++++++++++ libraries/audio/src/AudioInjector.h | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index b9a6d8a0ba..cc0a329641 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -152,3 +152,15 @@ void AudioInjector::addSamples(int16_t* sampleBuffer, int numSamples) { _indexOfNextSlot += numSamples; } } + +int16_t& AudioInjector::sampleAt(const int index) { + assert(index >= 0 && index < _numTotalSamples); + + return _audioSampleArray[index]; +} + +void AudioInjector::insertSample(const int index, int16_t sample) { + assert (index >= 0 && index < _numTotalSamples); + + _audioSampleArray[index] = sample; +} diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 5824086eb0..9054b08a16 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -29,6 +29,7 @@ class AudioInjector : public QObject { Q_OBJECT Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) + Q_PROPERTY(uchar volume READ getVolume WRITE setVolume); public: AudioInjector(const char* filename); AudioInjector(int maxNumSamples); @@ -54,6 +55,9 @@ public: void addSample(const int16_t sample); void addSamples(int16_t* sampleBuffer, int numSamples); +public slots: + int16_t& sampleAt(const int index); + void insertSample(const int index, int16_t sample); private: unsigned char _streamIdentifier[STREAM_IDENTIFIER_NUM_BYTES]; int16_t* _audioSampleArray; From 40dd6982937c293826648a51b90d08e96b8f57df Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Oct 2013 11:07:46 -0700 Subject: [PATCH 4/7] =?UTF-8?q?don=E2=80=99t=20have=20AvatarMixer=20ask=20?= =?UTF-8?q?DS=20for=20agents?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assignment-client/src/avatars/AvatarMixer.cpp | 12 +++++------- libraries/shared/src/NodeList.cpp | 13 ++++++++++++- libraries/shared/src/NodeList.h | 2 +- libraries/shared/src/UDPSocket.cpp | 4 ++-- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 1a4f9844eb..5c7e47a42a 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -98,7 +98,7 @@ void AvatarMixer::run() { nodeList->startSilentNodeRemovalThread(); - sockaddr* nodeAddress = new sockaddr; + sockaddr nodeAddress = {}; ssize_t receivedBytes = 0; unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE]; @@ -107,8 +107,6 @@ void AvatarMixer::run() { Node* avatarNode = NULL; timeval lastDomainServerCheckIn = {}; - // we only need to hear back about avatar nodes from the DS - nodeList->setNodeTypesOfInterest(&NODE_TYPE_AGENT, 1); while (true) { @@ -122,7 +120,7 @@ void AvatarMixer::run() { NodeList::getInstance()->sendDomainServerCheckIn(_uuid.toRfc4122().constData()); } - if (nodeList->getNodeSocket()->receive(nodeAddress, packetData, &receivedBytes) && + if (nodeList->getNodeSocket()->receive(&nodeAddress, packetData, &receivedBytes) && packetVersionMatch(packetData)) { switch (packetData[0]) { case PACKET_TYPE_HEAD_DATA: @@ -130,12 +128,12 @@ void AvatarMixer::run() { unpackNodeId(packetData + numBytesForPacketHeader(packetData), &nodeID); // add or update the node in our list - avatarNode = nodeList->addOrUpdateNode(nodeAddress, nodeAddress, NODE_TYPE_AGENT, nodeID); + avatarNode = nodeList->addOrUpdateNode(&nodeAddress, &nodeAddress, NODE_TYPE_AGENT, nodeID); // parse positional data from an node nodeList->updateNodeWithData(avatarNode, packetData, receivedBytes); case PACKET_TYPE_INJECT_AUDIO: - broadcastAvatarData(nodeList, nodeAddress); + broadcastAvatarData(nodeList, &nodeAddress); break; case PACKET_TYPE_AVATAR_URLS: case PACKET_TYPE_AVATAR_FACE_VIDEO: @@ -151,7 +149,7 @@ void AvatarMixer::run() { break; default: // hand this off to the NodeList - nodeList->processNodeData(nodeAddress, packetData, receivedBytes); + nodeList->processNodeData(&nodeAddress, packetData, receivedBytes); break; } } diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 4307810db3..b22b3188a6 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -428,18 +428,23 @@ void NodeList::sendAssignment(Assignment& assignment) { } Node* NodeList::addOrUpdateNode(sockaddr* publicSocket, sockaddr* localSocket, char nodeType, uint16_t nodeId) { + qDebug() << "BEGIN:" << publicSocket << "and" << localSocket << "\n"; NodeList::iterator node = end(); if (publicSocket) { for (node = begin(); node != end(); node++) { + qDebug() << "comparing to node with ID " << node->getNodeID() << "\n"; if (node->matches(publicSocket, localSocket, nodeType)) { // we already have this node, stop checking + qDebug() << "Matched node to existing\n"; break; } } } - if (node == end()) { + if (node == end()) { + qDebug() << "We're considering this a new node!\n"; + qDebug() << publicSocket << "and" << localSocket << "\n"; // we didn't have this node, so add them Node* newNode = new Node(publicSocket, localSocket, nodeType, nodeId); @@ -540,6 +545,10 @@ void* removeSilentNodes(void *args) { for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); ++node) { + node->lock(); + + qDebug() << "This node's LHMS is" << node->getLastHeardMicrostamp() << "\n"; + if ((checkTimeUSecs - node->getLastHeardMicrostamp()) > NODE_SILENCE_THRESHOLD_USECS) { qDebug() << "Killed " << *node << "\n"; @@ -548,6 +557,8 @@ void* removeSilentNodes(void *args) { node->setAlive(false); } + + node->unlock(); } sleepTime = NODE_SILENCE_THRESHOLD_USECS - (usecTimestampNow() - checkTimeUSecs); diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index 1bac084fe5..9914ac9094 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -30,7 +30,7 @@ const int NODES_PER_BUCKET = 100; const int MAX_PACKET_SIZE = 1500; -const int NODE_SILENCE_THRESHOLD_USECS = 2 * 1000000; +const uint64_t NODE_SILENCE_THRESHOLD_USECS = 2 * 1000000; const int DOMAIN_SERVER_CHECK_IN_USECS = 1 * 1000000; extern const char SOLO_NODE_TYPES[2]; diff --git a/libraries/shared/src/UDPSocket.cpp b/libraries/shared/src/UDPSocket.cpp index beee5c6879..68eb2ad82e 100644 --- a/libraries/shared/src/UDPSocket.cpp +++ b/libraries/shared/src/UDPSocket.cpp @@ -43,7 +43,7 @@ bool socketMatch(const sockaddr* first, const sockaddr* second) { const sockaddr_in *secondIn = (const sockaddr_in *) second; return firstIn->sin_addr.s_addr == secondIn->sin_addr.s_addr - && firstIn->sin_port == secondIn->sin_port; + && firstIn->sin_port == secondIn->sin_port; } else { return false; } @@ -254,7 +254,7 @@ bool UDPSocket::receive(sockaddr* recvAddress, void* receivedData, ssize_t* rece #ifdef _WIN32 int addressSize = sizeof(*recvAddress); #else - socklen_t addressSize = sizeof(&recvAddress); + socklen_t addressSize = sizeof(*recvAddress); #endif *receivedBytes = recvfrom(handle, static_cast(receivedData), MAX_BUFFER_LENGTH_BYTES, 0, recvAddress, &addressSize); From 0eae0f129cd96f473baa1979ec89625803e14e2b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Oct 2013 17:37:48 -0700 Subject: [PATCH 5/7] allow audio injection from javascript --- assignment-client/src/Agent.cpp | 75 ++++++++++++--------------- assignment-client/src/Agent.h | 1 + libraries/audio/src/AudioInjector.cpp | 32 ++++-------- libraries/audio/src/AudioInjector.h | 5 +- libraries/shared/src/NodeList.cpp | 2 - 5 files changed, 45 insertions(+), 70 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index b2b4a72a10..81fe4cb5e5 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -45,15 +45,6 @@ void Agent::setStaticInstance(Agent* staticInstance) { _staticInstance = staticInstance; } -QScriptValue Agent::AudioInjectorConstructor(QScriptContext *context, QScriptEngine *engine) { - AudioInjector* injector = new AudioInjector(BUFFER_LENGTH_SAMPLES_PER_CHANNEL); - - // add this injector to the vector of audio injectors so we know we have to tell it to send its audio during loop - _staticInstance->_audioInjectors.push_back(injector); - - return engine->newQObject(injector, QScriptEngine::ScriptOwnership); -} - QScriptValue vec3toScriptValue(QScriptEngine *engine, const glm::vec3 &vec3) { QScriptValue obj = engine->newObject(); obj.setProperty("x", vec3.x); @@ -126,19 +117,14 @@ void Agent::run() { QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE)); engine.globalObject().setProperty("TREE_SCALE", treeScaleValue); - - const long long VISUAL_DATA_SEND_INTERVAL_USECS = (1 / 60.0f) * 1000 * 1000; // let the VoxelPacketSender know how frequently we plan to call it - voxelScripter.getVoxelPacketSender()->setProcessCallIntervalHint(VISUAL_DATA_SEND_INTERVAL_USECS); - - QScriptValue visualSendIntervalValue = engine.newVariant((QVariant(VISUAL_DATA_SEND_INTERVAL_USECS / 1000))); - engine.globalObject().setProperty("VISUAL_DATA_SEND_INTERVAL_MS", visualSendIntervalValue); + voxelScripter.getVoxelPacketSender()->setProcessCallIntervalHint(INJECT_INTERVAL_USECS); // hook in a constructor for audio injectorss - QScriptValue audioInjectorConstructor = engine.newFunction(AudioInjectorConstructor); - QScriptValue audioMetaObject = engine.newQMetaObject(&AudioInjector::staticMetaObject, audioInjectorConstructor); - engine.globalObject().setProperty("AudioInjector", audioMetaObject); + AudioInjector scriptedAudioInjector(BUFFER_LENGTH_SAMPLES_PER_CHANNEL); + QScriptValue audioInjectorValue = engine.newQObject(&scriptedAudioInjector); + engine.globalObject().setProperty("AudioInjector", audioInjectorValue); qDebug() << "Downloaded script:" << scriptContents << "\n"; QScriptValue result = engine.evaluate(scriptContents); @@ -149,19 +135,20 @@ void Agent::run() { qDebug() << "Uncaught exception at line" << line << ":" << result.toString() << "\n"; } - timeval thisSend; + timeval startTime; + gettimeofday(&startTime, NULL); + timeval lastDomainServerCheckIn = {}; - int numMicrosecondsSleep = 0; sockaddr_in senderAddress; unsigned char receivedData[MAX_PACKET_SIZE]; ssize_t receivedBytes; - bool hasVoxelServer = false; + int thisFrame = 0; + + bool firstDomainCheckIn = false; while (!_shouldStop) { - // update the thisSend timeval to the current time - gettimeofday(&thisSend, NULL); // if we're not hearing from the domain-server we should stop running if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { @@ -174,38 +161,44 @@ void Agent::run() { NodeList::getInstance()->sendDomainServerCheckIn(); } - if (!hasVoxelServer) { - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { - if (node->getType() == NODE_TYPE_VOXEL_SERVER) { - hasVoxelServer = true; + if (firstDomainCheckIn) { + // find the audio-mixer in the NodeList so we can inject audio at it + Node* audioMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AUDIO_MIXER); + + emit willSendAudioDataCallback(); + + if (audioMixer) { + int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * INJECT_INTERVAL_USECS) - usecTimestampNow(); + if (usecToSleep > 0) { + usleep(usecToSleep); } + + scriptedAudioInjector.injectAudio(NodeList::getInstance()->getNodeSocket(), audioMixer->getPublicSocket()); } - } - - if (hasVoxelServer) { + // allow the scripter's call back to setup visual data emit willSendVisualDataCallback(); - if (engine.hasUncaughtException()) { - int line = engine.uncaughtExceptionLineNumber(); - qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n"; - } - // release the queue of edit voxel messages. voxelScripter.getVoxelPacketSender()->releaseQueuedMessages(); - + // since we're in non-threaded mode, call process so that the packets are sent voxelScripter.getVoxelPacketSender()->process(); + } + if (engine.hasUncaughtException()) { + int line = engine.uncaughtExceptionLineNumber(); + qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n"; + } + while (NodeList::getInstance()->getNodeSocket()->receive((sockaddr*) &senderAddress, receivedData, &receivedBytes)) { + if (!firstDomainCheckIn && receivedData[0] == PACKET_TYPE_DOMAIN) { + firstDomainCheckIn = true; + } + NodeList::getInstance()->processNodeData((sockaddr*) &senderAddress, receivedData, receivedBytes); } - - // sleep for the correct amount of time to have data send be consistently timed - if ((numMicrosecondsSleep = VISUAL_DATA_SEND_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&thisSend))) > 0) { - usleep(numMicrosecondsSleep); - } } } else { diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 84e8e11269..de6a94fd6b 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -27,6 +27,7 @@ public: public slots: void stop(); signals: + void willSendAudioDataCallback(); void willSendVisualDataCallback(); private: static void setStaticInstance(Agent* staticInstance); diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index cc0a329641..acdee03e8f 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -21,8 +21,7 @@ AudioInjector::AudioInjector(const char* filename) : _radius(0.0f), _volume(MAX_INJECTOR_VOLUME), _indexOfNextSlot(0), - _isInjectingAudio(false), - _lastFrameIntensity(0.0f) + _isInjectingAudio(false) { loadRandomIdentifier(_streamIdentifier, STREAM_IDENTIFIER_NUM_BYTES); @@ -52,8 +51,7 @@ AudioInjector::AudioInjector(int maxNumSamples) : _radius(0.0f), _volume(MAX_INJECTOR_VOLUME), _indexOfNextSlot(0), - _isInjectingAudio(false), - _lastFrameIntensity(0.0f) + _isInjectingAudio(false) { loadRandomIdentifier(_streamIdentifier, STREAM_IDENTIFIER_NUM_BYTES); @@ -103,6 +101,11 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination int nextFrame = 0; for (int i = 0; i < _numTotalSamples; i += BUFFER_LENGTH_SAMPLES_PER_CHANNEL) { + int usecToSleep = usecTimestamp(&startTime) + (nextFrame++ * INJECT_INTERVAL_USECS) - usecTimestampNow(); + if (usecToSleep > 0) { + usleep(usecToSleep); + } + int numSamplesToCopy = BUFFER_LENGTH_SAMPLES_PER_CHANNEL; if (_numTotalSamples - i < BUFFER_LENGTH_SAMPLES_PER_CHANNEL) { @@ -115,23 +118,6 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination memcpy(currentPacketPtr, _audioSampleArray + i, numSamplesToCopy * sizeof(int16_t)); injectorSocket->send(destinationSocket, dataPacket, sizeof(dataPacket)); - - // calculate the intensity for this frame - float lastRMS = 0; - - for (int j = 0; j < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; j++) { - lastRMS += _audioSampleArray[i + j] * _audioSampleArray[i + j]; - } - - lastRMS /= BUFFER_LENGTH_SAMPLES_PER_CHANNEL; - lastRMS = sqrtf(lastRMS); - - _lastFrameIntensity = lastRMS / std::numeric_limits::max(); - - int usecToSleep = usecTimestamp(&startTime) + (++nextFrame * INJECT_INTERVAL_USECS) - usecTimestampNow(); - if (usecToSleep > 0) { - usleep(usecToSleep); - } } _isInjectingAudio = false; @@ -159,8 +145,8 @@ int16_t& AudioInjector::sampleAt(const int index) { return _audioSampleArray[index]; } -void AudioInjector::insertSample(const int index, int16_t sample) { +void AudioInjector::insertSample(const int index, int sample) { assert (index >= 0 && index < _numTotalSamples); - _audioSampleArray[index] = sample; + _audioSampleArray[index] = (int16_t) sample; } diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 9054b08a16..626cdc3149 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -42,8 +42,6 @@ public: unsigned char getVolume() const { return _volume; } void setVolume(unsigned char volume) { _volume = volume; } - float getLastFrameIntensity() const { return _lastFrameIntensity; } - const glm::vec3& getPosition() const { return _position; } void setPosition(const glm::vec3& position) { _position = position; } @@ -57,7 +55,7 @@ public: void addSamples(int16_t* sampleBuffer, int numSamples); public slots: int16_t& sampleAt(const int index); - void insertSample(const int index, int16_t sample); + void insertSample(const int index, int sample); private: unsigned char _streamIdentifier[STREAM_IDENTIFIER_NUM_BYTES]; int16_t* _audioSampleArray; @@ -68,7 +66,6 @@ private: unsigned char _volume; int _indexOfNextSlot; bool _isInjectingAudio; - float _lastFrameIntensity; }; #endif /* defined(__hifi__AudioInjector__) */ diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index a559b58f10..12a24c535f 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -441,10 +441,8 @@ Node* NodeList::addOrUpdateNode(sockaddr* publicSocket, sockaddr* localSocket, c if (publicSocket) { for (node = begin(); node != end(); node++) { - qDebug() << "comparing to node with ID " << node->getNodeID() << "\n"; if (node->matches(publicSocket, localSocket, nodeType)) { // we already have this node, stop checking - qDebug() << "Matched node to existing\n"; break; } } From cdfb23207804c602ea4948e6264e3bb98b8088bd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Oct 2013 17:40:02 -0700 Subject: [PATCH 6/7] remove the Agent static instance --- assignment-client/src/Agent.cpp | 4 +--- assignment-client/src/Agent.h | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 81fe4cb5e5..6a5fe92b8d 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -16,15 +16,13 @@ #include "Agent.h" #include "voxels/VoxelScriptingInterface.h" -Agent* Agent::_staticInstance = NULL; - Agent::Agent(const unsigned char* dataBuffer, int numBytes) : Assignment(dataBuffer, numBytes), _shouldStop(false) { - setStaticInstance(this); } + void Agent::stop() { _shouldStop = true; } diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index de6a94fd6b..ba70fd58ec 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -30,8 +30,6 @@ signals: void willSendAudioDataCallback(); void willSendVisualDataCallback(); private: - static void setStaticInstance(Agent* staticInstance); - static Agent* _staticInstance; static QScriptValue AudioInjectorConstructor(QScriptContext *context, QScriptEngine *engine); bool volatile _shouldStop; From 2bbaf7d31e9405415f60e6e2b95ac615712d1fa2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Oct 2013 17:40:28 -0700 Subject: [PATCH 7/7] remove static instance set from Agent.cpp --- assignment-client/src/Agent.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 6a5fe92b8d..d9cf479b17 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -39,10 +39,6 @@ static size_t writeScriptDataToString(void *contents, size_t size, size_t nmemb, return realSize; } -void Agent::setStaticInstance(Agent* staticInstance) { - _staticInstance = staticInstance; -} - QScriptValue vec3toScriptValue(QScriptEngine *engine, const glm::vec3 &vec3) { QScriptValue obj = engine->newObject(); obj.setProperty("x", vec3.x);