add AudioInjectorLocalBuffer for more control

This commit is contained in:
Stephen Birarda 2014-11-11 16:34:00 -08:00
parent 0e30c65e60
commit a5a02b5f8a
8 changed files with 136 additions and 31 deletions

View file

@ -38,7 +38,8 @@ var panelsCenterShift = Vec3.subtract(panelsCenter, orbCenter);
var ORB_SHIFT = { x: 0, y: -1.4, z: -0.8};
var HELMET_ATTACHMENT_URL = HIFI_PUBLIC_BUCKET + "models/attachments/IronManMaskOnly.fbx"
var droneSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/drone.raw")
var droneSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/latin.raw")
var currentDrone;
function reticlePosition() {

View file

@ -1336,21 +1336,25 @@ void Audio::startDrumSound(float volume, float frequency, float duration, float
_drumSoundSample = 0;
}
QIODevice* Audio::newLocalOutputDevice(bool isStereo, qreal volume, int numBytes, AudioInjector* injector) {
QAudioFormat localFormat = _desiredOutputFormat;
localFormat.setChannelCount(isStereo ? 2 : 1);
bool Audio::outputLocalInjector(bool isStereo, qreal volume, AudioInjector* injector) {
if (injector->getLocalBuffer()) {
QAudioFormat localFormat = _desiredOutputFormat;
localFormat.setChannelCount(isStereo ? 2 : 1);
QAudioOutput* localOutput = new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName),
localFormat, this);
localOutput->setVolume(volume);
// add this to our list of local injected outputs, we will need to clean it up when the injector says it is done
_injectedOutputInterfaces.insert(injector, localOutput);
connect(injector, &AudioInjector::finished, this, &Audio::cleanupLocalOutputInterface);
localOutput->start(injector->getLocalBuffer());
return localOutput->state() == QAudio::ActiveState;
}
QAudioOutput* localOutput = new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName),
localFormat, this);
localOutput->setBufferSize(numBytes);
localOutput->setVolume(volume);
// add this to our list of local injected outputs, we will need to clean it up when the injector says it is done
_injectedOutputInterfaces.insert(injector, localOutput);
connect(injector, &AudioInjector::finished, this, &Audio::cleanupLocalOutputInterface);
return localOutput->start();
return false;
}
void Audio::cleanupLocalOutputInterface() {

View file

@ -155,7 +155,7 @@ public slots:
void selectAudioFilterBassCut();
void selectAudioFilterSmiley();
virtual QIODevice* newLocalOutputDevice(bool isStereo, qreal volume, int numBytes, AudioInjector* injector);
virtual bool outputLocalInjector(bool isStereo, qreal volume, AudioInjector* injector);
void sendDownstreamAudioStatsPacket();

View file

@ -18,6 +18,7 @@
#include "AudioInjectorOptions.h"
class AudioInjector;
class AudioInjectorLocalBuffer;
class AbstractAudioInterface : public QObject {
Q_OBJECT
@ -27,7 +28,7 @@ public:
virtual void startCollisionSound(float magnitude, float frequency, float noise, float duration, bool flashScreen) = 0;
virtual void startDrumSound(float volume, float frequency, float duration, float decay) = 0;
public slots:
virtual QIODevice* newLocalOutputDevice(bool isStereo, qreal volume, int numBytes, AudioInjector* injector) = 0;
virtual bool outputLocalInjector(bool isStereo, qreal volume, AudioInjector* injector) = 0;
};
Q_DECLARE_METATYPE(AbstractAudioInterface*)

View file

@ -37,7 +37,7 @@ AudioInjector::AudioInjector(QObject* parent) :
_loudness(0.0f),
_isFinished(false),
_currentSendPosition(0),
_localDevice(NULL)
_localBuffer(NULL)
{
}
@ -47,10 +47,17 @@ AudioInjector::AudioInjector(Sound* sound, const AudioInjectorOptions& injectorO
_shouldStop(false),
_loudness(0.0f),
_isFinished(false),
_currentSendPosition(0)
_currentSendPosition(0),
_localBuffer(NULL)
{
}
AudioInjector::~AudioInjector() {
if (_localBuffer) {
_localBuffer->stop();
}
}
void AudioInjector::setOptions(AudioInjectorOptions& options) {
_options = options;
}
@ -72,19 +79,25 @@ void AudioInjector::injectLocally() {
const QByteArray& soundByteArray = _sound->getByteArray();
if (soundByteArray.size() > 0) {
QMetaObject::invokeMethod(_localAudioInterface, "newLocalOutputDevice", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(QIODevice*, _localDevice),
bool successfulOutput = false;
_localBuffer = new AudioInjectorLocalBuffer(_sound->getByteArray(), this);
_localBuffer->open(QIODevice::ReadOnly);
_localBuffer->setIsLooping(_options.loop);
qDebug() << "Passing off AudioInjectorLocatBuffer to localAudioInterface";
QMetaObject::invokeMethod(_localAudioInterface, "outputLocalInjector",
Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, successfulOutput),
Q_ARG(bool, _options.stereo),
Q_ARG(qreal, _options.volume),
Q_ARG(int, soundByteArray.size()),
Q_ARG(AudioInjector*, this));
if (_localDevice) {
// immediately write the byte array to the local device
qDebug() << "Writing" << soundByteArray.size() << "bytes to local audio device";
_localDevice->write(soundByteArray);
} else {
qDebug() << "AudioInjector::injectLocally did not get a valid QIODevice from _localAudioInterface";
if (!successfulOutput) {
qDebug() << "AudioInjector::injectLocally could not output locally via _localAudioInterface";
}
} else {
qDebug() << "AudioInjector::injectLocally called without any data in Sound QByteArray";
@ -224,8 +237,11 @@ void AudioInjector::injectToMixer() {
void AudioInjector::stop() {
_shouldStop = true;
if (_localDevice) {
// we're only a local injector, so we can say we are finished and the AbstractAudioInterface should clean us up
if (_localBuffer) {
// we're only a local injector, so we can say we are finished right away too
_localBuffer->stop();
_isFinished = true;
emit finished();
}

View file

@ -18,6 +18,7 @@
#include <glm/glm.hpp>
#include <glm/gtx/quaternion.hpp>
#include "AudioInjectorLocalBuffer.h"
#include "AudioInjectorOptions.h"
#include "Sound.h"
@ -28,10 +29,14 @@ class AudioInjector : public QObject {
public:
AudioInjector(QObject* parent);
AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions);
~AudioInjector();
bool isFinished() const { return _isFinished; }
int getCurrentSendPosition() const { return _currentSendPosition; }
AudioInjectorLocalBuffer* getLocalBuffer() const { return _localBuffer; }
bool isLocalOnly() const { return _options.localOnly; }
void setLocalAudioInterface(AbstractAudioInterface* localAudioInterface) { _localAudioInterface = localAudioInterface; }
public slots:
void injectAudio();
@ -53,7 +58,7 @@ private:
bool _isFinished;
int _currentSendPosition;
AbstractAudioInterface* _localAudioInterface;
QIODevice* _localDevice;
AudioInjectorLocalBuffer* _localBuffer;
};
Q_DECLARE_METATYPE(AudioInjector*)

View file

@ -0,0 +1,43 @@
//
// AudioInjectorLocalBuffer.cpp
// libraries/audio/src
//
// Created by Stephen Birarda on 2014-11-11.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "AudioInjectorLocalBuffer.h"
AudioInjectorLocalBuffer::AudioInjectorLocalBuffer(const QByteArray& rawAudioArray, QObject* parent) :
QIODevice(parent),
_rawAudioArray(rawAudioArray),
_isLooping(false),
_isStopped(false)
{
}
void AudioInjectorLocalBuffer::stop() {
_isStopped = true;
QIODevice::close();
}
qint64 AudioInjectorLocalBuffer::readData(char* data, qint64 maxSize) {
if (!_isStopped) {
int bytesToEnd = _rawAudioArray.size() - pos();
int bytesToRead = maxSize;
if (maxSize > bytesToEnd) {
bytesToRead = bytesToEnd;
}
memcpy(data, _rawAudioArray.data() + pos(), bytesToRead);
return bytesToRead;
} else {
return 0;
}
}

View file

@ -0,0 +1,35 @@
//
// AudioInjectorLocalBuffer.h
// libraries/audio/src
//
// Created by Stephen Birarda on 2014-11-11.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_AudioInjectorLocalBuffer_h
#define hifi_AudioInjectorLocalBuffer_h
#include <QtCore/qiodevice.h>
class AudioInjectorLocalBuffer : public QIODevice {
Q_OBJECT
public:
AudioInjectorLocalBuffer(const QByteArray& rawAudioArray, QObject* parent);
void stop();
qint64 readData(char* data, qint64 maxSize);
qint64 writeData(const char* data, qint64 maxSize) { return 0; }
void setIsLooping(bool isLooping) { _isLooping = isLooping; }
private:
QByteArray _rawAudioArray;
bool _isLooping;
bool _isStopped;
};
#endif // hifi_AudioInjectorLocalBuffer_h