sACN  2.0.2
Implementation of ANSI E1.31 (Streaming ACN)
View other versions:
merge_receiver.h
Go to the documentation of this file.
1 /******************************************************************************
2  * Copyright 2022 ETC Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  ******************************************************************************
16  * This file is a part of sACN. For more information, go to:
17  * https://github.com/ETCLabs/sACN
18  *****************************************************************************/
19 
20 #ifndef SACN_CPP_MERGE_RECEIVER_H_
21 #define SACN_CPP_MERGE_RECEIVER_H_
22 
28 #include "sacn/cpp/common.h"
29 
30 #include "sacn/merge_receiver.h"
31 #include "etcpal/cpp/inet.h"
32 #include "etcpal/cpp/opaque_id.h"
33 #include "etcpal/cpp/uuid.h"
34 
41 namespace sacn
42 {
43 
44 namespace detail
45 {
47 {
48 };
49 }; // namespace detail
50 
61 {
62 public:
65 
71  {
72  public:
73  virtual ~NotifyHandler() = default;
74 
94  virtual void HandleMergedData(Handle handle, const SacnRecvMergedData& merged_data) = 0;
95 
115  virtual void HandleNonDmxData(Handle receiver_handle, const etcpal::SockAddr& source_addr,
116  const SacnRemoteSource& source_info, const SacnRecvUniverseData& universe_data) = 0;
117 
127  virtual void HandleSourceLimitExceeded(Handle handle, uint16_t universe)
128  {
129  ETCPAL_UNUSED_ARG(handle);
130  ETCPAL_UNUSED_ARG(universe);
131  }
132  };
133 
138  struct Settings
139  {
140  /********* Required values **********/
141 
143  uint16_t universe_id{0};
144 
145  /********* Optional values **********/
146 
149 
152 
157  bool use_pap{true};
158 
161 
163  Settings() = default;
164 
168  Settings(uint16_t new_universe_id);
169 
170  bool IsValid() const;
171  };
172 
177  struct NetintList
178  {
181 
185 
187  NetintList() = default;
188  NetintList(sacn_merge_receiver_t merge_receiver_handle);
189  };
190 
195  struct Source
196  {
205  };
206 
207  MergeReceiver() = default;
208  MergeReceiver(const MergeReceiver& other) = delete;
209  MergeReceiver& operator=(const MergeReceiver& other) = delete;
210  MergeReceiver(MergeReceiver&& other) = default;
211  MergeReceiver& operator=(MergeReceiver&& other) = default;
213  etcpal::Error Startup(const Settings& settings, NotifyHandler& notify_handler);
214  etcpal::Error Startup(const Settings& settings, NotifyHandler& notify_handler,
216  void Shutdown();
219  etcpal::Error ChangeUniverse(uint16_t new_universe_id);
221  etcpal::Error ChangeUniverseAndFootprint(uint16_t new_universe_id, const SacnRecvUniverseSubrange& new_footprint);
224 
228  std::vector<NetintList>& netint_lists);
229 
230  constexpr Handle handle() const;
231 
232 private:
233  SacnMergeReceiverConfig TranslateConfig(const Settings& settings, NotifyHandler& notify_handler);
234 
235  Handle handle_;
236 };
237 
242 namespace internal
243 {
244 extern "C" inline void MergeReceiverCbMergedData(sacn_merge_receiver_t handle, const SacnRecvMergedData* merged_data,
245  void* context)
246 {
247  if (context && merged_data)
248  {
249  static_cast<MergeReceiver::NotifyHandler*>(context)->HandleMergedData(MergeReceiver::Handle(handle), *merged_data);
250  }
251 }
252 
253 extern "C" inline void MergeReceiverCbNonDmx(sacn_merge_receiver_t receiver_handle, const EtcPalSockAddr* source_addr,
254  const SacnRemoteSource* source_info,
255  const SacnRecvUniverseData* universe_data, void* context)
256 {
257  if (context && source_addr && source_info && universe_data)
258  {
259  static_cast<MergeReceiver::NotifyHandler*>(context)->HandleNonDmxData(MergeReceiver::Handle(receiver_handle),
260  *source_addr, *source_info, *universe_data);
261  }
262 }
263 
264 extern "C" inline void MergeReceiverCbSourceLimitExceeded(sacn_merge_receiver_t handle, uint16_t universe,
265  void* context)
266 {
267  if (context)
268  {
269  static_cast<MergeReceiver::NotifyHandler*>(context)->HandleSourceLimitExceeded(MergeReceiver::Handle(handle),
270  universe);
271  }
272 }
273 
274 }; // namespace internal
275 
285 inline MergeReceiver::Settings::Settings(uint16_t new_universe_id) : universe_id(new_universe_id)
286 {
287 }
288 
291 {
292  return (universe_id > 0) && (footprint.start_address >= 1) && (footprint.start_address <= DMX_ADDRESS_COUNT) &&
293  (footprint.address_count >= 1) &&
294  (footprint.address_count <= (DMX_ADDRESS_COUNT - footprint.start_address + 1));
295 }
296 
303  : handle(merge_receiver_handle)
304 {
305 }
306 
329 inline etcpal::Error MergeReceiver::Startup(const Settings& settings, NotifyHandler& notify_handler)
330 {
332  return Startup(settings, notify_handler, netints);
333 }
334 
357 inline etcpal::Error MergeReceiver::Startup(const Settings& settings, NotifyHandler& notify_handler,
359 {
360  SacnMergeReceiverConfig config = TranslateConfig(settings, notify_handler);
361 
363  etcpal::Error result = kEtcPalErrOk;
364 
365  if (netints.empty())
366  {
367  result = sacn_merge_receiver_create(&config, &c_handle, NULL);
368  }
369  else
370  {
371  SacnNetintConfig netint_config = {netints.data(), netints.size()};
372  result = sacn_merge_receiver_create(&config, &c_handle, &netint_config);
373  }
374 
375  handle_.SetValue(c_handle);
376 
377  return result;
378 }
379 
387 {
389  handle_.Clear();
390 }
391 
398 {
399  uint16_t result = 0;
400  etcpal_error_t err = sacn_merge_receiver_get_universe(handle_.value(), &result);
401  if (err == kEtcPalErrOk)
402  return result;
403  else
404  return err;
405 }
406 
415 {
417  etcpal_error_t err = sacn_merge_receiver_get_footprint(handle_.value(), &result);
418  if (err == kEtcPalErrOk)
419  return result;
420  else
421  return err;
422 }
423 
439 inline etcpal::Error MergeReceiver::ChangeUniverse(uint16_t new_universe_id)
440 {
441  return sacn_merge_receiver_change_universe(handle_.value(), new_universe_id);
442 }
443 
454 {
455  return sacn_merge_receiver_change_footprint(handle_.value(), &new_footprint);
456 }
457 
469  const SacnRecvUniverseSubrange& new_footprint)
470 {
471  return sacn_merge_receiver_change_universe_and_footprint(handle_.value(), new_universe_id, &new_footprint);
472 }
473 
480 {
481  // This uses a guessing algorithm with a while loop to avoid race conditions.
483  size_t size_guess = 4u;
484  size_t num_netints = 0u;
485 
486  do
487  {
488  netints.resize(size_guess);
489  num_netints = sacn_merge_receiver_get_network_interfaces(handle_.value(), netints.data(), netints.size());
490  size_guess = num_netints + 4u;
491  } while (num_netints > netints.size());
492 
493  netints.resize(num_netints);
494  return netints;
495 }
496 
508 {
510  etcpal_error_t error = sacn_merge_receiver_get_source(handle_.value(), source_handle, &c_info);
511  if (error == kEtcPalErrOk)
512  {
514  res.handle = c_info.handle;
515  res.cid = c_info.cid;
516  res.name = c_info.name;
517  res.addr = c_info.addr;
518  return res;
519  }
520 
521  return error;
522 }
523 
547 {
549  return ResetNetworking(netints);
550 }
551 
576 {
577  if (sys_netints.empty())
578  return sacn_merge_receiver_reset_networking(nullptr);
579 
580  SacnNetintConfig netint_config = {sys_netints.data(), sys_netints.size()};
581  return sacn_merge_receiver_reset_networking(&netint_config);
582 }
583 
614  std::vector<NetintList>& per_receiver_netint_lists)
615 {
617  netint_lists_c.reserve(per_receiver_netint_lists.size());
618  std::transform(per_receiver_netint_lists.begin(), per_receiver_netint_lists.end(), std::back_inserter(netint_lists_c),
619  [](NetintList& list) {
620  // clang-format off
621  SacnMergeReceiverNetintList c_list = {
622  list.handle,
623  list.netints.data(),
624  list.netints.size()
625  };
626  // clang-format on
627 
628  return c_list;
629  });
630 
631  SacnNetintConfig netint_config = {sys_netints.data(), sys_netints.size()};
632  return sacn_merge_receiver_reset_networking_per_receiver(&netint_config, netint_lists_c.data(),
633  netint_lists_c.size());
634 }
635 
642 {
643  return handle_;
644 }
645 
646 inline SacnMergeReceiverConfig MergeReceiver::TranslateConfig(const Settings& settings, NotifyHandler& notify_handler)
647 {
648  // clang-format off
649  SacnMergeReceiverConfig config = {
650  settings.universe_id,
651  {
652  internal::MergeReceiverCbMergedData,
653  internal::MergeReceiverCbNonDmx,
654  internal::MergeReceiverCbSourceLimitExceeded,
655  &notify_handler
656  },
657  settings.footprint,
658  settings.source_count_max,
659  settings.use_pap,
660  settings.ip_supported
661  };
662  // clang-format on
663 
664  return config;
665 }
666 
667 }; // namespace sacn
668 
669 #endif // SACN_CPP_MERGE_RECEIVER_H_
T back_inserter(T... args)
T begin(T... args)
ETCPAL_CONSTEXPR_14 void Clear()
ETCPAL_CONSTEXPR_14 void SetValue(const ValueType &new_value)
constexpr ValueType value() const
A base class for a class that receives notification callbacks from a sACN merge receiver.
Definition: merge_receiver.h:71
virtual void HandleMergedData(Handle handle, const SacnRecvMergedData &merged_data)=0
Notify that a new data packet has been received and merged.
virtual void HandleSourceLimitExceeded(Handle handle, uint16_t universe)
Notify that more than the configured maximum number of sources are currently sending on the universe ...
Definition: merge_receiver.h:127
virtual void HandleNonDmxData(Handle receiver_handle, const etcpal::SockAddr &source_addr, const SacnRemoteSource &source_info, const SacnRecvUniverseData &universe_data)=0
Notify that a non-data packet has been received.
An instance of sACN Merge Receiver functionality; see Using the sACN Merge Receiver API.
Definition: merge_receiver.h:61
static etcpal::Error ResetNetworking()
Resets the underlying network sockets and packet receipt state for all sACN merge receivers.
Definition: merge_receiver.h:546
std::vector< EtcPalMcastNetintId > GetNetworkInterfaces()
Obtain a vector of this merge receiver's network interfaces.
Definition: merge_receiver.h:479
etcpal::Expected< uint16_t > GetUniverse() const
Get the universe this merge receiver is listening to.
Definition: merge_receiver.h:397
etcpal::OpaqueId< detail::MergeReceiverHandleType, sacn_merge_receiver_t, SACN_MERGE_RECEIVER_INVALID > Handle
Definition: merge_receiver.h:64
etcpal::Error ChangeFootprint(const SacnRecvUniverseSubrange &new_footprint)
Change the footprint within the universe this merge receiver is listening to. TODO: Not yet implement...
Definition: merge_receiver.h:453
MergeReceiver & operator=(MergeReceiver &&other)=default
constexpr Handle handle() const
Get the current handle to the underlying C merge receiver.
Definition: merge_receiver.h:641
etcpal::Error ChangeUniverse(uint16_t new_universe_id)
Change the universe this class is listening to.
Definition: merge_receiver.h:439
etcpal::Expected< SacnRecvUniverseSubrange > GetFootprint() const
Get the footprint within the universe this merge receiver is listening to.
Definition: merge_receiver.h:414
etcpal::Expected< Source > GetSource(sacn_remote_source_t source_handle)
Gets a copy of the information for the specified merge receiver source.
Definition: merge_receiver.h:507
etcpal::Error Startup(const Settings &settings, NotifyHandler &notify_handler)
Start listening for sACN data on a universe.
Definition: merge_receiver.h:329
etcpal::Error ChangeUniverseAndFootprint(uint16_t new_universe_id, const SacnRecvUniverseSubrange &new_footprint)
Change the universe and footprint this merge receiver is listening to. TODO: Not yet implemented.
Definition: merge_receiver.h:468
void Shutdown()
Stop listening for sACN data on a universe.
Definition: merge_receiver.h:386
MergeReceiver(MergeReceiver &&other)=default
Definition: merge_receiver.h:47
C++ wrapper for the sACN init/deinit functions.
T data(T... args)
T empty(T... args)
T end(T... args)
etcpal_error_t
kEtcPalErrOk
sacn_ip_support_t
Definition: common.h:71
uint16_t sacn_remote_source_t
Definition: common.h:58
#define DMX_ADDRESS_COUNT
Definition: common.h:55
@ kSacnIpV4AndIpV6
Definition: common.h:77
etcpal_error_t sacn_merge_receiver_reset_networking(const SacnNetintConfig *sys_netint_config)
Resets underlying network sockets and packet receipt state, determines network interfaces for all mer...
Definition: merge_receiver.c:376
size_t sacn_merge_receiver_get_network_interfaces(sacn_merge_receiver_t handle, EtcPalMcastNetintId *netints, size_t netints_size)
Obtain a list of a merge receiver's network interfaces.
Definition: merge_receiver.c:472
etcpal_error_t sacn_merge_receiver_destroy(sacn_merge_receiver_t handle)
Destroy a sACN Merge Receiver instance.
Definition: merge_receiver.c:182
etcpal_error_t sacn_merge_receiver_change_footprint(sacn_merge_receiver_t handle, const SacnRecvUniverseSubrange *new_footprint)
Change the footprint within the universe on which an sACN receiver is listening. TODO: Not yet implem...
Definition: merge_receiver.c:322
etcpal_error_t sacn_merge_receiver_reset_networking_per_receiver(const SacnNetintConfig *sys_netint_config, const SacnMergeReceiverNetintList *per_receiver_netint_lists, size_t num_per_receiver_netint_lists)
Resets underlying network sockets and packet receipt state, determines network interfaces for each me...
Definition: merge_receiver.c:413
etcpal_error_t sacn_merge_receiver_get_footprint(sacn_merge_receiver_t handle, SacnRecvUniverseSubrange *footprint)
Get the footprint within the universe on which a sACN Merge Receiver is currently listening.
Definition: merge_receiver.c:245
etcpal_error_t sacn_merge_receiver_get_universe(sacn_merge_receiver_t handle, uint16_t *universe_id)
Get the universe on which a sACN Merge Receiver is currently listening.
Definition: merge_receiver.c:226
etcpal_error_t sacn_merge_receiver_get_source(sacn_merge_receiver_t merge_receiver_handle, sacn_remote_source_t source_handle, SacnMergeReceiverSource *source_info)
Gets a copy of the information for the specified merge receiver source.
Definition: merge_receiver.c:491
etcpal_error_t sacn_merge_receiver_change_universe(sacn_merge_receiver_t handle, uint16_t new_universe_id)
Change the universe on which a sACN Merge Receiver is listening.
Definition: merge_receiver.c:268
etcpal_error_t sacn_merge_receiver_create(const SacnMergeReceiverConfig *config, sacn_merge_receiver_t *handle, const SacnNetintConfig *netint_config)
Create a new sACN Merge Receiver to listen and merge sACN data on a universe.
Definition: merge_receiver.c:88
etcpal_error_t sacn_merge_receiver_change_universe_and_footprint(sacn_merge_receiver_t handle, uint16_t new_universe_id, const SacnRecvUniverseSubrange *new_footprint)
Change the universe and footprint on which an sACN merge receiver is listening. TODO: Not yet impleme...
Definition: merge_receiver.c:342
int sacn_merge_receiver_t
Definition: merge_receiver.h:53
#define SACN_MERGE_RECEIVER_INVALID
Definition: merge_receiver.h:55
#define SACN_RECEIVER_INFINITE_SOURCES
Constant for "infinite" when listening or merging sACN universes.
Definition: receiver.h:68
sACN Merge Receiver API definitions
A namespace which contains all C++ language definitions in the sACN library.
Definition: common.h:50
T reserve(T... args)
T resize(T... args)
T size(T... args)
Definition: merge_receiver.h:158
uint16_t universe_id
Definition: merge_receiver.h:162
Definition: merge_receiver.h:206
EtcPalUuid cid
Definition: merge_receiver.h:210
EtcPalSockAddr addr
Definition: merge_receiver.h:214
char name[SACN_SOURCE_NAME_MAX_LEN]
Definition: merge_receiver.h:212
sacn_remote_source_t handle
Definition: merge_receiver.h:208
Definition: common.h:102
Definition: merge_receiver.h:61
Definition: receiver.h:89
Definition: receiver.h:80
Definition: receiver.h:124
A set of network interfaces for a particular merge receiver.
Definition: merge_receiver.h:178
std::vector< SacnMcastInterface > netints
Definition: merge_receiver.h:184
sacn_merge_receiver_t handle
Definition: merge_receiver.h:180
A set of configuration settings that a merge receiver needs to initialize.
Definition: merge_receiver.h:139
SacnRecvUniverseSubrange footprint
Definition: merge_receiver.h:148
uint16_t universe_id
Definition: merge_receiver.h:143
int source_count_max
Definition: merge_receiver.h:151
sacn_ip_support_t ip_supported
Definition: merge_receiver.h:160
bool IsValid() const
Definition: merge_receiver.h:290
bool use_pap
Definition: merge_receiver.h:157
Information about a remote sACN source being tracked by a merge receiver.
Definition: merge_receiver.h:196
etcpal::SockAddr addr
Definition: merge_receiver.h:204
std::string name
Definition: merge_receiver.h:202
etcpal::Uuid cid
Definition: merge_receiver.h:200
sacn_remote_source_t handle
Definition: merge_receiver.h:198
T transform(T... args)