Mercurial > hg > beaglert
view core/NetworkSend.cpp @ 219:0183185cab1b mergingClockSync
Removed obsolete Scope class
author | Giulio Moro <giuliomoro@yahoo.it> |
---|---|
date | Sat, 13 Feb 2016 15:55:33 +0000 |
parents | c42a6b4dc2d4 |
children | 46bd63a50933 |
line wrap: on
line source
#include "NetworkSend.h" #ifdef USE_JUCE #else //initialize the static members of NetworkSend bool NetworkSend::staticConstructed=false; int NetworkSend::sleepTimeMs; bool NetworkSend::threadIsExiting; bool NetworkSend::threadRunning; std::vector<NetworkSend*> NetworkSend::objAddrs(0); AuxiliaryTask NetworkSend::sendDataTask=NULL; void sendData(){ NetworkSend::run(); } void NetworkSend::staticConstructor(){ if(staticConstructed==true) return; staticConstructed=true; threadIsExiting=false; threadRunning=false; sendDataTask = BeagleRT_createAuxiliaryTask(::sendData, 95, "sendDataTask"); //TODO: allow variable priority } void NetworkSend::sendAllData(){ for(unsigned int n=0; n<NetworkSend::objAddrs.size(); n++){ NetworkSend::objAddrs[n]->sendData(); } } int NetworkSend::getNumInstances(){ return objAddrs.size(); } void NetworkSend::startThread(){ BeagleRT_scheduleAuxiliaryTask(sendDataTask); } void NetworkSend::stopThread(){ threadIsExiting=true; } bool NetworkSend::threadShouldExit(){ return(gShouldStop || threadIsExiting); } bool NetworkSend::isThreadRunning(){ return threadRunning; } #endif /* USE_JUCE */ #ifdef USE_JUCE NetworkSend::NetworkSend(const String &threadName): Thread(threadName) #else NetworkSend::NetworkSend() #endif /* USE_JUCE */ { channel.buffers=NULL; channel.doneOnTime=NULL; channel.readyToBeSent=NULL; channel.enabled=false; sleepTimeMs=2; //This should actually be initialized in the staticConstructor for non-Juce code, but doing it here makes it more portable channel.sampleCount=0; } NetworkSend::~NetworkSend(){ #ifdef USE_JUCE stopThread(1000); #else stopThread(); for(unsigned int n=0; n<objAddrs.size(); n++){ //keep track of deleted instances; if(objAddrs[n]==this){ objAddrs.erase(objAddrs.begin()+n); break; } } #endif dealloc(); } void NetworkSend::dealloc(){ channel.enabled=false; if(channel.buffers!=NULL){ for(int n=0; n<channel.numBuffers; n++){ free(channel.buffers[n]); channel.buffers[n]=NULL; } free(channel.buffers); channel.buffers=NULL; } free(channel.readyToBeSent); channel.readyToBeSent=NULL; free(channel.doneOnTime); channel.doneOnTime=NULL; } void NetworkSend::cleanup(){ dealloc(); } void NetworkSend::setup(float aSampleRate, int blockSize, int aChannelNumber, int aPort, const char *aServer){ #ifdef USE_JUCE #else 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 ... #endif /* USE_JUCE */ cleanup(); int numSamples=blockSize*4>4*channel.bufferLength ? blockSize*4 : 4*channel.bufferLength; channel.numBuffers= 1+numSamples/channel.bufferLength; //the +1 takes the ceil() of the division channel.buffers=(float**)malloc(channel.numBuffers*sizeof(float*)); printf("NumBuffers: %d\n", channel.numBuffers); if(channel.buffers==NULL) return; for(int n=0; n<channel.numBuffers; n++){ channel.buffers[n]=(float*)malloc(channel.bufferLength*sizeof(float)); if(channel.buffers[n]==NULL) return; } channel.readyToBeSent=(bool*)malloc(channel.numBuffers*sizeof(bool)); channel.doneOnTime=(bool*)malloc(channel.numBuffers*sizeof(bool)); for(int n=0; n<channel.numBuffers; n++){ channel.readyToBeSent[n]=false; channel.doneOnTime[n]=true; } if(channel.readyToBeSent==NULL || channel.doneOnTime==NULL) return; channel.writePointer=0; channel.writeBuffer=0; channel.readBuffer=0; setChannelNumber(aChannelNumber); setPort(aPort); //TODO: check for the return value setServer(aServer); //TODO: check for the return value printf("Channel %d is sending messages to: %s:%d at %fHz\n", getChannelNumber(), aServer, aPort, aSampleRate); channel.enabled=true; } void NetworkSend::log(float value){ //TODO: add a vectorized version of this method if(channel.enabled==false) return; if(channel.writePointer==channel.bufferLength){ // when the buffer is filled ... channel.readyToBeSent[channel.writeBuffer]=true; // flag it as such // printf("Scheduling for send %d\n",(int)channel.buffers[channel.writeBuffer][channel.headerTimestampIndex]); channel.writePointer=channel.headerLength; //reset the writePointer channel.writeBuffer=(channel.writeBuffer+1); //switch buffer if(channel.writeBuffer==channel.numBuffers) // and wrap it channel.writeBuffer=0; // printf("WriteBuffer:%d\n", channel.writeBuffer); if(channel.doneOnTime[channel.writeBuffer]==false){ //check if this buffer's last sending has completed on time ... printf("Network buffer underrun. timestamp: %d :-{\n", (int)channel.buffers[channel.writeBuffer][channel.headerTimestampIndex]); } channel.doneOnTime[channel.writeBuffer]=false; // ... and then reset the flag #ifdef USE_JUCE if(isThreadRunning()==false){ startThread(10); } #else if(isThreadRunning()==false){ startThread(); } #endif /* USE_JUCE */ } if(channel.writePointer==channel.headerLength){ // we are about to start writing in the buffer, let's set the header //set dynamic header values here. Static values are set in setup() and setChannelNumber(). channel.buffers[channel.writeBuffer][channel.headerTimestampIndex]=(float)channel.sampleCount; //timestamp channel.sampleCount++; //add here more header fields } channel.buffers[channel.writeBuffer][channel.writePointer++]=value; // sampleCount++; }; void NetworkSend::setServer(const char *aServer){ #ifdef USE_JUCE remoteHostname=String::fromUTF8(aServer); #else udpClient.setServer(aServer); #endif /* USE_JUCE */ } void NetworkSend::setPort(int aPort){ #ifdef USE_JUCE remotePortNumber=aPort; #else udpClient.setPort(aPort); #endif /* USE_JUCE */ } void NetworkSend::setChannelNumber(int aChannelNumber){ channel.channelNumber=aChannelNumber; for(int n=0; n<channel.numBuffers; n++){ //initialize the header channel.buffers[n][channel.headerChannelIndex]=channel.channelNumber; //add here more static header fields } }; int NetworkSend::getChannelNumber(){ return channel.channelNumber; }; int NetworkSend::getTimestamp(){ return channel.buffers[channel.readBuffer][channel.headerTimestampIndex]; } void NetworkSend::sendData(){ if(channel.enabled==false) return; while(channel.readyToBeSent[channel.readBuffer]==true){ channel.readyToBeSent[channel.readBuffer]=false; void* sourceBuffer=channel.buffers[channel.readBuffer]; // printf("Trying to send timestamp %d\n",(int)((float*)sourceBuffer)[channel.headerTimestampIndex]); // printf("ReadBuffer:%d\n", channel.readBuffer); unsigned int numBytesToSend=NETWORK_AUDIO_BUFFER_SIZE*sizeof(float); //TODO: call waitUntilReady before trying to write/send, to avoid blocks! (OR NOT?) #ifdef USE_JUCE if(1==udpClient.waitUntilReady(0, 5)){ udpClient.write(remoteHostname, remotePortNumber, sourceBuffer, numBytesToSend); channel.doneOnTime[channel.readBuffer]=true; // printf ("Sent timestamp: %d\n", (int)((float*)sourceBuffer)[1]); } else { // printf ("Not ready timestamp: %d\n", (int)((float*)sourceBuffer)[1]); } #else udpClient.send(sourceBuffer, numBytesToSend); channel.doneOnTime[channel.readBuffer]=true; #endif /* USE_JUCE */ channel.readBuffer++; if(channel.readBuffer==channel.numBuffers) channel.readBuffer=0; } } void NetworkSend::run(){ #ifdef USE_JUCE // std::chrono::high_resolution_clock::time_point t1; // std::chrono::high_resolution_clock::time_point t2; // std::chrono::high_resolution_clock::time_point t3; while(threadShouldExit()==false){ // t3 = std::chrono::high_resolution_clock::now(); // t1 = std::chrono::high_resolution_clock::now(); sendData(); // t2 = std::chrono::high_resolution_clock::now(); // auto duration1 = std::chrono::duration_cast<std::chrono::microseconds>( t3 - t1 ).count(); // auto duration2 = std::chrono::duration_cast<std::chrono::microseconds>( t2 - t1 ).count(); // if(duration2>0) // std::cout << "Duration is: " << duration2 <<". Whole loop is: " << duration1 << "\n"; usleep(1000); } #else threadRunning=true; while(threadShouldExit()==false){ sendAllData(); usleep(sleepTimeMs*1000); } threadRunning=false; #endif }