From 542d671e54db41da70c521d6c2749f63c6893e5d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 6 Nov 2014 20:01:09 -0800 Subject: [PATCH 01/10] cleanup entity scripts when changing domains or entity is deleted --- interface/src/entities/EntityTreeRenderer.cpp | 11 ++++++++++- interface/src/entities/EntityTreeRenderer.h | 3 +++ libraries/entities/src/EntityTree.cpp | 3 +++ libraries/entities/src/EntityTree.h | 3 +++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/interface/src/entities/EntityTreeRenderer.cpp b/interface/src/entities/EntityTreeRenderer.cpp index 46406e9f5e..2eaa0fa707 100644 --- a/interface/src/entities/EntityTreeRenderer.cpp +++ b/interface/src/entities/EntityTreeRenderer.cpp @@ -61,11 +61,13 @@ EntityTreeRenderer::~EntityTreeRenderer() { void EntityTreeRenderer::clear() { OctreeRenderer::clear(); + _entityScripts.clear(); } void EntityTreeRenderer::init() { OctreeRenderer::init(); - static_cast(_tree)->setFBXService(this); + EntityTree* entityTree = static_cast(_tree); + entityTree->setFBXService(this); if (_wantScripts) { _entitiesScriptEngine = new ScriptEngine(NO_SCRIPT, "Entities", @@ -77,6 +79,8 @@ void EntityTreeRenderer::init() { // first chance, we'll check for enter/leave entity events. glm::vec3 avatarPosition = Application::getInstance()->getAvatar()->getPosition(); _lastAvatarPosition = avatarPosition + glm::vec3(1.f, 1.f, 1.f); + + connect(entityTree, &EntityTree::deletingEntity, this, &EntityTreeRenderer::deletingEntity); } QScriptValue EntityTreeRenderer::loadEntityScript(const EntityItemID& entityItemID) { @@ -762,4 +766,9 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI } } +void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) { + if (_entityScripts.contains(entityID)) { + _entityScripts.remove(entityID); + } +} diff --git a/interface/src/entities/EntityTreeRenderer.h b/interface/src/entities/EntityTreeRenderer.h index b8acb28c3b..ff9066dd6d 100644 --- a/interface/src/entities/EntityTreeRenderer.h +++ b/interface/src/entities/EntityTreeRenderer.h @@ -101,6 +101,9 @@ signals: void enterEntity(const EntityItemID& entityItemID); void leaveEntity(const EntityItemID& entityItemID); + +public slots: + void deletingEntity(const EntityItemID& entityID); private: QList _releasedModels; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index f31f21ebe9..199bd92030 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -185,6 +185,8 @@ void EntityTree::trackDeletedEntity(const EntityItemID& entityID) { } void EntityTree::deleteEntity(const EntityItemID& entityID) { + emit deletingEntity(entityID); + // NOTE: callers must lock the tree before using this method DeleteEntityOperator theOperator(this, entityID); recurseTreeWithOperator(&theOperator); @@ -197,6 +199,7 @@ void EntityTree::deleteEntities(QSet entityIDs) { foreach(const EntityItemID& entityID, entityIDs) { // tell our delete operator about this entityID theOperator.addEntityIDToDeleteList(entityID); + emit deletingEntity(entityID); } recurseTreeWithOperator(&theOperator); diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 53b407c7f5..8d1acc0d01 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -141,6 +141,9 @@ public: void trackDeletedEntity(const EntityItemID& entityID); QList& getMovingEntities() { return _movingEntities; } + +signals: + void deletingEntity(const EntityItemID& entityID); private: From c48d79ad8bfd036223fdf2fe47e26346f0668663 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 7 Nov 2014 09:05:47 -0800 Subject: [PATCH 02/10] add gettable feature which lists texture names --- examples/libraries/entityPropertyDialogBox.js | 3 +++ .../entities/RenderableModelEntityItem.cpp | 11 +++++++++ .../src/entities/RenderableModelEntityItem.h | 1 + interface/src/renderer/GeometryCache.cpp | 23 +++++++++++++++++++ interface/src/renderer/GeometryCache.h | 1 + .../entities/src/EntityItemProperties.cpp | 3 +++ libraries/entities/src/EntityItemProperties.h | 4 ++++ 7 files changed, 46 insertions(+) diff --git a/examples/libraries/entityPropertyDialogBox.js b/examples/libraries/entityPropertyDialogBox.js index 01e0c76e0d..cf9cec8d24 100644 --- a/examples/libraries/entityPropertyDialogBox.js +++ b/examples/libraries/entityPropertyDialogBox.js @@ -54,6 +54,8 @@ EntityPropertyDialogBox = (function () { index++; array.push({ label: "Textures:", value: properties.textures }); index++; + array.push({ label: "Texture Names:" + properties.textureNames, type: "header" }); + index++; } array.push({ label: "Position:", type: "header" }); index++; @@ -239,6 +241,7 @@ EntityPropertyDialogBox = (function () { properties.animationFPS = array[index++].value; properties.animationFrameIndex = array[index++].value; properties.textures = array[index++].value; + index++; // skip textureNames label } index++; // skip header properties.position.x = array[index++].value; diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index ce8d497da3..1900b3facd 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -234,6 +234,17 @@ bool RenderableModelEntityItem::needsSimulation() const { return _needsInitialSimulation || simulationState == Moving || simulationState == Changing; } +EntityItemProperties RenderableModelEntityItem::getProperties() const { + EntityItemProperties properties = ModelEntityItem::getProperties(); // get the properties from our base class + if (_model) { + const QSharedPointer& networkGeometry = _model->getGeometry(); + if (networkGeometry) { + properties.setTextureNames(networkGeometry->getTextureNames()); + } + } + return properties; +} + diff --git a/interface/src/entities/RenderableModelEntityItem.h b/interface/src/entities/RenderableModelEntityItem.h index dbc77b7e48..53ad8243f8 100644 --- a/interface/src/entities/RenderableModelEntityItem.h +++ b/interface/src/entities/RenderableModelEntityItem.h @@ -41,6 +41,7 @@ public: virtual ~RenderableModelEntityItem(); + virtual EntityItemProperties getProperties() const; virtual bool setProperties(const EntityItemProperties& properties, bool forceCopy); virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index 1e53d06d7c..6d9c53f42c 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -734,6 +734,29 @@ void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& u } } +QStringList NetworkGeometry::getTextureNames() const { + QStringList result; + for (int i = 0; i < _meshes.size(); i++) { + const NetworkMesh& mesh = _meshes[i]; + for (int j = 0; j < mesh.parts.size(); j++) { + const NetworkMeshPart& part = mesh.parts[j]; + + if (!part.diffuseTextureName.isEmpty()) { + result << part.diffuseTextureName; + } + + if (!part.normalTextureName.isEmpty()) { + result << part.normalTextureName; + } + + if (!part.specularTextureName.isEmpty()) { + result << part.specularTextureName; + } + } + } + return result; +} + /// Reads geometry in a worker thread. class GeometryReader : public QRunnable { public: diff --git a/interface/src/renderer/GeometryCache.h b/interface/src/renderer/GeometryCache.h index 72d283c931..28f1341b5f 100644 --- a/interface/src/renderer/GeometryCache.h +++ b/interface/src/renderer/GeometryCache.h @@ -112,6 +112,7 @@ public: virtual void clearLoadPriority(const QPointer& owner); void setTextureWithNameToURL(const QString& name, const QUrl& url); + QStringList getTextureNames() const; protected: diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 11661b02f4..451fffec80 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -243,6 +243,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons boundingBox.setProperty("dimensions", boundingBoxDimensions); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(boundingBox, boundingBox); // gettable, but not settable + QString textureNamesList = _textureNames.join(","); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(textureNames, textureNamesList); // gettable, but not settable + return properties; } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 92fa344286..3ae2aa9c7a 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -285,6 +285,9 @@ public: const QString& getTextures() const { return _textures; } void setTextures(const QString& value) { _textures = value; _texturesChanged = true; } + + const QStringList& getTextureNames() const { return _textureNames; } + void setTextureNames(const QStringList& value) { _textureNames = value; } void setLastEdited(quint64 usecTime) { _lastEdited = usecTime; } @@ -381,6 +384,7 @@ private: // properties of model geometry. But these properties are not serialized like other properties. QVector _sittingPoints; glm::vec3 _naturalDimensions; + QStringList _textureNames; }; Q_DECLARE_METATYPE(EntityItemProperties); QScriptValue EntityItemPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties); From 7b40a7cd89de6db8b87bc771d642a2c4f4361c08 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 7 Nov 2014 09:07:28 -0800 Subject: [PATCH 03/10] CR feedback --- interface/src/entities/EntityTreeRenderer.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/interface/src/entities/EntityTreeRenderer.cpp b/interface/src/entities/EntityTreeRenderer.cpp index 2eaa0fa707..2f8ddb1095 100644 --- a/interface/src/entities/EntityTreeRenderer.cpp +++ b/interface/src/entities/EntityTreeRenderer.cpp @@ -767,8 +767,6 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI } void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) { - if (_entityScripts.contains(entityID)) { - _entityScripts.remove(entityID); - } + _entityScripts.remove(entityID); } From fdc5aa1da54fd6580796d8efec36c151c29fbe0c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 7 Nov 2014 09:54:13 -0800 Subject: [PATCH 04/10] include urls with texture names, make sure to wait till default textures loaded before setting new textures --- examples/libraries/entityPropertyDialogBox.js | 2 +- interface/src/entities/RenderableModelEntityItem.cpp | 5 ++++- interface/src/renderer/GeometryCache.cpp | 9 ++++++--- libraries/entities/src/EntityItemProperties.cpp | 2 +- libraries/networking/src/ResourceCache.h | 2 ++ 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/examples/libraries/entityPropertyDialogBox.js b/examples/libraries/entityPropertyDialogBox.js index cf9cec8d24..584d7a38d0 100644 --- a/examples/libraries/entityPropertyDialogBox.js +++ b/examples/libraries/entityPropertyDialogBox.js @@ -54,7 +54,7 @@ EntityPropertyDialogBox = (function () { index++; array.push({ label: "Textures:", value: properties.textures }); index++; - array.push({ label: "Texture Names:" + properties.textureNames, type: "header" }); + array.push({ label: "Texture Names:\n" + properties.textureNames, type: "header" }); index++; } array.push({ label: "Position:", type: "header" }); diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index 1900b3facd..b9d67bf619 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -62,10 +62,13 @@ void RenderableModelEntityItem::remapTextures() { return; // nothing to do if we don't have a model } + if (!_model->isLoadedWithTextures()) { + return; // nothing to do if the model has not yet loaded it's default textures + } + if (_currentTextures == _textures) { return; // nothing to do if our recently mapped textures match our desired textures } - qDebug() << "void RenderableModelEntityItem::remapTextures()...."; // since we're changing here, we need to run through our current texture map // and any textures in the recently mapped texture, that is not in our desired diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index 6d9c53f42c..1742afba05 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -742,15 +742,18 @@ QStringList NetworkGeometry::getTextureNames() const { const NetworkMeshPart& part = mesh.parts[j]; if (!part.diffuseTextureName.isEmpty()) { - result << part.diffuseTextureName; + QString textureURL = part.diffuseTexture->getURL().toString(); + result << part.diffuseTextureName + ":" + textureURL; } if (!part.normalTextureName.isEmpty()) { - result << part.normalTextureName; + QString textureURL = part.normalTexture->getURL().toString(); + result << part.normalTextureName + ":" + textureURL; } if (!part.specularTextureName.isEmpty()) { - result << part.specularTextureName; + QString textureURL = part.specularTexture->getURL().toString(); + result << part.specularTextureName + ":" + textureURL; } } } diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 451fffec80..27dbe35a6d 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -243,7 +243,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons boundingBox.setProperty("dimensions", boundingBoxDimensions); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(boundingBox, boundingBox); // gettable, but not settable - QString textureNamesList = _textureNames.join(","); + QString textureNamesList = _textureNames.join(",\n"); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(textureNames, textureNamesList); // gettable, but not settable return properties; diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index d9520a4e68..496839fdcd 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -123,6 +123,8 @@ public: void setCache(ResourceCache* cache) { _cache = cache; } Q_INVOKABLE void allReferencesCleared(); + + const QUrl& getURL() const { return _url; } signals: From 45ca063249c5fb170d4665363d1f045324a99492 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 7 Nov 2014 10:00:04 -0800 Subject: [PATCH 05/10] use original textures for textureNames --- .../src/entities/RenderableModelEntityItem.cpp | 15 ++++++++++----- .../src/entities/RenderableModelEntityItem.h | 5 ++++- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index b9d67bf619..3cee527273 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -66,6 +66,14 @@ void RenderableModelEntityItem::remapTextures() { return; // nothing to do if the model has not yet loaded it's default textures } + if (!_originalTexturesRead && _model->isLoadedWithTextures()) { + const QSharedPointer& networkGeometry = _model->getGeometry(); + if (networkGeometry) { + _originalTextures = networkGeometry->getTextureNames(); + _originalTexturesRead = true; + } + } + if (_currentTextures == _textures) { return; // nothing to do if our recently mapped textures match our desired textures } @@ -239,11 +247,8 @@ bool RenderableModelEntityItem::needsSimulation() const { EntityItemProperties RenderableModelEntityItem::getProperties() const { EntityItemProperties properties = ModelEntityItem::getProperties(); // get the properties from our base class - if (_model) { - const QSharedPointer& networkGeometry = _model->getGeometry(); - if (networkGeometry) { - properties.setTextureNames(networkGeometry->getTextureNames()); - } + if (_originalTexturesRead) { + properties.setTextureNames(_originalTextures); } return properties; } diff --git a/interface/src/entities/RenderableModelEntityItem.h b/interface/src/entities/RenderableModelEntityItem.h index 53ad8243f8..48c9a26051 100644 --- a/interface/src/entities/RenderableModelEntityItem.h +++ b/interface/src/entities/RenderableModelEntityItem.h @@ -37,7 +37,8 @@ public: _model(NULL), _needsInitialSimulation(true), _needsModelReload(true), - _myRenderer(NULL) { } + _myRenderer(NULL), + _originalTexturesRead(false) { } virtual ~RenderableModelEntityItem(); @@ -60,6 +61,8 @@ private: bool _needsModelReload; EntityTreeRenderer* _myRenderer; QString _currentTextures; + QStringList _originalTextures; + bool _originalTexturesRead; }; #endif // hifi_RenderableModelEntityItem_h From 53f5019ee730291d8756b678e935988560277732 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 7 Nov 2014 10:05:36 -0800 Subject: [PATCH 06/10] rename textureNames to originalTextures --- libraries/entities/src/EntityItemProperties.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 27dbe35a6d..9032cebc77 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -244,7 +244,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(boundingBox, boundingBox); // gettable, but not settable QString textureNamesList = _textureNames.join(",\n"); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(textureNames, textureNamesList); // gettable, but not settable + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(originalTextures, textureNamesList); // gettable, but not settable return properties; } From 742e6487c784b90283f46aeceaad6232041ff8db Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 7 Nov 2014 10:05:43 -0800 Subject: [PATCH 07/10] rename textureNames to originalTextures --- examples/libraries/entityPropertyDialogBox.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/libraries/entityPropertyDialogBox.js b/examples/libraries/entityPropertyDialogBox.js index 584d7a38d0..ef597549f2 100644 --- a/examples/libraries/entityPropertyDialogBox.js +++ b/examples/libraries/entityPropertyDialogBox.js @@ -54,7 +54,7 @@ EntityPropertyDialogBox = (function () { index++; array.push({ label: "Textures:", value: properties.textures }); index++; - array.push({ label: "Texture Names:\n" + properties.textureNames, type: "header" }); + array.push({ label: "Original Textures:\n" + properties.originalTextures, type: "header" }); index++; } array.push({ label: "Position:", type: "header" }); From f1a238a6c2280cc7d1f403cf8ce63b2ce694fd09 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 7 Nov 2014 10:08:09 -0800 Subject: [PATCH 08/10] piping for local UI sounds --- interface/src/Application.cpp | 3 +++ interface/src/Audio.cpp | 3 ++- interface/src/Audio.h | 2 +- libraries/audio/src/AbstractAudioInterface.h | 4 +++- libraries/audio/src/AudioInjector.cpp | 10 +--------- libraries/audio/src/AudioInjectorOptions.cpp | 5 +---- libraries/audio/src/AudioInjectorOptions.h | 8 ++------ .../audio/src/AudioScriptingInterface.cpp | 18 ++++++++++++++++++ libraries/audio/src/AudioScriptingInterface.h | 10 +++++++++- 9 files changed, 40 insertions(+), 23 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a62ce0e209..e58f79cb5e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -416,6 +416,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _trayIcon->show(); + // set the local loopback interface for local sounds from audio scripts + AudioScriptingInterface::getInstance().setLocalLoopbackInterface(&_audio); + #ifdef HAVE_RTMIDI // setup the MIDIManager MIDIManager& midiManagerInstance = MIDIManager::getInstance(); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 8c207c3d21..4bd9f35887 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -1331,9 +1331,10 @@ void Audio::startDrumSound(float volume, float frequency, float duration, float _drumSoundSample = 0; } -void Audio::handleAudioByteArray(const QByteArray& audioByteArray) { +void Audio::handleAudioByteArray(const QByteArray& audioByteArray, const AudioInjectorOptions& injectorOptions) { // TODO: either create a new audio device (up to the limit of the sound card or a hard limit) // or send to the mixer and use delayed loopback + } void Audio::renderToolBox(int x, int y, bool boxed) { diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 0924f65fab..bec2ce32a0 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -155,7 +155,7 @@ public slots: void selectAudioFilterBassCut(); void selectAudioFilterSmiley(); - virtual void handleAudioByteArray(const QByteArray& audioByteArray); + virtual void handleAudioByteArray(const QByteArray& audioByteArray, const AudioInjectorOptions& options); void sendDownstreamAudioStatsPacket(); diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index f950eefcbd..1ee71ee32d 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -14,6 +14,8 @@ #include +#include "AudioInjectorOptions.h" + class AbstractAudioInterface : public QObject { Q_OBJECT public: @@ -22,7 +24,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 void handleAudioByteArray(const QByteArray& audioByteArray) = 0; + virtual void handleAudioByteArray(const QByteArray& audioByteArray, const AudioInjectorOptions& options) = 0; }; Q_DECLARE_METATYPE(AbstractAudioInterface*) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index c61a00d218..45e1eb57e1 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -62,14 +62,6 @@ 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 (_options.getLoopbackAudioInterface()) { - // assume that localAudioInterface could be on a separate thread, use Qt::AutoConnection to handle properly - QMetaObject::invokeMethod(_options.getLoopbackAudioInterface(), "handleAudioByteArray", - Qt::AutoConnection, - Q_ARG(QByteArray, soundByteArray)); - - } // setup the packet for injected audio QByteArray injectAudioPacket = byteArrayWithPopulatedHeader(PacketTypeInjectAudio); @@ -86,7 +78,7 @@ void AudioInjector::injectAudio() { packetStream << _options.isStereo(); // pack the flag for loopback - uchar loopbackFlag = (uchar) (!_options.getLoopbackAudioInterface()); + uchar loopbackFlag = (uchar) true; packetStream << loopbackFlag; // pack the position for injected audio diff --git a/libraries/audio/src/AudioInjectorOptions.cpp b/libraries/audio/src/AudioInjectorOptions.cpp index a930e761ab..670bea2fef 100644 --- a/libraries/audio/src/AudioInjectorOptions.cpp +++ b/libraries/audio/src/AudioInjectorOptions.cpp @@ -18,8 +18,7 @@ AudioInjectorOptions::AudioInjectorOptions(QObject* parent) : _loop(false), _orientation(glm::vec3(0.0f, 0.0f, 0.0f)), _isStereo(false), - _ignorePenumbra(false), - _loopbackAudioInterface(NULL) + _ignorePenumbra(false) { } @@ -30,7 +29,6 @@ AudioInjectorOptions::AudioInjectorOptions(const AudioInjectorOptions& other) { _orientation = other._orientation; _isStereo = other._isStereo; _ignorePenumbra = other._ignorePenumbra; - _loopbackAudioInterface = other._loopbackAudioInterface; } void AudioInjectorOptions::operator=(const AudioInjectorOptions& other) { @@ -40,5 +38,4 @@ void AudioInjectorOptions::operator=(const AudioInjectorOptions& other) { _orientation = other._orientation; _isStereo = other._isStereo; _ignorePenumbra = other._ignorePenumbra; - _loopbackAudioInterface = other._loopbackAudioInterface; } \ No newline at end of file diff --git a/libraries/audio/src/AudioInjectorOptions.h b/libraries/audio/src/AudioInjectorOptions.h index e59517c10b..1ccd85be7e 100644 --- a/libraries/audio/src/AudioInjectorOptions.h +++ b/libraries/audio/src/AudioInjectorOptions.h @@ -19,8 +19,6 @@ #include -#include "AbstractAudioInterface.h" - class AudioInjectorOptions : public QObject { Q_OBJECT @@ -53,9 +51,6 @@ public: const bool ignorePenumbra() const {return _ignorePenumbra; } void setIgnorePenumbra(bool ignorePenumbra) { _ignorePenumbra = ignorePenumbra; } - AbstractAudioInterface* getLoopbackAudioInterface() const { return _loopbackAudioInterface; } - void setLoopbackAudioInterface(AbstractAudioInterface* loopbackAudioInterface) - { _loopbackAudioInterface = loopbackAudioInterface; } private: glm::vec3 _position; float _volume; @@ -63,7 +58,8 @@ private: glm::quat _orientation; bool _isStereo; bool _ignorePenumbra; - AbstractAudioInterface* _loopbackAudioInterface; }; +Q_DECLARE_METATYPE(AudioInjectorOptions) + #endif // hifi_AudioInjectorOptions_h diff --git a/libraries/audio/src/AudioScriptingInterface.cpp b/libraries/audio/src/AudioScriptingInterface.cpp index 418d25a563..33afcdb095 100644 --- a/libraries/audio/src/AudioScriptingInterface.cpp +++ b/libraries/audio/src/AudioScriptingInterface.cpp @@ -16,6 +16,12 @@ AudioScriptingInterface& AudioScriptingInterface::getInstance() { return staticInstance; } +AudioScriptingInterface::AudioScriptingInterface() : + _localLoopbackInterface(NULL) +{ + qRegisterMetaType("AudioInjectorOptions"); +} + void AudioScriptingInterface::stopAllInjectors() { QList >::iterator injector = _activeInjectors.begin(); while (injector != _activeInjectors.end()) { @@ -31,6 +37,18 @@ void AudioScriptingInterface::stopAllInjectors() { } } +void AudioScriptingInterface::playLocalSound(Sound* sound, const AudioInjectorOptions* injectorOptions) { + if (sound->isStereo()) { + const_cast(injectorOptions)->setIsStereo(true); + } + + // assume that localAudioInterface could be on a separate thread, use Qt::AutoConnection to handle properly + QMetaObject::invokeMethod(_localLoopbackInterface, "handleAudioByteArray", + Qt::AutoConnection, + Q_ARG(QByteArray, sound->getByteArray()), + Q_ARG(const AudioInjectorOptions&, *injectorOptions)); +} + AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions* injectorOptions) { if (sound->isStereo()) { diff --git a/libraries/audio/src/AudioScriptingInterface.h b/libraries/audio/src/AudioScriptingInterface.h index 8a49befe7b..709b82323c 100644 --- a/libraries/audio/src/AudioScriptingInterface.h +++ b/libraries/audio/src/AudioScriptingInterface.h @@ -14,9 +14,12 @@ #include +#include "AbstractAudioInterface.h" #include "AudioInjector.h" #include "Sound.h" +class AbstractAudioInterface; + const AudioInjectorOptions DEFAULT_INJECTOR_OPTIONS; class AudioScriptingInterface : public QObject { @@ -25,19 +28,24 @@ public: static AudioScriptingInterface& getInstance(); void stopAllInjectors(); + + void setLocalLoopbackInterface(AbstractAudioInterface* audioInterface) { _localLoopbackInterface = audioInterface; } public slots: static float getLoudness(AudioInjector* injector); + void playLocalSound(Sound *sound, const AudioInjectorOptions* injectorOptions = NULL); AudioInjector* playSound(Sound* sound, const AudioInjectorOptions* injectorOptions = NULL); + void stopInjector(AudioInjector* injector); bool isInjectorPlaying(AudioInjector* injector); void injectorStopped(); private: - AudioScriptingInterface() {}; + AudioScriptingInterface(); QList< QPointer > _activeInjectors; + AbstractAudioInterface* _localLoopbackInterface; }; From d0ca9ed14cd4bbe9844033b1f33fb6134267f579 Mon Sep 17 00:00:00 2001 From: Ryan Date: Fri, 7 Nov 2014 10:45:58 -0800 Subject: [PATCH 09/10] Changes to Hair to make it look more like clothing --- interface/src/Hair.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/Hair.h b/interface/src/Hair.h index 94378dfd6a..05c82e66f7 100644 --- a/interface/src/Hair.h +++ b/interface/src/Hair.h @@ -24,10 +24,10 @@ const int HAIR_CONSTRAINTS = 2; const int DEFAULT_HAIR_STRANDS = 20; -const int DEFAULT_HAIR_LINKS = 10; +const int DEFAULT_HAIR_LINKS = 11; const float DEFAULT_HAIR_RADIUS = 0.075f; -const float DEFAULT_HAIR_LINK_LENGTH = 0.06f; -const float DEFAULT_HAIR_THICKNESS = 0.025f; +const float DEFAULT_HAIR_LINK_LENGTH = 0.1f; +const float DEFAULT_HAIR_THICKNESS = 0.07f; const glm::vec3 DEFAULT_GRAVITY(0.0f, -9.8f, 0.0f); class Hair { From bd8b71a02af9b34a7359ad87ad3559692ecbe6f5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 7 Nov 2014 11:05:01 -0800 Subject: [PATCH 10/10] complete handling of local audio loopback --- interface/src/Audio.cpp | 22 +++++++++++++++---- libraries/audio/src/AudioScriptingInterface.h | 4 ---- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 4bd9f35887..3039b7adfb 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -184,9 +184,9 @@ QAudioDeviceInfo getNamedAudioDeviceForMode(QAudio::Mode mode, const QString& de QAudioDeviceInfo::defaultOutputDevice(); #else foreach(QAudioDeviceInfo audioDevice, QAudioDeviceInfo::availableDevices(mode)) { - qDebug() << audioDevice.deviceName() << " " << deviceName; if (audioDevice.deviceName().trimmed() == deviceName.trimmed()) { result = audioDevice; + break; } } #endif @@ -1332,9 +1332,21 @@ void Audio::startDrumSound(float volume, float frequency, float duration, float } void Audio::handleAudioByteArray(const QByteArray& audioByteArray, const AudioInjectorOptions& injectorOptions) { - // TODO: either create a new audio device (up to the limit of the sound card or a hard limit) - // or send to the mixer and use delayed loopback - + if (audioByteArray.size() > 0) { + QAudioFormat localFormat = _outputFormat; + + if (!injectorOptions.isStereo()) { + localFormat.setChannelCount(1); + } + + QAudioOutput* localSoundOutput = new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName), localFormat, this); + + QIODevice* localIODevice = localSoundOutput->start(); + qDebug() << "Writing" << audioByteArray.size() << "to" << localIODevice; + localIODevice->write(audioByteArray); + } else { + qDebug() << "Audio::handleAudioByteArray called with an empty byte array. Sound is likely still downloading."; + } } void Audio::renderToolBox(int x, int y, bool boxed) { @@ -1904,6 +1916,7 @@ bool Audio::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceInfo) { } } } + return supportedFormat; } @@ -1962,6 +1975,7 @@ bool Audio::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo) supportedFormat = true; } } + return supportedFormat; } diff --git a/libraries/audio/src/AudioScriptingInterface.h b/libraries/audio/src/AudioScriptingInterface.h index 709b82323c..5cd0f9e99a 100644 --- a/libraries/audio/src/AudioScriptingInterface.h +++ b/libraries/audio/src/AudioScriptingInterface.h @@ -18,8 +18,6 @@ #include "AudioInjector.h" #include "Sound.h" -class AbstractAudioInterface; - const AudioInjectorOptions DEFAULT_INJECTOR_OPTIONS; class AudioScriptingInterface : public QObject { @@ -46,7 +44,5 @@ private: AudioScriptingInterface(); QList< QPointer > _activeInjectors; AbstractAudioInterface* _localLoopbackInterface; - - }; #endif // hifi_AudioScriptingInterface_h