repairs to AudioMixer and audio injection flow

This commit is contained in:
Stephen Birarda 2014-01-02 17:15:46 -08:00
parent 594bd58774
commit 443c94a88f
13 changed files with 95 additions and 41 deletions

View file

@ -9,6 +9,8 @@
#include <PacketHeaders.h>
#include <UUID.h>
#include <QDebug>
#include "InjectedAudioRingBuffer.h"
#include "AudioMixerClientData.h"
@ -94,7 +96,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,7 +127,7 @@ 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.position = newPosition;
injectorOptions.shouldLoopback = false;
injectorOptions.loopbackAudioInterface = app->getAudio();
@ -216,7 +216,7 @@ 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.position = ballPosition;
injectorOptions.shouldLoopback = false;
injectorOptions.loopbackAudioInterface = app->getAudio();

View file

@ -20,11 +20,7 @@ int abstractAudioPointerMeta = qRegisterMetaType<AbstractAudioInterface*>("Abstr
AudioInjector::AudioInjector(Sound* sound, AudioInjectorOptions injectorOptions) :
_sound(sound),
_volume(injectorOptions.volume),
_shouldLoopback(injectorOptions.shouldLoopback),
_position(injectorOptions.position),
_orientation(injectorOptions.orientation),
_loopbackAudioInterface(injectorOptions.loopbackAudioInterface)
_options(injectorOptions)
{
}
@ -38,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.loopbackAudioInterface) {
// assume that localAudioInterface could be on a separate thread, use Qt::AutoConnection to handle properly
QMetaObject::invokeMethod(_loopbackAudioInterface, "handleAudioByteArray",
QMetaObject::invokeMethod(_options.loopbackAudioInterface, "handleAudioByteArray",
Qt::AutoConnection,
Q_ARG(QByteArray, soundByteArray));
@ -67,16 +63,16 @@ void AudioInjector::injectAudio() {
currentPacketPosition += rfcStreamUUID.size();
// pack the flag for loopback
memcpy(currentPacketPosition, &_shouldLoopback, sizeof(_shouldLoopback));
currentPacketPosition += sizeof(_shouldLoopback);
memcpy(currentPacketPosition, &_options.shouldLoopback, sizeof(_options.shouldLoopback));
currentPacketPosition += sizeof(_options.shouldLoopback);
// pack the position for injected audio
memcpy(currentPacketPosition, &_position, sizeof(_position));
currentPacketPosition += sizeof(_position);
memcpy(currentPacketPosition, &_options.position, sizeof(_options.position));
currentPacketPosition += sizeof(_options.position);
// pack our orientation for injected audio
memcpy(currentPacketPosition, &_orientation, sizeof(_orientation));
currentPacketPosition += sizeof(_orientation);
memcpy(currentPacketPosition, &_options.orientation, sizeof(_options.orientation));
currentPacketPosition += sizeof(_options.orientation);
// pack zero for radius
float radius = 0;
@ -84,7 +80,7 @@ void AudioInjector::injectAudio() {
currentPacketPosition += sizeof(radius);
// pack 255 for attenuation byte
uchar volume = MAX_INJECTOR_VOLUME * _volume;
uchar volume = MAX_INJECTOR_VOLUME * _options.volume;
memcpy(currentPacketPosition, &volume, sizeof(volume));
currentPacketPosition += sizeof(volume);

View file

@ -15,25 +15,12 @@
#include <glm/glm.hpp>
#include <glm/gtx/quaternion.hpp>
#include "AudioInjectorOptions.h"
#include "Sound.h"
class AbstractAudioInterface;
class AudioScriptingInterface;
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 AudioInjector : public QObject {
Q_OBJECT
public:
@ -42,11 +29,7 @@ private:
AudioInjector(Sound* sound, AudioInjectorOptions injectorOptions);
Sound* _sound;
float _volume;
uchar _shouldLoopback;
glm::vec3 _position;
glm::quat _orientation;
AbstractAudioInterface* _loopbackAudioInterface;
AudioInjectorOptions _options;
private slots:
void injectAudio();
signals:

View file

@ -0,0 +1,28 @@
//
// AudioInjectorOptions.cpp
// hifi
//
// Created by Stephen Birarda on 1/2/2014.
// Copyright (c) 2013 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)),
shouldLoopback(true),
loopbackAudioInterface(NULL)
{
}
AudioInjectorOptions::AudioInjectorOptions(const AudioInjectorOptions& other) {
position = other.position;
volume = other.volume;
orientation = other.orientation;
shouldLoopback = other.shouldLoopback;
loopbackAudioInterface = other.loopbackAudioInterface;
}

View file

@ -0,0 +1,32 @@
//
// AudioInjectorOptions.h
// hifi
//
// Created by Stephen Birarda on 1/2/2014.
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
//
#ifndef __hifi__AudioInjectorOptions__
#define __hifi__AudioInjectorOptions__
#include <QtCore/QObject>
#include <glm/glm.hpp>
#include <glm/gtx/quaternion.hpp>
#include "AbstractAudioInterface.h"
class AudioInjectorOptions : public QObject {
Q_OBJECT
public:
AudioInjectorOptions(QObject* parent = 0);
AudioInjectorOptions(const AudioInjectorOptions& other);
glm::vec3 position;
float volume;
glm::quat orientation;
bool shouldLoopback;
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

@ -6,9 +6,12 @@
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
//
#include <QtCore/qdebug.h>
#include "AudioScriptingInterface.h"
void AudioScriptingInterface::playSound(Sound* sound, AudioInjectorOptions injectorOptions) {
AudioInjector* injector = new AudioInjector(sound, injectorOptions);
QThread* injectorThread = new QThread();

View file

@ -12,9 +12,12 @@
#include "AudioInjector.h"
#include "Sound.h"
const AudioInjectorOptions DEFAULT_INJECTOR_OPTIONS;
class AudioScriptingInterface : public QObject {
Q_OBJECT
public slots:
static void playSound(Sound* sound, AudioInjectorOptions injectorOptions = AudioInjectorOptions());
static void playSound(Sound* sound, AudioInjectorOptions injectorOptions = DEFAULT_INJECTOR_OPTIONS);
};
#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

@ -113,6 +113,9 @@ void ScriptEngine::run() {
QScriptValue soundMetaObject = engine.newQMetaObject(&Sound::staticMetaObject, soundConstructorValue);
engine.globalObject().setProperty("Sound", soundMetaObject);
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;