dynamic switchover of audio mixer

This commit is contained in:
Stephen Birarda 2013-02-13 20:43:10 -08:00
parent 7f35fe9993
commit 9c822b9d58
11 changed files with 252 additions and 377 deletions

View file

@ -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;

View file

@ -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);
}
}
}

View file

@ -17,6 +17,7 @@
#include <fcntl.h>
#include <string.h>
#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

View file

@ -14,7 +14,6 @@
#include <cstring>
#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(&currentTime, NULL);
float timeLeftInCurrentBuffer = 0;
if (data->lastCallback.tv_usec > 0) timeLeftInCurrentBuffer = diffclock(&data->lastCallback, &currentTime)/(1000.0*(float)BUFFER_LENGTH_SAMPLES/(float)SAMPLE_RATE) * frameWidth;
if (audioData->lastCallback.tv_usec > 0) timeLeftInCurrentBuffer = diffclock(&audioData->lastCallback, &currentTime)/(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;
}

View file

@ -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*);

View file

@ -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;
}

View file

@ -12,7 +12,6 @@
#include <iostream>
#include <stdint.h>
#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__) */

View file

@ -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;
}

View file

@ -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__) */

View file

@ -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

View file

@ -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 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;
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;