implemented priority based selector module
Stefan Schuermans

Stefan Schuermans commited on 2011-11-21 22:01:04
Showing 10 changed files, with 642 additions and 0 deletions.

... ...
@@ -87,6 +87,7 @@
87 87
         <li><a href="canvas.html">Canvas</a></li>
88 88
         <li><a href="player.html">Player</a></li>
89 89
         <li><a href="printer.html">Printer</a></li>
90
+        <li><a href="priority.html">Priority</a></li>
90 91
         <li><a href="resizer.html">Resizer</a></li>
91 92
         <li><a href="scaler.html">Scaler</a></li>
92 93
         <li><a href="udp4sender.html">UDP4 Sender</a></li>
... ...
@@ -0,0 +1,47 @@
1
+<html>
2
+  <head>
3
+    <title>Blinker - Priority</title>
4
+  </head>
5
+  <body>
6
+    <h1>Blinker - Priority</h1>
7
+    <p>
8
+      The priority module is used to select one of several streams.
9
+      The selection is done on a priority basis.
10
+      Among all streams providing a frame, the one with the highest priority
11
+      is chosen.
12
+    </p>
13
+    <h2>Configuration</h2>
14
+    <p>
15
+      The configuration of the priority module with name <code>NAME</code>
16
+      is located in the <code>priority/NAME</code> subdirectory.
17
+    </p>
18
+    <h3>Input List</h3>
19
+    <p>
20
+      The inputs to be possibly selected are configured in the
21
+      <code>inputs</code> subdirectory.
22
+      Each input is configured in an own subdirectory in <code>inputs</code>.
23
+      E.g. the configurations for inputs with names <code>000lowprio</code>
24
+      and <code>999highprio</code> reside in subdirectories
25
+      <code>inputs/000lowprio</code> and <code>inputs/999highprio</code>
26
+      respectively.
27
+      All inputs are assigned a priority according to their alphanumerical
28
+      order, i.e. <code>999highprio</code> is selected over
29
+      <code>000lowprio</code> if both provide a frame.
30
+    </p>
31
+    <p>
32
+      The configuration inside an input subdirectory consists of the following
33
+      settings:
34
+    </p>
35
+    <h4>Input Stream</h4>
36
+    <p>
37
+      The file <code>instream</code> contains the name of the stream to
38
+      read for this input.
39
+    </p>
40
+    <h3>Output Stream</h3>
41
+    <p>
42
+      The file <code>outstream</code> contains the name of the stream to
43
+      send the frames to.
44
+    </p>
45
+  </body>
46
+</html>
47
+
... ...
@@ -0,0 +1,228 @@
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
+#include <list>
7
+#include <string>
8
+
9
+#include <BlinkenLib/BlinkenFrame.h>
10
+
11
+#include "CallMgr.h"
12
+#include "Directory.h"
13
+#include "File.h"
14
+#include "Module.h"
15
+#include "Priority.h"
16
+#include "PriorityInput.h"
17
+#include "SettingFile.h"
18
+#include "StreamMgr.h"
19
+#include "StreamRecv.h"
20
+
21
+namespace Blinker {
22
+
23
+/**
24
+ * @brief constructor
25
+ * @param[in] callMgr callback manager
26
+ * @param[in] streamMgr stream manager
27
+ * @param[in] dirBase base directory
28
+ */
29
+Priority::Priority(CallMgr &callMgr, StreamMgr &streamMgr, const Directory &dirBase):
30
+  Module(callMgr, streamMgr, dirBase),
31
+  m_dirInputs(dirBase.getSubdir("inputs")),
32
+  m_fileOutStream(dirBase.getFile("outstream")),
33
+  m_itCurIn(m_inList.rend()),
34
+  m_pOutStream(NULL)
35
+{
36
+  // set up
37
+  updateInListFull();
38
+  getOutStream();
39
+}
40
+
41
+/// virtual destructor
42
+Priority::~Priority()
43
+{
44
+  // clean up
45
+  releaseOutStream();
46
+  while (!m_inList.empty()) {
47
+    delete m_inList.back().m_pInput;
48
+    m_inList.pop_back();
49
+  }
50
+}
51
+
52
+/// check for update of configuration
53
+void Priority::updateConfig()
54
+{
55
+  // input list update (directory modified -> full, otherwise -> light)
56
+  if (m_dirInputs.checkModified())
57
+    updateInListFull();
58
+  else
59
+    updateInListLight();
60
+
61
+  // output stream name file was modified -> re-get output stream
62
+  if (m_fileOutStream.checkModified()) {
63
+    releaseOutStream();
64
+    getOutStream();
65
+  }
66
+}
67
+
68
+/// light update of input list, i.e. check all entries in current input list
69
+void Priority::updateInListLight()
70
+{
71
+  // walk through all inputs in input list and check for modification
72
+  InList::iterator itIn;
73
+  for (itIn = m_inList.begin(); itIn != m_inList.end(); ++itIn)
74
+    itIn->m_pInput->updateConfig();
75
+}
76
+
77
+/// full update of input list, i.e. scan subdirs in input list directory
78
+void Priority::updateInListFull()
79
+{
80
+  // get list of subdirs in input directory
81
+  typedef std::list<std::string> Subdirlist;
82
+  Subdirlist curSubdirs;
83
+  m_dirInputs.getEntries(Directory::TypeSubdir, curSubdirs);
84
+
85
+  // walk through current input list and subdir list simultaneously
86
+  Subdirlist::const_iterator itSubdir = curSubdirs.begin();
87
+  InList::iterator           itIn     = m_inList.begin();
88
+  while (itSubdir != curSubdirs.end() || itIn != m_inList.end()) {
89
+
90
+    // new input inserted
91
+    if (itIn == m_inList.end() ||
92
+        (itSubdir != curSubdirs.end() && *itSubdir < itIn->m_name)) {
93
+      // create input object
94
+      InEntry inEntry(*itSubdir);
95
+      inEntry.m_pInput = new Input(*this, *itSubdir,
96
+                                   m_dirInputs.getSubdir(*itSubdir));
97
+      if (inEntry.m_pInput)
98
+        // insert input list entry
99
+        m_inList.insert(itIn, inEntry);
100
+      // advance to next subdir
101
+      ++itSubdir;
102
+    }
103
+
104
+    // input removed
105
+    else if (itSubdir == curSubdirs.end() || *itSubdir > itIn->m_name) {
106
+      // remove input
107
+      delete itIn->m_pInput;
108
+      itIn = m_inList.erase(itIn);
109
+      // do not advance to next subdir
110
+    }
111
+
112
+    // input stayed in input list
113
+    else {
114
+      // check for update
115
+      itIn->m_pInput->updateConfig();
116
+      // advance to next file and next entry
117
+      ++itSubdir;
118
+      ++itIn;
119
+    }
120
+
121
+  } // while itFile itIn
122
+}
123
+
124
+/// get output stream
125
+void Priority::getOutStream()
126
+{
127
+  // get name of output stream
128
+  m_fileOutStream.getStr(m_nameOutStream);
129
+
130
+  // get output stream
131
+  m_pOutStream = &m_streamMgr.refStream(m_nameOutStream);
132
+
133
+  // send current frame to stream
134
+  curFrame();
135
+}
136
+
137
+/// release output stream
138
+void Priority::releaseOutStream()
139
+{
140
+  // send no frame information
141
+  if (m_pOutStream)
142
+    m_pOutStream->setNoFrame();
143
+
144
+  // unreference output stream
145
+  m_pOutStream = NULL;
146
+  m_streamMgr.unrefStream(m_nameOutStream);
147
+}
148
+
149
+/**
150
+ * @brief select specific input (called by inputs)
151
+ * @param[in] input input to select
152
+ */
153
+void Priority::select(const Input *pInput)
154
+{
155
+  // search inputs for passed input
156
+  m_itCurIn = m_inList.rbegin();
157
+  while (m_itCurIn != m_inList.rend() && m_itCurIn->m_pInput != pInput)
158
+    ++m_itCurIn;
159
+
160
+  // send current frame
161
+  curFrame();
162
+}
163
+
164
+/// select lower priority input (called by inputs)
165
+void Priority::selectLower()
166
+{
167
+  stBlinkenFrame *pFrame;
168
+
169
+  // search inputs with lower priority until a frame is found
170
+  while (m_itCurIn != m_inList.rend()) {
171
+    // check for frame
172
+    if (m_itCurIn->m_pInput->getCurFrame(pFrame)) {
173
+      // frame found -> keep this input as current, send frame
174
+      frame(pFrame);
175
+      return;
176
+    }
177
+    // try next input
178
+    ++m_itCurIn;
179
+  }
180
+
181
+  // no input has got a frame -> send no frame
182
+  noFrame();
183
+}
184
+
185
+/// send current frame to output stream
186
+void Priority::curFrame()
187
+{
188
+  stBlinkenFrame *pFrame;
189
+
190
+  // current input available and frame it it available -> send frame
191
+  if (m_itCurIn != m_inList.rend() &&
192
+      m_itCurIn->m_pInput->getCurFrame(pFrame))
193
+    frame(pFrame);
194
+  // no frame available -> send this information
195
+  else
196
+    noFrame();
197
+}
198
+
199
+/**
200
+ * @brief set current frame (also called by inputs)
201
+ * @param[in] pFrame new frame to use
202
+ */
203
+void Priority::frame(stBlinkenFrame *pFrame)
204
+{
205
+  if (m_pOutStream)
206
+    m_pOutStream->setFrame(pFrame);
207
+}
208
+
209
+/// set current frame to "no frame"
210
+void Priority::noFrame()
211
+{
212
+  if (m_pOutStream)
213
+    m_pOutStream->setNoFrame();
214
+}
215
+
216
+/* #####################
217
+   # Priority::InEntry #
218
+   ##################### */
219
+
220
+/// constructor
221
+Priority::InEntry::InEntry(const std::string &name):
222
+  m_name(name),
223
+  m_pInput(NULL)
224
+{
225
+}
226
+
227
+} // namespace Blinker
228
+
... ...
@@ -0,0 +1,112 @@
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 PRIORITY_H
7
+#define PRIORITY_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
+
21
+namespace Blinker {
22
+
23
+/// a priority based stream selector
24
+class Priority: public Module
25
+{
26
+protected:
27
+  /// input to priority based selector
28
+  class Input;
29
+
30
+  /// input list entry
31
+  struct InEntry {
32
+    std::string m_name;    ///< name of input list entry
33
+    Input       *m_pInput; ///< input object
34
+    InEntry(const std::string &name); ///< constructor
35
+  };
36
+
37
+  /// input list
38
+  typedef std::list<InEntry> InList;
39
+
40
+  /// input list iterator
41
+  typedef InList::const_reverse_iterator InListIt;
42
+
43
+public:
44
+  /**
45
+   * @brief constructor
46
+   * @param[in] callMgr callback manager
47
+   * @param[in] streamMgr stream manager
48
+   * @param[in] dirBase base directory
49
+   */
50
+  Priority(CallMgr &callMgr, StreamMgr &streamMgr, const Directory &dirBase);
51
+
52
+  /// virtual destructor
53
+  virtual ~Priority();
54
+
55
+private:
56
+  /// copy constructor disabled
57
+  Priority(const Priority &that);
58
+
59
+  /// assignment operator disabled
60
+  const Priority & operator=(const Priority &that);
61
+
62
+public:
63
+  /// check for update of configuration
64
+  virtual void updateConfig();
65
+
66
+protected:
67
+  /// light update of input list, i.e. check all entries in current input list
68
+  void updateInListLight();
69
+
70
+  /// full update of input list, i.e. scan subdirs in input list directory
71
+  void updateInListFull();
72
+
73
+  /// get output stream
74
+  void getOutStream();
75
+
76
+  /// release output stream
77
+  void releaseOutStream();
78
+
79
+  /**
80
+   * @brief select specific input (called by inputs)
81
+   * @param[in] input input to select
82
+   */
83
+  void select(const Input *pInput);
84
+
85
+  /// select lower priority input (called by inputs)
86
+  void selectLower();
87
+
88
+  /// send current frame to output stream
89
+  void curFrame();
90
+
91
+  /**
92
+   * @brief set current frame (also called by inputs)
93
+   * @param[in] pFrame new frame to use
94
+   */
95
+  void frame(stBlinkenFrame *pFrame);
96
+
97
+  /// set current frame to "no frame"
98
+  void noFrame();
99
+
100
+protected:
101
+  Directory      m_dirInputs;      ///< input stream directory
102
+  SettingFile    m_fileOutStream;  ///< output stream name file
103
+  InList         m_inList;         ///< current input list
104
+  InListIt       m_itCurIn;        ///< current input
105
+  std::string    m_nameOutStream;  ///< name of output stream
106
+  Stream         *m_pOutStream;    ///< output stream
107
+}; // class Priority
108
+
109
+} // namespace Blinker
110
+
111
+#endif // #ifndef PRIORITY_H
112
+
... ...
@@ -0,0 +1,152 @@
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
+#include <string>
7
+
8
+#include <BlinkenLib/BlinkenFrame.h>
9
+
10
+#include "Directory.h"
11
+#include "File.h"
12
+#include "Priority.h"
13
+#include "PriorityInput.h"
14
+#include "SettingFile.h"
15
+#include "StreamMgr.h"
16
+#include "StreamRecv.h"
17
+
18
+namespace Blinker {
19
+
20
+/**
21
+ * @brief constructor
22
+ * @param[in] priority owning priority based selector
23
+ * @param[in] name name of input (i.e. priority)
24
+ * @param[in] dirBase base directory
25
+ */
26
+Priority::Input::Input(Priority &priority, const std::string &name,
27
+                       const Directory &dirBase):
28
+  m_priority(priority),
29
+  m_name(name),
30
+  m_fileInStream(dirBase.getFile("instream")),
31
+  m_pInStream(NULL),
32
+  m_pFrame(NULL)
33
+{
34
+  // attach to input stream
35
+  getInStream();
36
+}
37
+
38
+/// virtual destructor
39
+Priority::Input::~Input()
40
+{
41
+  // detach from input stream and release it
42
+  releaseInStream();
43
+}
44
+
45
+/// check for update of configuration
46
+void Priority::Input::updateConfig()
47
+{
48
+  // input stream name file was modified -> re-get input stream
49
+  if (m_fileInStream.checkModified()) {
50
+    releaseInStream();
51
+    getInStream();
52
+  }
53
+}
54
+
55
+/**
56
+ * @brief set current frame
57
+ * @param[in] stream stream name
58
+ * @param[in] pFrame current frame
59
+ */
60
+void Priority::Input::setFrame(const std::string &stream, stBlinkenFrame *pFrame)
61
+{
62
+  frame(pFrame);
63
+  (void)stream; // unused
64
+}
65
+
66
+/**
67
+ * @brief set current frame to none
68
+ * @param[in] stream stream name
69
+ */
70
+void Priority::Input::setNoFrame(const std::string &stream)
71
+{
72
+  noFrame();
73
+  (void)stream; // unused
74
+}
75
+
76
+/**
77
+ * @brief get current frame
78
+ * @param[out] pFrame current frame
79
+ * @return if a current frame exists
80
+ */
81
+bool Priority::Input::getCurFrame(stBlinkenFrame *&pFrame)
82
+{
83
+  pFrame = m_pFrame;
84
+  return pFrame;
85
+}
86
+
87
+/// get input stream and attach to it
88
+void Priority::Input::getInStream()
89
+{
90
+  // get input stream
91
+  m_fileInStream.getStr(m_nameInStream);
92
+  m_pInStream = &m_priority.m_streamMgr.refStream(m_nameInStream);
93
+
94
+  // attach to input stream
95
+  if (m_pInStream)
96
+    m_pInStream->attach(this);
97
+
98
+  // processing of frame will happen automatically when stream sets frame
99
+}
100
+
101
+/// detach from input stream and release it
102
+void Priority::Input::releaseInStream()
103
+{
104
+  // set current frame to none
105
+  noFrame();
106
+
107
+  // detach from input stream
108
+  if (m_pInStream)
109
+    m_pInStream->detach(this);
110
+
111
+  // unreference stream
112
+  m_pInStream = NULL;
113
+  m_priority.m_streamMgr.unrefStream(m_nameInStream);
114
+}
115
+
116
+/**
117
+ * @brief set current frame
118
+ * @param[in] pFrame current frame
119
+ */
120
+void Priority::Input::frame(stBlinkenFrame *pFrame)
121
+{
122
+  // save new frame
123
+  m_pFrame = pFrame;
124
+
125
+  // if we are current input
126
+  if (m_priority.m_itCurIn != m_priority.m_inList.rend() &&
127
+      m_priority.m_itCurIn->m_pInput == this)
128
+    // pass on frame
129
+    m_priority.frame(pFrame);
130
+
131
+  // we have a higher priority than current input
132
+  if (m_priority.m_itCurIn == m_priority.m_inList.rend() ||
133
+      m_priority.m_itCurIn->m_name < m_name)
134
+    // tell priority based selector to select us as input
135
+    m_priority.select(this);
136
+}
137
+
138
+/// set current frame to none
139
+void Priority::Input::noFrame()
140
+{
141
+  // forget frame
142
+  m_pFrame = NULL;
143
+
144
+  // if we are current input
145
+  if (m_priority.m_itCurIn != m_priority.m_inList.rend() &&
146
+      m_priority.m_itCurIn->m_pInput == this)
147
+    // tell priority based selector to select lower priority input
148
+    m_priority.selectLower();
149
+}
150
+
151
+} // namespace Blinker
152
+
... ...
@@ -0,0 +1,96 @@
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 PRIORITYINPUT_H
7
+#define PRIORITYINPUT_H
8
+
9
+#include <string>
10
+
11
+#include <BlinkenLib/BlinkenFrame.h>
12
+
13
+#include "File.h"
14
+#include "Priority.h"
15
+#include "SettingFile.h"
16
+#include "StreamMgr.h"
17
+#include "StreamRecv.h"
18
+
19
+namespace Blinker {
20
+
21
+/// input to priority based selector
22
+class Priority::Input: public StreamRecv
23
+{
24
+public:
25
+  /**
26
+   * @brief constructor
27
+   * @param[in] priority owning priority based selector
28
+   * @param[in] name name of input (i.e. priority)
29
+   * @param[in] dirBase base directory
30
+   */
31
+  Input(Priority &priority, const std::string &name,
32
+        const Directory &dirBase);
33
+
34
+  /// virtual destructor
35
+  virtual ~Input();
36
+
37
+private:
38
+  /// copy constructor disabled
39
+  Input(const Input &that);
40
+
41
+  /// assignment operator disabled
42
+  const Input & operator=(const Input &that);
43
+
44
+public:
45
+  /// check for update of configuration
46
+  void updateConfig();
47
+
48
+  /**
49
+   * @brief set current frame
50
+   * @param[in] stream stream name
51
+   * @param[in] pFrame current frame
52
+   */
53
+  virtual void setFrame(const std::string &stream, stBlinkenFrame *pFrame);
54
+
55
+  /**
56
+   * @brief set current frame to none
57
+   * @param[in] stream stream name
58
+   */
59
+  virtual void setNoFrame(const std::string &stream);
60
+
61
+  /**
62
+   * @brief get current frame
63
+   * @param[out] pFrame current frame
64
+   * @return if a current frame exists
65
+   */
66
+  bool getCurFrame(stBlinkenFrame *&pFrame);
67
+
68
+protected:
69
+  /// get input stream and attach to it
70
+  void getInStream();
71
+
72
+  /// detach from input stream and release it
73
+  void releaseInStream();
74
+
75
+  /**
76
+   * @brief set current frame
77
+   * @param[in] pFrame current frame
78
+   */
79
+  void frame(stBlinkenFrame *pFrame);
80
+
81
+  /// set current frame to none
82
+  void noFrame();
83
+
84
+protected:
85
+  Priority       &m_priority;    ///< owning priority based selector
86
+  std::string    m_name;         ///< name of input (i.e. priority)
87
+  SettingFile    m_fileInStream; ///< input stream name file
88
+  std::string    m_nameInStream; ///< name of input stream
89
+  Stream         *m_pInStream;   ///< input stream
90
+  stBlinkenFrame *m_pFrame;      ///< current frame
91
+}; // class Priority::Input
92
+
93
+} // namespace Blinker
94
+
95
+#endif // #ifndef PRIORITYINPUT_H
96
+
... ...
@@ -12,6 +12,7 @@
12 12
 #include "ModuleMgr.h"
13 13
 #include "Player.h"
14 14
 #include "Printer.h"
15
+#include "Priority.h"
15 16
 #include "Resizer.h"
16 17
 #include "Scaler.h"
17 18
 #include "StreamMgr.h"
... ...
@@ -32,6 +33,8 @@ void run(const std::string &dirConfig)
32 33
                               dirCfg.getSubdir("players"));
33 34
   ModuleMgr<Printer> printerMgr(callMgr, streamMgr,
34 35
                                 dirCfg.getSubdir("printers"));
36
+  ModuleMgr<Priority> priorityMgr(callMgr, streamMgr,
37
+                                  dirCfg.getSubdir("priorities"));
35 38
   ModuleMgr<Resizer> resizerMgr(callMgr, streamMgr,
36 39
                                 dirCfg.getSubdir("resizers"));
37 40
   ModuleMgr<Scaler> scalersMgr(callMgr, streamMgr,
38 41