add an AudioInjectionManager to handle multiple injections, link eve to it

This commit is contained in:
Stephen Birarda 2013-05-16 12:40:23 -07:00
parent c8c4b8fda5
commit 5514966d9c
5 changed files with 175 additions and 105 deletions

View file

@ -15,6 +15,7 @@
#include <PacketHeaders.h>
#include <AgentList.h>
#include <AvatarData.h>
#include <AudioInjectionManager.h>
#include <AudioInjector.h>
const int EVE_AGENT_LISTEN_PORT = 55441;
@ -106,20 +107,19 @@ int main(int argc, const char* argv[]) {
// put her hand out so somebody can shake it
eve.setHandPosition(glm::vec3(eve.getPosition()[0] - 0.2,
0.5,
eve.getPosition()[2] + 0.1));
eve.getPosition()[2] + 0.1));
// prepare the audio injection manager by giving it a handle to our agent socket
AudioInjectionManager::setInjectorSocket(agentList->getAgentSocket());
// read eve's audio data
AudioInjector eveAudioInjector("/etc/highfidelity/eve/resources/eve.raw");
// lower Eve's volume by setting the attentuation modifier (this is a value out of 255)
eveAudioInjector.setAttenuationModifier(190);
// pass the agentList UDPSocket pointer to the audio injector
eveAudioInjector.setInjectorSocket(agentList->getAgentSocket());
eveAudioInjector.setVolume(190);
// set the position of the audio injector
float injectorPosition[3];
memcpy(injectorPosition, &eve.getPosition(), sizeof(injectorPosition));
eveAudioInjector.setPosition(injectorPosition);
eveAudioInjector.setPosition(eve.getPosition());
// register the callback for agent data creation
agentList->linkedDataCreateCallback = createAvatarDataForAgent;
@ -165,15 +165,11 @@ int main(int argc, const char* argv[]) {
Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER);
if (audioMixer) {
// until the audio mixer is setup for ping-reply, activate the public socket if it's not active
if (!audioMixer->getActiveSocket()) {
audioMixer->activatePublicSocket();
}
eveAudioInjector.setDestinationSocket(audioMixer->getActiveSocket());
// update the destination socket for the AIM, in case the mixer has changed
AudioInjectionManager::setDestinationSocket(*audioMixer->getPublicSocket());
// we have an active audio mixer we can send data to
eveAudioInjector.threadInjectionOfAudio();
AudioInjectionManager::threadInjector(&eveAudioInjector);
}
}
}

View file

@ -0,0 +1,106 @@
//
// AudioInjectionManager.cpp
// hifi
//
// Created by Stephen Birarda on 5/16/13.
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
//
#include <sys/time.h>
#include "SharedUtil.h"
#include "PacketHeaders.h"
#include "AudioInjectionManager.h"
UDPSocket* AudioInjectionManager::_injectorSocket = NULL;
sockaddr AudioInjectionManager::_destinationSocket;
AudioInjector* AudioInjectionManager::_injectors[50] = {};
AudioInjector* AudioInjectionManager::injectorWithSamplesFromFile(const char* filename) {
for (int i = 0; i < MAX_CONCURRENT_INJECTORS; i++) {
if (!_injectors[i]) {
_injectors[i] = new AudioInjector(filename);
return _injectors[i];
}
}
return NULL;
}
AudioInjector* AudioInjectionManager::injectorWithCapacity(int capacity) {
for (int i = 0; i < MAX_CONCURRENT_INJECTORS; i++) {
if (!_injectors[i]) {
_injectors[i] = new AudioInjector(capacity);
return _injectors[i];
}
}
return NULL;
}
void* AudioInjectionManager::injectAudioViaThread(void* args) {
AudioInjector* injector = (AudioInjector*) args;
if (injector->_audioSampleArray) {
injector->setIsInjectingAudio(true);
timeval startTime;
// one byte for header, 3 positional floats, 1 bearing float, 1 attenuation modifier byte
int leadingBytes = 1 + (sizeof(float) * 4) + 1;
unsigned char dataPacket[BUFFER_LENGTH_BYTES + leadingBytes];
dataPacket[0] = PACKET_HEADER_INJECT_AUDIO;
unsigned char *currentPacketPtr = dataPacket + 1;
memcpy(currentPacketPtr, &injector->getPosition(), sizeof(injector->getPosition()));
currentPacketPtr += sizeof(injector->getPosition());
*currentPacketPtr = injector->getVolume();
currentPacketPtr++;
memcpy(currentPacketPtr, &injector->_bearing, sizeof(injector->_bearing));
currentPacketPtr += sizeof(injector->_bearing);
for (int i = 0; i < injector->_numTotalSamples; i += BUFFER_LENGTH_SAMPLES) {
gettimeofday(&startTime, NULL);
int numSamplesToCopy = BUFFER_LENGTH_SAMPLES;
if (injector->_numTotalSamples - i < BUFFER_LENGTH_SAMPLES) {
numSamplesToCopy = injector->_numTotalSamples - i;
memset(currentPacketPtr + numSamplesToCopy, 0, BUFFER_LENGTH_BYTES - (numSamplesToCopy * sizeof(int16_t)));
}
memcpy(currentPacketPtr, injector->_audioSampleArray + i, numSamplesToCopy * sizeof(int16_t));
_injectorSocket->send(&_destinationSocket, dataPacket, sizeof(dataPacket));
double usecToSleep = BUFFER_SEND_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&startTime));
if (usecToSleep > 0) {
usleep(usecToSleep);
}
}
injector->_isInjectingAudio = false;
}
// if this an injector inside the injection manager's array we're responsible for deletion
for (int i = 0; i < MAX_CONCURRENT_INJECTORS; i++) {
if (_injectors[i] == injector) {
// pointer matched - delete this injector
delete injector;
// set the pointer to NULL so we can reuse this spot
_injectors[i] = NULL;
}
}
pthread_exit(0);
}
void AudioInjectionManager::threadInjector(AudioInjector* injector) {
pthread_t audioInjectThread;
pthread_create(&audioInjectThread, NULL, injectAudioViaThread, (void*) injector);
}

View file

@ -0,0 +1,36 @@
//
// AudioInjectionManager.h
// hifi
//
// Created by Stephen Birarda on 5/16/13.
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
//
#ifndef __hifi__AudioInjectionManager__
#define __hifi__AudioInjectionManager__
#include <iostream>
#include "UDPSocket.h"
#include "AudioInjector.h"
const int MAX_CONCURRENT_INJECTORS = 50;
class AudioInjectionManager {
public:
static AudioInjector* injectorWithCapacity(int capacity);
static AudioInjector* injectorWithSamplesFromFile(const char* filename);
static void threadInjector(AudioInjector* injector);
static void setInjectorSocket(UDPSocket* injectorSocket) { _injectorSocket = injectorSocket;}
static void setDestinationSocket(sockaddr& destinationSocket) { _destinationSocket = destinationSocket; }
private:
static void* injectAudioViaThread(void* args);
static UDPSocket* _injectorSocket;
static sockaddr _destinationSocket;
static AudioInjector* _injectors[MAX_CONCURRENT_INJECTORS];
};
#endif /* defined(__hifi__AudioInjectionManager__) */

View file

@ -3,27 +3,20 @@
// hifi
//
// Created by Stephen Birarda on 4/23/13.
//
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
//
#include <sys/time.h>
#include <fstream>
#include <cstring>
#include "SharedUtil.h"
#include "PacketHeaders.h"
#include "AudioInjector.h"
const int BUFFER_LENGTH_BYTES = 512;
const int BUFFER_LENGTH_SAMPLES = BUFFER_LENGTH_BYTES / sizeof(int16_t);
const float SAMPLE_RATE = 22050.0f;
const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES / SAMPLE_RATE) * 1000000;
AudioInjector::AudioInjector(const char* filename) :
_position(),
_bearing(0),
_attenuationModifier(255),
_volume(0xFF),
_indexOfNextSlot(0),
_isInjectingAudio(false)
{
@ -50,7 +43,7 @@ AudioInjector::AudioInjector(int maxNumSamples) :
_numTotalSamples(maxNumSamples),
_position(),
_bearing(0),
_attenuationModifier(255),
_volume(0xFF),
_indexOfNextSlot(0),
_isInjectingAudio(false)
{
@ -62,12 +55,6 @@ AudioInjector::~AudioInjector() {
delete[] _audioSampleArray;
}
void AudioInjector::setPosition(float* position) {
_position[0] = position[0];
_position[1] = position[1];
_position[2] = position[2];
}
void AudioInjector::addSample(const int16_t sample) {
if (_indexOfNextSlot != _numTotalSamples) {
// only add this sample if we actually have space for it
@ -82,63 +69,3 @@ void AudioInjector::addSamples(int16_t* sampleBuffer, int numSamples) {
_indexOfNextSlot += numSamples;
}
}
void AudioInjector::injectAudio() {
if (_audioSampleArray) {
_isInjectingAudio = true;
timeval startTime;
// one byte for header, 3 positional floats, 1 bearing float, 1 attenuation modifier byte
int leadingBytes = 1 + (sizeof(float) * 4) + 1;
unsigned char dataPacket[BUFFER_LENGTH_BYTES + leadingBytes];
dataPacket[0] = PACKET_HEADER_INJECT_AUDIO;
unsigned char *currentPacketPtr = dataPacket + 1;
for (int i = 0; i < 3; i++) {
memcpy(currentPacketPtr, &_position[i], sizeof(float));
currentPacketPtr += sizeof(float);
}
*currentPacketPtr = _attenuationModifier;
currentPacketPtr++;
memcpy(currentPacketPtr, &_bearing, sizeof(float));
currentPacketPtr += sizeof(float);
for (int i = 0; i < _numTotalSamples; i += BUFFER_LENGTH_SAMPLES) {
gettimeofday(&startTime, NULL);
int numSamplesToCopy = BUFFER_LENGTH_SAMPLES;
if (_numTotalSamples - i < BUFFER_LENGTH_SAMPLES) {
numSamplesToCopy = _numTotalSamples - i;
memset(currentPacketPtr + numSamplesToCopy, 0, BUFFER_LENGTH_BYTES - (numSamplesToCopy * sizeof(int16_t)));
}
memcpy(currentPacketPtr, _audioSampleArray + i, numSamplesToCopy * sizeof(int16_t));
_injectorSocket->send(&_destinationSocket, dataPacket, sizeof(dataPacket));
double usecToSleep = BUFFER_SEND_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&startTime));
if (usecToSleep > 0) {
usleep(usecToSleep);
}
}
_isInjectingAudio = false;
}
}
void* injectAudioViaThread(void* args) {
AudioInjector* parentInjector = (AudioInjector*) args;
parentInjector->injectAudio();
pthread_exit(0);
}
void AudioInjector::threadInjectionOfAudio() {
pthread_t audioInjectThread;
pthread_create(&audioInjectThread, NULL, injectAudioViaThread, (void*) this);
}

View file

@ -3,45 +3,50 @@
// hifi
//
// Created by Stephen Birarda on 4/23/13.
//
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
//
#ifndef __hifi__AudioInjector__
#define __hifi__AudioInjector__
#include <iostream>
#include <netinet/in.h>
#include "UDPSocket.h"
#include <glm/glm.hpp>
const int BUFFER_LENGTH_BYTES = 512;
const int BUFFER_LENGTH_SAMPLES = BUFFER_LENGTH_BYTES / sizeof(int16_t);
const float SAMPLE_RATE = 22050.0f;
const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES / SAMPLE_RATE) * 1000000;
class AudioInjector {
friend class AudioInjectionManager;
public:
AudioInjector(const char* filename);
AudioInjector(int maxNumSamples);
~AudioInjector();
bool isInjectingAudio() const { return _isInjectingAudio; }
void setIsInjectingAudio(bool isInjectingAudio) { _isInjectingAudio = isInjectingAudio; }
void setPosition(float* position);
unsigned char getVolume() const { return _volume; }
void setVolume(unsigned char volume) { _volume = volume; }
const glm::vec3& getPosition() const { return _position; }
void setPosition(const glm::vec3& position) { _position = position; }
float getBearing() const { return _bearing; }
void setBearing(float bearing) { _bearing = bearing; }
void setAttenuationModifier(unsigned char attenuationModifier) { _attenuationModifier = attenuationModifier; }
void setInjectorSocket(UDPSocket* injectorSocket) { _injectorSocket = injectorSocket; }
void setDestinationSocket(sockaddr* destinationSocket) { _destinationSocket = *destinationSocket; }
void addSample(const int16_t sample);
void addSamples(int16_t* sampleBuffer, int numSamples);
void injectAudio();
void threadInjectionOfAudio();
private:
int16_t* _audioSampleArray;
int _numTotalSamples;
float _position[3];
glm::vec3 _position;
float _bearing;
unsigned char _attenuationModifier;
unsigned char _volume;
int _indexOfNextSlot;
UDPSocket* _injectorSocket;
sockaddr _destinationSocket;
bool _isInjectingAudio;
};