giuliomoro@111
|
1 //scope.cpp
|
giuliomoro@112
|
2 #include <NetworkSend.h>
|
giuliomoro@111
|
3
|
giuliomoro@111
|
4 #define BUILD_FOR_UDPRECEIVE_PLUGIN
|
giuliomoro@111
|
5 #define NETWORK_AUDIO_BUFFER_SIZE 302
|
giuliomoro@111
|
6
|
giuliomoro@111
|
7 //initialize the static members of NetworkSend
|
giuliomoro@111
|
8 bool NetworkSend::staticConstructed=false;
|
giuliomoro@111
|
9 std::vector<NetworkSend*> NetworkSend::objAddrs(0);
|
giuliomoro@116
|
10 AuxiliaryTask NetworkSend::sendDataTask=NULL;
|
giuliomoro@111
|
11
|
giuliomoro@111
|
12 void transmitAudio(){
|
giuliomoro@111
|
13 NetworkSend::sendAllData();
|
giuliomoro@111
|
14 }
|
giuliomoro@111
|
15
|
giuliomoro@111
|
16 void NetworkSend::sendAllData(){
|
giuliomoro@111
|
17 for(unsigned int n=0; n<NetworkSend::objAddrs.size(); n++){
|
giuliomoro@111
|
18 NetworkSend::objAddrs[n]->sendData();
|
giuliomoro@111
|
19 }
|
giuliomoro@111
|
20 }
|
giuliomoro@111
|
21
|
giuliomoro@111
|
22 void NetworkSend::staticConstructor(){
|
giuliomoro@111
|
23 if(staticConstructed==true)
|
giuliomoro@111
|
24 return;
|
giuliomoro@111
|
25 staticConstructed=true;
|
giuliomoro@116
|
26 sendDataTask = BeagleRT_createAuxiliaryTask(transmitAudio, 95, "sendDataTask"); //TODO: allow variable priority
|
giuliomoro@111
|
27 };
|
giuliomoro@111
|
28
|
giuliomoro@111
|
29 NetworkSend::NetworkSend()
|
giuliomoro@111
|
30 {
|
giuliomoro@111
|
31 sampleCount = 0;
|
giuliomoro@111
|
32 channel.doneOnTime=true;
|
giuliomoro@111
|
33 channel.index=channel.headerLength; //leave space for the heading message (channel, timestamp)
|
giuliomoro@111
|
34 channel.activeBuffer=0;
|
giuliomoro@111
|
35 channel.readyToBeSent=false;
|
giuliomoro@111
|
36 }
|
giuliomoro@116
|
37
|
giuliomoro@111
|
38 NetworkSend::~NetworkSend(){
|
giuliomoro@111
|
39 for(unsigned int n=0; n<objAddrs.size(); n++){ //keep track of deleted instances;
|
giuliomoro@111
|
40 if(objAddrs[n]==this){
|
giuliomoro@111
|
41 objAddrs.erase(objAddrs.begin()+n);
|
giuliomoro@111
|
42 break;
|
giuliomoro@111
|
43 }
|
giuliomoro@111
|
44 }
|
giuliomoro@111
|
45 }
|
giuliomoro@111
|
46
|
giuliomoro@111
|
47 void NetworkSend::setup(float aSampleRate){
|
giuliomoro@111
|
48 setup(aSampleRate, 0, 9999, "192.168.7.1");//channelNumber=0
|
giuliomoro@111
|
49 }
|
giuliomoro@111
|
50 void NetworkSend::setup(float aSampleRate, int aChannelNumber, int aPort, const char *aServer){
|
giuliomoro@111
|
51 staticConstructor(); //FIXME: ideally this should be in the constructor, but this is not currently possible
|
giuliomoro@111
|
52 //because of limitations in BeagleRT_createAuxiliaryTask()
|
giuliomoro@111
|
53 //keep track of added active instances
|
giuliomoro@111
|
54 objAddrs.push_back(this);//TODO: this line should be in the constructor, but something weird happens if
|
giuliomoro@111
|
55 // an instance of NetworkSend is then declared globally: the constructor gets called,
|
giuliomoro@111
|
56 // and objAddrs.size()==1 but when you get to setup, objAddrs.size() has reverted back to 0, without
|
giuliomoro@111
|
57 // any destructor being called in between ...
|
giuliomoro@111
|
58 setChannelNumber(aChannelNumber);
|
giuliomoro@111
|
59 setPort(aPort);
|
giuliomoro@111
|
60 setServer(aServer);
|
giuliomoro@120
|
61 printf("Channel %d is sending messages to: %s:%d at %fHz\n", getChannelNumber(), aServer, aPort, aSampleRate);
|
giuliomoro@111
|
62 }
|
giuliomoro@111
|
63
|
giuliomoro@111
|
64 void NetworkSend::log(float value){ //TODO: add a vectorized version of this method
|
giuliomoro@111
|
65 if(channel.index==(NETWORK_AUDIO_BUFFER_SIZE)){ // when the buffer is ready ...
|
giuliomoro@111
|
66 channel.readyToBeSent=true;
|
giuliomoro@111
|
67 channel.index=channel.headerLength; //reset the counter
|
giuliomoro@111
|
68 if(channel.doneOnTime==false){
|
giuliomoro@111
|
69 printf("Network buffer underrun. timestamp: %d :-{\n", (int)channel.buffers[!channel.activeBuffer][1]);
|
giuliomoro@111
|
70 }
|
giuliomoro@111
|
71 channel.activeBuffer=!channel.activeBuffer; //switch buffer
|
giuliomoro@111
|
72 channel.doneOnTime=false;
|
giuliomoro@116
|
73 BeagleRT_scheduleAuxiliaryTask(NetworkSend::sendDataTask); //send the buffer
|
giuliomoro@120
|
74 // TODO: maybe we should have transmitAudioTask running in a loop instead of scheduling it multiple times?
|
giuliomoro@120
|
75 // The current solution allows to minimize latency when a single channel is used, as there is no inherent
|
giuliomoro@120
|
76 // rt_task_sleep in the thread, as we are signaling it every time.
|
giuliomoro@120
|
77 // Although, there is a possible race condition: if the auxiliaryTask is scheduled by channel 0,
|
giuliomoro@120
|
78 // it might still be executing when channel 1 schedules it. But if the AuxTask has already skipped
|
giuliomoro@120
|
79 // over channel 1, then we are at risk that channel 1 never gets sent.
|
giuliomoro@111
|
80 }
|
giuliomoro@111
|
81 if(channel.index==channel.headerLength){
|
giuliomoro@111
|
82 channel.buffers[channel.activeBuffer][0] = (float)channel.channelNumber; //TODO: this could actually be done just once in setup()
|
giuliomoro@111
|
83 channel.buffers[channel.activeBuffer][1]=(float)sampleCount; //timestamp
|
giuliomoro@111
|
84 //add here more header fields
|
giuliomoro@111
|
85 }
|
giuliomoro@111
|
86 channel.buffers[channel.activeBuffer][channel.index++]=value;
|
giuliomoro@111
|
87 sampleCount++;
|
giuliomoro@111
|
88 };
|
giuliomoro@111
|
89
|
giuliomoro@111
|
90 void NetworkSend::setServer(const char *aServer){
|
giuliomoro@111
|
91 udpClient.setServer(aServer);
|
giuliomoro@111
|
92 }
|
giuliomoro@111
|
93 void NetworkSend::setPort(int aPort){
|
giuliomoro@111
|
94 udpClient.setPort(aPort);
|
giuliomoro@111
|
95 }
|
giuliomoro@111
|
96
|
giuliomoro@111
|
97 void NetworkSend::setChannelNumber(int aChannelNumber){
|
giuliomoro@111
|
98 channel.channelNumber=aChannelNumber;
|
giuliomoro@111
|
99 };
|
giuliomoro@111
|
100 int NetworkSend::getChannelNumber(){
|
giuliomoro@111
|
101 return channel.channelNumber;
|
giuliomoro@111
|
102 };
|
giuliomoro@111
|
103
|
giuliomoro@111
|
104 void NetworkSend::sendData(){
|
giuliomoro@111
|
105 if(channel.readyToBeSent){
|
giuliomoro@111
|
106 channel.readyToBeSent=false;
|
giuliomoro@111
|
107 udpClient.send(
|
giuliomoro@111
|
108 channel.buffers[!channel.activeBuffer],
|
giuliomoro@111
|
109 NETWORK_AUDIO_BUFFER_SIZE*sizeof(float)
|
giuliomoro@111
|
110 );
|
giuliomoro@111
|
111 channel.doneOnTime=true;
|
giuliomoro@111
|
112 }
|
giuliomoro@111
|
113 }
|
giuliomoro@111
|
114
|
giuliomoro@111
|
115 int NetworkSend::getNumInstances(){
|
giuliomoro@111
|
116 return objAddrs.size();
|
giuliomoro@111
|
117 };
|
giuliomoro@111
|
118
|
giuliomoro@111
|
119 Scope::Scope(int aNumChannels):
|
giuliomoro@111
|
120 channels(aNumChannels)
|
giuliomoro@111
|
121 {};
|
giuliomoro@111
|
122 Scope::~Scope(){};
|
giuliomoro@111
|
123
|
giuliomoro@111
|
124 void Scope::log(int channel, float value){
|
giuliomoro@111
|
125 if(channel>=getNumChannels()) //TODO: assert this
|
giuliomoro@111
|
126 return;
|
giuliomoro@111
|
127 channels[channel].log(value);
|
giuliomoro@111
|
128 }
|
giuliomoro@111
|
129
|
giuliomoro@111
|
130 void Scope::setup(){
|
giuliomoro@111
|
131 setup(44100, 9999, "127.0.0.1");
|
giuliomoro@111
|
132 }
|
giuliomoro@111
|
133
|
giuliomoro@111
|
134 void Scope::setup(float sampleRate, int aPort, const char* aServer){
|
giuliomoro@111
|
135 for(int n=0; n<getNumChannels(); n++){
|
giuliomoro@111
|
136 channels[n].setup(sampleRate, n, aPort, aServer);
|
giuliomoro@111
|
137 }
|
giuliomoro@111
|
138 }
|
giuliomoro@111
|
139
|
giuliomoro@119
|
140 void Scope::setPort(int port){
|
giuliomoro@119
|
141 for(int n=0; n<getNumChannels(); n++){
|
giuliomoro@119
|
142 channels[n].setPort(port);
|
giuliomoro@119
|
143 }
|
giuliomoro@119
|
144 }
|
giuliomoro@120
|
145 void Scope::setPort(int channel, int aPort){
|
giuliomoro@120
|
146 channels[channel].setPort(aPort);
|
giuliomoro@120
|
147 printf("Channel %d is now sending to port %d\n", channel, aPort);
|
giuliomoro@119
|
148 }
|
giuliomoro@119
|
149
|
giuliomoro@111
|
150 int Scope::getNumChannels(){
|
giuliomoro@111
|
151 return channels.size();
|
giuliomoro@111
|
152 }
|
giuliomoro@111
|
153
|
giuliomoro@111
|
154 void Scope::sendData(){
|
giuliomoro@111
|
155 NetworkSend::sendAllData();
|
giuliomoro@111
|
156 }
|