diff --git a/audio-mixer/CMakeLists.txt b/audio-mixer/CMakeLists.txt index 3e2d9939b0..eac2792883 100644 --- a/audio-mixer/CMakeLists.txt +++ b/audio-mixer/CMakeLists.txt @@ -3,11 +3,18 @@ cmake_minimum_required(VERSION 2.8) set(ROOT_DIR ..) set(MACRO_DIR ${ROOT_DIR}/cmake/macros) +# setup for find modules +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") + set(TARGET_NAME audio-mixer) include(${MACRO_DIR}/SetupHifiProject.cmake) setup_hifi_project(${TARGET_NAME}) +# set up the external glm library +include(${MACRO_DIR}/IncludeGLM.cmake) +include_glm(${TARGET_NAME} ${ROOT_DIR}) + # link the shared hifi library include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index d987c807f7..e2028911ef 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -133,128 +133,130 @@ int main(int argc, const char* argv[]) { memset(distanceCoefficients, 0, sizeof(distanceCoefficients)); for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { - AudioRingBuffer* agentRingBuffer = (AudioRingBuffer*) agent->getLinkedData(); - - // zero out the client mix for this agent - memset(clientSamples, 0, sizeof(clientSamples)); - - for (AgentList::iterator otherAgent = agentList->begin(); otherAgent != agentList->end(); otherAgent++) { - if (otherAgent != agent || (otherAgent == agent && agentRingBuffer->shouldLoopbackForAgent())) { - AudioRingBuffer* otherAgentBuffer = (AudioRingBuffer*) otherAgent->getLinkedData(); - - if (otherAgentBuffer->shouldBeAddedToMix()) { + if (agent->getType() == AGENT_TYPE_AVATAR) { + AudioRingBuffer* agentRingBuffer = (AudioRingBuffer*) agent->getLinkedData(); + + // zero out the client mix for this agent + memset(clientSamples, 0, sizeof(clientSamples)); + + for (AgentList::iterator otherAgent = agentList->begin(); otherAgent != agentList->end(); otherAgent++) { + if (otherAgent != agent || (otherAgent == agent && agentRingBuffer->shouldLoopbackForAgent())) { + AudioRingBuffer* otherAgentBuffer = (AudioRingBuffer*) otherAgent->getLinkedData(); - float bearingRelativeAngleToSource = 0.f; - float attenuationCoefficient = 1.f; - int numSamplesDelay = 0; - float weakChannelAmplitudeRatio = 1.f; - - if (otherAgent != agent) { - Position agentPosition = agentRingBuffer->getPosition(); - Position otherAgentPosition = otherAgentBuffer->getPosition(); + if (otherAgentBuffer->shouldBeAddedToMix()) { - // calculate the distance to the other agent + float bearingRelativeAngleToSource = 0.f; + float attenuationCoefficient = 1.f; + int numSamplesDelay = 0; + float weakChannelAmplitudeRatio = 1.f; - // use the distance to the other agent to calculate the change in volume for this frame - int lowAgentIndex = std::min(agent.getAgentIndex(), otherAgent.getAgentIndex()); - int highAgentIndex = std::max(agent.getAgentIndex(), otherAgent.getAgentIndex()); - - if (distanceCoefficients[lowAgentIndex][highAgentIndex] == 0) { - float distanceToAgent = sqrtf(powf(agentPosition.x - otherAgentPosition.x, 2) + - powf(agentPosition.y - otherAgentPosition.y, 2) + - powf(agentPosition.z - otherAgentPosition.z, 2)); + if (otherAgent != agent) { + glm::vec3 agentPosition = agentRingBuffer->getPosition(); + glm::vec3 otherAgentPosition = otherAgentBuffer->getPosition(); - float minCoefficient = std::min(1.0f, - powf(0.5, - (logf(DISTANCE_RATIO * distanceToAgent) / logf(3)) - 1)); - distanceCoefficients[lowAgentIndex][highAgentIndex] = minCoefficient; - } - - - // get the angle from the right-angle triangle - float triangleAngle = atan2f(fabsf(agentPosition.z - otherAgentPosition.z), - fabsf(agentPosition.x - otherAgentPosition.x)) * (180 / M_PI); - float absoluteAngleToSource = 0; - bearingRelativeAngleToSource = 0; - - // find the angle we need for calculation based on the orientation of the triangle - if (otherAgentPosition.x > agentPosition.x) { - if (otherAgentPosition.z > agentPosition.z) { - absoluteAngleToSource = -90 + triangleAngle; - } else { - absoluteAngleToSource = -90 - triangleAngle; + // calculate the distance to the other agent + + // use the distance to the other agent to calculate the change in volume for this frame + int lowAgentIndex = std::min(agent.getAgentIndex(), otherAgent.getAgentIndex()); + int highAgentIndex = std::max(agent.getAgentIndex(), otherAgent.getAgentIndex()); + + if (distanceCoefficients[lowAgentIndex][highAgentIndex] == 0) { + float distanceToAgent = sqrtf(powf(agentPosition.x - otherAgentPosition.x, 2) + + powf(agentPosition.y - otherAgentPosition.y, 2) + + powf(agentPosition.z - otherAgentPosition.z, 2)); + + float minCoefficient = std::min(1.0f, + powf(0.5, + (logf(DISTANCE_RATIO * distanceToAgent) / logf(3)) - 1)); + distanceCoefficients[lowAgentIndex][highAgentIndex] = minCoefficient; } - } else { - if (otherAgentPosition.z > agentPosition.z) { - absoluteAngleToSource = 90 - triangleAngle; + + + // get the angle from the right-angle triangle + float triangleAngle = atan2f(fabsf(agentPosition.z - otherAgentPosition.z), + fabsf(agentPosition.x - otherAgentPosition.x)) * (180 / M_PI); + float absoluteAngleToSource = 0; + bearingRelativeAngleToSource = 0; + + // find the angle we need for calculation based on the orientation of the triangle + if (otherAgentPosition.x > agentPosition.x) { + if (otherAgentPosition.z > agentPosition.z) { + absoluteAngleToSource = -90 + triangleAngle; + } else { + absoluteAngleToSource = -90 - triangleAngle; + } } else { - absoluteAngleToSource = 90 + triangleAngle; + if (otherAgentPosition.z > agentPosition.z) { + absoluteAngleToSource = 90 - triangleAngle; + } else { + absoluteAngleToSource = 90 + triangleAngle; + } } + + bearingRelativeAngleToSource = absoluteAngleToSource - agentRingBuffer->getBearing(); + + if (bearingRelativeAngleToSource > 180) { + bearingRelativeAngleToSource -= 360; + } else if (bearingRelativeAngleToSource < -180) { + bearingRelativeAngleToSource += 360; + } + + float angleOfDelivery = absoluteAngleToSource - otherAgentBuffer->getBearing(); + + if (angleOfDelivery > 180) { + angleOfDelivery -= 360; + } else if (angleOfDelivery < -180) { + angleOfDelivery += 360; + } + + float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION + + (OFF_AXIS_ATTENUATION_FORMULA_STEP * (fabsf(angleOfDelivery) / 90.0f)); + + attenuationCoefficient = distanceCoefficients[lowAgentIndex][highAgentIndex] + * otherAgentBuffer->getAttenuationRatio() + * offAxisCoefficient; + + bearingRelativeAngleToSource *= (M_PI / 180); + + float sinRatio = fabsf(sinf(bearingRelativeAngleToSource)); + numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio; + weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio); } - bearingRelativeAngleToSource = absoluteAngleToSource - agentRingBuffer->getBearing(); - - if (bearingRelativeAngleToSource > 180) { - bearingRelativeAngleToSource -= 360; - } else if (bearingRelativeAngleToSource < -180) { - bearingRelativeAngleToSource += 360; - } - - float angleOfDelivery = absoluteAngleToSource - otherAgentBuffer->getBearing(); - - if (angleOfDelivery > 180) { - angleOfDelivery -= 360; - } else if (angleOfDelivery < -180) { - angleOfDelivery += 360; - } - - float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION + - (OFF_AXIS_ATTENUATION_FORMULA_STEP * (fabsf(angleOfDelivery) / 90.0f)); - - attenuationCoefficient = distanceCoefficients[lowAgentIndex][highAgentIndex] - * otherAgentBuffer->getAttenuationRatio() - * offAxisCoefficient; - - bearingRelativeAngleToSource *= (M_PI / 180); - - float sinRatio = fabsf(sinf(bearingRelativeAngleToSource)); - numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio; - weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio); - } - - int16_t* goodChannel = bearingRelativeAngleToSource > 0.0f + int16_t* goodChannel = bearingRelativeAngleToSource > 0.0f ? clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL : clientSamples; - int16_t* delayedChannel = bearingRelativeAngleToSource > 0.0f + int16_t* delayedChannel = bearingRelativeAngleToSource > 0.0f ? clientSamples : clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL; - - int16_t* delaySamplePointer = otherAgentBuffer->getNextOutput() == otherAgentBuffer->getBuffer() + + int16_t* delaySamplePointer = otherAgentBuffer->getNextOutput() == otherAgentBuffer->getBuffer() ? otherAgentBuffer->getBuffer() + RING_BUFFER_SAMPLES - numSamplesDelay : otherAgentBuffer->getNextOutput() - numSamplesDelay; - - for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) { - if (s < numSamplesDelay) { - // pull the earlier sample for the delayed channel - int earlierSample = delaySamplePointer[s] * attenuationCoefficient; - plateauAdditionOfSamples(delayedChannel[s], earlierSample * weakChannelAmplitudeRatio); - } - - int16_t currentSample = (otherAgentBuffer->getNextOutput()[s] * attenuationCoefficient); - plateauAdditionOfSamples(goodChannel[s], currentSample); - - if (s + numSamplesDelay < BUFFER_LENGTH_SAMPLES_PER_CHANNEL) { - plateauAdditionOfSamples(delayedChannel[s + numSamplesDelay], - currentSample * weakChannelAmplitudeRatio); + for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) { + + if (s < numSamplesDelay) { + // pull the earlier sample for the delayed channel + int earlierSample = delaySamplePointer[s] * attenuationCoefficient; + plateauAdditionOfSamples(delayedChannel[s], earlierSample * weakChannelAmplitudeRatio); + } + + int16_t currentSample = (otherAgentBuffer->getNextOutput()[s] * attenuationCoefficient); + plateauAdditionOfSamples(goodChannel[s], currentSample); + + if (s + numSamplesDelay < BUFFER_LENGTH_SAMPLES_PER_CHANNEL) { + plateauAdditionOfSamples(delayedChannel[s + numSamplesDelay], + currentSample * weakChannelAmplitudeRatio); + } } } } } + + memcpy(clientPacket + 1, clientSamples, sizeof(clientSamples)); + agentList->getAgentSocket()->send(agent->getPublicSocket(), clientPacket, BUFFER_LENGTH_BYTES + 1); } - - memcpy(clientPacket + 1, clientSamples, sizeof(clientSamples)); - agentList->getAgentSocket()->send(agent->getPublicSocket(), clientPacket, BUFFER_LENGTH_BYTES + 1); } // push forward the next output pointers for any audio buffers we used @@ -285,8 +287,30 @@ int main(int argc, const char* argv[]) { agentList->updateAgentWithData(agentAddress, packetData, receivedBytes); } else if (packetData[0] == PACKET_HEADER_INJECT_AUDIO) { + Agent* matchingInjector = NULL; - // this is an injector stream - check our map to see if we have it already + for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { + if (agent->getLinkedData()) { + AudioRingBuffer* ringBuffer = (AudioRingBuffer*) agent->getLinkedData(); + if (memcmp(ringBuffer->getStreamIdentifier(), packetData + 1, sizeof(STREAM_IDENTIFIER_NUM_BYTES))) { + // this is the matching stream, assign to matchingInjector and stop looking + matchingInjector = &*agent; + break; + } + } + } + + if (!matchingInjector) { + matchingInjector = agentList->addOrUpdateAgent(NULL, + NULL, + AGENT_TYPE_AUDIO_INJECTOR, + agentList->getLastAgentID()); + agentList->increaseAgentID(); + + } + + // give the new audio data to the matching injector agent + agentList->updateAgentWithData(matchingInjector, packetData, receivedBytes); } } diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 7a1747a355..6cc7ccd792 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -24,7 +24,7 @@ AudioInjector::AudioInjector(const char* filename) : _indexOfNextSlot(0), _isInjectingAudio(false) { - loadRandomIdentifier(_identifier, INJECTOR_IDENTIFIER_NUM_BYTES); + loadRandomIdentifier(_streamIdentifier, STREAM_IDENTIFIER_NUM_BYTES); std::fstream sourceFile; @@ -53,7 +53,7 @@ AudioInjector::AudioInjector(int maxNumSamples) : _indexOfNextSlot(0), _isInjectingAudio(false) { - loadRandomIdentifier(_identifier, INJECTOR_IDENTIFIER_NUM_BYTES); + loadRandomIdentifier(_streamIdentifier, STREAM_IDENTIFIER_NUM_BYTES); _audioSampleArray = new int16_t[maxNumSamples]; memset(_audioSampleArray, 0, _numTotalSamples * sizeof(int16_t)); @@ -76,6 +76,10 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination dataPacket[0] = PACKET_HEADER_INJECT_AUDIO; unsigned char *currentPacketPtr = dataPacket + 1; + // copy the identifier for this injector + memcpy(currentPacketPtr, &_streamIdentifier, sizeof(_streamIdentifier)); + currentPacketPtr += sizeof(_streamIdentifier); + memcpy(currentPacketPtr, &_position, sizeof(_position)); currentPacketPtr += sizeof(_position); @@ -85,10 +89,6 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination memcpy(currentPacketPtr, &_bearing, sizeof(_bearing)); currentPacketPtr += sizeof(_bearing); - // copy the identifier for this injector - memcpy(currentPacketPtr, &_identifier, sizeof(_identifier)); - currentPacketPtr += sizeof(_identifier); - for (int i = 0; i < _numTotalSamples; i += BUFFER_LENGTH_SAMPLES) { gettimeofday(&startTime, NULL); diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index fa907438bf..2571947e99 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -13,13 +13,13 @@ #include +#include "AudioRingBuffer.h" + const int BUFFER_LENGTH_BYTES = 512; const int BUFFER_LENGTH_SAMPLES = BUFFER_LENGTH_BYTES / sizeof(int16_t); const float SAMPLE_RATE = 22050.0f; const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES / SAMPLE_RATE) * 1000000; -const int INJECTOR_IDENTIFIER_NUM_BYTES = 8; - class AudioInjector { public: AudioInjector(const char* filename); @@ -43,7 +43,7 @@ public: void addSample(const int16_t sample); void addSamples(int16_t* sampleBuffer, int numSamples); private: - unsigned char _identifier[INJECTOR_IDENTIFIER_NUM_BYTES]; + unsigned char _streamIdentifier[STREAM_IDENTIFIER_NUM_BYTES]; int16_t* _audioSampleArray; int _numTotalSamples; glm::vec3 _position; diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp index 19fea1593a..59b35b18a3 100644 --- a/libraries/audio/src/AudioRingBuffer.cpp +++ b/libraries/audio/src/AudioRingBuffer.cpp @@ -18,8 +18,9 @@ AudioRingBuffer::AudioRingBuffer(int ringSamples, int bufferSamples) : _endOfLastWrite(NULL), _started(false), _shouldBeAddedToMix(false), - _shouldLoopbackForAgent(false) { - + _shouldLoopbackForAgent(false), + _streamIdentifier() +{ _buffer = new int16_t[_ringBufferLengthSamples]; _nextOutput = _buffer; }; @@ -39,6 +40,12 @@ int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { // if this came from an injector or interface client // there's data required for spatialization to pull out + if (sourceBuffer[0] == PACKET_HEADER_INJECT_AUDIO) { + // we've got a stream identifier to pull from the packet + memcpy(&_streamIdentifier, dataBuffer, sizeof(_streamIdentifier)); + dataBuffer += sizeof(_streamIdentifier); + } + memcpy(&_position, dataBuffer, sizeof(_position)); dataBuffer += (sizeof(_position)); diff --git a/libraries/audio/src/AudioRingBuffer.h b/libraries/audio/src/AudioRingBuffer.h index 68c35937a7..b448f93cee 100644 --- a/libraries/audio/src/AudioRingBuffer.h +++ b/libraries/audio/src/AudioRingBuffer.h @@ -10,13 +10,12 @@ #define __interface__AudioRingBuffer__ #include + +#include + #include "AgentData.h" -struct Position { - float x; - float y; - float z; -}; +const int STREAM_IDENTIFIER_NUM_BYTES = 8; class AudioRingBuffer : public AgentData { public: @@ -39,10 +38,11 @@ public: bool shouldBeAddedToMix() const { return _shouldBeAddedToMix; } void setShouldBeAddedToMix(bool shouldBeAddedToMix) { _shouldBeAddedToMix = shouldBeAddedToMix; } - const Position& getPosition() const { return _position; } + const glm::vec3& getPosition() const { return _position; } float getAttenuationRatio() const { return _attenuationRatio; } float getBearing() const { return _bearing; } bool shouldLoopbackForAgent() const { return _shouldLoopbackForAgent; } + const unsigned char* getStreamIdentifier() const { return _streamIdentifier; } short diffLastWriteNextOutput(); private: @@ -52,7 +52,7 @@ private: int _ringBufferLengthSamples; int _bufferLengthSamples; - Position _position; + glm::vec3 _position; float _attenuationRatio; float _bearing; int16_t* _nextOutput; @@ -61,6 +61,7 @@ private: bool _started; bool _shouldBeAddedToMix; bool _shouldLoopbackForAgent; + unsigned char _streamIdentifier[STREAM_IDENTIFIER_NUM_BYTES]; }; #endif /* defined(__interface__AudioRingBuffer__) */