diff --git a/audio-mixer/CMakeLists.txt b/audio-mixer/CMakeLists.txt index 1e6637aeb2..3e2d9939b0 100644 --- a/audio-mixer/CMakeLists.txt +++ b/audio-mixer/CMakeLists.txt @@ -11,7 +11,4 @@ setup_hifi_project(${TARGET_NAME}) # link the shared hifi library include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) - -# link the threads library -find_package(Threads REQUIRED) -target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT}) \ No newline at end of file +link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) \ No newline at end of file diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index 444edd1393..5bb33a9198 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/eve/CMakeLists.txt b/eve/CMakeLists.txt index cb38529b2d..acca9520ed 100644 --- a/eve/CMakeLists.txt +++ b/eve/CMakeLists.txt @@ -17,4 +17,5 @@ include_glm(${TARGET_NAME} ${ROOT_DIR}) # link the required hifi libraries include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) -link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR}) \ No newline at end of file +link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) \ No newline at end of file diff --git a/eve/src/main.cpp b/eve/src/main.cpp index 733bd2b715..52f307c18f 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; @@ -34,6 +35,7 @@ const int HAND_TIMER_SLEEP_ITERATIONS = 50; const float EVE_PELVIS_HEIGHT = 0.565925f; const float AUDIO_INJECT_PROXIMITY = 0.4f; +const int EVE_VOLUME_BYTE = 190; bool stopReceiveAgentDataThread; @@ -106,20 +108,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(EVE_VOLUME_BYTE); // 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 +166,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/injector/CMakeLists.txt b/injector/CMakeLists.txt index 6bea5b51d3..ba3393956a 100644 --- a/injector/CMakeLists.txt +++ b/injector/CMakeLists.txt @@ -3,15 +3,19 @@ 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 injector) 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}) - -# link the threads library -find_package(Threads REQUIRED) -target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT}) \ No newline at end of file +link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) \ No newline at end of file diff --git a/injector/src/main.cpp b/injector/src/main.cpp index dee09de6c8..df751f50a1 100644 --- a/injector/src/main.cpp +++ b/injector/src/main.cpp @@ -6,7 +6,6 @@ // Copyright (c) 2013 Leonardo Murillo. All rights reserved. // - #include #include #include @@ -15,15 +14,17 @@ #include #include - #include #include #include #include +#include char EC2_WEST_AUDIO_SERVER[] = "54.241.92.53"; const int AUDIO_UDP_LISTEN_PORT = 55443; +const int DEFAULT_INJECTOR_VOLUME = 0xFF; + // Command line parameter defaults bool loopAudio = true; float sleepIntervalMin = 1.00; @@ -31,7 +32,7 @@ float sleepIntervalMax = 2.00; char *sourceAudioFile = NULL; const char *allowedParameters = ":rb::t::c::a::f:"; float floatArguments[4] = {0.0f, 0.0f, 0.0f, 0.0f}; -unsigned char attenuationModifier = 255; +unsigned char volume = DEFAULT_INJECTOR_VOLUME; void usage(void) { @@ -82,7 +83,7 @@ bool processParameters(int parameterCount, char* parameterData[]) break; } case 'a': - ::attenuationModifier = atoi(optarg); + ::volume = atoi(optarg); std::cout << "[DEBUG] Attenuation modifier: " << optarg << std::endl; break; default: @@ -112,19 +113,17 @@ int main(int argc, char* argv[]) { exit(-1); } else { AudioInjector injector(sourceAudioFile); - injector.setInjectorSocket(&streamSocket); - injector.setDestinationSocket((sockaddr*) &mixerSocket); - injector.setPosition(::floatArguments); + injector.setPosition(glm::vec3(::floatArguments[0], ::floatArguments[1], ::floatArguments[2])); injector.setBearing(*(::floatArguments + 3)); - injector.setAttenuationModifier(::attenuationModifier); + injector.setVolume(::volume); float delay = 0; int usecDelay = 0; while (true) { - injector.injectAudio(); - + injector.injectAudio(&streamSocket, (sockaddr*) &mixerSocket); + if (!::loopAudio) { delay = randFloatInRange(::sleepIntervalMin, ::sleepIntervalMax); usecDelay = delay * 1000 * 1000; diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 56b41fbc69..dac0749f8d 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -71,6 +71,7 @@ include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) # find required libraries find_package(GLM REQUIRED) diff --git a/libraries/audio/CMakeLists.txt b/libraries/audio/CMakeLists.txt new file mode 100644 index 0000000000..686986340f --- /dev/null +++ b/libraries/audio/CMakeLists.txt @@ -0,0 +1,22 @@ +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) + +include(${MACRO_DIR}/SetupHifiLibrary.cmake) +setup_hifi_library(${TARGET_NAME}) + +include(${MACRO_DIR}/IncludeGLM.cmake) +include_glm(${TARGET_NAME} ${ROOT_DIR}) + +include(${MACRO_DIR}/LinkHifiLibrary.cmake) +link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) + +# link the threads library +find_package(Threads REQUIRED) +target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT}) \ No newline at end of file diff --git a/libraries/audio/src/AudioInjectionManager.cpp b/libraries/audio/src/AudioInjectionManager.cpp new file mode 100644 index 0000000000..ce252afd23 --- /dev/null +++ b/libraries/audio/src/AudioInjectionManager.cpp @@ -0,0 +1,64 @@ +// +// 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; + + injector->injectAudio(_injectorSocket, &_destinationSocket); + + // 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/audio/src/AudioInjectionManager.h b/libraries/audio/src/AudioInjectionManager.h new file mode 100644 index 0000000000..3297305475 --- /dev/null +++ b/libraries/audio/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/audio/src/AudioInjector.cpp similarity index 71% rename from libraries/shared/src/AudioInjector.cpp rename to libraries/audio/src/AudioInjector.cpp index c89385226c..689b4c6cd9 100644 --- a/libraries/shared/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -3,27 +3,24 @@ // 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 +#include +#include #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; +const int MAX_INJECTOR_VOLUME = 0xFF; AudioInjector::AudioInjector(const char* filename) : _position(), _bearing(0), - _attenuationModifier(255), + _volume(MAX_INJECTOR_VOLUME), _indexOfNextSlot(0), _isInjectingAudio(false) { @@ -50,7 +47,7 @@ AudioInjector::AudioInjector(int maxNumSamples) : _numTotalSamples(maxNumSamples), _position(), _bearing(0), - _attenuationModifier(255), + _volume(MAX_INJECTOR_VOLUME), _indexOfNextSlot(0), _isInjectingAudio(false) { @@ -62,10 +59,50 @@ AudioInjector::~AudioInjector() { delete[] _audioSampleArray; } -void AudioInjector::setPosition(float* position) { - _position[0] = position[0]; - _position[1] = position[1]; - _position[2] = position[2]; +void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destinationSocket) { + 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; + + memcpy(currentPacketPtr, &_position, sizeof(_position)); + currentPacketPtr += sizeof(_position); + + *currentPacketPtr = _volume; + currentPacketPtr++; + + memcpy(currentPacketPtr, &_bearing, sizeof(_bearing)); + currentPacketPtr += sizeof(_bearing); + + 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 AudioInjector::addSample(const int16_t sample) { @@ -82,63 +119,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/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h new file mode 100644 index 0000000000..eb22df1177 --- /dev/null +++ b/libraries/audio/src/AudioInjector.h @@ -0,0 +1,55 @@ +// +// AudioInjector.h +// 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 + +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(); + + void injectAudio(UDPSocket* injectorSocket, sockaddr* destinationSocket); + + bool isInjectingAudio() const { return _isInjectingAudio; } + void setIsInjectingAudio(bool isInjectingAudio) { _isInjectingAudio = isInjectingAudio; } + + 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 addSample(const int16_t sample); + void addSamples(int16_t* sampleBuffer, int numSamples); +private: + int16_t* _audioSampleArray; + int _numTotalSamples; + glm::vec3 _position; + float _bearing; + unsigned char _volume; + int _indexOfNextSlot; + bool _isInjectingAudio; +}; + +#endif /* defined(__hifi__AudioInjector__) */ diff --git a/libraries/shared/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp similarity index 100% rename from libraries/shared/src/AudioRingBuffer.cpp rename to libraries/audio/src/AudioRingBuffer.cpp diff --git a/libraries/shared/src/AudioRingBuffer.h b/libraries/audio/src/AudioRingBuffer.h similarity index 100% rename from libraries/shared/src/AudioRingBuffer.h rename to libraries/audio/src/AudioRingBuffer.h diff --git a/libraries/shared/src/AudioInjector.h b/libraries/shared/src/AudioInjector.h deleted file mode 100644 index 3e79869034..0000000000 --- a/libraries/shared/src/AudioInjector.h +++ /dev/null @@ -1,48 +0,0 @@ -// -// AudioInjector.h -// hifi -// -// Created by Stephen Birarda on 4/23/13. -// -// - -#ifndef __hifi__AudioInjector__ -#define __hifi__AudioInjector__ - -#include -#include - -#include "UDPSocket.h" - -class AudioInjector { -public: - AudioInjector(const char* filename); - AudioInjector(int maxNumSamples); - ~AudioInjector(); - - bool isInjectingAudio() const { return _isInjectingAudio; } - - void setPosition(float* position); - 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]; - float _bearing; - unsigned char _attenuationModifier; - int _indexOfNextSlot; - UDPSocket* _injectorSocket; - sockaddr _destinationSocket; - bool _isInjectingAudio; -}; - -#endif /* defined(__hifi__AudioInjector__) */