add trigger based firing to audio injector

This commit is contained in:
Stephen Birarda 2013-05-29 16:03:32 -07:00
parent 7611972bca
commit c0a9914efd

View file

@ -14,14 +14,16 @@
#include <string.h>
#include <sstream>
#include <AgentList.h>
#include <AgentTypes.h>
#include <AvatarData.h>
#include <SharedUtil.h>
#include <PacketHeaders.h>
#include <UDPSocket.h>
#include <AudioInjector.h>
#include <AudioInjectionManager.h>
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;
}