From eb5375869d0d6d2443902e84f0fe74d76d0ab7c9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 May 2013 14:34:58 -0700 Subject: [PATCH 1/5] also return the list of avatars to audio injectors --- avatar-mixer/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avatar-mixer/src/main.cpp b/avatar-mixer/src/main.cpp index eca698e673..3e46d698c8 100644 --- a/avatar-mixer/src/main.cpp +++ b/avatar-mixer/src/main.cpp @@ -86,7 +86,7 @@ int main(int argc, const char* argv[]) { agentList->updateAgentWithData(avatarAgent, packetData, receivedBytes); currentBufferPosition = broadcastPacket + 1; - + case PACKET_HEADER_INJECT_AUDIO: // send back a packet with other active agent data to this agent for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { if (agent->getLinkedData() && !socketMatch(agentAddress, agent->getActiveSocket())) { From 19e29585fc2afff19108bc8c92c5abeddce2d7c4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 May 2013 15:04:22 -0700 Subject: [PATCH 2/5] remove some spacing at the bottom of eve main --- eve/src/main.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/eve/src/main.cpp b/eve/src/main.cpp index bf32474b33..c670be050e 100644 --- a/eve/src/main.cpp +++ b/eve/src/main.cpp @@ -204,6 +204,4 @@ int main(int argc, const char* argv[]) { agentList->stopDomainServerCheckInThread(); agentList->stopPingUnknownAgentsThread(); agentList->stopSilentAgentRemovalThread(); -} - - +} \ No newline at end of file From c259b025db6abfed4c300d13b25e986346d5dea1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 May 2013 15:05:39 -0700 Subject: [PATCH 3/5] fix a crash in audio injector when there is no audio mixer --- libraries/audio/src/AudioInjectionManager.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioInjectionManager.cpp b/libraries/audio/src/AudioInjectionManager.cpp index 275161730e..f8fc9f742f 100644 --- a/libraries/audio/src/AudioInjectionManager.cpp +++ b/libraries/audio/src/AudioInjectionManager.cpp @@ -58,7 +58,11 @@ void* AudioInjectionManager::injectAudioViaThread(void* args) { // if we don't have an explicit destination socket then pull active socket for current audio mixer from agent list if (!_isDestinationSocketExplicit) { - _destinationSocket = *AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER)->getActiveSocket(); + Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER); + + if (audioMixer) { + _destinationSocket = *audioMixer->getActiveSocket(); + } } injector->injectAudio(_injectorSocket, &_destinationSocket); From 7611972bcaeb69148467f2529f7b4e6547601f4b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 May 2013 15:06:10 -0700 Subject: [PATCH 4/5] link the avatars library to the injector target --- injector/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/injector/CMakeLists.txt b/injector/CMakeLists.txt index ba3393956a..2c022b0e92 100644 --- a/injector/CMakeLists.txt +++ b/injector/CMakeLists.txt @@ -18,4 +18,5 @@ 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_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) \ No newline at end of file +link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR}) \ No newline at end of file From c0a9914efdc20b88839fa75f3578900ce1f58228 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 May 2013 16:03:32 -0700 Subject: [PATCH 5/5] add trigger based firing to audio injector --- injector/src/main.cpp | 168 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 139 insertions(+), 29 deletions(-) diff --git a/injector/src/main.cpp b/injector/src/main.cpp index df751f50a1..32a8442d8f 100644 --- a/injector/src/main.cpp +++ b/injector/src/main.cpp @@ -14,14 +14,16 @@ #include #include +#include +#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 AVATAR_MIXER_DATA_SEND_INTERVAL_MSECS = 15; const int DEFAULT_INJECTOR_VOLUME = 0xFF; @@ -30,12 +32,12 @@ bool loopAudio = true; float sleepIntervalMin = 1.00; float sleepIntervalMax = 2.00; char *sourceAudioFile = NULL; -const char *allowedParameters = ":rb::t::c::a::f:"; +const char *allowedParameters = ":rb::t::c::a::f::d:"; float floatArguments[4] = {0.0f, 0.0f, 0.0f, 0.0f}; unsigned char volume = DEFAULT_INJECTOR_VOLUME; +float triggerDistance = 0; -void usage(void) -{ +void usage(void) { std::cout << "High Fidelity - Interface audio injector" << std::endl; std::cout << " -r Random sleep mode. If not specified will default to constant loop." << std::endl; std::cout << " -b FLOAT Min. number of seconds to sleep. Only valid in random sleep mode. Default 1.0" << std::endl; @@ -43,10 +45,10 @@ void usage(void) std::cout << " -c FLOAT,FLOAT,FLOAT,FLOAT X,Y,Z,YAW position in universe where audio will be originating from and direction. Defaults to 0,0,0,0" << std::endl; std::cout << " -a 0-255 Attenuation curve modifier, defaults to 255" << std::endl; std::cout << " -f FILENAME Name of audio source file. Required - RAW format, 22050hz 16bit signed mono" << std::endl; + std::cout << " -d FLOAT Trigger distance for injection. If not specified will loop constantly" << std::endl; } -bool processParameters(int parameterCount, char* parameterData[]) -{ +bool processParameters(int parameterCount, char* parameterData[]) { int p; while ((p = getopt(parameterCount, parameterData, allowedParameters)) != -1) { switch (p) { @@ -86,6 +88,10 @@ bool processParameters(int parameterCount, char* parameterData[]) ::volume = atoi(optarg); std::cout << "[DEBUG] Attenuation modifier: " << optarg << std::endl; break; + case 'd': + ::triggerDistance = atof(optarg); + std::cout << "[DEBUG] Trigger distance: " << optarg << std::endl; + break; default: usage(); return false; @@ -94,45 +100,149 @@ bool processParameters(int parameterCount, char* parameterData[]) return true; }; -int main(int argc, char* argv[]) { +bool stopReceiveAgentDataThread; +void *receiveAgentData(void *args) { + sockaddr senderAddress; + ssize_t bytesReceived; + unsigned char incomingPacket[MAX_PACKET_SIZE]; + + AgentList* agentList = AgentList::getInstance(); + + while (!::stopReceiveAgentDataThread) { + if (agentList->getAgentSocket()->receive(&senderAddress, incomingPacket, &bytesReceived)) { + switch (incomingPacket[0]) { + case PACKET_HEADER_BULK_AVATAR_DATA: + // this is the positional data for other agents + // pass that off to the agentList processBulkAgentData method + agentList->processBulkAgentData(&senderAddress, incomingPacket, bytesReceived); + break; + default: + // have the agentList handle list of agents from DS, replies from other agents, etc. + agentList->processAgentData(&senderAddress, incomingPacket, bytesReceived); + break; + } + } + } + + pthread_exit(0); + return NULL; +} + +void createAvatarDataForAgent(Agent* agent) { + if (!agent->getLinkedData()) { + agent->setLinkedData(new AvatarData(agent)); + } +} + +int main(int argc, char* argv[]) { + // new seed for random audio sleep times srand(time(0)); + int AUDIO_UDP_SEND_PORT = 1500 + (rand() % (int)(1500 - 2000 + 1)); - UDPSocket streamSocket(AUDIO_UDP_SEND_PORT); - - sockaddr_in mixerSocket; - mixerSocket.sin_family = AF_INET; - mixerSocket.sin_addr.s_addr = inet_addr(EC2_WEST_AUDIO_SERVER); - mixerSocket.sin_port = htons((uint16_t)AUDIO_UDP_LISTEN_PORT); - - - if (processParameters(argc, argv)) { + if (processParameters(argc, argv)) { if (::sourceAudioFile == NULL) { std::cout << "[FATAL] Source audio file not specified" << std::endl; exit(-1); } else { AudioInjector injector(sourceAudioFile); + // create an AgentList instance to handle communication with other agents + AgentList* agentList = AgentList::createInstance(AGENT_TYPE_AUDIO_INJECTOR, AUDIO_UDP_SEND_PORT); + + pthread_t receiveAgentDataThread; + pthread_create(&receiveAgentDataThread, NULL, receiveAgentData, NULL); + + // start telling the domain server that we are alive + agentList->startDomainServerCheckInThread(); + + // start the agent list thread that will kill off agents when they stop talking + agentList->startSilentAgentRemovalThread(); + injector.setPosition(glm::vec3(::floatArguments[0], ::floatArguments[1], ::floatArguments[2])); injector.setBearing(*(::floatArguments + 3)); injector.setVolume(::volume); - - float delay = 0; - int usecDelay = 0; + + // register the callback for agent data creation + agentList->linkedDataCreateCallback = createAvatarDataForAgent; + + unsigned char broadcastPacket = PACKET_HEADER_INJECT_AUDIO; + + timeval thisSend; + double numMicrosecondsSleep = 0; while (true) { - injector.injectAudio(&streamSocket, (sockaddr*) &mixerSocket); - - if (!::loopAudio) { - delay = randFloatInRange(::sleepIntervalMin, ::sleepIntervalMax); - usecDelay = delay * 1000 * 1000; - usleep(usecDelay); + if (::triggerDistance) { + + // update the thisSend timeval to the current time + gettimeofday(&thisSend, NULL); + + // find the current avatar mixer + Agent* avatarMixer = agentList->soloAgentOfType(AGENT_TYPE_AVATAR_MIXER); + + // make sure we actually have an avatar mixer with an active socket + if (avatarMixer && avatarMixer->getActiveSocket() != NULL) { + // use the UDPSocket instance attached to our agent list to ask avatar mixer for a list of avatars + agentList->getAgentSocket()->send(avatarMixer->getActiveSocket(), + &broadcastPacket, + sizeof(broadcastPacket)); + } + + if (!injector.isInjectingAudio()) { + // enumerate the other agents to decide if one is close enough that we should inject + for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { + AvatarData* avatarData = (AvatarData*) agent->getLinkedData(); + + if (avatarData) { + glm::vec3 tempVector = injector.getPosition() - avatarData->getPosition(); + float squareDistance = glm::dot(tempVector, tempVector); + + if (squareDistance <= ::triggerDistance) { + // look for an audio mixer in our agent list + Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER); + + if (audioMixer) { + // we have an active audio mixer we can send data to + AudioInjectionManager::threadInjector(&injector); + } + } + } + } + } + + // sleep for the correct amount of time to have data send be consistently timed + if ((numMicrosecondsSleep = (AVATAR_MIXER_DATA_SEND_INTERVAL_MSECS * 1000) - + (usecTimestampNow() - usecTimestamp(&thisSend))) > 0) { + usleep(numMicrosecondsSleep); + } + } else { + // look for an audio mixer in our agent list + Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER); + + if (audioMixer) { + injector.injectAudio(agentList->getAgentSocket(), audioMixer->getActiveSocket()); + } + + float delay = 0; + int usecDelay = 0; + + if (!::loopAudio) { + delay = randFloatInRange(::sleepIntervalMin, ::sleepIntervalMax); + usecDelay = delay * 1000 * 1000; + usleep(usecDelay); + } } } - } + + // stop the receive agent data thread + stopReceiveAgentDataThread = true; + pthread_join(receiveAgentDataThread, NULL); + + // stop the agent list's threads + agentList->stopDomainServerCheckInThread(); + agentList->stopSilentAgentRemovalThread(); + } } - return 0; } -