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

OpenLightingProject / ola / 16911433572

12 Aug 2025 02:08PM UTC coverage: 45.869% (-0.04%) from 45.909%
16911433572

Pull #1739

github

web-flow
Merge 02faeaa2d into 3566c28d9
Pull Request #1739: New web UI, store highest channel number used

7157 of 16316 branches covered (43.86%)

20915 of 45597 relevant lines covered (45.87%)

52.03 hits per line

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

80.85
/plugins/osc/OSCPlugin.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
 * OSCPlugin.cpp
17
 * The OSC plugin for ola. This creates a single OSC device.
18
 * Copyright (C) 2012 Simon Newton
19
 */
20

21
#define __STDC_LIMIT_MACROS  // for UINT8_MAX & friends
22
#include <stdint.h>
23
#include <stdlib.h>
24
#include <stdio.h>
25
#include <memory>
26
#include <set>
27
#include <string>
28
#include <vector>
29

30
#include "ola/StringUtils.h"
31
#include "olad/PluginAdaptor.h"
32
#include "olad/Preferences.h"
33
#include "plugins/osc/OSCAddressTemplate.h"
34
#include "plugins/osc/OSCDevice.h"
35
#include "plugins/osc/OSCPlugin.h"
36

37
namespace ola {
38
namespace plugin {
39
namespace osc {
40

41
using ola::network::IPV4SocketAddress;
42
using std::set;
43
using std::string;
44
using std::vector;
45

46
const char OSCPlugin::DEFAULT_ADDRESS_TEMPLATE[] = "/dmx/universe/%d";
47
const char OSCPlugin::DEFAULT_TARGETS_TEMPLATE[] = "";
48
const char OSCPlugin::INPUT_PORT_COUNT_KEY[] = "input_ports";
49
const char OSCPlugin::OUTPUT_PORT_COUNT_KEY[] = "output_ports";
50
const char OSCPlugin::PLUGIN_NAME[] = "OSC";
51
const char OSCPlugin::PLUGIN_PREFIX[] = "osc";
52
const char OSCPlugin::PORT_ADDRESS_TEMPLATE[] = "port_%d_address";
53
const char OSCPlugin::PORT_TARGETS_TEMPLATE[] = "port_%d_targets";
54
const char OSCPlugin::PORT_FORMAT_TEMPLATE[] = "port_%d_output_format";
55
const char OSCPlugin::UDP_PORT_KEY[] = "udp_listen_port";
56

57
const char OSCPlugin::BLOB_FORMAT[] = "blob";
58
const char OSCPlugin::FLOAT_ARRAY_FORMAT[] = "float_array";
59
const char OSCPlugin::FLOAT_INDIVIDUAL_FORMAT[] = "individual_float";
60
const char OSCPlugin::INT_ARRAY_FORMAT[] = "int_array";
61
const char OSCPlugin::INT_INDIVIDUAL_FORMAT[] = "individual_int";
62

63
/*
64
 * Start the plugin.
65
 */
66
bool OSCPlugin::StartHook() {
1✔
67
  // Get the value of UDP_PORT_KEY or use the default value if it isn't valid.
68
  uint16_t udp_port = StringToIntOrDefault(
1✔
69
      m_preferences->GetValue(UDP_PORT_KEY),
2✔
70
      DEFAULT_UDP_PORT);
71

72
  // For each input port, add the address to the vector
73
  vector<string> port_addresses;
1✔
74
  for (unsigned int i = 0; i < GetPortCount(INPUT_PORT_COUNT_KEY); i++) {
6✔
75
    const string key = ExpandTemplate(PORT_ADDRESS_TEMPLATE, i);
5✔
76
    port_addresses.push_back(m_preferences->GetValue(key));
10✔
77
  }
5✔
78

79
  // For each output port, extract the list of OSCTargets and store them in
80
  // port_targets.
81
  OSCDevice::PortConfigs port_configs;
1✔
82
  for (unsigned int i = 0; i < GetPortCount(OUTPUT_PORT_COUNT_KEY); i++) {
6✔
83
    OSCDevice::PortConfig port_config;
5✔
84

85
    const string format_key = ExpandTemplate(PORT_FORMAT_TEMPLATE, i);
5✔
86
    SetDataFormat(m_preferences->GetValue(format_key), &port_config);
5✔
87

88
    const string key = ExpandTemplate(PORT_TARGETS_TEMPLATE, i);
5✔
89
    vector<string> tokens;
5✔
90
    StringSplit(m_preferences->GetValue(key), &tokens, ",");
10✔
91

92
    vector<string>::const_iterator iter = tokens.begin();
5✔
93
    for (; iter != tokens.end(); ++iter) {
10✔
94
      OSCTarget target;
5✔
95
      if (ExtractOSCTarget(*iter, &target)) {
5✔
96
        port_config.targets.push_back(target);
×
97
      }
98
    }
5✔
99

100
    port_configs.push_back(port_config);
5✔
101
  }
5✔
102

103
  // Finally create the new OSCDevice, start it and register the device.
104
  std::auto_ptr<OSCDevice> device(
1✔
105
    new OSCDevice(this, m_plugin_adaptor, udp_port, port_addresses,
106
                  port_configs));
1✔
107
  if (!device->Start()) {
1✔
108
    return false;
109
  }
110
  m_device = device.release();
1✔
111
  m_plugin_adaptor->RegisterDevice(m_device);
1✔
112
  return true;
113
}
1✔
114

115

116
/*
117
 * Stop the plugin
118
 * @return true on success, false on failure
119
 */
120
bool OSCPlugin::StopHook() {
1✔
121
  if (m_device) {
1✔
122
    m_plugin_adaptor->UnregisterDevice(m_device);
1✔
123
    bool ret = m_device->Stop();
1✔
124
    delete m_device;
1✔
125
    return ret;
1✔
126
  }
127
  return true;
128
}
129

130

131
string OSCPlugin::Description() const {
×
132
  return
×
133
"OSC (Open Sound Control) Plugin\n"
×
134
"--------------------------------\n"
135
"\n"
136
"This plugin allows OLA to send and receive OSC\n"
137
"( https://opensoundcontrol.stanford.edu/ ) messages.\n"
138
"\n"
139
"OLA uses the blob type for transporting DMX data.\n"
140
"\n"
141
"--- Config file : ola-osc.conf ---\n"
142
"\n"
143
"input_ports = <int>\n"
144
"The number of input ports to create.\n"
145
"\n"
146
"output_ports = <int>\n"
147
"The number of output ports to create.\n"
148
"\n"
149
"udp_listen_port = <int>\n"
150
"The UDP Port to listen on for OSC messages.\n"
151
"\n"
152
"port_N_address = /address\n"
153
"The OSC address to listen on for port N. If the address contains %d\n"
154
"it's replaced by the universe number for port N.\n"
155
"\n"
156
"port_N_targets = ip:port/address,ip:port/address,...\n"
157
"For output port N, the list of targets to send OSC messages to. If the\n"
158
"targets contain %d it's replaced by the universe number for port N\n"
159
"\n"
160
"port_N_output_format = \n"
161
"    [blob|float_array,individual_float,individual_int,int_array]\n"
162
"The format (OSC Type) to send the DMX data in:\n"
163
" - blob: a OSC-blob\n"
164
" - float_array: an array of float values. 0.0 - 1.0\n"
165
" - individual_float: one float message for each slot (channel). 0.0 - 1.0 \n"
166
" - individual_int: one int message for each slot (channel). 0 - 255.\n"
167
" - int_array: an array of int values. 0 - 255.\n"
168
"\n";
×
169
}
170

171

172
/**
173
 * Set the default preferences for the OSC plugin.
174
 */
175
bool OSCPlugin::SetDefaultPreferences() {
1✔
176
  if (!m_preferences) {
1✔
177
    return false;
178
  }
179

180
  bool save = false;
1✔
181

182
  save |= m_preferences->SetDefaultValue(INPUT_PORT_COUNT_KEY,
1✔
183
                                         UIntValidator(0, 32),
1✔
184
                                         DEFAULT_PORT_COUNT);
185

186
  save |= m_preferences->SetDefaultValue(OUTPUT_PORT_COUNT_KEY,
1✔
187
                                         UIntValidator(0, 32),
1✔
188
                                         DEFAULT_PORT_COUNT);
189

190
  save |= m_preferences->SetDefaultValue(UDP_PORT_KEY,
1✔
191
                                         UIntValidator(1, UINT16_MAX),
1✔
192
                                         DEFAULT_UDP_PORT);
193

194
  for (unsigned int i = 0; i < GetPortCount(INPUT_PORT_COUNT_KEY); i++) {
6✔
195
    const string key = ExpandTemplate(PORT_ADDRESS_TEMPLATE, i);
5✔
196
    save |= m_preferences->SetDefaultValue(key, StringValidator(),
5✔
197
                                           DEFAULT_ADDRESS_TEMPLATE);
198
  }
5✔
199

200
  set<string> valid_formats;
1✔
201
  valid_formats.insert(BLOB_FORMAT);
1✔
202
  valid_formats.insert(FLOAT_ARRAY_FORMAT);
1✔
203
  valid_formats.insert(FLOAT_INDIVIDUAL_FORMAT);
1✔
204
  valid_formats.insert(INT_ARRAY_FORMAT);
1✔
205
  valid_formats.insert(INT_INDIVIDUAL_FORMAT);
1✔
206

207
  SetValidator<string> format_validator = SetValidator<string>(valid_formats);
1✔
208

209
  for (unsigned int i = 0; i < GetPortCount(OUTPUT_PORT_COUNT_KEY); i++) {
6✔
210
    save |= m_preferences->SetDefaultValue(
10✔
211
        ExpandTemplate(PORT_TARGETS_TEMPLATE, i),
10✔
212
        StringValidator(true),
5✔
213
        DEFAULT_TARGETS_TEMPLATE);
214

215
    save |= m_preferences->SetDefaultValue(
10✔
216
        ExpandTemplate(PORT_FORMAT_TEMPLATE, i),
10✔
217
        format_validator,
218
        BLOB_FORMAT);
219
  }
220

221
  if (save) {
1✔
222
    m_preferences->Save();
1✔
223
  }
224

225
  return true;
1✔
226
}
1✔
227

228

229
/**
230
 * @brief Given a key, return the port count from the preferences.
231
 *
232
 * Defaults to DEFAULT_PORT_COUNT if the value was invalid.
233
 */
234
unsigned int OSCPlugin::GetPortCount(const string& key) const {
24✔
235
  unsigned int port_count;
24✔
236
  if (!StringToInt(m_preferences->GetValue(key), &port_count)) {
24✔
237
    return DEFAULT_PORT_COUNT;
238
  }
239
  return port_count;
24✔
240
}
241

242

243
/**
244
 * Try to parse the string as an OSC Target.
245
 */
246
bool OSCPlugin::ExtractOSCTarget(const string &str,
5✔
247
                                 OSCTarget *target) {
248
  size_t pos = str.find_first_of("/");
5✔
249
  if (pos == string::npos) {
5✔
250
    return false;
251
  }
252

253
  if (!IPV4SocketAddress::FromString(str.substr(0, pos),
×
254
                                     &target->socket_address)) {
255
    return false;
256
  }
257
  target->osc_address = str.substr(pos);
×
258
  return true;
×
259
}
260

261

262
/**
263
 * Set the PortConfig data format based on the option the user provides
264
 */
265
void OSCPlugin::SetDataFormat(const string &format_option,
5✔
266
                              OSCDevice::PortConfig *port_config) {
267
  if (format_option == BLOB_FORMAT) {
5✔
268
    port_config->data_format = OSCNode::FORMAT_BLOB;
5✔
269
  } else if (format_option == FLOAT_ARRAY_FORMAT) {
×
270
    port_config->data_format = OSCNode::FORMAT_FLOAT_ARRAY;
×
271
  } else if (format_option == FLOAT_INDIVIDUAL_FORMAT) {
×
272
    port_config->data_format = OSCNode::FORMAT_FLOAT_INDIVIDUAL;
×
273
  } else if (format_option == INT_ARRAY_FORMAT) {
×
274
    port_config->data_format = OSCNode::FORMAT_INT_ARRAY;
×
275
  } else if (format_option == INT_INDIVIDUAL_FORMAT) {
×
276
    port_config->data_format = OSCNode::FORMAT_INT_INDIVIDUAL;
×
277
  } else {
278
    OLA_WARN << "Unknown OSC format " << format_option
×
279
             << ", defaulting to blob";
×
280
  }
281
}
5✔
282
}  // namespace osc
283
}  // namespace plugin
284
}  // namespace ola
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

© 2025 Coveralls, Inc