Mercurial > hg > beaglert
view core/NetworkSend.cpp @ 120:cdd441a304a9 scope-refactoring
Added read to interleaved buffer
author | Giulio Moro <giuliomoro@yahoo.it> |
---|---|
date | Fri, 21 Aug 2015 15:52:37 +0100 |
parents | c692827083e1 |
children | cce58e6ec2a2 |
line wrap: on
line source
//scope.cpp #include <NetworkSend.h> #define BUILD_FOR_UDPRECEIVE_PLUGIN #define NETWORK_AUDIO_BUFFER_SIZE 302 //initialize the static members of NetworkSend bool NetworkSend::staticConstructed=false; std::vector<NetworkSend*> NetworkSend::objAddrs(0); AuxiliaryTask NetworkSend::sendDataTask=NULL; void transmitAudio(){ NetworkSend::sendAllData(); } void NetworkSend::sendAllData(){ for(unsigned int n=0; n<NetworkSend::objAddrs.size(); n++){ NetworkSend::objAddrs[n]->sendData(); } } void NetworkSend::staticConstructor(){ if(staticConstructed==true) return; staticConstructed=true; sendDataTask = BeagleRT_createAuxiliaryTask(transmitAudio, 95, "sendDataTask"); //TODO: allow variable priority }; NetworkSend::NetworkSend() { sampleCount = 0; channel.doneOnTime=true; channel.index=channel.headerLength; //leave space for the heading message (channel, timestamp) channel.activeBuffer=0; channel.readyToBeSent=false; } NetworkSend::~NetworkSend(){ for(unsigned int n=0; n<objAddrs.size(); n++){ //keep track of deleted instances; if(objAddrs[n]==this){ objAddrs.erase(objAddrs.begin()+n); break; } } } void NetworkSend::setup(float aSampleRate){ setup(aSampleRate, 0, 9999, "192.168.7.1");//channelNumber=0 } void NetworkSend::setup(float aSampleRate, int aChannelNumber, int aPort, const char *aServer){ staticConstructor(); //FIXME: ideally this should be in the constructor, but this is not currently possible //because of limitations in BeagleRT_createAuxiliaryTask() //keep track of added active instances objAddrs.push_back(this);//TODO: this line should be in the constructor, but something weird happens if // an instance of NetworkSend is then declared globally: the constructor gets called, // and objAddrs.size()==1 but when you get to setup, objAddrs.size() has reverted back to 0, without // any destructor being called in between ... setChannelNumber(aChannelNumber); setPort(aPort); setServer(aServer); printf("Channel %d is sending messages to: %s:%d at %fHz\n", getChannelNumber(), aServer, aPort, aSampleRate); } void NetworkSend::log(float value){ //TODO: add a vectorized version of this method if(channel.index==(NETWORK_AUDIO_BUFFER_SIZE)){ // when the buffer is ready ... channel.readyToBeSent=true; channel.index=channel.headerLength; //reset the counter if(channel.doneOnTime==false){ printf("Network buffer underrun. timestamp: %d :-{\n", (int)channel.buffers[!channel.activeBuffer][1]); } channel.activeBuffer=!channel.activeBuffer; //switch buffer channel.doneOnTime=false; BeagleRT_scheduleAuxiliaryTask(NetworkSend::sendDataTask); //send the buffer // TODO: maybe we should have transmitAudioTask running in a loop instead of scheduling it multiple times? // The current solution allows to minimize latency when a single channel is used, as there is no inherent // rt_task_sleep in the thread, as we are signaling it every time. // Although, there is a possible race condition: if the auxiliaryTask is scheduled by channel 0, // it might still be executing when channel 1 schedules it. But if the AuxTask has already skipped // over channel 1, then we are at risk that channel 1 never gets sent. } if(channel.index==channel.headerLength){ channel.buffers[channel.activeBuffer][0] = (float)channel.channelNumber; //TODO: this could actually be done just once in setup() channel.buffers[channel.activeBuffer][1]=(float)sampleCount; //timestamp //add here more header fields } channel.buffers[channel.activeBuffer][channel.index++]=value; sampleCount++; }; void NetworkSend::setServer(const char *aServer){ udpClient.setServer(aServer); } void NetworkSend::setPort(int aPort){ udpClient.setPort(aPort); } void NetworkSend::setChannelNumber(int aChannelNumber){ channel.channelNumber=aChannelNumber; }; int NetworkSend::getChannelNumber(){ return channel.channelNumber; }; void NetworkSend::sendData(){ if(channel.readyToBeSent){ channel.readyToBeSent=false; udpClient.send( channel.buffers[!channel.activeBuffer], NETWORK_AUDIO_BUFFER_SIZE*sizeof(float) ); channel.doneOnTime=true; } } int NetworkSend::getNumInstances(){ return objAddrs.size(); }; Scope::Scope(int aNumChannels): channels(aNumChannels) {}; Scope::~Scope(){}; void Scope::log(int channel, float value){ if(channel>=getNumChannels()) //TODO: assert this return; channels[channel].log(value); } void Scope::setup(){ setup(44100, 9999, "127.0.0.1"); } void Scope::setup(float sampleRate, int aPort, const char* aServer){ for(int n=0; n<getNumChannels(); n++){ channels[n].setup(sampleRate, n, aPort, aServer); } } void Scope::setPort(int port){ for(int n=0; n<getNumChannels(); n++){ channels[n].setPort(port); } } void Scope::setPort(int channel, int aPort){ channels[channel].setPort(aPort); printf("Channel %d is now sending to port %d\n", channel, aPort); } int Scope::getNumChannels(){ return channels.size(); } void Scope::sendData(){ NetworkSend::sendAllData(); }