mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 15:09:24 +02:00
add an AudioInjectionManager to handle multiple injections, link eve to it
This commit is contained in:
parent
c8c4b8fda5
commit
5514966d9c
5 changed files with 175 additions and 105 deletions
|
@ -15,6 +15,7 @@
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
#include <AgentList.h>
|
#include <AgentList.h>
|
||||||
#include <AvatarData.h>
|
#include <AvatarData.h>
|
||||||
|
#include <AudioInjectionManager.h>
|
||||||
#include <AudioInjector.h>
|
#include <AudioInjector.h>
|
||||||
|
|
||||||
const int EVE_AGENT_LISTEN_PORT = 55441;
|
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
|
// put her hand out so somebody can shake it
|
||||||
eve.setHandPosition(glm::vec3(eve.getPosition()[0] - 0.2,
|
eve.setHandPosition(glm::vec3(eve.getPosition()[0] - 0.2,
|
||||||
0.5,
|
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
|
// read eve's audio data
|
||||||
AudioInjector eveAudioInjector("/etc/highfidelity/eve/resources/eve.raw");
|
AudioInjector eveAudioInjector("/etc/highfidelity/eve/resources/eve.raw");
|
||||||
|
|
||||||
// lower Eve's volume by setting the attentuation modifier (this is a value out of 255)
|
// lower Eve's volume by setting the attentuation modifier (this is a value out of 255)
|
||||||
eveAudioInjector.setAttenuationModifier(190);
|
eveAudioInjector.setVolume(190);
|
||||||
|
|
||||||
// pass the agentList UDPSocket pointer to the audio injector
|
|
||||||
eveAudioInjector.setInjectorSocket(agentList->getAgentSocket());
|
|
||||||
|
|
||||||
// set the position of the audio injector
|
// set the position of the audio injector
|
||||||
float injectorPosition[3];
|
eveAudioInjector.setPosition(eve.getPosition());
|
||||||
memcpy(injectorPosition, &eve.getPosition(), sizeof(injectorPosition));
|
|
||||||
eveAudioInjector.setPosition(injectorPosition);
|
|
||||||
|
|
||||||
// register the callback for agent data creation
|
// register the callback for agent data creation
|
||||||
agentList->linkedDataCreateCallback = createAvatarDataForAgent;
|
agentList->linkedDataCreateCallback = createAvatarDataForAgent;
|
||||||
|
@ -165,15 +165,11 @@ int main(int argc, const char* argv[]) {
|
||||||
Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER);
|
Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER);
|
||||||
|
|
||||||
if (audioMixer) {
|
if (audioMixer) {
|
||||||
// until the audio mixer is setup for ping-reply, activate the public socket if it's not active
|
// update the destination socket for the AIM, in case the mixer has changed
|
||||||
if (!audioMixer->getActiveSocket()) {
|
AudioInjectionManager::setDestinationSocket(*audioMixer->getPublicSocket());
|
||||||
audioMixer->activatePublicSocket();
|
|
||||||
}
|
|
||||||
|
|
||||||
eveAudioInjector.setDestinationSocket(audioMixer->getActiveSocket());
|
|
||||||
|
|
||||||
// we have an active audio mixer we can send data to
|
// we have an active audio mixer we can send data to
|
||||||
eveAudioInjector.threadInjectionOfAudio();
|
AudioInjectionManager::threadInjector(&eveAudioInjector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
106
libraries/shared/src/AudioInjectionManager.cpp
Normal file
106
libraries/shared/src/AudioInjectionManager.cpp
Normal 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);
|
||||||
|
}
|
36
libraries/shared/src/AudioInjectionManager.h
Normal file
36
libraries/shared/src/AudioInjectionManager.h
Normal 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__) */
|
|
@ -3,27 +3,20 @@
|
||||||
// hifi
|
// hifi
|
||||||
//
|
//
|
||||||
// Created by Stephen Birarda on 4/23/13.
|
// Created by Stephen Birarda on 4/23/13.
|
||||||
//
|
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
#include "PacketHeaders.h"
|
|
||||||
|
|
||||||
#include "AudioInjector.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) :
|
AudioInjector::AudioInjector(const char* filename) :
|
||||||
_position(),
|
_position(),
|
||||||
_bearing(0),
|
_bearing(0),
|
||||||
_attenuationModifier(255),
|
_volume(0xFF),
|
||||||
_indexOfNextSlot(0),
|
_indexOfNextSlot(0),
|
||||||
_isInjectingAudio(false)
|
_isInjectingAudio(false)
|
||||||
{
|
{
|
||||||
|
@ -50,7 +43,7 @@ AudioInjector::AudioInjector(int maxNumSamples) :
|
||||||
_numTotalSamples(maxNumSamples),
|
_numTotalSamples(maxNumSamples),
|
||||||
_position(),
|
_position(),
|
||||||
_bearing(0),
|
_bearing(0),
|
||||||
_attenuationModifier(255),
|
_volume(0xFF),
|
||||||
_indexOfNextSlot(0),
|
_indexOfNextSlot(0),
|
||||||
_isInjectingAudio(false)
|
_isInjectingAudio(false)
|
||||||
{
|
{
|
||||||
|
@ -62,12 +55,6 @@ AudioInjector::~AudioInjector() {
|
||||||
delete[] _audioSampleArray;
|
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) {
|
void AudioInjector::addSample(const int16_t sample) {
|
||||||
if (_indexOfNextSlot != _numTotalSamples) {
|
if (_indexOfNextSlot != _numTotalSamples) {
|
||||||
// only add this sample if we actually have space for it
|
// 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;
|
_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);
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,45 +3,50 @@
|
||||||
// hifi
|
// hifi
|
||||||
//
|
//
|
||||||
// Created by Stephen Birarda on 4/23/13.
|
// Created by Stephen Birarda on 4/23/13.
|
||||||
//
|
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef __hifi__AudioInjector__
|
#ifndef __hifi__AudioInjector__
|
||||||
#define __hifi__AudioInjector__
|
#define __hifi__AudioInjector__
|
||||||
|
|
||||||
#include <iostream>
|
#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 {
|
class AudioInjector {
|
||||||
|
friend class AudioInjectionManager;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AudioInjector(const char* filename);
|
AudioInjector(const char* filename);
|
||||||
AudioInjector(int maxNumSamples);
|
AudioInjector(int maxNumSamples);
|
||||||
~AudioInjector();
|
~AudioInjector();
|
||||||
|
|
||||||
bool isInjectingAudio() const { return _isInjectingAudio; }
|
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 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 addSample(const int16_t sample);
|
||||||
void addSamples(int16_t* sampleBuffer, int numSamples);
|
void addSamples(int16_t* sampleBuffer, int numSamples);
|
||||||
|
|
||||||
void injectAudio();
|
|
||||||
void threadInjectionOfAudio();
|
|
||||||
private:
|
private:
|
||||||
int16_t* _audioSampleArray;
|
int16_t* _audioSampleArray;
|
||||||
int _numTotalSamples;
|
int _numTotalSamples;
|
||||||
float _position[3];
|
glm::vec3 _position;
|
||||||
float _bearing;
|
float _bearing;
|
||||||
unsigned char _attenuationModifier;
|
unsigned char _volume;
|
||||||
int _indexOfNextSlot;
|
int _indexOfNextSlot;
|
||||||
UDPSocket* _injectorSocket;
|
|
||||||
sockaddr _destinationSocket;
|
|
||||||
bool _isInjectingAudio;
|
bool _isInjectingAudio;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue