sACN  3.0.0
Implementation of ANSI E1.31 (Streaming ACN)
View other versions:
Loading...
Searching...
No Matches
merge_receiver.h
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright 2024 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"
33#include "etcpal/cpp/uuid.h"
34
41namespace sacn
42{
43
44namespace detail
45{
49}; // namespace detail
50
61{
62public:
65
71 {
72 public:
73 virtual ~NotifyHandler() = default;
74
98 virtual void HandleMergedData(Handle handle, const SacnRecvMergedData& merged_data) = 0;
99
119 virtual void HandleNonDmxData(Handle receiver_handle, const etcpal::SockAddr& source_addr,
120 const SacnRemoteSource& source_info, const SacnRecvUniverseData& universe_data)
121 {
122 ETCPAL_UNUSED_ARG(receiver_handle);
123 ETCPAL_UNUSED_ARG(source_addr);
124 ETCPAL_UNUSED_ARG(source_info);
125 ETCPAL_UNUSED_ARG(universe_data);
126 }
127
134 virtual void HandleSourcesLost(Handle handle, uint16_t universe, const std::vector<SacnLostSource>& lost_sources)
135 {
136 ETCPAL_UNUSED_ARG(handle);
137 ETCPAL_UNUSED_ARG(universe);
138 ETCPAL_UNUSED_ARG(lost_sources);
139 }
140
150 virtual void HandleSamplingPeriodStarted(Handle handle, uint16_t universe)
151 {
152 ETCPAL_UNUSED_ARG(handle);
153 ETCPAL_UNUSED_ARG(universe);
154 }
155
170 virtual void HandleSamplingPeriodEnded(Handle handle, uint16_t universe)
171 {
172 ETCPAL_UNUSED_ARG(handle);
173 ETCPAL_UNUSED_ARG(universe);
174 }
175
182 virtual void HandleSourcePapLost(Handle handle, uint16_t universe, const SacnRemoteSource& source)
183 {
184 ETCPAL_UNUSED_ARG(handle);
185 ETCPAL_UNUSED_ARG(universe);
186 ETCPAL_UNUSED_ARG(source);
187 }
188
198 virtual void HandleSourceLimitExceeded(Handle handle, uint16_t universe)
199 {
200 ETCPAL_UNUSED_ARG(handle);
201 ETCPAL_UNUSED_ARG(universe);
202 }
203 };
204
209 struct Settings
210 {
211 /********* Required values **********/
212
214 uint16_t universe_id{0};
215
216 /********* Optional values **********/
217
220
223
228 bool use_pap{true};
229
232
234 Settings() = default;
235
239 Settings(uint16_t new_universe_id);
240
241 bool IsValid() const;
242 };
243
249 {
252
256
258 bool no_netints{false};
259
261 NetintList() = default;
262 NetintList(sacn_merge_receiver_t merge_receiver_handle, McastMode mcast_mode);
263 NetintList(sacn_merge_receiver_t merge_receiver_handle, const std::vector<SacnMcastInterface>& network_interfaces);
264 };
265
285
286 MergeReceiver() = default;
287 MergeReceiver(const MergeReceiver& other) = delete;
288 MergeReceiver& operator=(const MergeReceiver& other) = delete;
289 MergeReceiver(MergeReceiver&& other) = default;
292 etcpal::Error Startup(const Settings& settings, NotifyHandler& notify_handler, McastMode mcast_mode);
293 etcpal::Error Startup(const Settings& settings, NotifyHandler& notify_handler,
295 void Shutdown();
298 etcpal::Error ChangeUniverse(uint16_t new_universe_id);
300 etcpal::Error ChangeUniverseAndFootprint(uint16_t new_universe_id, const SacnRecvUniverseSubrange& new_footprint);
303
304 static etcpal::Error ResetNetworking(McastMode mcast_mode);
307 std::vector<NetintList>& netint_lists);
308
309 constexpr Handle handle() const;
310
311private:
312 SacnMergeReceiverConfig TranslateConfig(const Settings& settings, NotifyHandler& notify_handler);
313
314 Handle handle_;
315};
316
321namespace internal
322{
323extern "C" inline void MergeReceiverCbMergedData(sacn_merge_receiver_t handle, const SacnRecvMergedData* merged_data,
324 void* context)
325{
326 if (context && merged_data)
327 {
328 static_cast<MergeReceiver::NotifyHandler*>(context)->HandleMergedData(MergeReceiver::Handle(handle), *merged_data);
329 }
330}
331
332extern "C" inline void MergeReceiverCbNonDmx(sacn_merge_receiver_t receiver_handle, const EtcPalSockAddr* source_addr,
333 const SacnRemoteSource* source_info,
334 const SacnRecvUniverseData* universe_data, void* context)
335{
336 if (context && source_addr && source_info && universe_data)
337 {
338 static_cast<MergeReceiver::NotifyHandler*>(context)->HandleNonDmxData(MergeReceiver::Handle(receiver_handle),
339 *source_addr, *source_info, *universe_data);
340 }
341}
342
343extern "C" inline void MergeReceiverCbSourcesLost(sacn_merge_receiver_t handle, uint16_t universe,
344 const SacnLostSource* lost_sources, size_t num_lost_sources,
345 void* context)
346{
347 if (context && lost_sources && (num_lost_sources > 0))
348 {
349 std::vector<SacnLostSource> lost_vec(lost_sources, lost_sources + num_lost_sources);
350 static_cast<MergeReceiver::NotifyHandler*>(context)->HandleSourcesLost(MergeReceiver::Handle(handle), universe,
351 lost_vec);
352 }
353}
354
355extern "C" inline void MergeReceiverCbSamplingPeriodStarted(sacn_merge_receiver_t handle, uint16_t universe,
356 void* context)
357{
358 if (context)
359 {
360 static_cast<MergeReceiver::NotifyHandler*>(context)->HandleSamplingPeriodStarted(MergeReceiver::Handle(handle),
361 universe);
362 }
363}
364
365extern "C" inline void MergeReceiverCbSamplingPeriodEnded(sacn_merge_receiver_t handle, uint16_t universe,
366 void* context)
367{
368 if (context)
369 {
370 static_cast<MergeReceiver::NotifyHandler*>(context)->HandleSamplingPeriodEnded(MergeReceiver::Handle(handle),
371 universe);
372 }
373}
374
375extern "C" inline void MergeReceiverCbSourcePapLost(sacn_merge_receiver_t handle, uint16_t universe,
376 const SacnRemoteSource* source, void* context)
377{
378 if (context && source)
379 {
380 static_cast<MergeReceiver::NotifyHandler*>(context)->HandleSourcePapLost(MergeReceiver::Handle(handle), universe,
381 *source);
382 }
383}
384
385extern "C" inline void MergeReceiverCbSourceLimitExceeded(sacn_merge_receiver_t handle, uint16_t universe,
386 void* context)
387{
388 if (context)
389 {
390 static_cast<MergeReceiver::NotifyHandler*>(context)->HandleSourceLimitExceeded(MergeReceiver::Handle(handle),
391 universe);
392 }
393}
394
395}; // namespace internal
396
406inline MergeReceiver::Settings::Settings(uint16_t new_universe_id) : universe_id(new_universe_id)
407{
408}
409
412{
413 return (universe_id > 0) && (footprint.start_address >= 1) && (footprint.start_address <= DMX_ADDRESS_COUNT) &&
414 (footprint.address_count >= 1) &&
415 (footprint.address_count <= (DMX_ADDRESS_COUNT - footprint.start_address + 1));
416}
417
424 McastMode mcast_mode = McastMode::kEnabledOnAllInterfaces)
425 : handle(merge_receiver_handle), no_netints(mcast_mode == McastMode::kDisabledOnAllInterfaces)
426{
427}
428
436 const std::vector<SacnMcastInterface>& network_interfaces)
437 : handle(merge_receiver_handle), netints(network_interfaces)
438{
439}
440
465inline etcpal::Error MergeReceiver::Startup(const Settings& settings, NotifyHandler& notify_handler,
466 McastMode mcast_mode = McastMode::kEnabledOnAllInterfaces)
467{
468 SacnMergeReceiverConfig config = TranslateConfig(settings, notify_handler);
469
470 SacnNetintConfig netint_config = SACN_NETINT_CONFIG_DEFAULT_INIT;
471 if (mcast_mode == McastMode::kDisabledOnAllInterfaces)
472 netint_config.no_netints = true;
473
475 etcpal::Error result = sacn_merge_receiver_create(&config, &c_handle, &netint_config);
476
477 handle_.SetValue(c_handle);
478
479 return result;
480}
481
504inline etcpal::Error MergeReceiver::Startup(const Settings& settings, NotifyHandler& notify_handler,
506{
507 SacnMergeReceiverConfig config = TranslateConfig(settings, notify_handler);
508
511
512 if (netints.empty())
513 {
514 result = sacn_merge_receiver_create(&config, &c_handle, NULL);
515 }
516 else
517 {
518 SacnNetintConfig netint_config = SACN_NETINT_CONFIG_DEFAULT_INIT;
519 netint_config.netints = netints.data();
520 netint_config.num_netints = netints.size();
521
522 result = sacn_merge_receiver_create(&config, &c_handle, &netint_config);
523 }
524
525 handle_.SetValue(c_handle);
526
527 return result;
528}
529
537{
539 handle_.Clear();
540}
541
548{
549 uint16_t result = 0;
550 etcpal_error_t err = sacn_merge_receiver_get_universe(handle_.value(), &result);
551 if (err == kEtcPalErrOk)
552 return result;
553 else
554 return err;
555}
556
565{
568 if (err == kEtcPalErrOk)
569 return result;
570 else
571 return err;
572}
573
589inline etcpal::Error MergeReceiver::ChangeUniverse(uint16_t new_universe_id)
590{
591 return sacn_merge_receiver_change_universe(handle_.value(), new_universe_id);
592}
593
604{
605 return sacn_merge_receiver_change_footprint(handle_.value(), &new_footprint);
606}
607
619 const SacnRecvUniverseSubrange& new_footprint)
620{
621 return sacn_merge_receiver_change_universe_and_footprint(handle_.value(), new_universe_id, &new_footprint);
622}
623
630{
631 // This uses a guessing algorithm with a while loop to avoid race conditions.
633 size_t size_guess = 4u;
634 size_t num_netints = 0u;
635
636 do
637 {
638 netints.resize(size_guess);
639 num_netints = sacn_merge_receiver_get_network_interfaces(handle_.value(), netints.data(), netints.size());
640 size_guess = num_netints + 4u;
641 } while (num_netints > netints.size());
642
643 netints.resize(num_netints);
644 return netints;
645}
646
658{
660 etcpal_error_t error = sacn_merge_receiver_get_source(handle_.value(), source_handle, &c_info);
661 if (error == kEtcPalErrOk)
662 {
664 res.handle = c_info.handle;
665 res.cid = c_info.cid;
666 res.name = c_info.name;
667 res.addr = c_info.addr;
670 return res;
671 }
672
673 return error;
674}
675
700inline etcpal::Error MergeReceiver::ResetNetworking(McastMode mcast_mode = McastMode::kEnabledOnAllInterfaces)
701{
702 SacnNetintConfig netint_config = SACN_NETINT_CONFIG_DEFAULT_INIT;
703 if (mcast_mode == McastMode::kDisabledOnAllInterfaces)
704 netint_config.no_netints = true;
705
706 return sacn_merge_receiver_reset_networking(&netint_config);
707}
708
733{
734 if (sys_netints.empty())
736
737 SacnNetintConfig netint_config = SACN_NETINT_CONFIG_DEFAULT_INIT;
738 netint_config.netints = sys_netints.data();
739 netint_config.num_netints = sys_netints.size();
740
741 return sacn_merge_receiver_reset_networking(&netint_config);
742}
743
774 std::vector<NetintList>& per_receiver_netint_lists)
775{
777 netint_lists_c.reserve(per_receiver_netint_lists.size());
779 per_receiver_netint_lists.begin(), per_receiver_netint_lists.end(), std::back_inserter(netint_lists_c),
780 [](NetintList& list) {
781 // clang-format off
782 SacnMergeReceiverNetintList c_list = {
783 list.handle,
784 list.netints.data(),
785 list.netints.size(),
786 list.no_netints
787 };
788 // clang-format on
789
790 return c_list;
791 });
792
793 SacnNetintConfig netint_config = SACN_NETINT_CONFIG_DEFAULT_INIT;
794 netint_config.netints = sys_netints.data();
795 netint_config.num_netints = sys_netints.size();
796
797 return sacn_merge_receiver_reset_networking_per_receiver(&netint_config, netint_lists_c.data(),
798 netint_lists_c.size());
799}
800
807{
808 return handle_;
809}
810
811inline SacnMergeReceiverConfig MergeReceiver::TranslateConfig(const Settings& settings, NotifyHandler& notify_handler)
812{
813 // clang-format off
814 SacnMergeReceiverConfig config = {
815 settings.universe_id,
816 {
817 internal::MergeReceiverCbMergedData,
818 internal::MergeReceiverCbNonDmx,
819 internal::MergeReceiverCbSourcesLost,
820 internal::MergeReceiverCbSamplingPeriodStarted,
821 internal::MergeReceiverCbSamplingPeriodEnded,
822 internal::MergeReceiverCbSourcePapLost,
823 internal::MergeReceiverCbSourceLimitExceeded,
824 &notify_handler
825 },
826 settings.footprint,
827 settings.source_count_max,
828 settings.use_pap,
829 settings.ip_supported
830 };
831 // clang-format on
832
833 return config;
834}
835
836}; // namespace sacn
837
838#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 HandleNonDmxData(Handle receiver_handle, const etcpal::SockAddr &source_addr, const SacnRemoteSource &source_info, const SacnRecvUniverseData &universe_data)
Notify that a non-data packet has been received.
Definition merge_receiver.h:119
virtual void HandleSamplingPeriodStarted(Handle handle, uint16_t universe)
Notify that a merge receiver's sampling period has begun.
Definition merge_receiver.h:150
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:198
virtual void HandleSourcesLost(Handle handle, uint16_t universe, const std::vector< SacnLostSource > &lost_sources)
Notify that one or more sources have entered a source loss state.
Definition merge_receiver.h:134
virtual void HandleSamplingPeriodEnded(Handle handle, uint16_t universe)
Notify that a merge receiver's sampling period has ended.
Definition merge_receiver.h:170
virtual void HandleSourcePapLost(Handle handle, uint16_t universe, const SacnRemoteSource &source)
Notify that a source has stopped transmission of per-address priority packets.
Definition merge_receiver.h:182
An instance of sACN Merge Receiver functionality; see Using the sACN Merge Receiver API.
Definition merge_receiver.h:61
etcpal::Error Startup(const Settings &settings, NotifyHandler &notify_handler, McastMode mcast_mode)
Start listening for sACN data on a universe.
Definition merge_receiver.h:465
std::vector< EtcPalMcastNetintId > GetNetworkInterfaces()
Obtain a vector of this merge receiver's network interfaces.
Definition merge_receiver.h:629
etcpal::Expected< uint16_t > GetUniverse() const
Get the universe this merge receiver is listening to.
Definition merge_receiver.h:547
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:603
MergeReceiver & operator=(MergeReceiver &&other)=default
constexpr Handle handle() const
Get the current handle to the underlying C merge receiver.
Definition merge_receiver.h:806
etcpal::Error ChangeUniverse(uint16_t new_universe_id)
Change the universe this class is listening to.
Definition merge_receiver.h:589
etcpal::Expected< SacnRecvUniverseSubrange > GetFootprint() const
Get the footprint within the universe this merge receiver is listening to.
Definition merge_receiver.h:564
static etcpal::Error ResetNetworking(McastMode mcast_mode)
Resets the underlying network sockets and packet receipt state for all sACN merge receivers.
Definition merge_receiver.h:700
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:657
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:618
void Shutdown()
Stop listening for sACN data on a universe.
Definition merge_receiver.h:536
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:410
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:507
etcpal_error_t sacn_merge_receiver_destroy(sacn_merge_receiver_t handle)
Destroy a sACN Merge Receiver instance.
Definition merge_receiver.c:205
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:356
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:447
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:272
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:253
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:526
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:295
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:89
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:376
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
McastMode
Definition common.h:53
T reserve(T... args)
T resize(T... args)
T size(T... args)
Definition receiver.h:138
Definition merge_receiver.h:246
uint16_t universe_id
Definition merge_receiver.h:250
Definition merge_receiver.h:296
bool per_address_priorities_active
Definition merge_receiver.h:306
EtcPalUuid cid
Definition merge_receiver.h:300
EtcPalSockAddr addr
Definition merge_receiver.h:304
char name[SACN_SOURCE_NAME_MAX_LEN]
Definition merge_receiver.h:302
sacn_remote_source_t handle
Definition merge_receiver.h:298
uint8_t universe_priority
Definition merge_receiver.h:308
Definition common.h:102
bool no_netints
Definition common.h:110
size_t num_netints
Definition common.h:107
SacnMcastInterface * netints
Definition common.h:105
Definition merge_receiver.h:61
Definition receiver.h:89
Definition receiver.h:80
Definition receiver.h:127
A set of network interfaces for a particular merge receiver.
Definition merge_receiver.h:249
std::vector< SacnMcastInterface > netints
Definition merge_receiver.h:255
bool no_netints
Definition merge_receiver.h:258
sacn_merge_receiver_t handle
Definition merge_receiver.h:251
A set of configuration settings that a merge receiver needs to initialize.
Definition merge_receiver.h:210
SacnRecvUniverseSubrange footprint
Definition merge_receiver.h:219
uint16_t universe_id
Definition merge_receiver.h:214
int source_count_max
Definition merge_receiver.h:222
sacn_ip_support_t ip_supported
Definition merge_receiver.h:231
bool IsValid() const
Definition merge_receiver.h:411
bool use_pap
Definition merge_receiver.h:228
Information about a remote sACN source being tracked by a merge receiver.
Definition merge_receiver.h:271
bool per_address_priorities_active
Definition merge_receiver.h:281
etcpal::SockAddr addr
Definition merge_receiver.h:279
std::string name
Definition merge_receiver.h:277
etcpal::Uuid cid
Definition merge_receiver.h:275
sacn_remote_source_t handle
Definition merge_receiver.h:273
uint8_t universe_priority
Definition merge_receiver.h:283
T transform(T... args)