mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 17:41:12 +02:00
dynamic switchover of audio mixer
This commit is contained in:
parent
7f35fe9993
commit
9c822b9d58
11 changed files with 252 additions and 377 deletions
|
@ -104,7 +104,7 @@ int addAgent(uint32_t ip, in_port_t port, char agentType, float x, float y, floa
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int is_new = 0;
|
int is_new = 0;
|
||||||
while ((ip != agents[i].ip || port != agents[i].port) && (i < num_agents)) {
|
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;
|
if ((i == num_agents) || (agents[i].active == false)) is_new = 1;
|
||||||
agents[i].ip = ip;
|
agents[i].ip = ip;
|
||||||
|
|
|
@ -102,7 +102,9 @@ int add_agent(char * address, unsigned short port, char agentType) {
|
||||||
agents[num_agents].port = port;
|
agents[num_agents].port = port;
|
||||||
agents[num_agents].agentType = agentType;
|
agents[num_agents].agentType = agentType;
|
||||||
std::cout << "Added Agent # " << num_agents << " with Address " <<
|
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++;
|
num_agents++;
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} 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";
|
//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)
|
if (sendToSelf || ((strcmp((char *)"127.0.0.1", agents[i].address) != 0)
|
||||||
&& (agents[i].port != AGENT_UDP_PORT)))
|
&& (agents[i].port != AGENT_UDP_PORT)))
|
||||||
sent_bytes = handle->send(agents[i].address, agents[i].port, data, length);
|
|
||||||
if (sent_bytes != length) {
|
if (agents[i].agentType != 'M') {
|
||||||
std::cout << "Broadcast to agents FAILED\n";
|
sent_bytes = handle->send(agents[i].address, agents[i].port, data, length);
|
||||||
return 0;
|
if (sent_bytes != length) {
|
||||||
}
|
std::cout << "Broadcast to agents FAILED\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -134,9 +139,12 @@ int broadcastToAgents(UDPSocket *handle, char * data, int length, int sendToSelf
|
||||||
void pingAgents(UDPSocket *handle) {
|
void pingAgents(UDPSocket *handle) {
|
||||||
char payload[] = "P";
|
char payload[] = "P";
|
||||||
for (int i = 0; i < num_agents; i++) {
|
for (int i = 0; i < num_agents; i++) {
|
||||||
gettimeofday(&agents[i].pingStarted, NULL);
|
if (agents[i].agentType != 'M') {
|
||||||
handle->send(agents[i].address, agents[i].port, payload, 1);
|
gettimeofday(&agents[i].pingStarted, NULL);
|
||||||
//printf("\nSent Ping at %d usecs\n", agents[i].pingStarted.tv_usec);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "UDPSocket.h"
|
#include "UDPSocket.h"
|
||||||
|
#include "Audio.h"
|
||||||
|
|
||||||
const int AGENT_UDP_PORT = 40103;
|
const int AGENT_UDP_PORT = 40103;
|
||||||
|
|
||||||
|
@ -27,5 +28,6 @@ void pingAgents(UDPSocket *handle);
|
||||||
void setAgentPing(char * address, unsigned short port);
|
void setAgentPing(char * address, unsigned short port);
|
||||||
void update_agent(char * address, unsigned short port, char * data, int length);
|
void update_agent(char * address, unsigned short port, char * data, int length);
|
||||||
void render_agents(int renderSelf);
|
void render_agents(int renderSelf);
|
||||||
|
void kludgyMixerUpdate(Audio audio);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include "Audio.h"
|
#include "Audio.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
#include "AudioSource.h"
|
|
||||||
#include "UDPSocket.h"
|
#include "UDPSocket.h"
|
||||||
|
|
||||||
Oscilloscope * scope;
|
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 NUM_AUDIO_SOURCES = 2;
|
||||||
const short ECHO_SERVER_TEST = 1;
|
const short ECHO_SERVER_TEST = 1;
|
||||||
|
|
||||||
char LOCALHOST_MIXER[] = "0.0.0.0";
|
const char LOCALHOST_MIXER[] = "0.0.0.0";
|
||||||
char WORKCLUB_MIXER[] = "192.168.1.19";
|
const char WORKCLUB_MIXER[] = "192.168.1.19";
|
||||||
char EC2_WEST_MIXER[] = "54.241.92.53";
|
const char EC2_WEST_MIXER[] = "54.241.92.53";
|
||||||
|
|
||||||
const int AUDIO_UDP_LISTEN_PORT = 55444;
|
const int AUDIO_UDP_LISTEN_PORT = 55444;
|
||||||
|
|
||||||
|
@ -50,10 +49,6 @@ StDev stdev;
|
||||||
|
|
||||||
#define LOG_SAMPLE_DELAY 1
|
#define LOG_SAMPLE_DELAY 1
|
||||||
|
|
||||||
bool Audio::initialized;
|
|
||||||
PaError Audio::err;
|
|
||||||
PaStream *Audio::stream;
|
|
||||||
AudioData *Audio::data;
|
|
||||||
std::ofstream logFile;
|
std::ofstream logFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -89,7 +84,10 @@ int audioCallback (const void *inputBuffer,
|
||||||
// int16_t *inputRight = ((int16_t **) inputBuffer)[1];
|
// int16_t *inputRight = ((int16_t **) inputBuffer)[1];
|
||||||
|
|
||||||
if (inputLeft != NULL) {
|
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
|
// 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) {
|
int16_t *queueBuffer = data->samplesToQueue;
|
||||||
AudioRingBuffer *ringBuffer = data->ringBuffer;
|
memset(queueBuffer, 0, BUFFER_LENGTH_BYTES);
|
||||||
|
|
||||||
int16_t *queueBuffer = data->samplesToQueue;
|
// if we've been reset, and there isn't any new packets yet
|
||||||
memset(queueBuffer, 0, BUFFER_LENGTH_BYTES);
|
// just play some silence
|
||||||
|
|
||||||
|
if (ringBuffer->endOfLastWrite != NULL) {
|
||||||
|
|
||||||
// if we've been reset, and there isn't any new packets yet
|
if (!ringBuffer->started && ringBuffer->diffLastWriteNextOutput() <= PACKET_LENGTH_SAMPLES + JITTER_BUFFER_SAMPLES) {
|
||||||
// just play some silence
|
printf("Held back\n");
|
||||||
|
} else if (ringBuffer->diffLastWriteNextOutput() < PACKET_LENGTH_SAMPLES) {
|
||||||
if (ringBuffer->endOfLastWrite != NULL) {
|
ringBuffer->started = false;
|
||||||
|
|
||||||
if (!ringBuffer->started && ringBuffer->diffLastWriteNextOutput() <= PACKET_LENGTH_SAMPLES + JITTER_BUFFER_SAMPLES) {
|
starve_counter++;
|
||||||
printf("Held back\n");
|
printf("Starved #%d\n", starve_counter);
|
||||||
} else if (ringBuffer->diffLastWriteNextOutput() < PACKET_LENGTH_SAMPLES) {
|
data->wasStarved = 10; // Frames to render the indication that the system was starved.
|
||||||
ringBuffer->started = false;
|
} else {
|
||||||
|
ringBuffer->started = true;
|
||||||
starve_counter++;
|
// play whatever we have in the audio buffer
|
||||||
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];
|
|
||||||
|
|
||||||
glm::vec3 headPos = data->linkedHead->getPos();
|
// no sample overlap, either a direct copy of the audio data, or a copy with some appended silence
|
||||||
glm::vec3 sourcePos = source->position;
|
memcpy(queueBuffer, ringBuffer->nextOutput, BUFFER_LENGTH_BYTES);
|
||||||
|
|
||||||
int startPointer = source->samplePointer;
|
ringBuffer->nextOutput += BUFFER_LENGTH_SAMPLES;
|
||||||
int wrapAroundSamples = (BUFFER_LENGTH_SAMPLES) - (source->lengthInSamples - source->samplePointer);
|
|
||||||
|
|
||||||
if (wrapAroundSamples <= 0) {
|
if (ringBuffer->nextOutput == ringBuffer->buffer + RING_BUFFER_SIZE_SAMPLES) {
|
||||||
memcpy(data->samplesToQueue, source->sourceData + source->samplePointer, BUFFER_LENGTH_BYTES);
|
ringBuffer->nextOutput = ringBuffer->buffer;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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);
|
gettimeofday(&data->lastCallback, NULL);
|
||||||
return paContinue;
|
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 {
|
struct AudioRecThreadStruct {
|
||||||
AudioData *sharedAudioData;
|
AudioData *sharedAudioData;
|
||||||
};
|
};
|
||||||
|
@ -318,88 +272,57 @@ void *receiveAudioViaUDP(void *args) {
|
||||||
* @return Returns true if successful or false if an error occurred.
|
* @return Returns true if successful or false if an error occurred.
|
||||||
Use Audio::getError() to retrieve the error code.
|
Use Audio::getError() to retrieve the error code.
|
||||||
*/
|
*/
|
||||||
bool Audio::init(Oscilloscope * s)
|
Audio::Audio(Head *mainHead, Oscilloscope * s)
|
||||||
{
|
{
|
||||||
Head *deadHead = new Head();
|
paError = Pa_Initialize();
|
||||||
return Audio::init(deadHead, s);
|
if (paError != paNoError) goto error;
|
||||||
}
|
|
||||||
|
|
||||||
bool Audio::init(Head *mainHead, Oscilloscope * s)
|
|
||||||
{
|
|
||||||
err = Pa_Initialize();
|
|
||||||
if (err != paNoError) goto error;
|
|
||||||
|
|
||||||
scope = s;
|
scope = s;
|
||||||
|
|
||||||
if (ECHO_SERVER_TEST) {
|
audioData = new AudioData(BUFFER_LENGTH_BYTES);
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
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, // input channels
|
||||||
2, // output channels
|
2, // output channels
|
||||||
(paInt16 | paNonInterleaved), // sample format
|
(paInt16 | paNonInterleaved), // sample format
|
||||||
22050, // sample rate (hz)
|
22050, // sample rate (hz)
|
||||||
512, // frames per buffer
|
512, // frames per buffer
|
||||||
audioCallback, // callback function
|
audioCallback, // callback function
|
||||||
(void *) data); // user data to be passed to callback
|
(void *) audioData); // user data to be passed to callback
|
||||||
if (err != paNoError) goto error;
|
if (paError != paNoError) goto error;
|
||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
|
|
||||||
// start the stream now that sources are good to go
|
// start the stream now that sources are good to go
|
||||||
Pa_StartStream(stream);
|
Pa_StartStream(stream);
|
||||||
if (err != paNoError) goto error;
|
if (paError != paNoError) goto error;
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
return paNoError;
|
|
||||||
error:
|
error:
|
||||||
fprintf(stderr, "-- Failed to initialize portaudio --\n");
|
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;
|
initialized = false;
|
||||||
delete[] data;
|
delete[] audioData;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
void Audio::getInputLoudness(float * lastLoudness, float * averageLoudness) {
|
||||||
*lastLoudness = data->lastInputLoudness;
|
*lastLoudness = audioData->lastInputLoudness;
|
||||||
*averageLoudness = data->averagedInputLoudness;
|
*averageLoudness = audioData->averagedInputLoudness;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::render(int screenWidth, int screenHeight)
|
void Audio::render(int screenWidth, int screenHeight)
|
||||||
|
@ -436,15 +359,15 @@ void Audio::render(int screenWidth, int screenHeight)
|
||||||
timeval currentTime;
|
timeval currentTime;
|
||||||
gettimeofday(¤tTime, NULL);
|
gettimeofday(¤tTime, NULL);
|
||||||
float timeLeftInCurrentBuffer = 0;
|
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)
|
if (audioData->ringBuffer->endOfLastWrite != NULL)
|
||||||
remainingBuffer = data->ringBuffer->diffLastWriteNextOutput() / BUFFER_LENGTH_SAMPLES * frameWidth;
|
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 {
|
else {
|
||||||
glColor3f(0.5 + (float)data->wasStarved/20.0, 0, 0);
|
glColor3f(0.5 + (float)audioData->wasStarved/20.0, 0, 0);
|
||||||
data->wasStarved--;
|
audioData->wasStarved--;
|
||||||
}
|
}
|
||||||
|
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
|
@ -454,25 +377,25 @@ void Audio::render(int screenWidth, int screenHeight)
|
||||||
glVertex2f(startX, bottomY - 5);
|
glVertex2f(startX, bottomY - 5);
|
||||||
glEnd();
|
glEnd();
|
||||||
|
|
||||||
if (data->averagedLatency == 0.0) data->averagedLatency = remainingBuffer + timeLeftInCurrentBuffer;
|
if (audioData->averagedLatency == 0.0) audioData->averagedLatency = remainingBuffer + timeLeftInCurrentBuffer;
|
||||||
else data->averagedLatency = 0.99*data->averagedLatency + 0.01*((float)remainingBuffer + (float)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)
|
// Show a yellow bar with the averaged msecs latency you are hearing (from time of packet receipt)
|
||||||
glColor3f(1,1,0);
|
glColor3f(1,1,0);
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
glVertex2f(startX + data->averagedLatency - 2, topY - 2);
|
glVertex2f(startX + audioData->averagedLatency - 2, topY - 2);
|
||||||
glVertex2f(startX + data->averagedLatency + 2, topY - 2);
|
glVertex2f(startX + audioData->averagedLatency + 2, topY - 2);
|
||||||
glVertex2f(startX + data->averagedLatency + 2, bottomY + 2);
|
glVertex2f(startX + audioData->averagedLatency + 2, bottomY + 2);
|
||||||
glVertex2f(startX + data->averagedLatency - 2, bottomY + 2);
|
glVertex2f(startX + audioData->averagedLatency - 2, bottomY + 2);
|
||||||
glEnd();
|
glEnd();
|
||||||
|
|
||||||
char out[20];
|
char out[20];
|
||||||
sprintf(out, "%3.0f\n", data->averagedLatency/(float)frameWidth*(1000.0*(float)BUFFER_LENGTH_SAMPLES/(float)SAMPLE_RATE));
|
sprintf(out, "%3.0f\n", audioData->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);
|
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
|
// 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);
|
glColor3f(0,1,1);
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
|
@ -482,7 +405,7 @@ void Audio::render(int screenWidth, int screenHeight)
|
||||||
glVertex2f(startX + jitterPels - 2, bottomY + 2);
|
glVertex2f(startX + jitterPels - 2, bottomY + 2);
|
||||||
glEnd();
|
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);
|
drawtext(startX + jitterPels - 5, topY-10, 0.08, 0, 1, 0, out, 0,1,1);
|
||||||
|
|
||||||
sprintf(out, "%3.1fms\n", JITTER_BUFFER_LENGTH_MSECS);
|
sprintf(out, "%3.1fms\n", JITTER_BUFFER_LENGTH_MSECS);
|
||||||
|
@ -504,13 +427,13 @@ bool Audio::terminate ()
|
||||||
if (initialized) {
|
if (initialized) {
|
||||||
initialized = false;
|
initialized = false;
|
||||||
|
|
||||||
err = Pa_CloseStream(stream);
|
paError = Pa_CloseStream(stream);
|
||||||
if (err != paNoError) goto error;
|
if (paError != paNoError) goto error;
|
||||||
|
|
||||||
err = Pa_Terminate();
|
paError = Pa_Terminate();
|
||||||
if (err != paNoError) goto error;
|
if (paError != paNoError) goto error;
|
||||||
|
|
||||||
delete data;
|
delete audioData;
|
||||||
|
|
||||||
logFile.close();
|
logFile.close();
|
||||||
}
|
}
|
||||||
|
@ -519,7 +442,7 @@ bool Audio::terminate ()
|
||||||
|
|
||||||
error:
|
error:
|
||||||
fprintf(stderr, "-- portaudio termination error --\n");
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,30 +18,33 @@
|
||||||
class Audio {
|
class Audio {
|
||||||
public:
|
public:
|
||||||
// initializes audio I/O
|
// initializes audio I/O
|
||||||
static bool init(Oscilloscope * s);
|
Audio(Head* mainHead, Oscilloscope * s);
|
||||||
static bool init(Head* mainHead, Oscilloscope * s);
|
|
||||||
|
|
||||||
static void render();
|
void render();
|
||||||
static void render(int screenWidth, int screenHeight);
|
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
|
// terminates audio I/O
|
||||||
static bool terminate();
|
bool terminate();
|
||||||
private:
|
private:
|
||||||
static bool initialized;
|
bool initialized;
|
||||||
|
|
||||||
static AudioData *data;
|
|
||||||
|
|
||||||
|
AudioData *audioData;
|
||||||
|
|
||||||
// protects constructor so that public init method is used
|
// protects constructor so that public init method is used
|
||||||
Audio();
|
Audio();
|
||||||
|
|
||||||
|
// store current mixer address and port
|
||||||
|
char *mixerAddress;
|
||||||
|
int mixerPort;
|
||||||
|
|
||||||
// hold potential error returned from PortAudio functions
|
// hold potential error returned from PortAudio functions
|
||||||
static PaError err;
|
PaError paError;
|
||||||
|
|
||||||
// audio stream handle
|
// audio stream handle
|
||||||
static PaStream *stream;
|
PaStream *stream;
|
||||||
|
|
||||||
// give access to AudioData class from audioCallback
|
// give access to AudioData class from audioCallback
|
||||||
friend int audioCallback (const void*, void*, unsigned long, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void*);
|
friend int audioCallback (const void*, void*, unsigned long, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void*);
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
#include "AudioData.h"
|
#include "AudioData.h"
|
||||||
|
|
||||||
AudioData::AudioData(int bufferLength) {
|
AudioData::AudioData(int bufferLength) {
|
||||||
sources = NULL;
|
mixerAddress = NULL;
|
||||||
|
mixerPort = 0;
|
||||||
|
|
||||||
samplesToQueue = new int16_t[bufferLength / sizeof(int16_t)];
|
samplesToQueue = new int16_t[bufferLength / sizeof(int16_t)];
|
||||||
averagedLatency = 0.0;
|
averagedLatency = 0.0;
|
||||||
|
@ -19,32 +20,8 @@ AudioData::AudioData(int bufferLength) {
|
||||||
jitterBuffer = 0;
|
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() {
|
AudioData::~AudioData() {
|
||||||
if (sources != NULL) {
|
|
||||||
for (int s = 0; s < _numberOfSources; s++) {
|
|
||||||
delete sources[s];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] samplesToQueue;
|
delete[] samplesToQueue;
|
||||||
|
|
||||||
delete audioSocket;
|
delete audioSocket;
|
||||||
}
|
}
|
|
@ -12,7 +12,6 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "AudioRingBuffer.h"
|
#include "AudioRingBuffer.h"
|
||||||
#include "AudioSource.h"
|
|
||||||
#include "Head.h"
|
#include "Head.h"
|
||||||
#include "UDPSocket.h"
|
#include "UDPSocket.h"
|
||||||
|
|
||||||
|
@ -21,12 +20,14 @@ class AudioData {
|
||||||
Head *linkedHead;
|
Head *linkedHead;
|
||||||
|
|
||||||
AudioRingBuffer *ringBuffer;
|
AudioRingBuffer *ringBuffer;
|
||||||
AudioSource **sources;
|
|
||||||
|
|
||||||
UDPSocket *audioSocket;
|
UDPSocket *audioSocket;
|
||||||
|
|
||||||
int16_t *samplesToQueue;
|
int16_t *samplesToQueue;
|
||||||
|
|
||||||
|
char *mixerAddress;
|
||||||
|
unsigned short mixerPort;
|
||||||
|
|
||||||
timeval lastCallback;
|
timeval lastCallback;
|
||||||
float averagedLatency;
|
float averagedLatency;
|
||||||
float measuredJitter;
|
float measuredJitter;
|
||||||
|
@ -37,11 +38,7 @@ class AudioData {
|
||||||
float averagedInputLoudness;
|
float averagedInputLoudness;
|
||||||
|
|
||||||
AudioData(int bufferLength);
|
AudioData(int bufferLength);
|
||||||
AudioData(int numberOfSources, int bufferLength);
|
|
||||||
~AudioData();
|
~AudioData();
|
||||||
|
|
||||||
private:
|
|
||||||
int _numberOfSources;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__interface__AudioData__) */
|
#endif /* defined(__interface__AudioData__) */
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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 <iostream>
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
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__) */
|
|
|
@ -109,6 +109,8 @@ Lattice lattice(160,100);
|
||||||
Finger myFinger(WIDTH, HEIGHT);
|
Finger myFinger(WIDTH, HEIGHT);
|
||||||
Field field;
|
Field field;
|
||||||
|
|
||||||
|
Audio audio(&myHead, &audioScope);
|
||||||
|
|
||||||
#define RENDER_FRAME_MSECS 8
|
#define RENDER_FRAME_MSECS 8
|
||||||
#define SLEEP 0
|
#define SLEEP 0
|
||||||
int steps_per_frame = 0;
|
int steps_per_frame = 0;
|
||||||
|
@ -300,15 +302,6 @@ void initDisplay(void)
|
||||||
void init(void)
|
void init(void)
|
||||||
{
|
{
|
||||||
myHead.setRenderYaw(start_yaw);
|
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_x = WIDTH/2;
|
||||||
head_mouse_y = HEIGHT/2;
|
head_mouse_y = HEIGHT/2;
|
||||||
|
@ -367,9 +360,7 @@ void terminate () {
|
||||||
// Close serial port
|
// Close serial port
|
||||||
//close(serial_fd);
|
//close(serial_fd);
|
||||||
|
|
||||||
if (audio_on) {
|
audio.terminate();
|
||||||
Audio::terminate();
|
|
||||||
}
|
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,7 +513,7 @@ void update_pos(float frametime)
|
||||||
|
|
||||||
// Get audio loudness data from audio input device
|
// Get audio loudness data from audio input device
|
||||||
float loudness, averageLoudness;
|
float loudness, averageLoudness;
|
||||||
Audio::getInputLoudness(&loudness, &averageLoudness);
|
audio.getInputLoudness(&loudness, &averageLoudness);
|
||||||
myHead.setLoudness(loudness);
|
myHead.setLoudness(loudness);
|
||||||
myHead.setAverageLoudness(averageLoudness);
|
myHead.setAverageLoudness(averageLoudness);
|
||||||
|
|
||||||
|
@ -596,14 +587,7 @@ void display(void)
|
||||||
glTranslatef(0.f, 0.f, -7.f);
|
glTranslatef(0.f, 0.f, -7.f);
|
||||||
myHead.render(1);
|
myHead.render(1);
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
// render audio sources and start them
|
|
||||||
if (audio_on) {
|
|
||||||
Audio::render();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//glm::vec3 test(0.5, 0.5, 0.5);
|
//glm::vec3 test(0.5, 0.5, 0.5);
|
||||||
//render_vector(&test);
|
//render_vector(&test);
|
||||||
|
|
||||||
|
@ -619,7 +603,7 @@ void display(void)
|
||||||
|
|
||||||
// lattice.render(WIDTH, HEIGHT);
|
// lattice.render(WIDTH, HEIGHT);
|
||||||
// myFinger.render();
|
// myFinger.render();
|
||||||
Audio::render(WIDTH, HEIGHT);
|
audio.render(WIDTH, HEIGHT);
|
||||||
if (audioScope.getState()) audioScope.render();
|
if (audioScope.getState()) audioScope.render();
|
||||||
|
|
||||||
|
|
||||||
|
@ -811,8 +795,9 @@ void *networkReceive(void *args)
|
||||||
//
|
//
|
||||||
// Message from domainserver
|
// Message from domainserver
|
||||||
//
|
//
|
||||||
//printf("agent list received!\n");
|
// printf("agent list received!\n");
|
||||||
nearbyAgents = update_agents(&incomingPacket[1], bytesRecvd - 1);
|
nearbyAgents = update_agents(&incomingPacket[1], bytesRecvd - 1);
|
||||||
|
kludgyMixerUpdate(audio);
|
||||||
} else if (incomingPacket[0] == 'H') {
|
} else if (incomingPacket[0] == 'H') {
|
||||||
//
|
//
|
||||||
// Broadcast packet from another agent
|
// Broadcast packet from another agent
|
||||||
|
|
|
@ -34,10 +34,16 @@ const short RING_BUFFER_SAMPLES = RING_BUFFER_FRAMES * BUFFER_LENGTH_SAMPLES;
|
||||||
const long MAX_SAMPLE_VALUE = std::numeric_limits<int16_t>::max();
|
const long MAX_SAMPLE_VALUE = std::numeric_limits<int16_t>::max();
|
||||||
const long MIN_SAMPLE_VALUE = std::numeric_limits<int16_t>::min();
|
const long MIN_SAMPLE_VALUE = std::numeric_limits<int16_t>::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;
|
const int MAX_SOURCE_BUFFERS = 20;
|
||||||
|
|
||||||
sockaddr_in agentAddress;
|
sockaddr_in agentAddress;
|
||||||
|
|
||||||
|
UDPSocket audioSocket = UDPSocket(MIXER_LISTEN_PORT);
|
||||||
|
|
||||||
struct AgentList {
|
struct AgentList {
|
||||||
char *address;
|
char *address;
|
||||||
unsigned short port;
|
unsigned short port;
|
||||||
|
@ -61,65 +67,8 @@ double usecTimestamp(timeval *time, double addedUsecs = 0) {
|
||||||
return (time->tv_sec * 1000000.0) + time->tv_usec + addedUsecs;
|
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)
|
void *sendBuffer(void *args)
|
||||||
{
|
{
|
||||||
struct sendBufferStruct *bufferArgs = (struct sendBufferStruct *)args;
|
|
||||||
UDPSocket *audioSocket = bufferArgs->audioSocket;
|
|
||||||
|
|
||||||
int sentBytes;
|
int sentBytes;
|
||||||
int currentFrame = 1;
|
int currentFrame = 1;
|
||||||
timeval startTime, sendTime, now;
|
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) {
|
if (sentBytes < BUFFER_LENGTH_BYTES) {
|
||||||
std::cout << "Error sending mix packet! " << sentBytes << strerror(errno) << "\n";
|
std::cout << "Error sending mix packet! " << sentBytes << strerror(errno) << "\n";
|
||||||
|
@ -222,13 +171,102 @@ void *sendBuffer(void *args)
|
||||||
pthread_exit(0);
|
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[])
|
int main(int argc, const char * argv[])
|
||||||
{
|
{
|
||||||
timeval lastAgentUpdate;
|
timeval lastAgentUpdate;
|
||||||
int receivedBytes = 0;
|
int receivedBytes = 0;
|
||||||
|
|
||||||
// setup our socket
|
// Lookup the IP address of things we have hostnames
|
||||||
UDPSocket audioSocket = UDPSocket(MIXER_LISTEN_PORT);
|
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);
|
gettimeofday(&lastAgentUpdate, NULL);
|
||||||
|
|
||||||
|
@ -238,11 +276,8 @@ int main(int argc, const char * argv[])
|
||||||
sourceBuffers[b] = new AudioRingBuffer(10 * BUFFER_LENGTH_SAMPLES);
|
sourceBuffers[b] = new AudioRingBuffer(10 * BUFFER_LENGTH_SAMPLES);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sendBufferStruct sendBufferArgs;
|
|
||||||
sendBufferArgs.audioSocket = &audioSocket;
|
|
||||||
|
|
||||||
pthread_t sendBufferThread;
|
pthread_t sendBufferThread;
|
||||||
pthread_create(&sendBufferThread, NULL, sendBuffer, (void *)&sendBufferArgs);
|
pthread_create(&sendBufferThread, NULL, sendBuffer, NULL);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if(audioSocket.receive(&agentAddress, packetData, &receivedBytes)) {
|
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);
|
pthread_join(sendBufferThread, NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in a new issue