From e2c3c253a8ed4ad9918ae92e47e85298d5942f13 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 25 Feb 2013 15:19:53 -0800 Subject: [PATCH 01/11] fix birarda's stupid bug in timestamp creation --- shared/src/SharedUtil.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/src/SharedUtil.cpp b/shared/src/SharedUtil.cpp index 5880b8919a..d9de883024 100644 --- a/shared/src/SharedUtil.cpp +++ b/shared/src/SharedUtil.cpp @@ -9,11 +9,11 @@ #include "SharedUtil.h" double usecTimestamp(timeval *time) { - return (time->tv_sec * 1000000.0); + return (time->tv_sec * 1000000.0 + time->tv_usec); } double usecTimestampNow() { timeval now; gettimeofday(&now, NULL); - return (now.tv_sec * 1000000.0); + return (now.tv_sec * 1000000.0 + now.tv_usec); } \ No newline at end of file From abfd3a01685722fb41e63e578e1916b8d1e88613 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 25 Feb 2013 17:07:32 -0800 Subject: [PATCH 02/11] refactor mixer to use AgentList, AudioRingBuffer as AgentData --- interface/src/Audio.cpp | 53 +++---- interface/src/Head.cpp | 4 + interface/src/Head.h | 2 + mixer/src/main.cpp | 266 +++++++++++---------------------- shared/src/Agent.cpp | 9 +- shared/src/AgentData.h | 1 + shared/src/AgentList.h | 2 +- shared/src/AudioRingBuffer.cpp | 89 +++++++++-- shared/src/AudioRingBuffer.h | 36 ++++- shared/src/UDPSocket.cpp | 1 - 10 files changed, 222 insertions(+), 241 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index b433b2a199..27c2a33a0b 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -18,18 +18,12 @@ Oscilloscope * scope; -const short BUFFER_LENGTH_BYTES = 1024; -const short BUFFER_LENGTH_SAMPLES = BUFFER_LENGTH_BYTES / sizeof(int16_t); - const short PACKET_LENGTH_BYTES = 1024; const short PACKET_LENGTH_SAMPLES = PACKET_LENGTH_BYTES / sizeof(int16_t); const int PHASE_DELAY_AT_90 = 20; const float AMPLITUDE_RATIO_AT_90 = 0.5; -const short RING_BUFFER_FRAMES = 10; -const short RING_BUFFER_SIZE_SAMPLES = RING_BUFFER_FRAMES * BUFFER_LENGTH_SAMPLES; - const int SAMPLE_RATE = 22050; const float JITTER_BUFFER_LENGTH_MSECS = 30.0; const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_LENGTH_MSECS * (SAMPLE_RATE / 1000.0); @@ -90,7 +84,7 @@ int audioCallback (const void *inputBuffer, audioMixerSocket.sin_family = AF_INET; audioMixerSocket.sin_addr.s_addr = data->mixerAddress; audioMixerSocket.sin_port = data->mixerPort; - data->audioSocket->send((sockaddr *)&audioMixerSocket, (void *)inputLeft, BUFFER_LENGTH_BYTES); + data->audioSocket->send((sockaddr *)&audioMixerSocket, (void *)inputLeft, BUFFER_LENGTH_BYTES); } // @@ -134,27 +128,27 @@ int audioCallback (const void *inputBuffer, // if we've been reset, and there isn't any new packets yet // just play some silence - if (ringBuffer->endOfLastWrite != NULL) { + if (ringBuffer->getEndOfLastWrite() != NULL) { - if (!ringBuffer->started && ringBuffer->diffLastWriteNextOutput() <= PACKET_LENGTH_SAMPLES + JITTER_BUFFER_SAMPLES) { + if (!ringBuffer->isStarted() && ringBuffer->diffLastWriteNextOutput() <= PACKET_LENGTH_SAMPLES + JITTER_BUFFER_SAMPLES) { printf("Held back\n"); } else if (ringBuffer->diffLastWriteNextOutput() < PACKET_LENGTH_SAMPLES) { - ringBuffer->started = false; + ringBuffer->setStarted(false); starve_counter++; printf("Starved #%d\n", starve_counter); data->wasStarved = 10; // Frames to render the indication that the system was starved. } else { - ringBuffer->started = true; + ringBuffer->setStarted(true); // play whatever we have in the audio buffer // no sample overlap, either a direct copy of the audio data, or a copy with some appended silence - memcpy(queueBuffer, ringBuffer->nextOutput, BUFFER_LENGTH_BYTES); + memcpy(queueBuffer, ringBuffer->getNextOutput(), BUFFER_LENGTH_BYTES); - ringBuffer->nextOutput += BUFFER_LENGTH_SAMPLES; + ringBuffer->setNextOutput(ringBuffer->getNextOutput() + BUFFER_LENGTH_SAMPLES); - if (ringBuffer->nextOutput == ringBuffer->buffer + RING_BUFFER_SIZE_SAMPLES) { - ringBuffer->nextOutput = ringBuffer->buffer; + if (ringBuffer->getNextOutput() == ringBuffer->getBuffer() + RING_BUFFER_SAMPLES) { + ringBuffer->setNextOutput(ringBuffer->getBuffer()); } } } @@ -204,7 +198,6 @@ void *receiveAudioViaUDP(void *args) { while (!stopAudioReceiveThread) { if (sharedAudioData->audioSocket->receive((void *)receivedData, &receivedBytes)) { - bool firstSample = (currentReceiveTime.tv_sec == 0); gettimeofday(¤tReceiveTime, NULL); @@ -233,28 +226,24 @@ void *receiveAudioViaUDP(void *args) { AudioRingBuffer *ringBuffer = sharedAudioData->ringBuffer; - if (ringBuffer->endOfLastWrite == NULL) { - ringBuffer->endOfLastWrite = ringBuffer->buffer; - } else if (ringBuffer->diffLastWriteNextOutput() > RING_BUFFER_SIZE_SAMPLES - PACKET_LENGTH_SAMPLES) { - std::cout << "NAB: " << ringBuffer->nextOutput - ringBuffer->buffer << "\n"; - std::cout << "LAW: " << ringBuffer->endOfLastWrite - ringBuffer->buffer << "\n"; - std::cout << "D: " << ringBuffer->diffLastWriteNextOutput() << "\n"; - std::cout << "Full\n"; + if (ringBuffer->getEndOfLastWrite() == NULL) { + ringBuffer->setEndOfLastWrite(ringBuffer->getBuffer()); + } else if (ringBuffer->diffLastWriteNextOutput() > RING_BUFFER_SAMPLES - PACKET_LENGTH_SAMPLES) { // reset us to started state - ringBuffer->endOfLastWrite = ringBuffer->buffer; - ringBuffer->nextOutput = ringBuffer->buffer; - ringBuffer->started = false; + ringBuffer->setEndOfLastWrite(ringBuffer->getBuffer()); + ringBuffer->setNextOutput(ringBuffer->getBuffer()); + ringBuffer->setStarted(false); } - int16_t *copyToPointer = ringBuffer->endOfLastWrite; + int16_t *copyToPointer = ringBuffer->getEndOfLastWrite(); // just copy the recieved data to the right spot and then add packet length to previous pointer memcpy(copyToPointer, receivedData, PACKET_LENGTH_BYTES); - ringBuffer->endOfLastWrite += PACKET_LENGTH_SAMPLES; + ringBuffer->setEndOfLastWrite(ringBuffer->getEndOfLastWrite() + PACKET_LENGTH_SAMPLES); - if (ringBuffer->endOfLastWrite == ringBuffer->buffer + RING_BUFFER_SIZE_SAMPLES) { - ringBuffer->endOfLastWrite = ringBuffer->buffer; + if (ringBuffer->getEndOfLastWrite() == ringBuffer->getBuffer() + RING_BUFFER_SAMPLES) { + ringBuffer->setEndOfLastWrite(ringBuffer->getBuffer()); } if (LOG_SAMPLE_DELAY) { @@ -284,7 +273,7 @@ Audio::Audio(Oscilloscope * s) // setup a UDPSocket audioData->audioSocket = new UDPSocket(AUDIO_UDP_LISTEN_PORT); - audioData->ringBuffer = new AudioRingBuffer(RING_BUFFER_SIZE_SAMPLES); + audioData->ringBuffer = new AudioRingBuffer(); AudioRecThreadStruct threadArgs; threadArgs.sharedAudioData = audioData; @@ -359,7 +348,7 @@ void Audio::render(int screenWidth, int screenHeight) float timeLeftInCurrentBuffer = 0; if (audioData->lastCallback.tv_usec > 0) timeLeftInCurrentBuffer = diffclock(&audioData->lastCallback, ¤tTime)/(1000.0*(float)BUFFER_LENGTH_SAMPLES/(float)SAMPLE_RATE) * frameWidth; - if (audioData->ringBuffer->endOfLastWrite != NULL) + if (audioData->ringBuffer->getEndOfLastWrite() != NULL) remainingBuffer = audioData->ringBuffer->diffLastWriteNextOutput() / BUFFER_LENGTH_SAMPLES * frameWidth; if (audioData->wasStarved == 0) glColor3f(0, 1, 0); diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index d69a3fa35f..6930d7a77a 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -64,6 +64,10 @@ Head::~Head() { // all data is primitive, do nothing } +Head* Head::clone() const { + return new Head(*this); +} + void Head::reset() { Pitch = Yaw = Roll = 0; diff --git a/interface/src/Head.h b/interface/src/Head.h index 038f37bfc5..94714d97b0 100644 --- a/interface/src/Head.h +++ b/interface/src/Head.h @@ -24,6 +24,8 @@ class Head : public AgentData { public: Head(); ~Head(); + Head* clone() const; + void reset(); void UpdatePos(float frametime, SerialInterface * serialInterface, int head_mirror, glm::vec3 * gravity); void setNoise (float mag) { noise = mag; } diff --git a/mixer/src/main.cpp b/mixer/src/main.cpp index eb125e1831..379298b828 100644 --- a/mixer/src/main.cpp +++ b/mixer/src/main.cpp @@ -13,24 +13,21 @@ #include #include #include "AudioRingBuffer.h" -#include "UDPSocket.h" +#include +#include const int MAX_AGENTS = 1000; const int LOGOFF_CHECK_INTERVAL = 1000; const unsigned short MIXER_LISTEN_PORT = 55443; -const int BUFFER_LENGTH_BYTES = 1024; -const int BUFFER_LENGTH_SAMPLES = BUFFER_LENGTH_BYTES / sizeof(int16_t); + const float SAMPLE_RATE = 22050.0; const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES/SAMPLE_RATE) * 1000000; const short JITTER_BUFFER_MSECS = 20; const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_MSECS * (SAMPLE_RATE / 1000.0); -const short RING_BUFFER_FRAMES = 10; -const short RING_BUFFER_SAMPLES = RING_BUFFER_FRAMES * BUFFER_LENGTH_SAMPLES; - const long MAX_SAMPLE_VALUE = std::numeric_limits::max(); const long MIN_SAMPLE_VALUE = std::numeric_limits::min(); @@ -40,190 +37,100 @@ const int DOMAINSERVER_PORT = 40102; const int MAX_SOURCE_BUFFERS = 20; -sockaddr_in agentAddress; - -UDPSocket audioSocket = UDPSocket(MIXER_LISTEN_PORT); - -struct AgentList { - char *address; - unsigned short port; - bool active; - timeval time; - bool bufferTransmitted; -} agents[MAX_AGENTS]; - -int numAgents = 0; - -AudioRingBuffer *sourceBuffers[MAX_SOURCE_BUFFERS]; - -double diffclock(timeval *clock1, timeval *clock2) -{ - double diffms = (clock2->tv_sec - clock1->tv_sec) * 1000.0; - diffms += (clock2->tv_usec - clock1->tv_usec) / 1000.0; // us to ms - return diffms; -} - -double usecTimestamp(timeval *time, double addedUsecs = 0) { - return (time->tv_sec * 1000000.0) + time->tv_usec + addedUsecs; -} +AgentList agentList(MIXER_LISTEN_PORT); void *sendBuffer(void *args) { int sentBytes; - int currentFrame = 1; - timeval startTime, sendTime, now; + int nextFrame = 0; + timeval startTime; int16_t *clientMix = new int16_t[BUFFER_LENGTH_SAMPLES]; long *masterMix = new long[BUFFER_LENGTH_SAMPLES]; - + gettimeofday(&startTime, NULL); while (true) { sentBytes = 0; - - for (int wb = 0; wb < BUFFER_LENGTH_SAMPLES; wb++) { - masterMix[wb] = 0; + + for (int ms = 0; ms < BUFFER_LENGTH_SAMPLES; ms++) { + masterMix[ms] = 0; } - gettimeofday(&sendTime, NULL); - - for (int b = 0; b < MAX_SOURCE_BUFFERS; b++) { - if (sourceBuffers[b]->endOfLastWrite != NULL) { - if (!sourceBuffers[b]->started - && sourceBuffers[b]->diffLastWriteNextOutput() <= BUFFER_LENGTH_SAMPLES + JITTER_BUFFER_SAMPLES) { - std::cout << "Held back buffer " << b << ".\n"; - } else if (sourceBuffers[b]->diffLastWriteNextOutput() < BUFFER_LENGTH_SAMPLES) { - std::cout << "Buffer " << b << " starved.\n"; - sourceBuffers[b]->started = false; - } else { - sourceBuffers[b]->started = true; - agents[b].bufferTransmitted = true; - - for (int s = 0; s < BUFFER_LENGTH_SAMPLES; s++) { - masterMix[s] += sourceBuffers[b]->nextOutput[s]; - } - - sourceBuffers[b]->nextOutput += BUFFER_LENGTH_SAMPLES; - - if (sourceBuffers[b]->nextOutput >= sourceBuffers[b]->buffer + RING_BUFFER_SAMPLES) { - sourceBuffers[b]->nextOutput = sourceBuffers[b]->buffer; - } - } - } - } - - for (int a = 0; a < numAgents; a++) { - if (diffclock(&agents[a].time, &sendTime) <= LOGOFF_CHECK_INTERVAL) { - - int16_t *previousOutput = NULL; - if (agents[a].bufferTransmitted) { - previousOutput = (sourceBuffers[a]->nextOutput == sourceBuffers[a]->buffer) - ? sourceBuffers[a]->buffer + RING_BUFFER_SAMPLES - BUFFER_LENGTH_SAMPLES - : sourceBuffers[a]->nextOutput - BUFFER_LENGTH_SAMPLES; - agents[a].bufferTransmitted = false; - } - - for(int as = 0; as < BUFFER_LENGTH_SAMPLES; as++) { - long longSample = previousOutput != NULL - ? masterMix[as] - previousOutput[as] - : masterMix[as]; - - int16_t shortSample; - - if (longSample < 0) { - shortSample = std::max(longSample, MIN_SAMPLE_VALUE); - } else { - shortSample = std::min(longSample, MAX_SAMPLE_VALUE); - } - - clientMix[as] = shortSample; - - // std::cout << as << " - CM: " << clientMix[as] << " MM: " << masterMix[as] << "\n"; - // std::cout << previousOutput - sourceBuffers[a]->buffer << "\n"; - - if (previousOutput != NULL) { - // std::cout << "PO: " << previousOutput[as] << "\n"; - } - - } - - sentBytes = audioSocket.send(agents[a].address, agents[a].port, clientMix, BUFFER_LENGTH_BYTES); + for (int ab = 0; ab < agentList.getAgents().size(); ab++) { + AudioRingBuffer *agentBuffer = (AudioRingBuffer *)agentList.getAgents()[ab].getLinkedData(); - if (sentBytes < BUFFER_LENGTH_BYTES) { - std::cout << "Error sending mix packet! " << sentBytes << strerror(errno) << "\n"; + if (agentBuffer != NULL && agentBuffer->getEndOfLastWrite() != NULL) { + if (!agentBuffer->isStarted() && agentBuffer->diffLastWriteNextOutput() <= BUFFER_LENGTH_SAMPLES + JITTER_BUFFER_SAMPLES) { + printf("Held back buffer %d.\n", ab); + } else if (agentBuffer->diffLastWriteNextOutput() < BUFFER_LENGTH_SAMPLES) { + printf("Buffer %d starved.\n", ab); + agentBuffer->setStarted(false); + } else { + // good buffer, add this to the mix + agentBuffer->setStarted(true); + agentBuffer->setAddedToMix(true); + + for (int s = 0; s < BUFFER_LENGTH_SAMPLES; s++) { + masterMix[s] += agentBuffer->getNextOutput()[s]; + } + + agentBuffer->setNextOutput(agentBuffer->getNextOutput() + BUFFER_LENGTH_SAMPLES); + + if (agentBuffer->getNextOutput() >= agentBuffer->getBuffer() + RING_BUFFER_SAMPLES) { + agentBuffer->setNextOutput(agentBuffer->getBuffer()); + } } } - } - - gettimeofday(&now, NULL); + } - double usecToSleep = usecTimestamp(&startTime, (currentFrame * BUFFER_SEND_INTERVAL_USECS)) - usecTimestamp(&now); + for (int ab = 0; ab < agentList.getAgents().size(); ab++) { + Agent *agent = &agentList.getAgents()[ab]; + AudioRingBuffer *agentBuffer = (AudioRingBuffer *)agent->getLinkedData(); + int16_t *previousOutput = NULL; + + if (agentBuffer != NULL && agentBuffer->wasAddedToMix()) { + previousOutput = (agentBuffer->getNextOutput() == agentBuffer->getBuffer()) + ? agentBuffer->getBuffer() + RING_BUFFER_SAMPLES - BUFFER_LENGTH_SAMPLES + : agentBuffer->getNextOutput() - BUFFER_LENGTH_SAMPLES; + agentBuffer->setAddedToMix(false); + } + + for (int s = 0; s < BUFFER_LENGTH_SAMPLES; s++) { + long longSample = (previousOutput != NULL) + ? masterMix[s] - previousOutput[s] + : masterMix[s]; + + int16_t shortSample; + + if (longSample < 0) { + shortSample = std::max(longSample, MIN_SAMPLE_VALUE); + } else { + shortSample = std::min(longSample, MAX_SAMPLE_VALUE); + } + + clientMix[s] = shortSample; + } + + agentList.getAgentSocket().send(agent->getPublicSocket(), clientMix, BUFFER_LENGTH_BYTES); + } + + double usecToSleep = usecTimestamp(&startTime) + (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - usecTimestampNow(); + if (usecToSleep > 0) { usleep(usecToSleep); } else { - std::cout << "NOT SLEEPING!"; + std::cout << "Took too much time, not sleeping!\n"; } - - currentFrame++; } pthread_exit(0); } -int addAgent(sockaddr_in *newAddress, void *audioData) { - // Search for agent in list and add if needed - int is_new = 0; - int i = 0; - - for (i = 0; i < numAgents; i++) { - if (strcmp(inet_ntoa(newAddress->sin_addr), agents[i].address) == 0 - && ntohs(newAddress->sin_port) == agents[i].port) { - break; - } - } - - if ((i == numAgents) || (agents[i].active == false)) { - is_new = 1; - - agents[i].address = new char(); - strcpy(agents[i].address, inet_ntoa(newAddress->sin_addr)); - - agents[i].bufferTransmitted = false; - } - - - agents[i].port = ntohs(newAddress->sin_port); - agents[i].active = true; - gettimeofday(&agents[i].time, NULL); - - if (sourceBuffers[i]->endOfLastWrite == NULL) { - sourceBuffers[i]->endOfLastWrite = sourceBuffers[i]->buffer; - } else if (sourceBuffers[i]->diffLastWriteNextOutput() > RING_BUFFER_SAMPLES - BUFFER_LENGTH_SAMPLES) { - // reset us to started state - sourceBuffers[i]->endOfLastWrite = sourceBuffers[i]->buffer; - sourceBuffers[i]->nextOutput = sourceBuffers[i]->buffer; - sourceBuffers[i]->started = false; - } - - memcpy(sourceBuffers[i]->endOfLastWrite, audioData, BUFFER_LENGTH_BYTES); - - sourceBuffers[i]->endOfLastWrite += BUFFER_LENGTH_SAMPLES; - - if (sourceBuffers[i]->endOfLastWrite >= sourceBuffers[i]->buffer + RING_BUFFER_SAMPLES) { - sourceBuffers[i]->endOfLastWrite = sourceBuffers[i]->buffer; - } - - if (i == numAgents) { - numAgents++; - } - - return is_new; -} - void *reportAliveToDS(void *args) { - timeval lastSend, now; + timeval lastSend; unsigned char output[7]; while (true) { @@ -231,11 +138,9 @@ void *reportAliveToDS(void *args) { *output = 'M'; packSocket(output + 1, 895283510, htons(MIXER_LISTEN_PORT)); - audioSocket.send(DOMAIN_IP, DOMAINSERVER_PORT, output, 7); + agentList.getAgentSocket().send(DOMAIN_IP, DOMAINSERVER_PORT, output, 7); - gettimeofday(&now, NULL); - - double usecToSleep = 1000000 - (usecTimestamp(&now) - usecTimestamp(&lastSend)); + double usecToSleep = 1000000 - (usecTimestampNow() - usecTimestamp(&lastSend)); if (usecToSleep > 0) { usleep(usecToSleep); @@ -245,11 +150,18 @@ void *reportAliveToDS(void *args) { } } +void attachNewBufferToAgent(Agent *newAgent) { + if (newAgent->getLinkedData() == NULL) { + newAgent->setLinkedData(new AudioRingBuffer()); + } +} + int main(int argc, const char * argv[]) -{ - timeval lastAgentUpdate; +{ ssize_t receivedBytes = 0; + agentList.linkedDataCreateCallback = attachNewBufferToAgent; + // setup the agentSocket to report to domain server pthread_t reportAliveThread; pthread_create(&reportAliveThread, NULL, reportAliveToDS, NULL); @@ -270,25 +182,19 @@ int main(int argc, const char * argv[]) printf("Using static domainserver IP: %s\n", DOMAIN_IP); } - gettimeofday(&lastAgentUpdate, NULL); - - int16_t packetData[BUFFER_LENGTH_SAMPLES]; - - for (int b = 0; b < MAX_SOURCE_BUFFERS; b++) { - sourceBuffers[b] = new AudioRingBuffer(10 * BUFFER_LENGTH_SAMPLES); - } + int16_t *packetData = new int16_t[BUFFER_LENGTH_SAMPLES]; pthread_t sendBufferThread; pthread_create(&sendBufferThread, NULL, sendBuffer, NULL); + + sockaddr *agentAddress = new sockaddr; while (true) { - if(audioSocket.receive((sockaddr *)&agentAddress, packetData, &receivedBytes)) { + if(agentList.getAgentSocket().receive(agentAddress, packetData, &receivedBytes)) { if (receivedBytes == BUFFER_LENGTH_BYTES) { - if (addAgent(&agentAddress, packetData)) { - std::cout << "Added agent: " << - inet_ntoa(agentAddress.sin_addr) << " on " << - ntohs(agentAddress.sin_port) << "\n"; - } + // add or update the existing interface agent + agentList.addOrUpdateAgent(agentAddress, agentAddress, 'I'); + agentList.updateAgentWithData(agentAddress, (void *)packetData, receivedBytes); } } } diff --git a/shared/src/Agent.cpp b/shared/src/Agent.cpp index a635314b64..cacb3a5f94 100644 --- a/shared/src/Agent.cpp +++ b/shared/src/Agent.cpp @@ -49,8 +49,11 @@ Agent::Agent(const Agent &otherAgent) { lastRecvTimeUsecs = otherAgent.lastRecvTimeUsecs; type = otherAgent.type; - // linked data is transient, gets re-assigned on next packet receive - linkedData = NULL; + if (otherAgent.linkedData != NULL) { + linkedData = otherAgent.linkedData->clone(); + } else { + linkedData = NULL; + } } Agent& Agent::operator=(Agent otherAgent) { @@ -116,8 +119,6 @@ void Agent::activatePublicSocket() { activeSocket = publicSocket; } - - AgentData* Agent::getLinkedData() { return linkedData; } diff --git a/shared/src/AgentData.h b/shared/src/AgentData.h index e39f5ade6b..9db7535521 100644 --- a/shared/src/AgentData.h +++ b/shared/src/AgentData.h @@ -13,6 +13,7 @@ class AgentData { public: virtual ~AgentData() = 0; virtual void parseData(void * data, int size) = 0; + virtual AgentData* clone() const = 0; }; #endif diff --git a/shared/src/AgentList.h b/shared/src/AgentList.h index 2755058503..0741e63d7b 100644 --- a/shared/src/AgentList.h +++ b/shared/src/AgentList.h @@ -33,6 +33,7 @@ class AgentList { int updateList(unsigned char *packetData, size_t dataBytes); bool addOrUpdateAgent(sockaddr *publicSocket, sockaddr *localSocket, char agentType); void processAgentData(sockaddr *senderAddress, void *packetData, size_t dataBytes); + void updateAgentWithData(sockaddr *senderAddress, void *packetData, size_t dataBytes); void broadcastToAgents(char *broadcastData, size_t dataBytes); void sendToAgent(Agent *destAgent, void *packetData, size_t dataBytes); void pingAgents(); @@ -44,7 +45,6 @@ class AgentList { pthread_t removeSilentAgentsThread; int indexOfMatchingAgent(sockaddr *senderAddress); - void updateAgentWithData(sockaddr *senderAddress, void *packetData, size_t dataBytes); void handlePingReply(sockaddr *agentAddress); }; diff --git a/shared/src/AudioRingBuffer.cpp b/shared/src/AudioRingBuffer.cpp index f79df7945d..48b916588b 100644 --- a/shared/src/AudioRingBuffer.cpp +++ b/shared/src/AudioRingBuffer.cpp @@ -8,20 +8,90 @@ #include "AudioRingBuffer.h" -AudioRingBuffer::AudioRingBuffer(short ringBufferSamples) { - ringBufferLengthSamples = ringBufferSamples; +AudioRingBuffer::AudioRingBuffer() { started = false; + addedToMix = false; endOfLastWrite = NULL; - buffer = new int16_t[ringBufferLengthSamples]; + buffer = new int16_t[RING_BUFFER_SAMPLES]; nextOutput = buffer; }; +AudioRingBuffer::AudioRingBuffer(const AudioRingBuffer &otherRingBuffer) { + started = otherRingBuffer.started; + addedToMix = otherRingBuffer.addedToMix; + + buffer = new int16_t[RING_BUFFER_SAMPLES]; + memcpy(buffer, otherRingBuffer.buffer, sizeof(int16_t) * RING_BUFFER_SAMPLES); + + nextOutput = buffer + (otherRingBuffer.nextOutput - otherRingBuffer.buffer); + endOfLastWrite = buffer + (otherRingBuffer.endOfLastWrite - otherRingBuffer.buffer); +} + AudioRingBuffer::~AudioRingBuffer() { delete[] buffer; }; +AudioRingBuffer* AudioRingBuffer::clone() const { + return new AudioRingBuffer(*this); +} + +int16_t* AudioRingBuffer::getNextOutput() { + return nextOutput; +} + +void AudioRingBuffer::setNextOutput(int16_t *newPointer) { + nextOutput = newPointer; +} + +int16_t* AudioRingBuffer::getEndOfLastWrite() { + return endOfLastWrite; +} + +void AudioRingBuffer::setEndOfLastWrite(int16_t *newPointer) { + endOfLastWrite = newPointer; +} + +int16_t* AudioRingBuffer::getBuffer() { + return buffer; +} + +bool AudioRingBuffer::isStarted() { + return started; +} + +void AudioRingBuffer::setStarted(bool status) { + started = status; +} + +bool AudioRingBuffer::wasAddedToMix() { + return addedToMix; +} + +void AudioRingBuffer::setAddedToMix(bool added) { + addedToMix = added; +} + +void AudioRingBuffer::parseData(void *data, int size) { + int16_t *audioData = (int16_t *)data; + + if (endOfLastWrite == NULL) { + endOfLastWrite = buffer; + } else if (diffLastWriteNextOutput() > RING_BUFFER_SAMPLES - BUFFER_LENGTH_SAMPLES) { + endOfLastWrite = buffer; + nextOutput = buffer; + started = false; + } + + memcpy(endOfLastWrite, audioData, BUFFER_LENGTH_BYTES); + endOfLastWrite += BUFFER_LENGTH_SAMPLES; + + if (endOfLastWrite >= buffer + RING_BUFFER_SAMPLES) { + endOfLastWrite = buffer; + } +} + short AudioRingBuffer::diffLastWriteNextOutput() { if (endOfLastWrite == NULL) { @@ -30,20 +100,9 @@ short AudioRingBuffer::diffLastWriteNextOutput() short sampleDifference = endOfLastWrite - nextOutput; if (sampleDifference < 0) { - sampleDifference += ringBufferLengthSamples; + sampleDifference += RING_BUFFER_SAMPLES; } return sampleDifference; } } - -short AudioRingBuffer::bufferOverlap(int16_t *pointer, short addedDistance) -{ - short samplesLeft = (buffer + ringBufferLengthSamples) - pointer; - - if (samplesLeft < addedDistance) { - return addedDistance - samplesLeft; - } else { - return 0; - } -} diff --git a/shared/src/AudioRingBuffer.h b/shared/src/AudioRingBuffer.h index eecdbd0c55..c8a656728d 100644 --- a/shared/src/AudioRingBuffer.h +++ b/shared/src/AudioRingBuffer.h @@ -11,20 +11,40 @@ #include #include +#include "AgentData.h" -class AudioRingBuffer { +const int BUFFER_LENGTH_BYTES = 1024; +const int BUFFER_LENGTH_SAMPLES = BUFFER_LENGTH_BYTES / sizeof(int16_t); + +const short RING_BUFFER_FRAMES = 10; +const short RING_BUFFER_SAMPLES = RING_BUFFER_FRAMES * BUFFER_LENGTH_SAMPLES; + +class AudioRingBuffer : public AgentData { public: + AudioRingBuffer(); + ~AudioRingBuffer(); + AudioRingBuffer(const AudioRingBuffer &otherRingBuffer); + + void parseData(void *data, int size); + AudioRingBuffer* clone() const; + + int16_t* getNextOutput(); + void setNextOutput(int16_t *newPointer); + int16_t* getEndOfLastWrite(); + void setEndOfLastWrite(int16_t *newPointer); + int16_t* getBuffer(); + bool isStarted(); + void setStarted(bool status); + bool wasAddedToMix(); + void setAddedToMix(bool added); + + short diffLastWriteNextOutput(); + private: int16_t *nextOutput; int16_t *endOfLastWrite; int16_t *buffer; - short ringBufferLengthSamples; bool started; - - short diffLastWriteNextOutput(); - short bufferOverlap(int16_t *pointer, short addedDistance); - - AudioRingBuffer(short ringBufferSamples); - ~AudioRingBuffer(); + bool addedToMix; }; #endif /* defined(__interface__AudioRingBuffer__) */ diff --git a/shared/src/UDPSocket.cpp b/shared/src/UDPSocket.cpp index ec4c63803e..85ebcf2056 100644 --- a/shared/src/UDPSocket.cpp +++ b/shared/src/UDPSocket.cpp @@ -113,7 +113,6 @@ bool UDPSocket::receive(sockaddr *recvAddress, void *receivedData, ssize_t *rece int UDPSocket::send(sockaddr *destAddress, const void *data, size_t byteLength) { // send data via UDP - int sent_bytes = sendto(handle, (const char*)data, byteLength, 0, (sockaddr *) destAddress, sizeof(sockaddr_in)); From bf94f1f861e2b3764efaa7d3d3d3d72a310e2a43 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 25 Feb 2013 17:13:44 -0800 Subject: [PATCH 03/11] refactor Audio.cpp in interface to use parseData in ARB --- interface/src/Audio.cpp | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 27c2a33a0b..6e9136b4b5 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -225,26 +225,7 @@ void *receiveAudioViaUDP(void *args) { } AudioRingBuffer *ringBuffer = sharedAudioData->ringBuffer; - - if (ringBuffer->getEndOfLastWrite() == NULL) { - ringBuffer->setEndOfLastWrite(ringBuffer->getBuffer()); - } else if (ringBuffer->diffLastWriteNextOutput() > RING_BUFFER_SAMPLES - PACKET_LENGTH_SAMPLES) { - - // reset us to started state - ringBuffer->setEndOfLastWrite(ringBuffer->getBuffer()); - ringBuffer->setNextOutput(ringBuffer->getBuffer()); - ringBuffer->setStarted(false); - } - - int16_t *copyToPointer = ringBuffer->getEndOfLastWrite(); - - // just copy the recieved data to the right spot and then add packet length to previous pointer - memcpy(copyToPointer, receivedData, PACKET_LENGTH_BYTES); - ringBuffer->setEndOfLastWrite(ringBuffer->getEndOfLastWrite() + PACKET_LENGTH_SAMPLES); - - if (ringBuffer->getEndOfLastWrite() == ringBuffer->getBuffer() + RING_BUFFER_SAMPLES) { - ringBuffer->setEndOfLastWrite(ringBuffer->getBuffer()); - } + ringBuffer->parseData(receivedData, PACKET_LENGTH_BYTES); if (LOG_SAMPLE_DELAY) { gettimeofday(&previousReceiveTime, NULL); From df1186660bd55d8a86ea750a868078ce488d4e9b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 26 Feb 2013 10:28:47 -0800 Subject: [PATCH 04/11] add missing cstring include for memcpy --- shared/src/AudioRingBuffer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/shared/src/AudioRingBuffer.cpp b/shared/src/AudioRingBuffer.cpp index 48b916588b..d234a405e3 100644 --- a/shared/src/AudioRingBuffer.cpp +++ b/shared/src/AudioRingBuffer.cpp @@ -6,6 +6,7 @@ // Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // +#include #include "AudioRingBuffer.h" AudioRingBuffer::AudioRingBuffer() { From 1783ee5f85f193b75d73f48cf7bc03c920f880a6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 26 Feb 2013 13:13:40 -0800 Subject: [PATCH 05/11] send interface client position to audio mixer --- domain/src/main.cpp | 2 -- interface/src/Audio.cpp | 24 +++++++++++++++++++++++- interface/src/Audio.h | 3 ++- interface/src/AudioData.h | 10 ++++++---- interface/src/main.cpp | 2 +- mixer/src/main.cpp | 11 +++-------- shared/src/AgentList.cpp | 2 +- shared/src/AgentList.h | 1 + shared/src/AudioRingBuffer.cpp | 16 ++++++++++++++-- shared/src/UDPSocket.h | 2 +- 10 files changed, 52 insertions(+), 21 deletions(-) diff --git a/domain/src/main.cpp b/domain/src/main.cpp index 7b6f75ad3f..9a8b6bc64f 100644 --- a/domain/src/main.cpp +++ b/domain/src/main.cpp @@ -32,8 +32,6 @@ #include "SharedUtil.h" const int DOMAIN_LISTEN_PORT = 40102; - -const int MAX_PACKET_SIZE = 1500; unsigned char packetData[MAX_PACKET_SIZE]; const int LOGOFF_CHECK_INTERVAL = 5000; diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 6e9136b4b5..4990e4f5de 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -84,7 +84,25 @@ int audioCallback (const void *inputBuffer, audioMixerSocket.sin_family = AF_INET; audioMixerSocket.sin_addr.s_addr = data->mixerAddress; audioMixerSocket.sin_port = data->mixerPort; - data->audioSocket->send((sockaddr *)&audioMixerSocket, (void *)inputLeft, BUFFER_LENGTH_BYTES); + + int leadingBytes = 1 + (sizeof(float) * 3); + + // we need the amount of bytes in the buffer + 1 for type + 12 for 3 floats for position + unsigned char *dataPacket = new unsigned char[BUFFER_LENGTH_BYTES + leadingBytes]; + + dataPacket[0] = 'I'; + + // memcpy the three float positions + for (int p = 0; p < 3; p++) { + memcpy(dataPacket + 1 + (p * sizeof(float)), &data->sourcePosition[p], sizeof(float)); + } + + // copy the audio data to the last 1024 bytes of the data packet + memcpy(dataPacket + leadingBytes, inputLeft, BUFFER_LENGTH_BYTES); + + data->audioSocket->send((sockaddr *)&audioMixerSocket, dataPacket, BUFFER_LENGTH_BYTES + leadingBytes); + + delete dataPacket; } // @@ -236,6 +254,10 @@ void *receiveAudioViaUDP(void *args) { pthread_exit(0); } +void Audio::setSourcePosition(glm::vec3 newPosition) { + audioData->sourcePosition = newPosition; +} + /** * Initialize portaudio and start an audio stream. * Should be called at the beginning of program exection. diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 7f1fa9143f..0798486106 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -25,11 +25,12 @@ public: void getInputLoudness(float * lastLoudness, float * averageLoudness); void updateMixerParams(in_addr_t mixerAddress, in_port_t mixerPort); + void setSourcePosition(glm::vec3 position); + // terminates audio I/O bool terminate(); private: bool initialized; - AudioData *audioData; // protects constructor so that public init method is used diff --git a/interface/src/AudioData.h b/interface/src/AudioData.h index e5094f8263..4efe39884a 100644 --- a/interface/src/AudioData.h +++ b/interface/src/AudioData.h @@ -11,17 +11,22 @@ #include #include +#include #include "AudioRingBuffer.h" #include "UDPSocket.h" class AudioData { - public: + public: + AudioData(int bufferLength); + ~AudioData(); AudioRingBuffer *ringBuffer; UDPSocket *audioSocket; int16_t *samplesToQueue; + glm::vec3 sourcePosition; + // store current mixer address and port in_addr_t mixerAddress; in_port_t mixerPort; @@ -34,9 +39,6 @@ class AudioData { float lastInputLoudness; float averagedInputLoudness; - - AudioData(int bufferLength); - ~AudioData(); }; #endif /* defined(__interface__AudioData__) */ diff --git a/interface/src/main.cpp b/interface/src/main.cpp index e6901a2829..c86d3c179d 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -53,7 +53,6 @@ int simulate_on = 1; // Network Socket and network constants // -const int MAX_PACKET_SIZE = 1500; char DOMAIN_HOSTNAME[] = "highfidelity.below92.com"; char DOMAIN_IP[100] = ""; // IP Address will be used first if not empty string const int DOMAINSERVER_PORT = 40102; @@ -513,6 +512,7 @@ void simulateHead(float frametime) myHead.setRenderYaw(myHead.getRenderYaw() + render_yaw_rate); myHead.setRenderPitch(render_pitch); myHead.setPos(glm::vec3(location[0], location[1], location[2])); + audio.setSourcePosition(glm::vec3(location[0], location[1], location[2])); // Get audio loudness data from audio input device float loudness, averageLoudness; diff --git a/mixer/src/main.cpp b/mixer/src/main.cpp index 379298b828..37093396ce 100644 --- a/mixer/src/main.cpp +++ b/mixer/src/main.cpp @@ -16,12 +16,8 @@ #include #include -const int MAX_AGENTS = 1000; -const int LOGOFF_CHECK_INTERVAL = 1000; - const unsigned short MIXER_LISTEN_PORT = 55443; - const float SAMPLE_RATE = 22050.0; const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES/SAMPLE_RATE) * 1000000; @@ -35,7 +31,6 @@ char DOMAIN_HOSTNAME[] = "highfidelity.below92.com"; char DOMAIN_IP[100] = ""; // IP Address will be re-set by lookup on startup const int DOMAINSERVER_PORT = 40102; -const int MAX_SOURCE_BUFFERS = 20; AgentList agentList(MIXER_LISTEN_PORT); @@ -182,7 +177,7 @@ int main(int argc, const char * argv[]) printf("Using static domainserver IP: %s\n", DOMAIN_IP); } - int16_t *packetData = new int16_t[BUFFER_LENGTH_SAMPLES]; + unsigned char *packetData = new unsigned char[MAX_PACKET_SIZE]; pthread_t sendBufferThread; pthread_create(&sendBufferThread, NULL, sendBuffer, NULL); @@ -191,9 +186,9 @@ int main(int argc, const char * argv[]) while (true) { if(agentList.getAgentSocket().receive(agentAddress, packetData, &receivedBytes)) { - if (receivedBytes == BUFFER_LENGTH_BYTES) { + if (receivedBytes > BUFFER_LENGTH_BYTES) { // add or update the existing interface agent - agentList.addOrUpdateAgent(agentAddress, agentAddress, 'I'); + agentList.addOrUpdateAgent(agentAddress, agentAddress, packetData[0]); agentList.updateAgentWithData(agentAddress, (void *)packetData, receivedBytes); } } diff --git a/shared/src/AgentList.cpp b/shared/src/AgentList.cpp index d1c4db24ce..fe280894ac 100644 --- a/shared/src/AgentList.cpp +++ b/shared/src/AgentList.cpp @@ -147,7 +147,7 @@ bool AgentList::addOrUpdateAgent(sockaddr *publicSocket, sockaddr *localSocket, // this is an audio mixer // for now that means we need to tell the audio class // to use the local socket information the domain server gave us - sockaddr_in *localSocketIn = (sockaddr_in *)localSocket; + sockaddr_in *localSocketIn = (sockaddr_in *)publicSocket; audioMixerSocketUpdate(localSocketIn->sin_addr.s_addr, localSocketIn->sin_port); } diff --git a/shared/src/AgentList.h b/shared/src/AgentList.h index 0741e63d7b..4fb6a2d989 100644 --- a/shared/src/AgentList.h +++ b/shared/src/AgentList.h @@ -14,6 +14,7 @@ #include "Agent.h" #include "UDPSocket.h" +const int MAX_PACKET_SIZE = 1500; const unsigned short AGENT_SOCKET_LISTEN_PORT = 40103; const int AGENT_SILENCE_THRESHOLD_USECS = 2 * 1000000; extern const char *SOLO_AGENT_TYPES_STRING; diff --git a/shared/src/AudioRingBuffer.cpp b/shared/src/AudioRingBuffer.cpp index d234a405e3..e20860a7bf 100644 --- a/shared/src/AudioRingBuffer.cpp +++ b/shared/src/AudioRingBuffer.cpp @@ -75,8 +75,20 @@ void AudioRingBuffer::setAddedToMix(bool added) { } void AudioRingBuffer::parseData(void *data, int size) { - int16_t *audioData = (int16_t *)data; + int16_t *audioDataStart = (int16_t *) data; + if (size > BUFFER_LENGTH_BYTES) { + float position[3]; + unsigned char *charData = (unsigned char *) data; + + for (int p = 0; p < 3; p ++) { + memcpy(&position[p], charData + 1 + (sizeof(float) * p), sizeof(float)); + } + + audioDataStart = (int16_t *) charData + 1 + (sizeof(float) * 3); + } + + if (endOfLastWrite == NULL) { endOfLastWrite = buffer; } else if (diffLastWriteNextOutput() > RING_BUFFER_SAMPLES - BUFFER_LENGTH_SAMPLES) { @@ -85,7 +97,7 @@ void AudioRingBuffer::parseData(void *data, int size) { started = false; } - memcpy(endOfLastWrite, audioData, BUFFER_LENGTH_BYTES); + memcpy(endOfLastWrite, audioDataStart, BUFFER_LENGTH_BYTES); endOfLastWrite += BUFFER_LENGTH_SAMPLES; if (endOfLastWrite >= buffer + RING_BUFFER_SAMPLES) { diff --git a/shared/src/UDPSocket.h b/shared/src/UDPSocket.h index 27a3c48ad3..b2389ad73f 100644 --- a/shared/src/UDPSocket.h +++ b/shared/src/UDPSocket.h @@ -13,7 +13,7 @@ #include #include -#define MAX_BUFFER_LENGTH_BYTES 1024 +#define MAX_BUFFER_LENGTH_BYTES 1500 class UDPSocket { public: From c6458308094d16ad3d5f0e6c9f2a4f9d815d58b6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 26 Feb 2013 13:43:50 -0800 Subject: [PATCH 06/11] temporary test against birarda's domain server --- interface/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index c86d3c179d..a408bb5db1 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -54,7 +54,7 @@ int simulate_on = 1; // char DOMAIN_HOSTNAME[] = "highfidelity.below92.com"; -char DOMAIN_IP[100] = ""; // IP Address will be used first if not empty string +char DOMAIN_IP[100] = "192.168.1.47"; // IP Address will be used first if not empty string const int DOMAINSERVER_PORT = 40102; AgentList agentList; From c123990d7ae48c2d5b79d0bfc0f6ced480429ef4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 26 Feb 2013 13:59:33 -0800 Subject: [PATCH 07/11] switch back to EC2 DS for sanity check --- interface/src/main.cpp | 2 +- shared/src/AgentList.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index a408bb5db1..c86d3c179d 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -54,7 +54,7 @@ int simulate_on = 1; // char DOMAIN_HOSTNAME[] = "highfidelity.below92.com"; -char DOMAIN_IP[100] = "192.168.1.47"; // IP Address will be used first if not empty string +char DOMAIN_IP[100] = ""; // IP Address will be used first if not empty string const int DOMAINSERVER_PORT = 40102; AgentList agentList; diff --git a/shared/src/AgentList.cpp b/shared/src/AgentList.cpp index fe280894ac..d1c4db24ce 100644 --- a/shared/src/AgentList.cpp +++ b/shared/src/AgentList.cpp @@ -147,7 +147,7 @@ bool AgentList::addOrUpdateAgent(sockaddr *publicSocket, sockaddr *localSocket, // this is an audio mixer // for now that means we need to tell the audio class // to use the local socket information the domain server gave us - sockaddr_in *localSocketIn = (sockaddr_in *)publicSocket; + sockaddr_in *localSocketIn = (sockaddr_in *)localSocket; audioMixerSocketUpdate(localSocketIn->sin_addr.s_addr, localSocketIn->sin_port); } From 971f5b6ad60d51f3be35f09b7280ed6372944624 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 26 Feb 2013 16:55:39 -0800 Subject: [PATCH 08/11] recreate the newestSoloAgents map for each broadcastPacket --- domain/src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/domain/src/main.cpp b/domain/src/main.cpp index 9a8b6bc64f..81b2ccc7d9 100644 --- a/domain/src/main.cpp +++ b/domain/src/main.cpp @@ -68,10 +68,10 @@ int main(int argc, const char * argv[]) agentList.startSilentAgentRemovalThread(); - std::map newestSoloAgents; - while (true) { if (agentList.getAgentSocket().receive((sockaddr *)&agentPublicAddress, packetData, &receivedBytes)) { + std::map newestSoloAgents; + agentType = packetData[0]; unpackSocket(&packetData[1], (sockaddr *)&agentLocalAddress); From 31a164fd19bc7a468d2102eb70151e8db804d281 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 26 Feb 2013 16:57:33 -0800 Subject: [PATCH 09/11] initial changing of volumne of source based on distance --- interface/src/Audio.cpp | 4 +- mixer/src/main.cpp | 94 ++++++++++++++++------------------ shared/src/AudioRingBuffer.cpp | 22 +++++--- shared/src/AudioRingBuffer.h | 3 ++ 4 files changed, 64 insertions(+), 59 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 4990e4f5de..74f6d51e7c 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -88,7 +88,7 @@ int audioCallback (const void *inputBuffer, int leadingBytes = 1 + (sizeof(float) * 3); // we need the amount of bytes in the buffer + 1 for type + 12 for 3 floats for position - unsigned char *dataPacket = new unsigned char[BUFFER_LENGTH_BYTES + leadingBytes]; + unsigned char dataPacket[BUFFER_LENGTH_BYTES + leadingBytes]; dataPacket[0] = 'I'; @@ -101,8 +101,6 @@ int audioCallback (const void *inputBuffer, memcpy(dataPacket + leadingBytes, inputLeft, BUFFER_LENGTH_BYTES); data->audioSocket->send((sockaddr *)&audioMixerSocket, dataPacket, BUFFER_LENGTH_BYTES + leadingBytes); - - delete dataPacket; } // diff --git a/mixer/src/main.cpp b/mixer/src/main.cpp index 37093396ce..1e9f665df7 100644 --- a/mixer/src/main.cpp +++ b/mixer/src/main.cpp @@ -27,10 +27,11 @@ const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_MSECS * (SAMPLE_RATE / 1000.0) const long MAX_SAMPLE_VALUE = std::numeric_limits::max(); const long MIN_SAMPLE_VALUE = std::numeric_limits::min(); +const float DISTANCE_RATIO = 3.0/4.2; + char DOMAIN_HOSTNAME[] = "highfidelity.below92.com"; char DOMAIN_IP[100] = ""; // IP Address will be re-set by lookup on startup -const int DOMAINSERVER_PORT = 40102; - +const int DOMAINSERVER_PORT = 40102; AgentList agentList(MIXER_LISTEN_PORT); @@ -39,78 +40,70 @@ void *sendBuffer(void *args) int sentBytes; int nextFrame = 0; timeval startTime; - - int16_t *clientMix = new int16_t[BUFFER_LENGTH_SAMPLES]; - long *masterMix = new long[BUFFER_LENGTH_SAMPLES]; gettimeofday(&startTime, NULL); while (true) { sentBytes = 0; - for (int ms = 0; ms < BUFFER_LENGTH_SAMPLES; ms++) { - masterMix[ms] = 0; - } - - for (int ab = 0; ab < agentList.getAgents().size(); ab++) { - AudioRingBuffer *agentBuffer = (AudioRingBuffer *)agentList.getAgents()[ab].getLinkedData(); + for (int i = 0; i < agentList.getAgents().size(); i++) { + AudioRingBuffer *agentBuffer = (AudioRingBuffer *) agentList.getAgents()[i].getLinkedData(); if (agentBuffer != NULL && agentBuffer->getEndOfLastWrite() != NULL) { + if (!agentBuffer->isStarted() && agentBuffer->diffLastWriteNextOutput() <= BUFFER_LENGTH_SAMPLES + JITTER_BUFFER_SAMPLES) { - printf("Held back buffer %d.\n", ab); + printf("Held back buffer %d.\n", i); } else if (agentBuffer->diffLastWriteNextOutput() < BUFFER_LENGTH_SAMPLES) { - printf("Buffer %d starved.\n", ab); + printf("Buffer %d starved.\n", i); agentBuffer->setStarted(false); } else { // good buffer, add this to the mix agentBuffer->setStarted(true); agentBuffer->setAddedToMix(true); - - for (int s = 0; s < BUFFER_LENGTH_SAMPLES; s++) { - masterMix[s] += agentBuffer->getNextOutput()[s]; - } - - agentBuffer->setNextOutput(agentBuffer->getNextOutput() + BUFFER_LENGTH_SAMPLES); - - if (agentBuffer->getNextOutput() >= agentBuffer->getBuffer() + RING_BUFFER_SAMPLES) { - agentBuffer->setNextOutput(agentBuffer->getBuffer()); - } } + } } - - for (int ab = 0; ab < agentList.getAgents().size(); ab++) { - Agent *agent = &agentList.getAgents()[ab]; - AudioRingBuffer *agentBuffer = (AudioRingBuffer *)agent->getLinkedData(); - int16_t *previousOutput = NULL; - - if (agentBuffer != NULL && agentBuffer->wasAddedToMix()) { - previousOutput = (agentBuffer->getNextOutput() == agentBuffer->getBuffer()) - ? agentBuffer->getBuffer() + RING_BUFFER_SAMPLES - BUFFER_LENGTH_SAMPLES - : agentBuffer->getNextOutput() - BUFFER_LENGTH_SAMPLES; - agentBuffer->setAddedToMix(false); - } - - for (int s = 0; s < BUFFER_LENGTH_SAMPLES; s++) { - long longSample = (previousOutput != NULL) - ? masterMix[s] - previousOutput[s] - : masterMix[s]; + for (int i = 0; i < agentList.getAgents().size(); i++) { + Agent *agent = &agentList.getAgents()[i]; - int16_t shortSample; - - if (longSample < 0) { - shortSample = std::max(longSample, MIN_SAMPLE_VALUE); - } else { - shortSample = std::min(longSample, MAX_SAMPLE_VALUE); + int16_t clientMix[BUFFER_LENGTH_SAMPLES] = {}; + + for (int j = 0; j < agentList.getAgents().size(); j++) { + if (i != j) { + AudioRingBuffer *otherAgentBuffer = (AudioRingBuffer *)agentList.getAgents()[j].getLinkedData(); + + float *agentPosition = ((AudioRingBuffer *)agent->getLinkedData())->getPosition(); + float *otherAgentPosition = otherAgentBuffer->getPosition(); + float distanceToAgent = sqrtf(powf(agentPosition[0] - otherAgentPosition[0], 2) + + powf(agentPosition[1] - otherAgentPosition[1], 2) + + powf(agentPosition[2] - otherAgentPosition[2], 2)); + float distanceCoeff = 1 / (log(DISTANCE_RATIO * distanceToAgent) / log(3)); + + for (int s = 0; s < BUFFER_LENGTH_SAMPLES; s++) { + int16_t sample = (otherAgentBuffer->getNextOutput()[s] * distanceCoeff); + clientMix[s] += sample; + } } - - clientMix[s] = shortSample; } agentList.getAgentSocket().send(agent->getPublicSocket(), clientMix, BUFFER_LENGTH_BYTES); } + for (int i = 0; i < agentList.getAgents().size(); i++) { + AudioRingBuffer *agentBuffer = (AudioRingBuffer *)agentList.getAgents()[i].getLinkedData(); + if (agentBuffer->wasAddedToMix()) { + agentBuffer->setNextOutput(agentBuffer->getNextOutput() + BUFFER_LENGTH_SAMPLES); + + if (agentBuffer->getNextOutput() >= agentBuffer->getBuffer() + RING_BUFFER_SAMPLES) { + agentBuffer->setNextOutput(agentBuffer->getBuffer()); + } + + agentBuffer->setAddedToMix(false); + } + } + double usecToSleep = usecTimestamp(&startTime) + (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - usecTimestampNow(); if (usecToSleep > 0) { @@ -132,7 +125,8 @@ void *reportAliveToDS(void *args) { gettimeofday(&lastSend, NULL); *output = 'M'; - packSocket(output + 1, 895283510, htons(MIXER_LISTEN_PORT)); +// packSocket(output + 1, 895283510, htons(MIXER_LISTEN_PORT)); + packSocket(output + 1, 788637888, htons(MIXER_LISTEN_PORT)); agentList.getAgentSocket().send(DOMAIN_IP, DOMAINSERVER_PORT, output, 7); double usecToSleep = 1000000 - (usecTimestampNow() - usecTimestamp(&lastSend)); @@ -186,7 +180,7 @@ int main(int argc, const char * argv[]) while (true) { if(agentList.getAgentSocket().receive(agentAddress, packetData, &receivedBytes)) { - if (receivedBytes > BUFFER_LENGTH_BYTES) { + if (receivedBytes >= BUFFER_LENGTH_BYTES) { // add or update the existing interface agent agentList.addOrUpdateAgent(agentAddress, agentAddress, packetData[0]); agentList.updateAgentWithData(agentAddress, (void *)packetData, receivedBytes); diff --git a/shared/src/AudioRingBuffer.cpp b/shared/src/AudioRingBuffer.cpp index e20860a7bf..15743b7d19 100644 --- a/shared/src/AudioRingBuffer.cpp +++ b/shared/src/AudioRingBuffer.cpp @@ -74,20 +74,27 @@ void AudioRingBuffer::setAddedToMix(bool added) { addedToMix = added; } +float* AudioRingBuffer::getPosition() { + return position; +} + +void AudioRingBuffer::setPosition(float *newPosition) { + position[0] = newPosition[0]; + position[1] = newPosition[1]; + position[2] = newPosition[2]; +} + void AudioRingBuffer::parseData(void *data, int size) { - int16_t *audioDataStart = (int16_t *) data; + unsigned char *audioDataStart = (unsigned char *) data; if (size > BUFFER_LENGTH_BYTES) { - float position[3]; - unsigned char *charData = (unsigned char *) data; for (int p = 0; p < 3; p ++) { - memcpy(&position[p], charData + 1 + (sizeof(float) * p), sizeof(float)); + memcpy(&position[p], audioDataStart + 1 + (sizeof(float) * p), sizeof(float)); } - audioDataStart = (int16_t *) charData + 1 + (sizeof(float) * 3); + audioDataStart += (1 + (sizeof(float) * 3)); } - if (endOfLastWrite == NULL) { endOfLastWrite = buffer; @@ -98,8 +105,11 @@ void AudioRingBuffer::parseData(void *data, int size) { } memcpy(endOfLastWrite, audioDataStart, BUFFER_LENGTH_BYTES); + endOfLastWrite += BUFFER_LENGTH_SAMPLES; + addedToMix = false; + if (endOfLastWrite >= buffer + RING_BUFFER_SAMPLES) { endOfLastWrite = buffer; } diff --git a/shared/src/AudioRingBuffer.h b/shared/src/AudioRingBuffer.h index c8a656728d..f9c3f5e136 100644 --- a/shared/src/AudioRingBuffer.h +++ b/shared/src/AudioRingBuffer.h @@ -37,9 +37,12 @@ class AudioRingBuffer : public AgentData { void setStarted(bool status); bool wasAddedToMix(); void setAddedToMix(bool added); + float* getPosition(); + void setPosition(float newPosition[]); short diffLastWriteNextOutput(); private: + float position[3]; int16_t *nextOutput; int16_t *endOfLastWrite; int16_t *buffer; From c1d66e4026a436aff20575a1e94a2b9d1b61d24c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 26 Feb 2013 17:04:57 -0800 Subject: [PATCH 10/11] have mixer kill off silent agents --- mixer/src/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mixer/src/main.cpp b/mixer/src/main.cpp index 1e9f665df7..e008a4709f 100644 --- a/mixer/src/main.cpp +++ b/mixer/src/main.cpp @@ -151,6 +151,8 @@ int main(int argc, const char * argv[]) agentList.linkedDataCreateCallback = attachNewBufferToAgent; + agentList.startSilentAgentRemovalThread(); + // setup the agentSocket to report to domain server pthread_t reportAliveThread; pthread_create(&reportAliveThread, NULL, reportAliveToDS, NULL); @@ -188,6 +190,7 @@ int main(int argc, const char * argv[]) } } + agentList.stopSilentAgentRemovalThread(); pthread_join(reportAliveThread, NULL); pthread_join(sendBufferThread, NULL); From ba2b79b0785deba77fb48aa88061caee38574f7c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 26 Feb 2013 17:12:41 -0800 Subject: [PATCH 11/11] accentuate the distance dampening by squaring the coefficient --- mixer/src/main.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mixer/src/main.cpp b/mixer/src/main.cpp index e008a4709f..85313b6a6e 100644 --- a/mixer/src/main.cpp +++ b/mixer/src/main.cpp @@ -76,13 +76,15 @@ void *sendBuffer(void *args) float *agentPosition = ((AudioRingBuffer *)agent->getLinkedData())->getPosition(); float *otherAgentPosition = otherAgentBuffer->getPosition(); + float distanceToAgent = sqrtf(powf(agentPosition[0] - otherAgentPosition[0], 2) + powf(agentPosition[1] - otherAgentPosition[1], 2) + powf(agentPosition[2] - otherAgentPosition[2], 2)); - float distanceCoeff = 1 / (log(DISTANCE_RATIO * distanceToAgent) / log(3)); + + float distanceCoeff = powf((logf(DISTANCE_RATIO * distanceToAgent) / logf(3)), 2); for (int s = 0; s < BUFFER_LENGTH_SAMPLES; s++) { - int16_t sample = (otherAgentBuffer->getNextOutput()[s] * distanceCoeff); + int16_t sample = (otherAgentBuffer->getNextOutput()[s] / distanceCoeff); clientMix[s] += sample; } }