mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
add support for AudioDevice scripting interface, and switching audio input/output device on the fly
This commit is contained in:
parent
938959a9f6
commit
82d620b1d9
5 changed files with 190 additions and 23 deletions
|
@ -72,6 +72,7 @@
|
||||||
#include "devices/TV3DManager.h"
|
#include "devices/TV3DManager.h"
|
||||||
#include "renderer/ProgramObject.h"
|
#include "renderer/ProgramObject.h"
|
||||||
|
|
||||||
|
#include "scripting/AudioDeviceScriptingInterface.h"
|
||||||
#include "scripting/ClipboardScriptingInterface.h"
|
#include "scripting/ClipboardScriptingInterface.h"
|
||||||
#include "scripting/MenuScriptingInterface.h"
|
#include "scripting/MenuScriptingInterface.h"
|
||||||
#include "scripting/SettingsScriptingInterface.h"
|
#include "scripting/SettingsScriptingInterface.h"
|
||||||
|
@ -3552,6 +3553,7 @@ void Application::loadScript(const QString& fileNameString) {
|
||||||
scriptEngine->registerGlobalObject("Overlays", &_overlays);
|
scriptEngine->registerGlobalObject("Overlays", &_overlays);
|
||||||
scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance());
|
scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance());
|
||||||
scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance());
|
scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance());
|
||||||
|
scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance());
|
||||||
|
|
||||||
QThread* workerThread = new QThread(this);
|
QThread* workerThread = new QThread(this);
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,16 @@ void Audio::reset() {
|
||||||
_ringBuffer.reset();
|
_ringBuffer.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QAudioDeviceInfo getNamedAudioDeviceForMode(QAudio::Mode mode, const QString& deviceName) {
|
||||||
|
QAudioDeviceInfo result;
|
||||||
|
foreach(QAudioDeviceInfo audioDevice, QAudioDeviceInfo::availableDevices(mode)) {
|
||||||
|
if (audioDevice.deviceName().trimmed() == deviceName.trimmed()) {
|
||||||
|
result = audioDevice;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) {
|
QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) {
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
if (QAudioDeviceInfo::availableDevices(mode).size() > 1) {
|
if (QAudioDeviceInfo::availableDevices(mode).size() > 1) {
|
||||||
|
@ -249,27 +259,92 @@ void Audio::start() {
|
||||||
_desiredOutputFormat.setChannelCount(2);
|
_desiredOutputFormat.setChannelCount(2);
|
||||||
|
|
||||||
QAudioDeviceInfo inputDeviceInfo = defaultAudioDeviceForMode(QAudio::AudioInput);
|
QAudioDeviceInfo inputDeviceInfo = defaultAudioDeviceForMode(QAudio::AudioInput);
|
||||||
qDebug() << "The audio input device is" << inputDeviceInfo.deviceName();
|
qDebug() << "The default audio input device is" << inputDeviceInfo.deviceName();
|
||||||
|
bool inputFormatSupported = switchInputToAudioDevice(inputDeviceInfo.deviceName());
|
||||||
|
|
||||||
|
QAudioDeviceInfo outputDeviceInfo = defaultAudioDeviceForMode(QAudio::AudioOutput);
|
||||||
|
qDebug() << "The default audio output device is" << outputDeviceInfo.deviceName();
|
||||||
|
bool outputFormatSupported = switchOutputToAudioDevice(outputDeviceInfo.deviceName());
|
||||||
|
|
||||||
if (adjustedFormatForAudioDevice(inputDeviceInfo, _desiredInputFormat, _inputFormat)) {
|
if (!inputFormatSupported || !outputFormatSupported) {
|
||||||
qDebug() << "The format to be used for audio input is" << _inputFormat;
|
qDebug() << "Unable to set up audio I/O because of a problem with input or output formats.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Audio::switchInputToAudioDevice(const QString& inputDeviceName) {
|
||||||
|
bool supportedFormat = false;
|
||||||
|
|
||||||
|
// cleanup any previously initialized device
|
||||||
|
if (_audioInput) {
|
||||||
|
_audioInput->stop();
|
||||||
|
disconnect(_inputDevice, 0, 0, 0);
|
||||||
|
_inputDevice = NULL;
|
||||||
|
|
||||||
|
delete _audioInput;
|
||||||
|
_audioInput = NULL;
|
||||||
|
_numInputCallbackBytes = 0;
|
||||||
|
|
||||||
|
_inputAudioDeviceName = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
QAudioDeviceInfo inputDeviceInfo = getNamedAudioDeviceForMode(QAudio::AudioInput, inputDeviceName);
|
||||||
|
|
||||||
|
if (!inputDeviceInfo.isNull()) {
|
||||||
|
qDebug() << "The audio input device " << inputDeviceInfo.deviceName() << "is available.";
|
||||||
|
_inputAudioDeviceName = inputDeviceInfo.deviceName().trimmed();
|
||||||
|
|
||||||
|
if (adjustedFormatForAudioDevice(inputDeviceInfo, _desiredInputFormat, _inputFormat)) {
|
||||||
|
qDebug() << "The format to be used for audio input is" << _inputFormat;
|
||||||
|
|
||||||
_audioInput = new QAudioInput(inputDeviceInfo, _inputFormat, this);
|
_audioInput = new QAudioInput(inputDeviceInfo, _inputFormat, this);
|
||||||
_numInputCallbackBytes = NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL * _inputFormat.channelCount()
|
_numInputCallbackBytes = NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL * _inputFormat.channelCount()
|
||||||
* (_inputFormat.sampleRate() / SAMPLE_RATE)
|
* (_inputFormat.sampleRate() / SAMPLE_RATE)
|
||||||
/ CALLBACK_ACCELERATOR_RATIO;
|
/ CALLBACK_ACCELERATOR_RATIO;
|
||||||
_audioInput->setBufferSize(_numInputCallbackBytes);
|
_audioInput->setBufferSize(_numInputCallbackBytes);
|
||||||
|
|
||||||
QAudioDeviceInfo outputDeviceInfo = defaultAudioDeviceForMode(QAudio::AudioOutput);
|
// how do we want to handle input working, but output not working?
|
||||||
qDebug() << "The audio output device is" << outputDeviceInfo.deviceName();
|
|
||||||
|
|
||||||
if (adjustedFormatForAudioDevice(outputDeviceInfo, _desiredOutputFormat, _outputFormat)) {
|
|
||||||
qDebug() << "The format to be used for audio output is" << _outputFormat;
|
|
||||||
|
|
||||||
_inputRingBuffer.resizeForFrameSize(_numInputCallbackBytes * CALLBACK_ACCELERATOR_RATIO / sizeof(int16_t));
|
_inputRingBuffer.resizeForFrameSize(_numInputCallbackBytes * CALLBACK_ACCELERATOR_RATIO / sizeof(int16_t));
|
||||||
_inputDevice = _audioInput->start();
|
_inputDevice = _audioInput->start();
|
||||||
connect(_inputDevice, SIGNAL(readyRead()), this, SLOT(handleAudioInput()));
|
connect(_inputDevice, SIGNAL(readyRead()), this, SLOT(handleAudioInput()));
|
||||||
|
|
||||||
|
supportedFormat = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return supportedFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Audio::switchOutputToAudioDevice(const QString& outputDeviceName) {
|
||||||
|
bool supportedFormat = false;
|
||||||
|
|
||||||
|
// cleanup any previously initialized device
|
||||||
|
if (_audioOutput) {
|
||||||
|
_audioOutput->stop();
|
||||||
|
disconnect(_outputDevice, 0, 0, 0);
|
||||||
|
_outputDevice = NULL;
|
||||||
|
|
||||||
|
delete _audioOutput;
|
||||||
|
_audioOutput = NULL;
|
||||||
|
_numInputCallbackBytes = 0;
|
||||||
|
|
||||||
|
_loopbackOutputDevice = NULL;
|
||||||
|
delete _loopbackAudioOutput;
|
||||||
|
_loopbackAudioOutput = NULL;
|
||||||
|
|
||||||
|
_proceduralOutputDevice = NULL;
|
||||||
|
delete _proceduralAudioOutput;
|
||||||
|
_proceduralAudioOutput = NULL;
|
||||||
|
_outputAudioDeviceName = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
QAudioDeviceInfo outputDeviceInfo = getNamedAudioDeviceForMode(QAudio::AudioOutput, outputDeviceName);
|
||||||
|
|
||||||
|
if (!outputDeviceInfo.isNull()) {
|
||||||
|
qDebug() << "The audio output device " << outputDeviceInfo.deviceName() << "is available.";
|
||||||
|
_outputAudioDeviceName = outputDeviceInfo.deviceName().trimmed();
|
||||||
|
|
||||||
|
if (adjustedFormatForAudioDevice(outputDeviceInfo, _desiredOutputFormat, _outputFormat)) {
|
||||||
|
qDebug() << "The format to be used for audio output is" << _outputFormat;
|
||||||
|
|
||||||
// setup our general output device for audio-mixer audio
|
// setup our general output device for audio-mixer audio
|
||||||
_audioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
|
_audioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
|
||||||
_audioOutput->setBufferSize(_ringBuffer.getSampleCapacity() * sizeof(int16_t));
|
_audioOutput->setBufferSize(_ringBuffer.getSampleCapacity() * sizeof(int16_t));
|
||||||
|
@ -278,17 +353,15 @@ void Audio::start() {
|
||||||
|
|
||||||
// setup a loopback audio output device
|
// setup a loopback audio output device
|
||||||
_loopbackAudioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
|
_loopbackAudioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
|
||||||
|
|
||||||
// setup a procedural audio output device
|
// setup a procedural audio output device
|
||||||
_proceduralAudioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
|
_proceduralAudioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
|
||||||
|
|
||||||
gettimeofday(&_lastReceiveTime, NULL);
|
gettimeofday(&_lastReceiveTime, NULL);
|
||||||
|
supportedFormat = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
return supportedFormat;
|
||||||
qDebug() << "Unable to set up audio I/O because of a problem with input or output formats.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::handleAudioInput() {
|
void Audio::handleAudioInput() {
|
||||||
|
@ -315,7 +388,9 @@ void Audio::handleAudioInput() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_inputFormat == _outputFormat) {
|
if (_inputFormat == _outputFormat) {
|
||||||
_loopbackOutputDevice->write(inputByteArray);
|
if (_loopbackOutputDevice) {
|
||||||
|
_loopbackOutputDevice->write(inputByteArray);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
static float loopbackOutputToInputRatio = (_outputFormat.sampleRate() / (float) _inputFormat.sampleRate())
|
static float loopbackOutputToInputRatio = (_outputFormat.sampleRate() / (float) _inputFormat.sampleRate())
|
||||||
* (_outputFormat.channelCount() / _inputFormat.channelCount());
|
* (_outputFormat.channelCount() / _inputFormat.channelCount());
|
||||||
|
@ -326,7 +401,9 @@ void Audio::handleAudioInput() {
|
||||||
inputByteArray.size() / sizeof(int16_t),
|
inputByteArray.size() / sizeof(int16_t),
|
||||||
loopBackByteArray.size() / sizeof(int16_t), _inputFormat, _outputFormat);
|
loopBackByteArray.size() / sizeof(int16_t), _inputFormat, _outputFormat);
|
||||||
|
|
||||||
_loopbackOutputDevice->write(loopBackByteArray);
|
if (_loopbackOutputDevice) {
|
||||||
|
_loopbackOutputDevice->write(loopBackByteArray);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,7 +546,9 @@ void Audio::handleAudioInput() {
|
||||||
NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * 4,
|
NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * 4,
|
||||||
_desiredInputFormat, _outputFormat);
|
_desiredInputFormat, _outputFormat);
|
||||||
|
|
||||||
_proceduralOutputDevice->write(proceduralOutput);
|
if (_proceduralOutputDevice) {
|
||||||
|
_proceduralOutputDevice->write(proceduralOutput);
|
||||||
|
}
|
||||||
|
|
||||||
NodeList* nodeList = NodeList::getInstance();
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer);
|
SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer);
|
||||||
|
|
|
@ -72,7 +72,7 @@ public:
|
||||||
|
|
||||||
int getNetworkSampleRate() { return SAMPLE_RATE; }
|
int getNetworkSampleRate() { return SAMPLE_RATE; }
|
||||||
int getNetworkBufferLengthSamplesPerChannel() { return NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; }
|
int getNetworkBufferLengthSamplesPerChannel() { return NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void start();
|
void start();
|
||||||
void addReceivedAudioToBuffer(const QByteArray& audioByteArray);
|
void addReceivedAudioToBuffer(const QByteArray& audioByteArray);
|
||||||
|
@ -83,10 +83,18 @@ public slots:
|
||||||
|
|
||||||
virtual void handleAudioByteArray(const QByteArray& audioByteArray);
|
virtual void handleAudioByteArray(const QByteArray& audioByteArray);
|
||||||
|
|
||||||
|
bool switchInputToAudioDevice(const QString& inputDeviceName);
|
||||||
|
bool switchOutputToAudioDevice(const QString& outputDeviceName);
|
||||||
|
|
||||||
|
QString getInputAudioDeviceName() const { return _inputAudioDeviceName; }
|
||||||
|
QString getOutputAudioDeviceName() const { return _outputAudioDeviceName; }
|
||||||
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
bool muteToggled();
|
bool muteToggled();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
QByteArray firstInputFrame;
|
QByteArray firstInputFrame;
|
||||||
QAudioInput* _audioInput;
|
QAudioInput* _audioInput;
|
||||||
QAudioFormat _desiredInputFormat;
|
QAudioFormat _desiredInputFormat;
|
||||||
|
@ -105,6 +113,9 @@ private:
|
||||||
QIODevice* _proceduralOutputDevice;
|
QIODevice* _proceduralOutputDevice;
|
||||||
AudioRingBuffer _inputRingBuffer;
|
AudioRingBuffer _inputRingBuffer;
|
||||||
AudioRingBuffer _ringBuffer;
|
AudioRingBuffer _ringBuffer;
|
||||||
|
|
||||||
|
QString _inputAudioDeviceName;
|
||||||
|
QString _outputAudioDeviceName;
|
||||||
|
|
||||||
Oscilloscope* _scope;
|
Oscilloscope* _scope;
|
||||||
StDev _stdev;
|
StDev _stdev;
|
||||||
|
|
44
interface/src/scripting/AudioDeviceScriptingInterface.cpp
Normal file
44
interface/src/scripting/AudioDeviceScriptingInterface.cpp
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
//
|
||||||
|
// AudioDeviceScriptingInterface.cpp
|
||||||
|
// hifi
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 3/23/14
|
||||||
|
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
#include "AudioDeviceScriptingInterface.h"
|
||||||
|
|
||||||
|
|
||||||
|
AudioDeviceScriptingInterface* AudioDeviceScriptingInterface::getInstance() {
|
||||||
|
static AudioDeviceScriptingInterface sharedInstance;
|
||||||
|
return &sharedInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AudioDeviceScriptingInterface::setInputDevice(const QString& deviceName) {
|
||||||
|
bool result;
|
||||||
|
QMetaObject::invokeMethod(Application::getInstance()->getAudio(), "switchInputToAudioDevice",
|
||||||
|
Qt::BlockingQueuedConnection,
|
||||||
|
Q_RETURN_ARG(bool, result),
|
||||||
|
Q_ARG(const QString&, deviceName));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AudioDeviceScriptingInterface::setOutputDevice(const QString& deviceName) {
|
||||||
|
bool result;
|
||||||
|
QMetaObject::invokeMethod(Application::getInstance()->getAudio(), "switchOutputToAudioDevice",
|
||||||
|
Qt::BlockingQueuedConnection,
|
||||||
|
Q_RETURN_ARG(bool, result),
|
||||||
|
Q_ARG(const QString&, deviceName));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString AudioDeviceScriptingInterface::getInputDevice() {
|
||||||
|
return Application::getInstance()->getAudio()->getInputAudioDeviceName();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString AudioDeviceScriptingInterface::getOutputDevice() {
|
||||||
|
return Application::getInstance()->getAudio()->getOutputAudioDeviceName();
|
||||||
|
}
|
31
interface/src/scripting/AudioDeviceScriptingInterface.h
Normal file
31
interface/src/scripting/AudioDeviceScriptingInterface.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
//
|
||||||
|
// AudioDeviceScriptingInterface.h
|
||||||
|
// hifi
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 3/22/14
|
||||||
|
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __hifi__AudioDeviceScriptingInterface__
|
||||||
|
#define __hifi__AudioDeviceScriptingInterface__
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
|
||||||
|
class AudioDeviceScriptingInterface : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
AudioDeviceScriptingInterface() { };
|
||||||
|
public:
|
||||||
|
static AudioDeviceScriptingInterface* getInstance();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
bool setInputDevice(const QString& deviceName);
|
||||||
|
bool setOutputDevice(const QString& deviceName);
|
||||||
|
QString getInputDevice();
|
||||||
|
QString getOutputDevice();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* defined(__hifi__AudioDeviceScriptingInterface__) */
|
Loading…
Reference in a new issue