• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OpenLightingProject / ola / 24609258679

18 Apr 2026 04:46PM UTC coverage: 44.825% (-0.04%) from 44.864%
24609258679

Pull #1607

github

web-flow
Merge 8f509a535 into c6196f753
Pull Request #1607: Various minor improvements to the example programs

8554 of 19875 branches covered (43.04%)

0 of 49 new or added lines in 3 files covered. (0.0%)

12 existing lines in 4 files now uncovered.

22105 of 49314 relevant lines covered (44.82%)

48.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

37.5
/examples/ola-recorder.cpp
1
/*
2
 * This program is free software; you can redistribute it and/or modify
3
 * it under the terms of the GNU General Public License as published by
4
 * the Free Software Foundation; either version 2 of the License, or
5
 * (at your option) any later version.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU Library General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
15
 *
16
 * ola-recorder.cpp
17
 * A simple tool to record & playback shows.
18
 * Copyright (C) 2011 Simon Newton
19
 */
20

21
#include <ola/Callback.h>
22
#include <ola/DmxBuffer.h>
23
#include <ola/Logging.h>
24
#include <ola/StringUtils.h>
25
#include <ola/base/Flags.h>
26
#include <ola/base/Init.h>
27
#include <ola/base/SysExits.h>
28
#include <signal.h>
29
#include <iostream>
30
#include <map>
31
#include <memory>
32
#include <string>
33
#include <vector>
34

35
#include "examples/ShowPlayer.h"
36
#include "examples/ShowLoader.h"
37
#include "examples/ShowRecorder.h"
38

39
// On MinGW, SignalThread.h pulls in pthread.h which pulls in Windows.h, which
40
// needs to be after WinSock2.h, hence this order
41
#include <ola/thread/SignalThread.h>  // NOLINT(build/include_order)
42

43
using std::auto_ptr;
44
using std::cout;
45
using std::endl;
46
using std::map;
47
using std::vector;
48
using std::string;
49

50
DEFINE_s_string(playback, p, "", "The show file to playback.");
51
DEFINE_s_string(record, r, "", "The show file to record data to.");
52
DEFINE_string(verify, "", "The show file to verify.");
53
DEFINE_default_bool(verify_playback, true,
54
                    "Don't verify show file before playback");
55
DEFINE_s_string(universes, u, "",
56
                "A comma separated list of universes to record");
57
DEFINE_s_uint32(delay, d, 0, "The delay in ms between successive iterations.");
58
DEFINE_uint32(duration, 0, "Total playback time (seconds) to play or record "
59
                           "for; the program will close after this time has "
60
                           "elapsed. This option overrides the iteration "
61
                           "option during playback.");
62
// 0 means infinite looping
63
DEFINE_s_uint32(iterations, i, 1,
64
                "The number of times to repeat the show, 0 means unlimited. "
65
                "The duration option overrides this option.");
66
DEFINE_uint32(start, 0,
67
              "Time (milliseconds) in show file to start playback from.");
68
DEFINE_uint32(stop, 0,
69
              "Time (milliseconds) in show file to stop playback at. If "
70
              "the show file is shorter, the last look will be held until the "
71
              "stop point.");
72

73

74
void TerminateRecorder(ShowRecorder *recorder) {
×
75
  recorder->Stop();
×
76
}
×
77

78

79
/**
80
 * Record a show
81
 */
82
int RecordShow() {
×
83
  if (FLAGS_universes.str().empty()) {
×
84
    OLA_FATAL << "No universes specified, use -u";
×
85
    exit(ola::EXIT_USAGE);
×
86
  }
87

88
  vector<string> universe_strs;
×
89
  vector<unsigned int> universes;
×
90
  ola::StringSplit(FLAGS_universes.str(), &universe_strs, ",");
×
91
  vector<string>::const_iterator iter = universe_strs.begin();
×
92
  for (; iter != universe_strs.end(); ++iter) {
×
93
    unsigned int universe;
×
94
    if (!ola::StringToInt(*iter, &universe)) {
×
95
      OLA_FATAL << *iter << " isn't a valid universe number";
×
96
      exit(ola::EXIT_USAGE);
×
97
    }
98
    universes.push_back(universe);
×
99
  }
100

NEW
101
  ShowRecorder show_recorder(FLAGS_record.str(), universes, FLAGS_duration);
×
102
  int status = show_recorder.Init();
×
103
  if (status)
×
104
    return status;
105

106
  {
×
107
    ola::thread::SignalThread signal_thread;
×
NEW
108
    cout << "Recording, ";
×
NEW
109
    if (FLAGS_duration != 0) {
×
NEW
110
      cout << "will stop automatically after " << FLAGS_duration << "s, or ";
×
111
    }
NEW
112
    cout << "hit Control-C to end" << endl;
×
UNCOV
113
    signal_thread.InstallSignalHandler(
×
114
        SIGINT, ola::NewCallback(TerminateRecorder, &show_recorder));
115
    signal_thread.InstallSignalHandler(
×
116
        SIGTERM, ola::NewCallback(TerminateRecorder, &show_recorder));
117
    if (!signal_thread.Start()) {
×
118
      show_recorder.Stop();
×
119
    }
120
    show_recorder.Record();
×
121
  }
×
122
  cout << "Saved " << show_recorder.FrameCount() << " frames" << endl;
×
123
  return ola::EXIT_OK;
×
124
}
×
125

126

127
/**
128
 * Verify a show file is valid
129
 * @param[in] filename file to check
130
 * @param[out] stream to receive a textual summary of the show
131
 */
132
int VerifyShow(const string &filename, std::ostream *summary) {
5✔
133
  ShowPlayer player(filename);
5✔
134
  int exit_status = player.Init(true);
5✔
135
  if (exit_status != ola::EXIT_OK) {
5✔
136
    // The init process will log any errors it encounters
137
    OLA_FATAL << "Error initializing the player. This is usually because of "
×
138
                 "incorrect command-line arguments or a system error, not "
139
                 "because of data. See any error messages above for details.";
×
140
    return exit_status;
×
141
  }
142
  // The playback simulation process will log any errors it encounters
143
  exit_status = player.Playback(FLAGS_iterations,
5✔
144
                                FLAGS_duration,
145
                                FLAGS_delay,
146
                                FLAGS_start,
147
                                FLAGS_stop);
148

149
  if (exit_status == ola::EXIT_OK) {
5✔
150
    if (summary != NULL) {
5✔
151
      map<unsigned int, uint64_t> frames_by_universe = player.GetFrameCount();
5✔
152
      const uint64_t total_time = player.GetRunTime();
5✔
153
      map<unsigned int, uint64_t>::const_iterator iter;
5✔
154
      uint64_t total = 0;
5✔
155
      *summary << "------------ Summary ----------" << endl;
5✔
156
      if (FLAGS_start > 0) {
5✔
157
        *summary << "Starting at " << FLAGS_start / 1000.0 << " second(s) from "
×
158
                 << "the start of the recording" << endl;
×
159
      }
160
      if (FLAGS_stop > 0) {
5✔
161
        *summary << "Stopping at " << FLAGS_stop / 1000.0 << " second(s) from "
×
162
                 << "the start of the recording" << endl;
×
163
      }
164
      if (FLAGS_delay > 0) {
5✔
165
        *summary << "Waiting " << FLAGS_delay / 1000.0 << " before looping"
×
166
                 << endl;
5✔
167
      }
168
      if (FLAGS_iterations == 0 && FLAGS_duration == 0) {
5✔
169
        // Infinite loop
170
        *summary << "For each iteration:" << endl;
×
171
      } else {
172
        if (FLAGS_iterations > 0) {
5✔
173
          // Defined iterations
174
          *summary << "For all (" << FLAGS_iterations << ") iterations:"
5✔
175
                   << endl;
5✔
176
        }
177
        if (FLAGS_duration > 0) {
5✔
178
          // Defined duration
179
          *summary << "After playing for " << FLAGS_duration << " second(s) "
×
180
                   << "total:" << endl;
×
181
        }
182
      }
183
      for (iter = frames_by_universe.begin(); iter != frames_by_universe.end();
11✔
184
           ++iter) {
6✔
185
        const unsigned int univ_frames = iter->second;
6✔
186
        *summary << "Universe " << iter->first << ": " << univ_frames
6✔
187
                 << " frames" << endl;
6✔
188
        total += univ_frames;
6✔
189
      }
190
      *summary << endl
5✔
191
               << "Total frames: " << total << endl
5✔
192
               << "Total playback time: " << total_time / 1000.0 << " seconds"
5✔
193
               << endl;
5✔
194
    }
5✔
195
    return exit_status;
5✔
196
  } else {
197
    // The ShowPlayer will have printed details about the problem(s), so direct
198
    // the user's attention there.
199
    OLA_FATAL << "Error loading show. See error message above for details.";
×
200
    return exit_status;
×
201
  }
202
}
5✔
203

204

205
/**
206
 * Playback a recorded show
207
 */
208
int PlaybackShow() {
×
209
  const string filename = FLAGS_playback.str();
×
210
  if (FLAGS_verify_playback) {
×
211
    // Verify the show and print a summary before running
212
    std::ostringstream summary;
×
213
    const int verified = VerifyShow(filename, &summary);
×
214
    OLA_INFO << "Verification of " << filename << ":" << endl << summary.str();
×
215
    if (verified != ola::EXIT_OK) {
×
216
      // Show did not pass verification
217
      // The Verify method has already informed the user, so fail with that
218
      // method's result.
219
      return verified;
×
220
    }
221
  }
×
222

223
  // Begin playback
224
  ShowPlayer player(filename);
×
225
  int status = player.Init();
×
226
  if (status == ola::EXIT_OK) {
×
227
    status = player.Playback(FLAGS_iterations,
×
228
                             FLAGS_duration,
229
                             FLAGS_delay,
230
                             FLAGS_start,
231
                             FLAGS_stop);
232
  }
233
  return status;
×
234
}
×
235

236

237
/*
238
 * Main
239
 */
240
int main(int argc, char *argv[]) {
5✔
241
  ola::AppInit(&argc, argv,
10✔
242
               "[--record <file> --universes <universe_list>] [--playback "
243
               "<file>] [--verify <file>]",
244
               "Record a series of universes, or playback a previously "
245
               "recorded show.");
246

247
  if (FLAGS_stop > 0 && FLAGS_stop < FLAGS_start) {
5✔
248
    OLA_FATAL << "Stop time must be later than start time.";
×
249
    return ola::EXIT_USAGE;
×
250
  }
251

252
  if (!FLAGS_playback.str().empty()) {
5✔
253
    return PlaybackShow();
×
254
  } else if (!FLAGS_record.str().empty()) {
5✔
255
    return RecordShow();
×
256
  } else if (!FLAGS_verify.str().empty()) {
5✔
257
    const int verified = VerifyShow(FLAGS_verify.str(), &cout);
5✔
258
    return verified;
5✔
259
  } else {
260
    OLA_FATAL << "One of --record or --playback or --verify must be provided";
×
261
    ola::DisplayUsage();
×
262
  }
263
  return ola::EXIT_OK;
×
264
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc