From 5514966d9c82bf84bd8da36eda26a3d7250273ea Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 16 May 2013 12:40:23 -0700 Subject: [PATCH] add an AudioInjectionManager to handle multiple injections, link eve to it --- eve/src/main.cpp | 26 ++--- .../shared/src/AudioInjectionManager.cpp | 106 ++++++++++++++++++ libraries/shared/src/AudioInjectionManager.h | 36 ++++++ libraries/shared/src/AudioInjector.cpp | 79 +------------ libraries/shared/src/AudioInjector.h | 33 +++--- 5 files changed, 175 insertions(+), 105 deletions(-) create mode 100644 libraries/shared/src/AudioInjectionManager.cpp create mode 100644 libraries/shared/src/AudioInjectionManager.h diff --git a/eve/src/main.cpp b/eve/src/main.cpp index 733bd2b715..4f056174e1 100644 --- a/eve/src/main.cpp +++ b/eve/src/main.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include const int EVE_AGENT_LISTEN_PORT = 55441; @@ -106,20 +107,19 @@ int main(int argc, const char* argv[]) { // put her hand out so somebody can shake it eve.setHandPosition(glm::vec3(eve.getPosition()[0] - 0.2, 0.5, - eve.getPosition()[2] + 0.1)); + eve.getPosition()[2] + 0.1)); + + // prepare the audio injection manager by giving it a handle to our agent socket + AudioInjectionManager::setInjectorSocket(agentList->getAgentSocket()); + // read eve's audio data AudioInjector eveAudioInjector("/etc/highfidelity/eve/resources/eve.raw"); // lower Eve's volume by setting the attentuation modifier (this is a value out of 255) - eveAudioInjector.setAttenuationModifier(190); - - // pass the agentList UDPSocket pointer to the audio injector - eveAudioInjector.setInjectorSocket(agentList->getAgentSocket()); + eveAudioInjector.setVolume(190); // set the position of the audio injector - float injectorPosition[3]; - memcpy(injectorPosition, &eve.getPosition(), sizeof(injectorPosition)); - eveAudioInjector.setPosition(injectorPosition); + eveAudioInjector.setPosition(eve.getPosition()); // register the callback for agent data creation agentList->linkedDataCreateCallback = createAvatarDataForAgent; @@ -165,15 +165,11 @@ int main(int argc, const char* argv[]) { Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER); if (audioMixer) { - // until the audio mixer is setup for ping-reply, activate the public socket if it's not active - if (!audioMixer->getActiveSocket()) { - audioMixer->activatePublicSocket(); - } - - eveAudioInjector.setDestinationSocket(audioMixer->getActiveSocket()); + // update the destination socket for the AIM, in case the mixer has changed + AudioInjectionManager::setDestinationSocket(*audioMixer->getPublicSocket()); // we have an active audio mixer we can send data to - eveAudioInjector.threadInjectionOfAudio(); + AudioInjectionManager::threadInjector(&eveAudioInjector); } } } diff --git a/libraries/shared/src/AudioInjectionManager.cpp b/libraries/shared/src/AudioInjectionManager.cpp new file mode 100644 index 0000000000..b9ca3a4150 --- /dev/null +++ b/libraries/shared/src/AudioInjectionManager.cpp @@ -0,0 +1,106 @@ +// +// AudioInjectionManager.cpp +// hifi +// +// Created by Stephen Birarda on 5/16/13. +// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. +// + +#include + +#include "SharedUtil.h" +#include "PacketHeaders.h" + +#include "AudioInjectionManager.h" + +UDPSocket* AudioInjectionManager::_injectorSocket = NULL; +sockaddr AudioInjectionManager::_destinationSocket; +AudioInjector* AudioInjectionManager::_injectors[50] = {}; + +AudioInjector* AudioInjectionManager::injectorWithSamplesFromFile(const char* filename) { + for (int i = 0; i < MAX_CONCURRENT_INJECTORS; i++) { + if (!_injectors[i]) { + _injectors[i] = new AudioInjector(filename); + return _injectors[i]; + } + } + + return NULL; +} + +AudioInjector* AudioInjectionManager::injectorWithCapacity(int capacity) { + for (int i = 0; i < MAX_CONCURRENT_INJECTORS; i++) { + if (!_injectors[i]) { + _injectors[i] = new AudioInjector(capacity); + return _injectors[i]; + } + } + + return NULL; +} + +void* AudioInjectionManager::injectAudioViaThread(void* args) { + AudioInjector* injector = (AudioInjector*) args; + + if (injector->_audioSampleArray) { + injector->setIsInjectingAudio(true); + + timeval startTime; + + // one byte for header, 3 positional floats, 1 bearing float, 1 attenuation modifier byte + int leadingBytes = 1 + (sizeof(float) * 4) + 1; + unsigned char dataPacket[BUFFER_LENGTH_BYTES + leadingBytes]; + + dataPacket[0] = PACKET_HEADER_INJECT_AUDIO; + unsigned char *currentPacketPtr = dataPacket + 1; + + memcpy(currentPacketPtr, &injector->getPosition(), sizeof(injector->getPosition())); + currentPacketPtr += sizeof(injector->getPosition()); + + *currentPacketPtr = injector->getVolume(); + currentPacketPtr++; + + memcpy(currentPacketPtr, &injector->_bearing, sizeof(injector->_bearing)); + currentPacketPtr += sizeof(injector->_bearing); + + for (int i = 0; i < injector->_numTotalSamples; i += BUFFER_LENGTH_SAMPLES) { + gettimeofday(&startTime, NULL); + + int numSamplesToCopy = BUFFER_LENGTH_SAMPLES; + + if (injector->_numTotalSamples - i < BUFFER_LENGTH_SAMPLES) { + numSamplesToCopy = injector->_numTotalSamples - i; + memset(currentPacketPtr + numSamplesToCopy, 0, BUFFER_LENGTH_BYTES - (numSamplesToCopy * sizeof(int16_t))); + } + + memcpy(currentPacketPtr, injector->_audioSampleArray + i, numSamplesToCopy * sizeof(int16_t)); + + _injectorSocket->send(&_destinationSocket, dataPacket, sizeof(dataPacket)); + + double usecToSleep = BUFFER_SEND_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&startTime)); + if (usecToSleep > 0) { + usleep(usecToSleep); + } + } + + injector->_isInjectingAudio = false; + } + + // if this an injector inside the injection manager's array we're responsible for deletion + for (int i = 0; i < MAX_CONCURRENT_INJECTORS; i++) { + if (_injectors[i] == injector) { + // pointer matched - delete this injector + delete injector; + + // set the pointer to NULL so we can reuse this spot + _injectors[i] = NULL; + } + } + + pthread_exit(0); +} + +void AudioInjectionManager::threadInjector(AudioInjector* injector) { + pthread_t audioInjectThread; + pthread_create(&audioInjectThread, NULL, injectAudioViaThread, (void*) injector); +} \ No newline at end of file diff --git a/libraries/shared/src/AudioInjectionManager.h b/libraries/shared/src/AudioInjectionManager.h new file mode 100644 index 0000000000..3297305475 --- /dev/null +++ b/libraries/shared/src/AudioInjectionManager.h @@ -0,0 +1,36 @@ +// +// AudioInjectionManager.h +// hifi +// +// Created by Stephen Birarda on 5/16/13. +// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. +// + +#ifndef __hifi__AudioInjectionManager__ +#define __hifi__AudioInjectionManager__ + +#include + +#include "UDPSocket.h" +#include "AudioInjector.h" + +const int MAX_CONCURRENT_INJECTORS = 50; + +class AudioInjectionManager { +public: + static AudioInjector* injectorWithCapacity(int capacity); + static AudioInjector* injectorWithSamplesFromFile(const char* filename); + + static void threadInjector(AudioInjector* injector); + + static void setInjectorSocket(UDPSocket* injectorSocket) { _injectorSocket = injectorSocket;} + static void setDestinationSocket(sockaddr& destinationSocket) { _destinationSocket = destinationSocket; } +private: + static void* injectAudioViaThread(void* args); + + static UDPSocket* _injectorSocket; + static sockaddr _destinationSocket; + static AudioInjector* _injectors[MAX_CONCURRENT_INJECTORS]; +}; + +#endif /* defined(__hifi__AudioInjectionManager__) */ diff --git a/libraries/shared/src/AudioInjector.cpp b/libraries/shared/src/AudioInjector.cpp index c89385226c..05530cebe3 100644 --- a/libraries/shared/src/AudioInjector.cpp +++ b/libraries/shared/src/AudioInjector.cpp @@ -3,27 +3,20 @@ // hifi // // Created by Stephen Birarda on 4/23/13. -// +// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. // -#include #include #include #include "SharedUtil.h" -#include "PacketHeaders.h" #include "AudioInjector.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; - AudioInjector::AudioInjector(const char* filename) : _position(), _bearing(0), - _attenuationModifier(255), + _volume(0xFF), _indexOfNextSlot(0), _isInjectingAudio(false) { @@ -50,7 +43,7 @@ AudioInjector::AudioInjector(int maxNumSamples) : _numTotalSamples(maxNumSamples), _position(), _bearing(0), - _attenuationModifier(255), + _volume(0xFF), _indexOfNextSlot(0), _isInjectingAudio(false) { @@ -62,12 +55,6 @@ AudioInjector::~AudioInjector() { delete[] _audioSampleArray; } -void AudioInjector::setPosition(float* position) { - _position[0] = position[0]; - _position[1] = position[1]; - _position[2] = position[2]; -} - void AudioInjector::addSample(const int16_t sample) { if (_indexOfNextSlot != _numTotalSamples) { // only add this sample if we actually have space for it @@ -82,63 +69,3 @@ void AudioInjector::addSamples(int16_t* sampleBuffer, int numSamples) { _indexOfNextSlot += numSamples; } } - -void AudioInjector::injectAudio() { - if (_audioSampleArray) { - _isInjectingAudio = true; - - timeval startTime; - - // one byte for header, 3 positional floats, 1 bearing float, 1 attenuation modifier byte - int leadingBytes = 1 + (sizeof(float) * 4) + 1; - unsigned char dataPacket[BUFFER_LENGTH_BYTES + leadingBytes]; - - dataPacket[0] = PACKET_HEADER_INJECT_AUDIO; - unsigned char *currentPacketPtr = dataPacket + 1; - - for (int i = 0; i < 3; i++) { - memcpy(currentPacketPtr, &_position[i], sizeof(float)); - currentPacketPtr += sizeof(float); - } - - *currentPacketPtr = _attenuationModifier; - currentPacketPtr++; - - memcpy(currentPacketPtr, &_bearing, sizeof(float)); - currentPacketPtr += sizeof(float); - - for (int i = 0; i < _numTotalSamples; i += BUFFER_LENGTH_SAMPLES) { - gettimeofday(&startTime, NULL); - - int numSamplesToCopy = BUFFER_LENGTH_SAMPLES; - - if (_numTotalSamples - i < BUFFER_LENGTH_SAMPLES) { - numSamplesToCopy = _numTotalSamples - i; - memset(currentPacketPtr + numSamplesToCopy, 0, BUFFER_LENGTH_BYTES - (numSamplesToCopy * sizeof(int16_t))); - } - - memcpy(currentPacketPtr, _audioSampleArray + i, numSamplesToCopy * sizeof(int16_t)); - - _injectorSocket->send(&_destinationSocket, dataPacket, sizeof(dataPacket)); - - double usecToSleep = BUFFER_SEND_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&startTime)); - if (usecToSleep > 0) { - usleep(usecToSleep); - } - } - - _isInjectingAudio = false; - } -} - -void* injectAudioViaThread(void* args) { - AudioInjector* parentInjector = (AudioInjector*) args; - parentInjector->injectAudio(); - - pthread_exit(0); -} - -void AudioInjector::threadInjectionOfAudio() { - pthread_t audioInjectThread; - pthread_create(&audioInjectThread, NULL, injectAudioViaThread, (void*) this); -} diff --git a/libraries/shared/src/AudioInjector.h b/libraries/shared/src/AudioInjector.h index 3e79869034..fb5bf86c58 100644 --- a/libraries/shared/src/AudioInjector.h +++ b/libraries/shared/src/AudioInjector.h @@ -3,45 +3,50 @@ // hifi // // Created by Stephen Birarda on 4/23/13. -// +// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. // #ifndef __hifi__AudioInjector__ #define __hifi__AudioInjector__ #include -#include -#include "UDPSocket.h" +#include + +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; class AudioInjector { + friend class AudioInjectionManager; + public: AudioInjector(const char* filename); AudioInjector(int maxNumSamples); ~AudioInjector(); bool isInjectingAudio() const { return _isInjectingAudio; } + void setIsInjectingAudio(bool isInjectingAudio) { _isInjectingAudio = isInjectingAudio; } - void setPosition(float* position); + unsigned char getVolume() const { return _volume; } + void setVolume(unsigned char volume) { _volume = volume; } + + const glm::vec3& getPosition() const { return _position; } + void setPosition(const glm::vec3& position) { _position = position; } + + float getBearing() const { return _bearing; } void setBearing(float bearing) { _bearing = bearing; } - void setAttenuationModifier(unsigned char attenuationModifier) { _attenuationModifier = attenuationModifier; } - void setInjectorSocket(UDPSocket* injectorSocket) { _injectorSocket = injectorSocket; } - void setDestinationSocket(sockaddr* destinationSocket) { _destinationSocket = *destinationSocket; } void addSample(const int16_t sample); void addSamples(int16_t* sampleBuffer, int numSamples); - - void injectAudio(); - void threadInjectionOfAudio(); private: int16_t* _audioSampleArray; int _numTotalSamples; - float _position[3]; + glm::vec3 _position; float _bearing; - unsigned char _attenuationModifier; + unsigned char _volume; int _indexOfNextSlot; - UDPSocket* _injectorSocket; - sockaddr _destinationSocket; bool _isInjectingAudio; };