Merge branch 'master' of https://github.com/worklist/hifi into 19466

This commit is contained in:
stojce 2014-01-03 22:53:30 +01:00
commit 594a20e248
17 changed files with 189 additions and 78 deletions

View file

@ -94,7 +94,8 @@ void AudioMixerClientData::pushBuffersAfterFrameSend() {
audioBuffer->shiftReadPosition(NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
audioBuffer->setWillBeAddedToMix(false);
} else if (audioBuffer->hasStarted() && audioBuffer->isStarved()) {
} else if (audioBuffer->getType() == PositionalAudioRingBuffer::Injector
&& audioBuffer->hasStarted() && audioBuffer->isStarved()) {
// this is an empty audio buffer that has starved, safe to delete
delete audioBuffer;
_ringBuffers.erase(_ringBuffers.begin() + i);

View file

@ -127,11 +127,10 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f
// use the threadSound static method to inject the catch sound
// pass an AudioInjectorOptions struct to set position and disable loopback
AudioInjectorOptions injectorOptions;
injectorOptions.position = targetPosition;
injectorOptions.shouldLoopback = false;
injectorOptions.loopbackAudioInterface = app->getAudio();
AudioInjector::threadSound(&_catchSound, injectorOptions);
injectorOptions.setPosition(newPosition);
injectorOptions.setLoopbackAudioInterface(app->getAudio());
AudioScriptingInterface::playSound(&_catchSound, &injectorOptions);
}
}
@ -216,11 +215,10 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f
// use the threadSound static method to inject the throw sound
// pass an AudioInjectorOptions struct to set position and disable loopback
AudioInjectorOptions injectorOptions;
injectorOptions.position = targetPosition;
injectorOptions.shouldLoopback = false;
injectorOptions.loopbackAudioInterface = app->getAudio();
injectorOptions.setPosition(ballPosition);
injectorOptions.setLoopbackAudioInterface(app->getAudio());
AudioInjector::threadSound(&_throwSound, injectorOptions);
AudioScriptingInterface::playSound(&_throwSound, &injectorOptions);
}
}

View file

@ -17,7 +17,7 @@
#include <SharedUtil.h>
#include <AvatarData.h>
#include <AudioInjector.h>
#include <AudioScriptingInterface.h>
#include <HandData.h>
#include <ParticleEditHandle.h>

View file

@ -3,7 +3,7 @@
// hifi
//
// Created by Stephen Birarda on 1/2/2014.
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
//
#include <NodeList.h>
@ -18,33 +18,11 @@
int abstractAudioPointerMeta = qRegisterMetaType<AbstractAudioInterface*>("AbstractAudioInterface*");
AudioInjector::AudioInjector(Sound* sound, AudioInjectorOptions injectorOptions) :
_thread(NULL),
AudioInjector::AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions) :
_sound(sound),
_volume(injectorOptions.volume),
_shouldLoopback(injectorOptions.shouldLoopback),
_position(injectorOptions.position),
_orientation(injectorOptions.orientation),
_loopbackAudioInterface(injectorOptions.loopbackAudioInterface)
_options(injectorOptions)
{
_thread = new QThread();
// we want to live on our own thread
moveToThread(_thread);
}
void AudioInjector::threadSound(Sound* sound, AudioInjectorOptions injectorOptions) {
AudioInjector* injector = new AudioInjector(sound, injectorOptions);
// start injecting when the injector thread starts
connect(injector->_thread, SIGNAL(started()), injector, SLOT(injectAudio()));
// connect the right slots and signals so that the AudioInjector is killed once the injection is complete
connect(injector, SIGNAL(finished()), injector, SLOT(deleteLater()));
connect(injector, SIGNAL(finished()), injector->_thread, SLOT(quit()));
connect(injector->_thread, SIGNAL(finished()), injector->_thread, SLOT(deleteLater()));
injector->_thread->start();
}
const uchar MAX_INJECTOR_VOLUME = 0xFF;
@ -56,9 +34,9 @@ void AudioInjector::injectAudio() {
// make sure we actually have samples downloaded to inject
if (soundByteArray.size()) {
// give our sample byte array to the local audio interface, if we have it, so it can be handled locally
if (_loopbackAudioInterface) {
if (_options.getLoopbackAudioInterface()) {
// assume that localAudioInterface could be on a separate thread, use Qt::AutoConnection to handle properly
QMetaObject::invokeMethod(_loopbackAudioInterface, "handleAudioByteArray",
QMetaObject::invokeMethod(_options.getLoopbackAudioInterface(), "handleAudioByteArray",
Qt::AutoConnection,
Q_ARG(QByteArray, soundByteArray));
@ -85,16 +63,17 @@ void AudioInjector::injectAudio() {
currentPacketPosition += rfcStreamUUID.size();
// pack the flag for loopback
memcpy(currentPacketPosition, &_shouldLoopback, sizeof(_shouldLoopback));
currentPacketPosition += sizeof(_shouldLoopback);
bool loopbackFlag = (_options.getLoopbackAudioInterface() == NULL);
memcpy(currentPacketPosition, &loopbackFlag, sizeof(loopbackFlag));
currentPacketPosition += sizeof(loopbackFlag);
// pack the position for injected audio
memcpy(currentPacketPosition, &_position, sizeof(_position));
currentPacketPosition += sizeof(_position);
memcpy(currentPacketPosition, &_options.getPosition(), sizeof(_options.getPosition()));
currentPacketPosition += sizeof(_options.getPosition());
// pack our orientation for injected audio
memcpy(currentPacketPosition, &_orientation, sizeof(_orientation));
currentPacketPosition += sizeof(_orientation);
memcpy(currentPacketPosition, &_options.getOrientation(), sizeof(_options.getOrientation()));
currentPacketPosition += sizeof(_options.getOrientation());
// pack zero for radius
float radius = 0;
@ -102,7 +81,7 @@ void AudioInjector::injectAudio() {
currentPacketPosition += sizeof(radius);
// pack 255 for attenuation byte
uchar volume = MAX_INJECTOR_VOLUME * _volume;
uchar volume = MAX_INJECTOR_VOLUME * _options.getVolume();
memcpy(currentPacketPosition, &volume, sizeof(volume));
currentPacketPosition += sizeof(volume);

View file

@ -3,7 +3,7 @@
// hifi
//
// Created by Stephen Birarda on 1/2/2014.
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
//
#ifndef __hifi__AudioInjector__
@ -15,39 +15,20 @@
#include <glm/glm.hpp>
#include <glm/gtx/quaternion.hpp>
#include "AudioInjectorOptions.h"
#include "Sound.h"
class AbstractAudioInterface;
struct AudioInjectorOptions {
AudioInjectorOptions() : position(glm::vec3(0.0f, 0.0f, 0.0f)),
volume(1.0f),
orientation(glm::quat()),
shouldLoopback(true),
loopbackAudioInterface(NULL) {};
glm::vec3 position;
float volume;
const glm::quat orientation;
bool shouldLoopback;
AbstractAudioInterface* loopbackAudioInterface;
};
class AudioScriptingInterface;
class AudioInjector : public QObject {
Q_OBJECT
public:
static void threadSound(Sound* sound, AudioInjectorOptions injectorOptions = AudioInjectorOptions());
AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions);
private:
AudioInjector(Sound* sound, AudioInjectorOptions injectorOptions);
QThread* _thread;
Sound* _sound;
float _volume;
uchar _shouldLoopback;
glm::vec3 _position;
glm::quat _orientation;
AbstractAudioInterface* _loopbackAudioInterface;
private slots:
AudioInjectorOptions _options;
public slots:
void injectAudio();
signals:
void finished();

View file

@ -0,0 +1,26 @@
//
// AudioInjectorOptions.cpp
// hifi
//
// Created by Stephen Birarda on 1/2/2014.
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
//
#include "AudioInjectorOptions.h"
AudioInjectorOptions::AudioInjectorOptions(QObject* parent) :
QObject(parent),
_position(0.0f, 0.0f, 0.0f),
_volume(1.0f),
_orientation(glm::vec3(0.0f, 0.0f, 0.0f)),
_loopbackAudioInterface(NULL)
{
}
AudioInjectorOptions::AudioInjectorOptions(const AudioInjectorOptions& other) {
_position = other._position;
_volume = other._volume;
_orientation = other._orientation;
_loopbackAudioInterface = other._loopbackAudioInterface;
}

View file

@ -0,0 +1,48 @@
//
// AudioInjectorOptions.h
// hifi
//
// Created by Stephen Birarda on 1/2/2014.
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
//
#ifndef __hifi__AudioInjectorOptions__
#define __hifi__AudioInjectorOptions__
#include <QtCore/QObject>
#include <glm/glm.hpp>
#include <glm/gtx/quaternion.hpp>
#include <RegisteredMetaTypes.h>
#include "AbstractAudioInterface.h"
class AudioInjectorOptions : public QObject {
Q_OBJECT
Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition)
public:
AudioInjectorOptions(QObject* parent = 0);
AudioInjectorOptions(const AudioInjectorOptions& other);
const glm::vec3& getPosition() const { return _position; }
void setPosition(const glm::vec3& position) { _position = position; }
float getVolume() const { return _volume; }
void setVolume(float volume) { _volume = volume; }
const glm::quat& getOrientation() const { return _orientation; }
void setOrientation(const glm::quat& orientation) { _orientation = orientation; }
AbstractAudioInterface* getLoopbackAudioInterface() const { return _loopbackAudioInterface; }
void setLoopbackAudioInterface(AbstractAudioInterface* loopbackAudioInterface)
{ _loopbackAudioInterface = loopbackAudioInterface; }
private:
glm::vec3 _position;
float _volume;
glm::quat _orientation;
AbstractAudioInterface* _loopbackAudioInterface;
};
#endif /* defined(__hifi__AudioInjectorOptions__) */

View file

@ -107,8 +107,6 @@ qint64 AudioRingBuffer::writeData(const char* data, qint64 maxSize) {
_isStarved = true;
}
_hasStarted = true;
if (_endOfLastWrite + samplesToCopy <= _buffer + _sampleCapacity) {
memcpy(_endOfLastWrite, data, samplesToCopy * sizeof(int16_t));
} else {

View file

@ -0,0 +1,28 @@
//
// AudioScriptingInterface.cpp
// hifi
//
// Created by Stephen Birarda on 1/2/2014.
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
//
#include "AudioScriptingInterface.h"
void AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions* injectorOptions) {
AudioInjector* injector = new AudioInjector(sound, *injectorOptions);
QThread* injectorThread = new QThread();
injector->moveToThread(injectorThread);
// start injecting when the injector thread starts
connect(injectorThread, SIGNAL(started()), injector, SLOT(injectAudio()));
// connect the right slots and signals so that the AudioInjector is killed once the injection is complete
connect(injector, SIGNAL(finished()), injector, SLOT(deleteLater()));
connect(injector, SIGNAL(finished()), injectorThread, SLOT(quit()));
connect(injectorThread, SIGNAL(finished()), injectorThread, SLOT(deleteLater()));
injectorThread->start();
}

View file

@ -0,0 +1,23 @@
//
// AudioScriptingInterface.h
// hifi
//
// Created by Stephen Birarda on 1/2/2014.
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
//
#ifndef __hifi__AudioScriptingInterface__
#define __hifi__AudioScriptingInterface__
#include "AudioInjector.h"
#include "Sound.h"
const AudioInjectorOptions DEFAULT_INJECTOR_OPTIONS;
class AudioScriptingInterface : public QObject {
Q_OBJECT
public slots:
static void playSound(Sound* sound, const AudioInjectorOptions* injectorOptions = NULL);
};
#endif /* defined(__hifi__AudioScriptingInterface__) */

View file

@ -48,8 +48,6 @@ int InjectedAudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes
unsigned int attenuationByte = *(currentBuffer++);
_attenuationRatio = attenuationByte / (float) MAX_INJECTOR_VOLUME;
qDebug() << "Copying" << numBytes - (currentBuffer - sourceBuffer) << "for injected ring buffer\n";
currentBuffer += writeData((char*) currentBuffer, numBytes - (currentBuffer - sourceBuffer));
return currentBuffer - sourceBuffer;

View file

@ -66,6 +66,10 @@ bool PositionalAudioRingBuffer::shouldBeAddedToMix(int numJitterBufferSamples) {
} else {
// good buffer, add this to the mix
_isStarved = false;
// since we've read data from ring buffer at least once - we've started
_hasStarted = true;
return true;
}

View file

@ -3,7 +3,7 @@
// hifi
//
// Created by Stephen Birarda on 1/2/2014.
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
//
#include <QtNetwork/QNetworkAccessManager>
@ -12,7 +12,9 @@
#include "Sound.h"
Sound::Sound(const QUrl& sampleURL) {
Sound::Sound(const QUrl& sampleURL, QObject* parent) :
QObject(parent)
{
// assume we have a QApplication or QCoreApplication instance and use the
// QNetworkAccess manager to grab the raw audio file at the given URL

View file

@ -3,7 +3,7 @@
// hifi
//
// Created by Stephen Birarda on 1/2/2014.
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
//
#ifndef __hifi__Sound__
@ -16,7 +16,7 @@ class QNetworkReply;
class Sound : public QObject {
Q_OBJECT
public:
Sound(const QUrl& sampleURL);
Sound(const QUrl& sampleURL, QObject* parent = 0);
const QByteArray& getByteArray() { return _byteArray; }
private:

View file

@ -20,12 +20,20 @@
#include <UUID.h>
#include <VoxelConstants.h>
#include <Sound.h>
#include "ScriptEngine.h"
int ScriptEngine::_scriptNumber = 1;
VoxelsScriptingInterface ScriptEngine::_voxelsScriptingInterface;
ParticlesScriptingInterface ScriptEngine::_particlesScriptingInterface;
static QScriptValue soundConstructor(QScriptContext* context, QScriptEngine* engine) {
QUrl soundURL = QUrl(context->argument(0).toString());
QScriptValue soundScriptValue = engine->newQObject(new Sound(soundURL), QScriptEngine::ScriptOwnership);
return soundScriptValue;
}
ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems,
const char* scriptMenuName, AbstractMenuInterface* menu,
@ -82,6 +90,8 @@ bool ScriptEngine::setScriptContents(const QString& scriptContents) {
return true;
}
Q_SCRIPT_DECLARE_QMETAOBJECT(AudioInjectorOptions, QObject*)
void ScriptEngine::run() {
_isRunning = true;
QScriptEngine engine;
@ -101,6 +111,17 @@ void ScriptEngine::run() {
QScriptValue particleScripterValue = engine.newQObject(&_particlesScriptingInterface);
engine.globalObject().setProperty("Particles", particleScripterValue);
QScriptValue soundConstructorValue = engine.newFunction(soundConstructor);
QScriptValue soundMetaObject = engine.newQMetaObject(&Sound::staticMetaObject, soundConstructorValue);
engine.globalObject().setProperty("Sound", soundMetaObject);
QScriptValue injectionOptionValue = engine.scriptValueFromQMetaObject<AudioInjectorOptions>();
engine.globalObject().setProperty("AudioInjectionOptions", injectionOptionValue);
QScriptValue audioScriptingInterfaceValue = engine.newQObject(&_audioScriptingInterface);
engine.globalObject().setProperty("Audio", audioScriptingInterfaceValue);
if (_controllerScriptingInterface) {
QScriptValue controllerScripterValue = engine.newQObject(_controllerScriptingInterface);
engine.globalObject().setProperty("Controller", controllerScripterValue);

View file

@ -16,8 +16,10 @@
#include <QtCore/QUrl>
#include <AbstractMenuInterface.h>
#include <AudioScriptingInterface.h>
#include <ParticlesScriptingInterface.h>
#include <VoxelsScriptingInterface.h>
#include "AbstractControllerScriptingInterface.h"
const QString NO_SCRIPT("");
@ -61,6 +63,7 @@ private:
static VoxelsScriptingInterface _voxelsScriptingInterface;
static ParticlesScriptingInterface _particlesScriptingInterface;
AbstractControllerScriptingInterface* _controllerScriptingInterface;
AudioScriptingInterface _audioScriptingInterface;
bool _wantMenuItems;
QString _scriptMenuName;
AbstractMenuInterface* _menu;

View file

@ -12,6 +12,7 @@
#define hifi_RegisteredMetaTypes_h
#include <glm/glm.hpp>
#include <QtScript/QScriptEngine>
#include "SharedUtil.h"