allow audio injection from javascript

This commit is contained in:
Stephen Birarda 2013-10-11 17:37:48 -07:00
parent 515e2d5a23
commit 0eae0f129c
5 changed files with 45 additions and 70 deletions

View file

@ -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 {

View file

@ -27,6 +27,7 @@ public:
public slots:
void stop();
signals:
void willSendAudioDataCallback();
void willSendVisualDataCallback();
private:
static void setStaticInstance(Agent* staticInstance);

View file

@ -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<int16_t>::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;
}

View file

@ -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__) */

View file

@ -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;
}
}