From 9c822b9d587840f0e9d1d5bf722157419214366b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Feb 2013 20:43:10 -0800 Subject: [PATCH] dynamic switchover of audio mixer --- domain/src/main.cpp | 2 +- interface/src/Agent.cpp | 34 +++-- interface/src/Agent.h | 2 + interface/src/Audio.cpp | 263 ++++++++++++---------------------- interface/src/Audio.h | 25 ++-- interface/src/AudioData.cpp | 29 +--- interface/src/AudioData.h | 11 +- interface/src/AudioSource.cpp | 35 ----- interface/src/AudioSource.h | 29 ---- interface/src/main.cpp | 31 ++-- mixer/src/main.cpp | 168 +++++++++++++--------- 11 files changed, 252 insertions(+), 377 deletions(-) delete mode 100644 interface/src/AudioSource.cpp delete mode 100644 interface/src/AudioSource.h diff --git a/domain/src/main.cpp b/domain/src/main.cpp index 4202400ece..1d92582d23 100644 --- a/domain/src/main.cpp +++ b/domain/src/main.cpp @@ -104,7 +104,7 @@ int addAgent(uint32_t ip, in_port_t port, char agentType, float x, float y, floa int i = 0; int is_new = 0; while ((ip != agents[i].ip || port != agents[i].port) && (i < num_agents)) { - i++; + i++; } if ((i == num_agents) || (agents[i].active == false)) is_new = 1; agents[i].ip = ip; diff --git a/interface/src/Agent.cpp b/interface/src/Agent.cpp index 1feaa63703..a454b23d57 100644 --- a/interface/src/Agent.cpp +++ b/interface/src/Agent.cpp @@ -102,7 +102,9 @@ int add_agent(char * address, unsigned short port, char agentType) { agents[num_agents].port = port; agents[num_agents].agentType = agentType; std::cout << "Added Agent # " << num_agents << " with Address " << - agents[num_agents].address << ":" << agents[num_agents].port << "\n"; + agents[num_agents].address << ":" << agents[num_agents].port << " T: " << + agentType << "\n"; + num_agents++; return 1; } else { @@ -121,11 +123,14 @@ int broadcastToAgents(UDPSocket *handle, char * data, int length, int sendToSelf //std::cout << "to: Agent address " << agents[i].address << " port " << agents[i].port << "\n"; if (sendToSelf || ((strcmp((char *)"127.0.0.1", agents[i].address) != 0) && (agents[i].port != AGENT_UDP_PORT))) - sent_bytes = handle->send(agents[i].address, agents[i].port, data, length); - if (sent_bytes != length) { - std::cout << "Broadcast to agents FAILED\n"; - return 0; - } + + if (agents[i].agentType != 'M') { + sent_bytes = handle->send(agents[i].address, agents[i].port, data, length); + if (sent_bytes != length) { + std::cout << "Broadcast to agents FAILED\n"; + return 0; + } + } } return 1; } @@ -134,9 +139,12 @@ int broadcastToAgents(UDPSocket *handle, char * data, int length, int sendToSelf void pingAgents(UDPSocket *handle) { char payload[] = "P"; for (int i = 0; i < num_agents; i++) { - gettimeofday(&agents[i].pingStarted, NULL); - handle->send(agents[i].address, agents[i].port, payload, 1); - //printf("\nSent Ping at %d usecs\n", agents[i].pingStarted.tv_usec); + if (agents[i].agentType != 'M') { + gettimeofday(&agents[i].pingStarted, NULL); + handle->send(agents[i].address, agents[i].port, payload, 1); +// printf("\nSent Ping at %d usecs\n", agents[i].pingStarted.tv_usec); + } + } } @@ -153,3 +161,11 @@ void setAgentPing(char * address, unsigned short port) { } } +void kludgyMixerUpdate(Audio audio) { + for (int i = 0; i < num_agents; i++) { + if (agents[i].agentType == 'M') { + audio.updateMixerParams(agents[i].address, agents[i].port); + } + } +} + diff --git a/interface/src/Agent.h b/interface/src/Agent.h index 5542388aba..e7dce9dd5f 100644 --- a/interface/src/Agent.h +++ b/interface/src/Agent.h @@ -17,6 +17,7 @@ #include #include #include "UDPSocket.h" +#include "Audio.h" const int AGENT_UDP_PORT = 40103; @@ -27,5 +28,6 @@ void pingAgents(UDPSocket *handle); void setAgentPing(char * address, unsigned short port); void update_agent(char * address, unsigned short port, char * data, int length); void render_agents(int renderSelf); +void kludgyMixerUpdate(Audio audio); #endif diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 8d5e0f9647..f559b806d2 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -14,7 +14,6 @@ #include #include "Audio.h" #include "Util.h" -#include "AudioSource.h" #include "UDPSocket.h" Oscilloscope * scope; @@ -38,9 +37,9 @@ const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_LENGTH_MSECS * (SAMPLE_RATE / const short NUM_AUDIO_SOURCES = 2; const short ECHO_SERVER_TEST = 1; -char LOCALHOST_MIXER[] = "0.0.0.0"; -char WORKCLUB_MIXER[] = "192.168.1.19"; -char EC2_WEST_MIXER[] = "54.241.92.53"; +const char LOCALHOST_MIXER[] = "0.0.0.0"; +const char WORKCLUB_MIXER[] = "192.168.1.19"; +const char EC2_WEST_MIXER[] = "54.241.92.53"; const int AUDIO_UDP_LISTEN_PORT = 55444; @@ -50,10 +49,6 @@ StDev stdev; #define LOG_SAMPLE_DELAY 1 -bool Audio::initialized; -PaError Audio::err; -PaStream *Audio::stream; -AudioData *Audio::data; std::ofstream logFile; /** @@ -89,7 +84,10 @@ int audioCallback (const void *inputBuffer, // int16_t *inputRight = ((int16_t **) inputBuffer)[1]; if (inputLeft != NULL) { - data->audioSocket->send((char *) EC2_WEST_MIXER, 55443, (void *)inputLeft, BUFFER_LENGTH_BYTES); + if (data->mixerAddress != NULL) { + data->audioSocket->send(data->mixerAddress, data->mixerPort, (void *)inputLeft, BUFFER_LENGTH_BYTES); + } + // // Measure the loudness of the signal from the microphone and store in audio object // @@ -123,102 +121,58 @@ int audioCallback (const void *inputBuffer, } } + AudioRingBuffer *ringBuffer = data->ringBuffer; - if (ECHO_SERVER_TEST) { - AudioRingBuffer *ringBuffer = data->ringBuffer; - - int16_t *queueBuffer = data->samplesToQueue; - memset(queueBuffer, 0, BUFFER_LENGTH_BYTES); + int16_t *queueBuffer = data->samplesToQueue; + memset(queueBuffer, 0, BUFFER_LENGTH_BYTES); + + // if we've been reset, and there isn't any new packets yet + // just play some silence + + if (ringBuffer->endOfLastWrite != NULL) { - // if we've been reset, and there isn't any new packets yet - // just play some silence - - if (ringBuffer->endOfLastWrite != NULL) { + if (!ringBuffer->started && ringBuffer->diffLastWriteNextOutput() <= PACKET_LENGTH_SAMPLES + JITTER_BUFFER_SAMPLES) { + printf("Held back\n"); + } else if (ringBuffer->diffLastWriteNextOutput() < PACKET_LENGTH_SAMPLES) { + ringBuffer->started = false; - if (!ringBuffer->started && ringBuffer->diffLastWriteNextOutput() <= PACKET_LENGTH_SAMPLES + JITTER_BUFFER_SAMPLES) { - printf("Held back\n"); - } else if (ringBuffer->diffLastWriteNextOutput() < PACKET_LENGTH_SAMPLES) { - ringBuffer->started = 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; - // 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); - - ringBuffer->nextOutput += BUFFER_LENGTH_SAMPLES; - - if (ringBuffer->nextOutput == ringBuffer->buffer + RING_BUFFER_SIZE_SAMPLES) { - ringBuffer->nextOutput = ringBuffer->buffer; - } - } - } - - // copy whatever is in the queueBuffer to the outputLeft and outputRight buffers - memcpy(outputLeft, queueBuffer, BUFFER_LENGTH_BYTES); - memcpy(outputRight, queueBuffer, BUFFER_LENGTH_BYTES); - - } else { - - for (int s = 0; s < NUM_AUDIO_SOURCES; s++) { - AudioSource *source = data->sources[s]; + 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; + // play whatever we have in the audio buffer - glm::vec3 headPos = data->linkedHead->getPos(); - glm::vec3 sourcePos = source->position; + // 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); - int startPointer = source->samplePointer; - int wrapAroundSamples = (BUFFER_LENGTH_SAMPLES) - (source->lengthInSamples - source->samplePointer); + ringBuffer->nextOutput += BUFFER_LENGTH_SAMPLES; - if (wrapAroundSamples <= 0) { - memcpy(data->samplesToQueue, source->sourceData + source->samplePointer, BUFFER_LENGTH_BYTES); - source->samplePointer += (BUFFER_LENGTH_SAMPLES); - } else { - memcpy(data->samplesToQueue, source->sourceData + source->samplePointer, (source->lengthInSamples - source->samplePointer) * sizeof(int16_t)); - memcpy(data->samplesToQueue + (source->lengthInSamples - source->samplePointer), source->sourceData, wrapAroundSamples * sizeof(int16_t)); - source->samplePointer = wrapAroundSamples; - } - - float distance = sqrtf(powf(-headPos[0] - sourcePos[0], 2) + powf(-headPos[2] - sourcePos[2], 2)); - float distanceAmpRatio = powf(0.5, cbrtf(distance * 10)); - - float angleToSource = angle_to(headPos * -1.f, sourcePos, data->linkedHead->getRenderYaw(), data->linkedHead->getYaw()) * M_PI/180; - float sinRatio = sqrt(fabsf(sinf(angleToSource))); - int numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio; - - float phaseAmpRatio = 1.f - (AMPLITUDE_RATIO_AT_90 * sinRatio); - - // std::cout << "S: " << numSamplesDelay << " A: " << angleToSource << " S: " << sinRatio << " AR: " << phaseAmpRatio << "\n"; - - int16_t *leadingOutput = angleToSource > 0 ? outputLeft : outputRight; - int16_t *trailingOutput = angleToSource > 0 ? outputRight : outputLeft; - - for (int i = 0; i < BUFFER_LENGTH_SAMPLES; i++) { - data->samplesToQueue[i] *= distanceAmpRatio / NUM_AUDIO_SOURCES; - leadingOutput[i] += data->samplesToQueue[i]; - - if (i >= numSamplesDelay) { - trailingOutput[i] += data->samplesToQueue[i - numSamplesDelay]; - } else { - int sampleIndex = startPointer - numSamplesDelay + i; - - if (sampleIndex < 0) { - sampleIndex += source->lengthInSamples; - } - - trailingOutput[i] += source->sourceData[sampleIndex] * (distanceAmpRatio * phaseAmpRatio / NUM_AUDIO_SOURCES); - } + if (ringBuffer->nextOutput == ringBuffer->buffer + RING_BUFFER_SIZE_SAMPLES) { + ringBuffer->nextOutput = ringBuffer->buffer; } } } + // copy whatever is in the queueBuffer to the outputLeft and outputRight buffers + memcpy(outputLeft, queueBuffer, BUFFER_LENGTH_BYTES); + memcpy(outputRight, queueBuffer, BUFFER_LENGTH_BYTES); + gettimeofday(&data->lastCallback, NULL); return paContinue; } +void Audio::updateMixerParams(char *newAddress, unsigned short newPort) { + if (audioData->mixerAddress == NULL) { + audioData->mixerAddress = new char[255]; + } + + strcpy(audioData->mixerAddress, newAddress); + audioData->mixerPort = newPort; + + std::cout << "Audio Mixer now at " << audioData->mixerAddress << ":" << newPort << ".\n"; +} + struct AudioRecThreadStruct { AudioData *sharedAudioData; }; @@ -318,88 +272,57 @@ void *receiveAudioViaUDP(void *args) { * @return Returns true if successful or false if an error occurred. Use Audio::getError() to retrieve the error code. */ -bool Audio::init(Oscilloscope * s) +Audio::Audio(Head *mainHead, Oscilloscope * s) { - Head *deadHead = new Head(); - return Audio::init(deadHead, s); -} - -bool Audio::init(Head *mainHead, Oscilloscope * s) -{ - err = Pa_Initialize(); - if (err != paNoError) goto error; + paError = Pa_Initialize(); + if (paError != paNoError) goto error; scope = s; - if (ECHO_SERVER_TEST) { - data = new AudioData(BUFFER_LENGTH_BYTES); - - // setup a UDPSocket - data->audioSocket = new UDPSocket(AUDIO_UDP_LISTEN_PORT); - data->ringBuffer = new AudioRingBuffer(RING_BUFFER_SIZE_SAMPLES); - - pthread_t audioReceiveThread; - - AudioRecThreadStruct threadArgs; - threadArgs.sharedAudioData = data; - - pthread_create(&audioReceiveThread, NULL, receiveAudioViaUDP, (void *) &threadArgs); - } else { - data = new AudioData(NUM_AUDIO_SOURCES, BUFFER_LENGTH_BYTES); - - data->sources[0]->position = glm::vec3(6, 0, -1); - data->sources[0]->loadDataFromFile("jeska.raw"); - - data->sources[1]->position = glm::vec3(6, 0, 6); - data->sources[1]->loadDataFromFile("grayson.raw"); - } + audioData = new AudioData(BUFFER_LENGTH_BYTES); - data->linkedHead = mainHead; + // setup a UDPSocket + audioData->audioSocket = new UDPSocket(AUDIO_UDP_LISTEN_PORT); + audioData->ringBuffer = new AudioRingBuffer(RING_BUFFER_SIZE_SAMPLES); - err = Pa_OpenDefaultStream(&stream, + pthread_t audioReceiveThread; + + AudioRecThreadStruct threadArgs; + threadArgs.sharedAudioData = audioData; + + pthread_create(&audioReceiveThread, NULL, receiveAudioViaUDP, (void *) &threadArgs); + + audioData->linkedHead = mainHead; + + paError = Pa_OpenDefaultStream(&stream, 2, // input channels 2, // output channels (paInt16 | paNonInterleaved), // sample format 22050, // sample rate (hz) 512, // frames per buffer audioCallback, // callback function - (void *) data); // user data to be passed to callback - if (err != paNoError) goto error; + (void *) audioData); // user data to be passed to callback + if (paError != paNoError) goto error; initialized = true; // start the stream now that sources are good to go Pa_StartStream(stream); - if (err != paNoError) goto error; + if (paError != paNoError) goto error; + + return; - return paNoError; error: fprintf(stderr, "-- Failed to initialize portaudio --\n"); - fprintf(stderr, "PortAudio error (%d): %s\n", err, Pa_GetErrorText(err)); + fprintf(stderr, "PortAudio error (%d): %s\n", paError, Pa_GetErrorText(paError)); initialized = false; - delete[] data; - return false; + delete[] audioData; } -void Audio::render() -{ - if (initialized && !ECHO_SERVER_TEST) { - for (int s = 0; s < NUM_AUDIO_SOURCES; s++) { - // render gl objects on screen for our sources - glPushMatrix(); - - glTranslatef(data->sources[s]->position[0], data->sources[s]->position[1], data->sources[s]->position[2]); - glColor3f((s == 0 ? 1 : 0), (s == 1 ? 1 : 0), (s == 2 ? 1 : 0)); - glutSolidCube(0.5); - - glPopMatrix(); - } - } -} void Audio::getInputLoudness(float * lastLoudness, float * averageLoudness) { - *lastLoudness = data->lastInputLoudness; - *averageLoudness = data->averagedInputLoudness; + *lastLoudness = audioData->lastInputLoudness; + *averageLoudness = audioData->averagedInputLoudness; } void Audio::render(int screenWidth, int screenHeight) @@ -436,15 +359,15 @@ void Audio::render(int screenWidth, int screenHeight) timeval currentTime; gettimeofday(¤tTime, NULL); float timeLeftInCurrentBuffer = 0; - if (data->lastCallback.tv_usec > 0) timeLeftInCurrentBuffer = diffclock(&data->lastCallback, ¤tTime)/(1000.0*(float)BUFFER_LENGTH_SAMPLES/(float)SAMPLE_RATE) * frameWidth; + if (audioData->lastCallback.tv_usec > 0) timeLeftInCurrentBuffer = diffclock(&audioData->lastCallback, ¤tTime)/(1000.0*(float)BUFFER_LENGTH_SAMPLES/(float)SAMPLE_RATE) * frameWidth; - if (data->ringBuffer->endOfLastWrite != NULL) - remainingBuffer = data->ringBuffer->diffLastWriteNextOutput() / BUFFER_LENGTH_SAMPLES * frameWidth; + if (audioData->ringBuffer->endOfLastWrite != NULL) + remainingBuffer = audioData->ringBuffer->diffLastWriteNextOutput() / BUFFER_LENGTH_SAMPLES * frameWidth; - if (data->wasStarved == 0) glColor3f(0, 1, 0); + if (audioData->wasStarved == 0) glColor3f(0, 1, 0); else { - glColor3f(0.5 + (float)data->wasStarved/20.0, 0, 0); - data->wasStarved--; + glColor3f(0.5 + (float)audioData->wasStarved/20.0, 0, 0); + audioData->wasStarved--; } glBegin(GL_QUADS); @@ -454,25 +377,25 @@ void Audio::render(int screenWidth, int screenHeight) glVertex2f(startX, bottomY - 5); glEnd(); - if (data->averagedLatency == 0.0) data->averagedLatency = remainingBuffer + timeLeftInCurrentBuffer; - else data->averagedLatency = 0.99*data->averagedLatency + 0.01*((float)remainingBuffer + (float)timeLeftInCurrentBuffer); + if (audioData->averagedLatency == 0.0) audioData->averagedLatency = remainingBuffer + timeLeftInCurrentBuffer; + else audioData->averagedLatency = 0.99*audioData->averagedLatency + 0.01*((float)remainingBuffer + (float)timeLeftInCurrentBuffer); // Show a yellow bar with the averaged msecs latency you are hearing (from time of packet receipt) glColor3f(1,1,0); glBegin(GL_QUADS); - glVertex2f(startX + data->averagedLatency - 2, topY - 2); - glVertex2f(startX + data->averagedLatency + 2, topY - 2); - glVertex2f(startX + data->averagedLatency + 2, bottomY + 2); - glVertex2f(startX + data->averagedLatency - 2, bottomY + 2); + glVertex2f(startX + audioData->averagedLatency - 2, topY - 2); + glVertex2f(startX + audioData->averagedLatency + 2, topY - 2); + glVertex2f(startX + audioData->averagedLatency + 2, bottomY + 2); + glVertex2f(startX + audioData->averagedLatency - 2, bottomY + 2); glEnd(); char out[20]; - sprintf(out, "%3.0f\n", data->averagedLatency/(float)frameWidth*(1000.0*(float)BUFFER_LENGTH_SAMPLES/(float)SAMPLE_RATE)); - drawtext(startX + data->averagedLatency - 10, topY-10, 0.08, 0, 1, 0, out, 1,1,0); + sprintf(out, "%3.0f\n", audioData->averagedLatency/(float)frameWidth*(1000.0*(float)BUFFER_LENGTH_SAMPLES/(float)SAMPLE_RATE)); + drawtext(startX + audioData->averagedLatency - 10, topY-10, 0.08, 0, 1, 0, out, 1,1,0); // Show a Cyan bar with the most recently measured jitter stdev - int jitterPels = (float) data->measuredJitter/ ((1000.0*(float)BUFFER_LENGTH_SAMPLES/(float)SAMPLE_RATE)) * (float)frameWidth; + int jitterPels = (float) audioData->measuredJitter/ ((1000.0*(float)BUFFER_LENGTH_SAMPLES/(float)SAMPLE_RATE)) * (float)frameWidth; glColor3f(0,1,1); glBegin(GL_QUADS); @@ -482,7 +405,7 @@ void Audio::render(int screenWidth, int screenHeight) glVertex2f(startX + jitterPels - 2, bottomY + 2); glEnd(); - sprintf(out,"%3.1f\n", data->measuredJitter); + sprintf(out,"%3.1f\n", audioData->measuredJitter); drawtext(startX + jitterPels - 5, topY-10, 0.08, 0, 1, 0, out, 0,1,1); sprintf(out, "%3.1fms\n", JITTER_BUFFER_LENGTH_MSECS); @@ -504,13 +427,13 @@ bool Audio::terminate () if (initialized) { initialized = false; - err = Pa_CloseStream(stream); - if (err != paNoError) goto error; + paError = Pa_CloseStream(stream); + if (paError != paNoError) goto error; - err = Pa_Terminate(); - if (err != paNoError) goto error; + paError = Pa_Terminate(); + if (paError != paNoError) goto error; - delete data; + delete audioData; logFile.close(); } @@ -519,7 +442,7 @@ bool Audio::terminate () error: fprintf(stderr, "-- portaudio termination error --\n"); - fprintf(stderr, "PortAudio error (%d): %s\n", err, Pa_GetErrorText(err)); + fprintf(stderr, "PortAudio error (%d): %s\n", paError, Pa_GetErrorText(paError)); return false; } diff --git a/interface/src/Audio.h b/interface/src/Audio.h index be6460ebe0..82c20549d3 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -18,30 +18,33 @@ class Audio { public: // initializes audio I/O - static bool init(Oscilloscope * s); - static bool init(Head* mainHead, Oscilloscope * s); + Audio(Head* mainHead, Oscilloscope * s); - static void render(); - static void render(int screenWidth, int screenHeight); + void render(); + void render(int screenWidth, int screenHeight); - static void getInputLoudness(float * lastLoudness, float * averageLoudness); + void getInputLoudness(float * lastLoudness, float * averageLoudness); + void updateMixerParams(char *mixerAddress, unsigned short mixerPort); // terminates audio I/O - static bool terminate(); + bool terminate(); private: - static bool initialized; - - static AudioData *data; + bool initialized; + AudioData *audioData; // protects constructor so that public init method is used Audio(); + // store current mixer address and port + char *mixerAddress; + int mixerPort; + // hold potential error returned from PortAudio functions - static PaError err; + PaError paError; // audio stream handle - static PaStream *stream; + PaStream *stream; // give access to AudioData class from audioCallback friend int audioCallback (const void*, void*, unsigned long, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void*); diff --git a/interface/src/AudioData.cpp b/interface/src/AudioData.cpp index 32416a402a..9ef1cbc8ed 100644 --- a/interface/src/AudioData.cpp +++ b/interface/src/AudioData.cpp @@ -9,7 +9,8 @@ #include "AudioData.h" AudioData::AudioData(int bufferLength) { - sources = NULL; + mixerAddress = NULL; + mixerPort = 0; samplesToQueue = new int16_t[bufferLength / sizeof(int16_t)]; averagedLatency = 0.0; @@ -19,32 +20,8 @@ AudioData::AudioData(int bufferLength) { jitterBuffer = 0; } -AudioData::AudioData(int numberOfSources, int bufferLength) { - _numberOfSources = numberOfSources; - - sources = new AudioSource*[numberOfSources]; - - for(int s = 0; s < numberOfSources; s++) { - sources[s] = new AudioSource(); - } - - samplesToQueue = new int16_t[bufferLength / sizeof(int16_t)]; - averagedLatency = 0.0; - lastCallback.tv_usec = 0; - wasStarved = 0; - measuredJitter = 0; - jitterBuffer = 0; - -} -AudioData::~AudioData() { - if (sources != NULL) { - for (int s = 0; s < _numberOfSources; s++) { - delete sources[s]; - } - } - +AudioData::~AudioData() { delete[] samplesToQueue; - delete audioSocket; } \ No newline at end of file diff --git a/interface/src/AudioData.h b/interface/src/AudioData.h index 3a98330e48..e66e89d314 100644 --- a/interface/src/AudioData.h +++ b/interface/src/AudioData.h @@ -12,7 +12,6 @@ #include #include #include "AudioRingBuffer.h" -#include "AudioSource.h" #include "Head.h" #include "UDPSocket.h" @@ -21,12 +20,14 @@ class AudioData { Head *linkedHead; AudioRingBuffer *ringBuffer; - AudioSource **sources; - + UDPSocket *audioSocket; int16_t *samplesToQueue; + char *mixerAddress; + unsigned short mixerPort; + timeval lastCallback; float averagedLatency; float measuredJitter; @@ -37,11 +38,7 @@ class AudioData { float averagedInputLoudness; AudioData(int bufferLength); - AudioData(int numberOfSources, int bufferLength); ~AudioData(); - - private: - int _numberOfSources; }; #endif /* defined(__interface__AudioData__) */ diff --git a/interface/src/AudioSource.cpp b/interface/src/AudioSource.cpp deleted file mode 100644 index 07b3d2ce65..0000000000 --- a/interface/src/AudioSource.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// -// AudioSource.cpp -// interface -// -// Created by Stephen Birarda on 1/29/13. -// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. -// - -#include "AudioSource.h" - -AudioSource::~AudioSource() -{ - delete[] sourceData; -} - - -int AudioSource::loadDataFromFile(const char *filename) { - FILE *soundFile = fopen(filename, "r"); - - // get length of file: - std::fseek(soundFile, 0, SEEK_END); - lengthInSamples = std::ftell(soundFile) / sizeof(int16_t); - std::rewind(soundFile); - - sourceData = new int16_t[lengthInSamples]; - size_t bytesRead = std::fread(sourceData, sizeof(int16_t), lengthInSamples, soundFile); - - if (bytesRead != lengthInSamples) { - std::cout << "Error loading audio source data from file " << filename << "!\n"; - } - - std::fclose(soundFile); - - return 0; -} \ No newline at end of file diff --git a/interface/src/AudioSource.h b/interface/src/AudioSource.h deleted file mode 100644 index 3fc2506a72..0000000000 --- a/interface/src/AudioSource.h +++ /dev/null @@ -1,29 +0,0 @@ -// -// AudioSource.h -// interface -// -// Created by Stephen Birarda on 1/29/13. -// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. -// - -#ifndef __interface__AudioSource__ -#define __interface__AudioSource__ - -#include -#include -#include - -class AudioSource { - public: - glm::vec3 position; - int16_t *sourceData; - int lengthInSamples; - int samplePointer; - - AudioSource() { samplePointer = 0; sourceData = NULL; } - ~AudioSource(); - - int loadDataFromFile(const char *filename); -}; - -#endif /* defined(__interface__AudioSource__) */ diff --git a/interface/src/main.cpp b/interface/src/main.cpp index dd602bd037..3f1ff96f2e 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -109,6 +109,8 @@ Lattice lattice(160,100); Finger myFinger(WIDTH, HEIGHT); Field field; +Audio audio(&myHead, &audioScope); + #define RENDER_FRAME_MSECS 8 #define SLEEP 0 int steps_per_frame = 0; @@ -300,15 +302,6 @@ void initDisplay(void) void init(void) { myHead.setRenderYaw(start_yaw); - - if (audio_on) { - if (serial_on) { - Audio::init(&myHead, &audioScope); - } else { - Audio::init(&audioScope); - } - printf( "Audio started.\n" ); - } head_mouse_x = WIDTH/2; head_mouse_y = HEIGHT/2; @@ -367,9 +360,7 @@ void terminate () { // Close serial port //close(serial_fd); - if (audio_on) { - Audio::terminate(); - } + audio.terminate(); exit(EXIT_SUCCESS); } @@ -522,7 +513,7 @@ void update_pos(float frametime) // Get audio loudness data from audio input device float loudness, averageLoudness; - Audio::getInputLoudness(&loudness, &averageLoudness); + audio.getInputLoudness(&loudness, &averageLoudness); myHead.setLoudness(loudness); myHead.setAverageLoudness(averageLoudness); @@ -596,14 +587,7 @@ void display(void) glTranslatef(0.f, 0.f, -7.f); myHead.render(1); glPopMatrix(); - } - - // render audio sources and start them - if (audio_on) { - Audio::render(); - } - - + } //glm::vec3 test(0.5, 0.5, 0.5); //render_vector(&test); @@ -619,7 +603,7 @@ void display(void) // lattice.render(WIDTH, HEIGHT); // myFinger.render(); - Audio::render(WIDTH, HEIGHT); + audio.render(WIDTH, HEIGHT); if (audioScope.getState()) audioScope.render(); @@ -811,8 +795,9 @@ void *networkReceive(void *args) // // Message from domainserver // - //printf("agent list received!\n"); + // printf("agent list received!\n"); nearbyAgents = update_agents(&incomingPacket[1], bytesRecvd - 1); + kludgyMixerUpdate(audio); } else if (incomingPacket[0] == 'H') { // // Broadcast packet from another agent diff --git a/mixer/src/main.cpp b/mixer/src/main.cpp index d532f521a4..45c9e2d93b 100644 --- a/mixer/src/main.cpp +++ b/mixer/src/main.cpp @@ -34,10 +34,16 @@ 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(); +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; sockaddr_in agentAddress; +UDPSocket audioSocket = UDPSocket(MIXER_LISTEN_PORT); + struct AgentList { char *address; unsigned short port; @@ -61,65 +67,8 @@ double usecTimestamp(timeval *time, double addedUsecs = 0) { return (time->tv_sec * 1000000.0) + time->tv_usec + addedUsecs; } -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; -} - -struct sendBufferStruct { - UDPSocket *audioSocket; -}; - void *sendBuffer(void *args) { - struct sendBufferStruct *bufferArgs = (struct sendBufferStruct *)args; - UDPSocket *audioSocket = bufferArgs->audioSocket; - int sentBytes; int currentFrame = 1; timeval startTime, sendTime, now; @@ -198,7 +147,7 @@ void *sendBuffer(void *args) } - sentBytes = audioSocket->send(agents[a].address, agents[a].port, clientMix, BUFFER_LENGTH_BYTES); + sentBytes = audioSocket.send(agents[a].address, agents[a].port, clientMix, BUFFER_LENGTH_BYTES); if (sentBytes < BUFFER_LENGTH_BYTES) { std::cout << "Error sending mix packet! " << sentBytes << strerror(errno) << "\n"; @@ -222,13 +171,102 @@ void *sendBuffer(void *args) 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; + char output[100]; + + while (true) { + gettimeofday(&lastSend, NULL); + + sprintf(output, "%c %f,%f,%f", 'M', 0.f, 0.f, 0.f); + int packetSize = strlen(output); + audioSocket.send(DOMAIN_IP, DOMAINSERVER_PORT, output, packetSize); + + gettimeofday(&now, NULL); + + double usecToSleep = 1000000 - (usecTimestamp(&now) - usecTimestamp(&lastSend)); + + if (usecToSleep > 0) { + usleep(usecToSleep); + } else { + std::cout << "No sleep required!"; + } + } +} + int main(int argc, const char * argv[]) -{ +{ timeval lastAgentUpdate; int receivedBytes = 0; - // setup our socket - UDPSocket audioSocket = UDPSocket(MIXER_LISTEN_PORT); + // Lookup the IP address of things we have hostnames + printf("need to look this one up\n"); + struct hostent* pHostInfo; + if ((pHostInfo = gethostbyname(DOMAIN_HOSTNAME)) != NULL) { + sockaddr_in tempAddress; + memcpy(&tempAddress.sin_addr, pHostInfo->h_addr_list[0], pHostInfo->h_length); + strcpy(DOMAIN_IP, inet_ntoa(tempAddress.sin_addr)); + printf("Domain server found: %s\n", DOMAIN_IP); + + } else { + printf("Failed lookup domain server\n"); + } + + // setup the agentSocket to report to domain server + pthread_t reportAliveThread; + pthread_create(&reportAliveThread, NULL, reportAliveToDS, NULL); + gettimeofday(&lastAgentUpdate, NULL); @@ -238,11 +276,8 @@ int main(int argc, const char * argv[]) sourceBuffers[b] = new AudioRingBuffer(10 * BUFFER_LENGTH_SAMPLES); } - struct sendBufferStruct sendBufferArgs; - sendBufferArgs.audioSocket = &audioSocket; - pthread_t sendBufferThread; - pthread_create(&sendBufferThread, NULL, sendBuffer, (void *)&sendBufferArgs); + pthread_create(&sendBufferThread, NULL, sendBuffer, NULL); while (true) { if(audioSocket.receive(&agentAddress, packetData, &receivedBytes)) { @@ -254,7 +289,8 @@ int main(int argc, const char * argv[]) } } } - + + pthread_join(reportAliveThread, NULL); pthread_join(sendBufferThread, NULL); return 0;