MCUF sender module implemented
Stefan Schuermans

Stefan Schuermans commited on 2011-11-13 20:54:03
Showing 2 changed files, with 493 additions and 0 deletions.

... ...
@@ -0,0 +1,472 @@
1
+/* Blinker
2
+   Copyright 2011 Stefan Schuermans <stefan@blinkenarea.org>
3
+   Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html
4
+   a blinkenarea.org project */
5
+
6
+#ifndef SENDER_H
7
+#define SENDER_H
8
+
9
+#include <list>
10
+#include <string>
11
+
12
+#include <BlinkenLib/BlinkenFrame.h>
13
+
14
+#include "CallMgr.h"
15
+#include "Directory.h"
16
+#include "File.h"
17
+#include "Module.h"
18
+#include "SettingFile.h"
19
+#include "StreamMgr.h"
20
+#include "StreamRecv.h"
21
+
22
+namespace Blinker {
23
+
24
+/// stream sender
25
+template<typename ADDR, typename SOCK>
26
+class Sender: public Module, public StreamRecv
27
+{
28
+protected:
29
+  /// static destination
30
+  struct Dest {
31
+    std::string m_name; ///< name of static destination
32
+    SettingFile m_file; ///< setting file object
33
+    ADDR        m_addr; ///< parsed address
34
+    Dest(const std::string &name, const File &file); ///< constructor
35
+    bool parse();       ///< parse address from current file
36
+  };
37
+
38
+  /// static destinations
39
+  typedef std::list<Dest> Dests;
40
+
41
+public:
42
+  /**
43
+   * @brief constructor
44
+   * @param[in] callMgr callback manager
45
+   * @param[in] streamMgr stream manager
46
+   * @param[in] dirBase base directory
47
+   */
48
+  Sender(CallMgr &callMgr, StreamMgr &streamMgr, const Directory &dirBase);
49
+
50
+  /// virtual destructor
51
+  virtual ~Sender();
52
+
53
+private:
54
+  /// copy constructor disabled
55
+  Sender(const Sender &that);
56
+
57
+  /// assignment operator disabled
58
+  const Sender & operator=(const Sender &that);
59
+
60
+public:
61
+  /// check for update of configuration
62
+  virtual void updateConfig();
63
+
64
+  /**
65
+   * @brief set current frame
66
+   * @param[in] pFrame current frame
67
+   */
68
+  virtual void setFrame(stBlinkenFrame *pFrame);
69
+
70
+  /// set current frame to none
71
+  virtual void setNoFrame();
72
+
73
+protected:
74
+  /// get input stream and attach to it
75
+  void getInStream();
76
+
77
+  /// detach from input stream and release it
78
+  void releaseInStream();
79
+
80
+  /// create socket and bind it
81
+  void createSock();
82
+
83
+  /// destroy socket
84
+  void destroySock();
85
+
86
+  /**
87
+   * @brief light update of static destinations,
88
+   *        i.e. stat all files in current static destination directory
89
+   */
90
+  void updateDestsLight();
91
+
92
+  /**
93
+   * @brief full update of static destinations,
94
+   *        i.e. scan files in playlist directory
95
+   */
96
+  void updateDestsFull();
97
+
98
+  /**
99
+   * @brief send current frame to address
100
+   * @param[in] addr address to send to
101
+   */
102
+  void sendCurFrame(const ADDR &addr);
103
+
104
+  /**
105
+   * @brief send frame to address
106
+   * @param[in] mcuf MCUF data of frame
107
+   * @param[in] addr address to send to
108
+   */
109
+  void sendFrame(const std::string &mcuf, const ADDR &addr);
110
+
111
+  /**
112
+   * @brief send "no frame" to address
113
+   * @param[in] addr address to send to
114
+   */
115
+  void sendNoFrame(const ADDR &addr);
116
+
117
+  /**
118
+   * @brief convert frame to MCUF data
119
+   * @param[in] pFrame frame
120
+   * @param[out] mcuf MCUF data
121
+   */
122
+  void frame2mcuf(stBlinkenFrame *pFrame, std::string &mcuf);
123
+
124
+protected:
125
+  SettingFile m_fileInStream; ///< input stream name file
126
+  SettingFile m_fileBind;     ///< bind address file
127
+  Directory   m_dirDests;     ///< static destinations directory
128
+  std::string m_nameInStream; ///< name of input stream
129
+  Stream      *m_pInStream;   ///< input stream
130
+  SOCK        *m_pSock;       ///< socket to use for sending streams
131
+  Dests        m_dests;        ///< current static destinations
132
+}; // class Sender
133
+
134
+/* ##########
135
+   # Sender #
136
+   ########## */
137
+
138
+/**
139
+ * @brief constructor
140
+ * @param[in] callMgr callback manager
141
+ * @param[in] streamMgr stream manager
142
+ * @param[in] dirBase base directory
143
+ */
144
+template<typename ADDR, typename SOCK>
145
+Sender<ADDR, SOCK>::Sender(CallMgr &callMgr, StreamMgr &streamMgr,
146
+                           const Directory &dirBase):
147
+  Module(callMgr, streamMgr, dirBase),
148
+  m_fileInStream(dirBase.getFile("instream")),
149
+  m_fileBind(dirBase.getFile("bind")),
150
+  m_dirDests(dirBase.getSubdir("destinations")),
151
+  m_pInStream(NULL),
152
+  m_pSock(NULL)
153
+{
154
+  // get input stream and attach to it
155
+  getInStream();
156
+  // create and bind socket
157
+  createSock();
158
+
159
+  // load static destinations
160
+  updateDestsFull();
161
+}
162
+
163
+/// virtual destructor
164
+template<typename ADDR, typename SOCK>
165
+Sender<ADDR, SOCK>::~Sender()
166
+{
167
+  // send no frame to all static destinations
168
+  typename Dests::const_iterator itDest;
169
+  for (itDest = m_dests.begin(); itDest != m_dests.end(); ++itDest)
170
+    sendNoFrame(itDest->m_addr);
171
+
172
+  // destroy socket
173
+  destroySock();
174
+  // detach from input stream and release it
175
+  releaseInStream();
176
+}
177
+
178
+/// check for update of configuration
179
+template<typename ADDR, typename SOCK>
180
+void Sender<ADDR, SOCK>::updateConfig()
181
+{
182
+  // input stream name file was modified -> re-get input stream
183
+  if (m_fileInStream.checkModified()) {
184
+    releaseInStream();
185
+    getInStream();
186
+  }
187
+
188
+  // bind address file was modified -> re-create socket
189
+  if (m_fileBind.checkModified()) {
190
+    destroySock();
191
+    createSock();
192
+  }
193
+
194
+  // static destinations update
195
+  // (directory modified -> full, otherwise -> light)
196
+  if (m_dirDests.checkModified())
197
+    updateDestsFull();
198
+  else
199
+    updateDestsLight();
200
+}
201
+
202
+/**
203
+ * @brief set current frame
204
+ * @param[in] pFrame current frame
205
+ */
206
+template<typename ADDR, typename SOCK>
207
+void Sender<ADDR, SOCK>::setFrame(stBlinkenFrame *pFrame)
208
+{
209
+  std::string mcuf;
210
+
211
+  // convert frame to MCUF packet
212
+  frame2mcuf(pFrame, mcuf);
213
+
214
+  // send frame to all static destinations
215
+  typename Dests::const_iterator itDest;
216
+  for (itDest = m_dests.begin(); itDest != m_dests.end(); ++itDest)
217
+    sendFrame(mcuf, itDest->m_addr);
218
+}
219
+
220
+/// set current frame to none
221
+template<typename ADDR, typename SOCK>
222
+void Sender<ADDR, SOCK>::setNoFrame()
223
+{
224
+  // send "no frame" to all static destinations
225
+  typename Dests::const_iterator itDest;
226
+  for (itDest = m_dests.begin(); itDest != m_dests.end(); ++itDest)
227
+    sendNoFrame(itDest->m_addr);
228
+}
229
+
230
+/// get input stream and attach to it
231
+template<typename ADDR, typename SOCK>
232
+void Sender<ADDR, SOCK>::getInStream()
233
+{
234
+  // get input stream
235
+  m_fileInStream.getStr(m_nameInStream);
236
+  m_pInStream = &m_streamMgr.refStream(m_nameInStream);
237
+
238
+  // attach to input stream
239
+  if (m_pInStream)
240
+    m_pInStream->attach(this);
241
+}
242
+
243
+/// detach from input stream and release it
244
+template<typename ADDR, typename SOCK>
245
+void Sender<ADDR, SOCK>::releaseInStream()
246
+{
247
+  // detach from input stream
248
+  if (m_pInStream)
249
+    m_pInStream->detach(this);
250
+
251
+  // unreference stream
252
+  m_pInStream = NULL;
253
+  m_streamMgr.unrefStream(m_nameInStream);
254
+}
255
+
256
+/// create socket and bind it
257
+template<typename ADDR, typename SOCK>
258
+void Sender<ADDR, SOCK>::createSock()
259
+{
260
+  std::string strAddr;
261
+  ADDR addr;
262
+
263
+  // create socket
264
+  if (!m_pSock) {
265
+    m_pSock = new SOCK();
266
+    if (!m_pSock)
267
+      return;
268
+  }
269
+
270
+  // get bind address from bind address setting file
271
+  if (!m_fileBind.getStr(strAddr) || !addr.fromStr(strAddr)) {
272
+    delete m_pSock;
273
+    m_pSock = NULL;
274
+    return;
275
+  }
276
+
277
+  // bind socket
278
+  if (!m_pSock->bind(addr)) {
279
+    delete m_pSock;
280
+    m_pSock = NULL;
281
+    return;
282
+  }
283
+}
284
+
285
+/// destroy socket
286
+template<typename ADDR, typename SOCK>
287
+void Sender<ADDR, SOCK>::destroySock()
288
+{
289
+  // destroy socket
290
+  if (m_pSock) {
291
+    delete m_pSock;
292
+    m_pSock = NULL;
293
+  }
294
+}
295
+
296
+/**
297
+ * @brief light update of static destinations,
298
+ *        i.e. stat all files in current static destination directory
299
+ */
300
+template<typename ADDR, typename SOCK>
301
+void Sender<ADDR, SOCK>::updateDestsLight()
302
+{
303
+  // walk through all files in static dest dir and check for modification
304
+  typename Dests::iterator itDest = m_dests.begin();
305
+  while (itDest != m_dests.end()) {
306
+
307
+    // address changed
308
+    if (itDest->m_file.checkModified()) {
309
+      // send "no frame" to old address
310
+      sendNoFrame(itDest->m_addr);
311
+      // re-load address
312
+      if (!itDest->parse()) {
313
+        // parsing address failed -> remove destination
314
+        itDest = m_dests.erase(itDest);
315
+        // do not advance to next destination
316
+        continue;
317
+      }
318
+      // send current frame to new address
319
+      sendCurFrame(itDest->m_addr);
320
+    }
321
+
322
+    // advance to next destination
323
+    ++itDest;
324
+
325
+  } // while itDest
326
+}
327
+
328
+/**
329
+ * @brief full update of static destinations,
330
+ *        i.e. scan files in playlist directory
331
+ */
332
+template<typename ADDR, typename SOCK>
333
+void Sender<ADDR, SOCK>::updateDestsFull()
334
+{
335
+  // get list of files in static destinations directory
336
+  typedef std::list<std::string> Filelist;
337
+  Filelist curFiles;
338
+  m_dirDests.getEntries(Directory::TypeFile, curFiles);
339
+
340
+  // walk through current static destinations and file list simultaneously
341
+  Filelist::const_iterator itFile = curFiles.begin();
342
+  typename Dests::iterator itDest = m_dests.begin();
343
+  while (itFile != curFiles.end() || itDest != m_dests.end()) {
344
+
345
+    // new static destination inserted
346
+    if (itDest == m_dests.end() ||
347
+        (itFile != curFiles.end() && *itFile < itDest->m_name)) {
348
+      // parse new address
349
+      Dest dest(*itFile, m_dirDests.getFile(*itFile));
350
+      if (dest.parse()) {
351
+        // insert new static destination
352
+        m_dests.insert(itDest, dest);
353
+        // send current frame to new static destination
354
+        sendCurFrame(itDest->m_addr);
355
+      }
356
+      // advance to next file
357
+      ++itFile;
358
+    }
359
+
360
+    // static destination removed
361
+    // static destination changed (=> remove and re-insert in next iteration)
362
+    else if (itFile == curFiles.end() || *itFile > itDest->m_name ||
363
+             itDest->m_file.checkModified()) {
364
+      // send "no frame" to old static destination
365
+      sendNoFrame(itDest->m_addr);
366
+      // remove static destination
367
+      itDest = m_dests.erase(itDest);
368
+      // do not advance to next file
369
+    }
370
+
371
+    // static destination stayed in playlist and did not change
372
+    else {
373
+      // advance to next file and next static destination
374
+      ++itFile;
375
+      ++itDest;
376
+    }
377
+
378
+  } // while itFile itDest
379
+}
380
+
381
+/**
382
+ * @brief send current frame to address
383
+ * @param[in] addr address to send to
384
+ */
385
+template<typename ADDR, typename SOCK>
386
+void Sender<ADDR, SOCK>::sendCurFrame(const ADDR &addr)
387
+{
388
+  stBlinkenFrame *pFrame;
389
+  std::string mcuf;
390
+
391
+  // get current frame from stream
392
+  if (m_pInStream && m_pInStream->getCurFrame(pFrame)) {
393
+    // convert frame to MCUF packet
394
+    frame2mcuf(pFrame, mcuf);
395
+    // send frame to address
396
+    sendFrame(mcuf, addr);
397
+  }
398
+
399
+  // no stream of no current frame
400
+  else {
401
+    // send "no frame" to address
402
+    sendNoFrame(addr);
403
+  }
404
+}
405
+
406
+/**
407
+ * @brief send frame to address
408
+ * @param[in] mcuf MCUF data of frame
409
+ * @param[in] addr address to send to
410
+ */
411
+template<typename ADDR, typename SOCK>
412
+void Sender<ADDR, SOCK>::sendFrame(const std::string &mcuf, const ADDR &addr)
413
+{
414
+  if (m_pSock) {
415
+    m_pSock->send(mcuf, addr);
416
+  }
417
+}
418
+
419
+/**
420
+ * @brief send "no frame" to address
421
+ * @param[in] addr address to send to
422
+ */
423
+template<typename ADDR, typename SOCK>
424
+void Sender<ADDR, SOCK>::sendNoFrame(const ADDR &addr)
425
+{
426
+  std::string noframe; // FIXME
427
+
428
+  if (m_pSock) {
429
+    m_pSock->send(noframe, addr);
430
+  }
431
+}
432
+
433
+/**
434
+ * @brief convert frame to MCUF data
435
+ * @param[in] pFrame frame
436
+ * @param[out] mcuf MCUF data
437
+ */
438
+template<typename ADDR, typename SOCK>
439
+void Sender<ADDR, SOCK>::frame2mcuf(stBlinkenFrame *pFrame, std::string &mcuf)
440
+{
441
+  char buf[65536];
442
+  int len;
443
+
444
+  // convert frame to MCUF packet
445
+  len = BlinkenFrameToNetwork(pFrame, BlinkenProtoMcuf, buf, sizeof(buf));
446
+  mcuf.assign(buf, len);
447
+}
448
+
449
+/* ################
450
+   # Sender::Dest #
451
+   ################ */
452
+
453
+/// constructor
454
+template<typename ADDR, typename SOCK>
455
+Sender<ADDR, SOCK>::Dest::Dest(const std::string &name, const File &file):
456
+  m_name(name),
457
+  m_file(file)
458
+{
459
+}
460
+
461
+/// parse address from current file
462
+template<typename ADDR, typename SOCK>
463
+bool Sender<ADDR, SOCK>::Dest::parse()
464
+{
465
+  std::string strAddr;
466
+  return m_file.getStr(strAddr) && m_addr.fromStr(strAddr);
467
+}
468
+
469
+} // namespace Blinker
470
+
471
+#endif // #ifndef SENDER_H
472
+
... ...
@@ -0,0 +1,21 @@
1
+/* Blinker
2
+   Copyright 2011 Stefan Schuermans <stefan@blinkenarea.org>
3
+   Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html
4
+   a blinkenarea.org project */
5
+
6
+#ifndef UDP4SENDER_H
7
+#define UDP4SENDER_H
8
+
9
+#include "Sender.h"
10
+#include "Udp4Addr.h"
11
+#include "Udp4Sock.h"
12
+
13
+namespace Blinker {
14
+
15
+/// UDP v4 stream sender
16
+typedef Sender<Udp4Addr, Udp4Sock> Udp4Sender;
17
+
18
+} // namespace Blinker
19
+
20
+#endif // #ifndef UDP4SENDER_H
21
+
0 22