5G-MAG Reference Tools - MBMS Middleware
ServiceAnnouncement.cpp
Go to the documentation of this file.
1 // 5G-MAG Reference Tools
2 // MBMS Middleware Process
3 //
4 // Copyright (C) 2021 Klaus Kühnhammer (Österreichische Rundfunksender GmbH & Co KG)
5 //
6 // Licensed under the License terms and conditions for use, reproduction, and
7 // distribution of 5G-MAG software (the “License”). You may not use this file
8 // except in compliance with the License. You may obtain a copy of the License at
9 // https://www.5g-mag.com/reference-tools. Unless required by applicable law or
10 // agreed to in writing, software distributed under the License is distributed on
11 // an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12 // or implied.
13 //
14 // See the License for the specific language governing permissions and limitations
15 // under the License.
16 //
17 
18 #include <regex>
19 #include <iostream> // std::cin, std::cout
20 #include <iomanip> // std::get_time
21 #include <ctime> // struct std::tm
22 #include <boost/algorithm/string/trim.hpp>
23 #include "ServiceAnnouncement.h"
24 #include "Service.h"
25 #include "Receiver.h"
26 #include "seamless/SeamlessContentStream.h"
27 #include "Constants.h"
28 
29 #include "spdlog/spdlog.h"
30 #include "gmime/gmime.h"
31 #include "tinyxml2.h"
32 #include "cpprest/base_uri.h"
33 #include <gzip/decompress.hpp>
34 
35 
36 MBMS_RT::ServiceAnnouncement::ServiceAnnouncement(const libconfig::Config &cfg, std::string tmgi,
37  const std::string &mcast,
38  unsigned long long tsi, std::string iface,
39  boost::asio::io_service &io_service, CacheManagement &cache,
40  bool seamless_switching,
41  get_service_callback_t get_service,
42  set_service_callback_t set_service)
43  : _cfg(cfg), _tmgi(std::move(tmgi)), _tsi(tsi), _iface(std::move(iface)), _io_service(io_service), _cache(cache),
44  _flute_thread{}, _seamless(seamless_switching), _get_service(std::move(get_service)),
45  _set_service(std::move(set_service)) {
46 }
47 
49  spdlog::info("Closing service announcement session with TMGI {}", _tmgi);
50  _flute_receiver.reset();
51  if (_flute_thread.joinable()) {
52  _flute_thread.join();
53  }
54 }
55 
61 auto MBMS_RT::ServiceAnnouncement::start_flute_receiver(const std::string &mcast_address) -> void {
62  size_t delim = mcast_address.find(':');
63  if (delim == std::string::npos) {
64  spdlog::error("Invalid multicast address {}", mcast_address);
65  return;
66  }
67  _mcast_addr = mcast_address.substr(0, delim);
68  _mcast_port = mcast_address.substr(delim + 1);
69  spdlog::info("Starting FLUTE receiver on {}:{} for TSI {}", _mcast_addr, _mcast_port, _tsi);
70  _flute_thread = std::thread{[&]() {
71  _flute_receiver = std::make_unique<LibFlute::Receiver>(_iface, _mcast_addr, atoi(_mcast_port.c_str()), _tsi,
72  _io_service);
73  _flute_receiver->register_completion_callback(
74  [&](std::shared_ptr<LibFlute::File> file) { //NOLINT
75  spdlog::info("{} (TOI {}) has been received",
76  file->meta().content_location, file->meta().toi);
77  if (!_bootstrapped || _toi != file->meta().toi) {
78  _toi = file->meta().toi;
79  if (file->meta().content_type == "application/x-gzip") {
80  _raw_content = gzip::decompress(file->buffer(), file->length());
81  } else {
82  _raw_content = std::string(file->buffer());
83  }
84  parse_bootstrap(file->buffer());
85  }
86  });
87  }};
88 }
89 
94 auto
95 MBMS_RT::ServiceAnnouncement::parse_bootstrap(const std::string &str) -> void {
96  std::string bootstrap_format = ServiceAnnouncementFormatConstants::DEFAULT;
97  _cfg.lookupValue("mw.bootstrap_format", bootstrap_format);
98 
99  // Add all the SA items including their content to _items
100  _addServiceAnnouncementItems(str);
101 
102  // Parse MBMS envelope: <metadataEnvelope>
103  for (const auto &item: _items) {
104  if (item.content_type == ContentTypeConstants::MBMS_ENVELOPE) {
105  _handleMbmsEnvelope(item);
106  }
107  }
108 
109  // Parse MBMS user service description bundle
110  for (const auto &item: _items) {
111  if (item.content_type == ContentTypeConstants::MBMS_USER_SERVICE_DESCRIPTION) {
112  _handleMbmbsUserServiceDescriptionBundle(item, bootstrap_format);
113  }
114  }
115 }
116 
122  g_mime_init();
123  auto stream = g_mime_stream_mem_new_with_buffer(str.c_str(), str.length());
124  auto parser = g_mime_parser_new_with_stream(stream);
125  g_object_unref(stream);
126 
127  auto mpart = g_mime_parser_construct_part(parser, nullptr);
128  g_object_unref(parser);
129 
130  auto iter = g_mime_part_iter_new(mpart);
131  do {
132  GMimeObject *current = g_mime_part_iter_get_current(iter);
133  GMimeObject *parent = g_mime_part_iter_get_parent(iter);
134 
135  if (GMIME_IS_PART (current)) {
136  auto type = std::string(g_mime_content_type_get_mime_type(g_mime_object_get_content_type(current)));
137  std::string location = "";
138  if (g_mime_object_get_header(current, "Content-Location")) {
139  location = std::string(g_mime_object_get_header(current, "Content-Location"));
140  }
141  auto options = g_mime_format_options_new();
142  g_mime_format_options_add_hidden_header(options, "Content-Type");
143  g_mime_format_options_add_hidden_header(options, "Content-Transfer-Encoding");
144  g_mime_format_options_add_hidden_header(options, "Content-Location");
145  std::string content = g_mime_object_to_string(current, options);
146  boost::algorithm::trim_left(content);
147 
148  if (location != "") {
149  _items.emplace_back(Item{
150  type,
151  location,
152  0, 0, 0,
153  content
154  });
155  }
156  }
157  } while (g_mime_part_iter_next(iter));
158 
159 }
160 
166  try {
167  tinyxml2::XMLDocument doc;
168  doc.Parse(item.content.c_str());
169  auto envelope = doc.FirstChildElement(ServiceAnnouncementXmlElements::METADATA_ENVELOPE);
170  for (auto *i = envelope->FirstChildElement(ServiceAnnouncementXmlElements::ITEM);
171  i != nullptr; i = i->NextSiblingElement(ServiceAnnouncementXmlElements::ITEM)) {
172  spdlog::debug("uri: {}", i->Attribute(ServiceAnnouncementXmlElements::METADATA_URI));
173  for (auto &ir: _items) {
174  if (ir.uri == i->Attribute(ServiceAnnouncementXmlElements::METADATA_URI)) {
175  std::stringstream ss_from(i->Attribute(ServiceAnnouncementXmlElements::VALID_FROM));
176  struct std::tm from;
177  ss_from >> std::get_time(&from, "%Y-%m-%dT%H:%M:%S.%fZ");
178  ir.valid_from = mktime(&from);
179  std::stringstream ss_until(i->Attribute(ServiceAnnouncementXmlElements::VALID_UNTIL));
180  struct std::tm until;
181  ss_until >> std::get_time(&until, "%Y-%m-%dT%H:%M:%S.%fZ");
182  ir.valid_until = mktime(&until);
183  ir.version = atoi(i->Attribute(ServiceAnnouncementXmlElements::VERSION));
184  }
185  }
186  }
187  } catch (std::exception e) {
188  spdlog::warn("MBMS envelope parsing failed: {}", e.what());
189  }
190 }
191 
196 void
198  const std::string &bootstrap_format) {
199  try {
200  tinyxml2::XMLDocument doc;
201  doc.Parse(item.content.c_str());
202 
203  auto bundle = doc.FirstChildElement(ServiceAnnouncementXmlElements::BUNDLE_DESCRIPTION);
204  for (auto *usd = bundle->FirstChildElement(ServiceAnnouncementXmlElements::USER_SERVICE_DESCRIPTION);
205  usd != nullptr;
206  usd = usd->NextSiblingElement(ServiceAnnouncementXmlElements::USER_SERVICE_DESCRIPTION)) {
207 
208  // Create a new service
209  auto service_id = usd->Attribute(ServiceAnnouncementXmlElements::SERVICE_ID);
210  auto[service, is_new_service] = _registerService(usd, service_id);
211 
212  // Handle the app service element. Will read the master manifest as provided in the SA
213  auto app_service = usd->FirstChildElement(ServiceAnnouncementXmlElements::APP_SERVICE);
214  _handleAppService(app_service, service);
215 
216  // For the default format we need an alternativeContent attribute to setup the service
217  if (bootstrap_format == ServiceAnnouncementFormatConstants::FIVEG_MAG_BC_UC) {
218  _setupBy5GMagConfig(app_service, service, usd);
219  } else if (bootstrap_format == ServiceAnnouncementFormatConstants::FIVEG_MAG_LEGACY) {
220  _setupBy5GMagLegacyFormat(app_service, service, usd);
221  } else {
222  _setupByAlternativeContentElement(app_service, service, usd);
223  }
224 
225  if (is_new_service && service->content_streams().size() > 0) {
226  _set_service(service_id, service);
227  }
228  }
229  } catch (std::exception e) {
230  spdlog::warn("MBMS user service desription parsing failed: {}", e.what());
231  }
232 }
233 
240 auto
241 MBMS_RT::ServiceAnnouncement::_registerService(tinyxml2::XMLElement *usd, const std::string &service_id) -> std::tuple<std::shared_ptr<MBMS_RT::Service>, bool> {
242  // Register a new service if we have not seen this service id before
243 
244  bool is_new_service = false;
245  auto service = _get_service(service_id);
246  if (service == nullptr) {
247  service = std::make_shared<Service>(_cache);
248  is_new_service = true;
249  }
250 
251  // read the names
252  for (auto *name = usd->FirstChildElement(ServiceAnnouncementXmlElements::NAME);
253  name != nullptr; name = name->NextSiblingElement(ServiceAnnouncementXmlElements::NAME)) {
254  auto lang = name->Attribute(ServiceAnnouncementXmlElements::LANG);
255  auto namestr = name->GetText();
256  if (lang && namestr) {
257  service->add_name(namestr, lang);
258  }
259  }
260 
261  return {service, is_new_service};
262 }
263 
272 void MBMS_RT::ServiceAnnouncement::_handleAppService(tinyxml2::XMLElement *app_service,const
273  std::shared_ptr<MBMS_RT::Service> &service) {
274 
275  service->set_delivery_protocol_from_mime_type(app_service->Attribute(ServiceAnnouncementXmlElements::MIME_TYPE));
276 
277  // Now search for the content that corresponds to appServiceDescriptionURI. For instance appServiceDescriptionURI="http://localhost/watchfolder/manifest.m3u8"
278  // The attribute appServiceDescriptionURI of r12:appService references an Application Service Description which may be a Media Presentation Description fragment corresponding to a unified MPD.
279  for (const auto &item: _items) {
280  // item.uri is derived from the Content-Location of each entry in the bootstrap file. For HLS we are looking for the content of the master manifest in the bootstrap file:
281  if (item.uri == app_service->Attribute(ServiceAnnouncementXmlElements::APP_SERVICE_DESCRIPTION_URI)) {
282  web::uri uri(item.uri);
283 
284  // remove file, leave only dir
285  const std::string &path = uri.path();
286  size_t spos = path.rfind('/');
287  auto base_path = path.substr(0, spos + 1);
288 
289  // make relative path: remove leading /
290  if (base_path[0] == '/') {
291  base_path.erase(0, 1);
292  }
293  service->read_master_manifest(item.content, base_path);
294  _base_path = base_path;
295  }
296  }
297 }
298 
299 void MBMS_RT::ServiceAnnouncement::_setupBy5GMagConfig(tinyxml2::XMLElement *app_service,
300  const std::shared_ptr<MBMS_RT::Service> &service,
301  tinyxml2::XMLElement *usd) {
302 
303  std::vector<std::shared_ptr<ContentStream>> broadcastContentStreams;
304  std::vector<std::shared_ptr<SeamlessContentStream>> unicastContentStreams;
305 // Create content stream objects for each broadcastAppService::basePattern element.
306  for (auto *delivery_method = usd->FirstChildElement(ServiceAnnouncementXmlElements::DELIVERY_METHOD);
307  delivery_method != nullptr;
308  delivery_method = delivery_method->NextSiblingElement(ServiceAnnouncementXmlElements::DELIVERY_METHOD)) {
309  auto sdp_uri = delivery_method->Attribute(ServiceAnnouncementXmlElements::SESSION_DESCRIPTION_URI);
310  // We assume that the master manifest is signaled in the SA and that we can simply replace the .sdp ending with .m3u8 to find the element with the right Content-Location
311  auto manifest_url = std::regex_replace(sdp_uri, std::regex(".sdp"), ".m3u8");
312  auto broadcast_app_service = delivery_method->FirstChildElement(
314 
315  if (broadcast_app_service != nullptr) {
316  for (auto *base_pattern = broadcast_app_service->FirstChildElement(ServiceAnnouncementXmlElements::BASE_PATTERN);
317  base_pattern != nullptr;
318  base_pattern = base_pattern->NextSiblingElement(ServiceAnnouncementXmlElements::BASE_PATTERN)) {
319 
320  std::string broadcast_url = base_pattern->GetText();
321 
322  // create a content stream
323  std::shared_ptr<ContentStream> cs;
324  if (_seamless) {
325  cs = std::make_shared<SeamlessContentStream>(broadcast_url, _iface, _io_service, _cache,
326  service->delivery_protocol(), _cfg);
327  } else {
328  cs = std::make_shared<ContentStream>(broadcast_url, _iface, _io_service, _cache, service->delivery_protocol(),
329  _cfg);
330  }
331 
332  for (const auto &item: _items) {
333  if (item.uri == manifest_url) {
334  cs->read_master_manifest(item.content);
335  }
336  if (item.content_type == ContentTypeConstants::SDP &&
337  item.uri == sdp_uri) {
338  cs->configure_5gbc_delivery_from_sdp(item.content);
339  }
340  }
341 
342  broadcastContentStreams.push_back(cs);
343  }
344  }
345 
346  if (_seamless) {
347  // Iterate through unicastAppService elements. If we find a match in identical content we add the CDN information to the existing broadcast content stream
348  // If not we create a new content stream object pointing to the CDN url
349  auto unicast_app_service = delivery_method->FirstChildElement(
351  if (unicast_app_service != nullptr) {
352  for (auto *base_pattern = unicast_app_service->FirstChildElement(
354  base_pattern != nullptr;
355  base_pattern = base_pattern->NextSiblingElement(ServiceAnnouncementXmlElements::BASE_PATTERN)) {
356  // For HLS streams base_pattern now holds the url to the media manifest
357  std::string unicast_url = base_pattern->GetText();
358  // Check for identical content entries that contain this base pattern.
359  for (auto *identical_content = app_service->FirstChildElement(
361  identical_content != nullptr;
362  identical_content = identical_content->NextSiblingElement(
364  std::shared_ptr<SeamlessContentStream> broadcast_content_stream;
365  bool found_identical_element = false;
366  for (auto *base_pattern_ic = identical_content->FirstChildElement(
368  base_pattern_ic != nullptr;
369  base_pattern_ic = base_pattern_ic->NextSiblingElement(ServiceAnnouncementXmlElements::BASE_PATTERN)) {
370  // For HLS streams base_pattern_ic now holds either an url that points to a BC media playlist or to a UC playlist
371  std::string identical_content_url = base_pattern_ic->GetText();
372  // Check if we have a match of our current unicast url with the url in the identical content element
373  // Otherwise check if the current identical content url points to an existing BC element
374  if (unicast_url == identical_content_url) {
375  found_identical_element = true;
376  } else {
377  for (auto &element: broadcastContentStreams) {
378  if (element->base() == identical_content_url) {
379  broadcast_content_stream = std::dynamic_pointer_cast<SeamlessContentStream>(element);
380  }
381  }
382  }
383  }
384  // If we found a matching broadcast stream we add the CDN url to this one. Otherwise, we create a new SeamlessContentStream element
385  if (broadcast_content_stream != nullptr && found_identical_element) {
386  broadcast_content_stream->set_cdn_endpoint(unicast_url);
387  } else {
388  std::shared_ptr<SeamlessContentStream> cs = std::make_shared<SeamlessContentStream>(manifest_url, _iface,
389  _io_service, _cache,
390  service->delivery_protocol(),
391  _cfg);
392  cs->set_cdn_endpoint(unicast_url);
393  unicastContentStreams.push_back(cs);
394  }
395  }
396  }
397  }
398  }
399 
400  for (auto &element: unicastContentStreams) {
401  service->add_and_start_content_stream(element);
402  }
403 
404  for (auto &element: broadcastContentStreams) {
405  service->add_and_start_content_stream(element);
406  }
407 
408  spdlog::info("Finished SA setup with 5G-MAG Format");
409  }
410 
411 }
412 
419 void MBMS_RT::ServiceAnnouncement::_setupBy5GMagLegacyFormat(tinyxml2::XMLElement *app_service,
420  const std::shared_ptr<MBMS_RT::Service> &service,
421  tinyxml2::XMLElement *usd) {
422 
423  std::vector<std::shared_ptr<ContentStream>> broadcastContentStreams;
424 // Create content stream objects for each broadcastAppService::basePattern element.
425  for (auto *delivery_method = usd->FirstChildElement(ServiceAnnouncementXmlElements::DELIVERY_METHOD);
426  delivery_method != nullptr;
427  delivery_method = delivery_method->NextSiblingElement(ServiceAnnouncementXmlElements::DELIVERY_METHOD)) {
428  auto sdp_uri = delivery_method->Attribute(ServiceAnnouncementXmlElements::SESSION_DESCRIPTION_URI);
429  // We assume that the master manifest is signaled in the SA and that we can simply replace the .sdp ending with .m3u8 or .mpd to find the element with the right Content-Location
430  std::string manifest_type = service->delivery_protocol() == DeliveryProtocol::HLS ? ContentTypeConstants::HLS_MANIFEST : ContentTypeConstants::DASH_MANIFEST;
431  auto manifest_url = std::regex_replace(sdp_uri, std::regex(".sdp"), "." + manifest_type);
432  auto broadcast_app_service = delivery_method->FirstChildElement(
434 
435  if (broadcast_app_service != nullptr) {
436  for (auto *base_pattern = broadcast_app_service->FirstChildElement(ServiceAnnouncementXmlElements::BASE_PATTERN);
437  base_pattern != nullptr;
438  base_pattern = base_pattern->NextSiblingElement(ServiceAnnouncementXmlElements::BASE_PATTERN)) {
439 
440  std::string broadcast_url = base_pattern->GetText();
441 
442  // create a content stream if this is not a base pattern that points to file://
443  if (service->delivery_protocol() == DeliveryProtocol::DASH || (service->delivery_protocol() == DeliveryProtocol::HLS && broadcast_url.find("file://") == std::string::npos)) {
444 
445  std::shared_ptr<ContentStream> cs;
446  cs = std::make_shared<ContentStream>(broadcast_url, _iface, _io_service, _cache, service->delivery_protocol(),
447  _cfg);
448 
449  cs->set_base_path(_base_path);
450  for (const auto &item: _items) {
451  if (item.uri == manifest_url && service->delivery_protocol() == DeliveryProtocol::HLS) {
452  cs->read_master_manifest(item.content);
453  }
454  if (item.content_type == ContentTypeConstants::SDP &&
455  item.uri == sdp_uri) {
456  cs->configure_5gbc_delivery_from_sdp(item.content);
457  }
458  }
459 
460  broadcastContentStreams.push_back(cs);
461  }
462  }
463  }
464 
465  for (auto &element: broadcastContentStreams) {
466  service->add_and_start_content_stream(element);
467  }
468 
469  spdlog::info("Finished SA setup with 5G-MAG Legacy Format");
470 
471  }
472 }
473 
474 
482  const std::shared_ptr<MBMS_RT::Service> &service,
483  tinyxml2::XMLElement *usd) {
484  auto alternative_content = app_service->FirstChildElement(ServiceAnnouncementXmlElements::ALTERNATIVE_CONTENT);
485  if (alternative_content != nullptr) {
486  for (auto *base_pattern = alternative_content->FirstChildElement(ServiceAnnouncementXmlElements::BASE_PATTERN);
487  base_pattern != nullptr;
488  base_pattern = base_pattern->NextSiblingElement(ServiceAnnouncementXmlElements::BASE_PATTERN)) {
489  std::string base = base_pattern->GetText();
490 
491  // create a content stream
492  std::shared_ptr<ContentStream> cs;
493  if (_seamless) {
494  cs = std::make_shared<SeamlessContentStream>(base, _iface, _io_service, _cache,
495  service->delivery_protocol(), _cfg);
496  } else {
497  cs = std::make_shared<ContentStream>(base, _iface, _io_service, _cache, service->delivery_protocol(),
498  _cfg);
499  }
500 
501 
502  // Check for 5GBC delivery method elements
503  bool broadcast_delivery_available = false;
504  for (auto *delivery_method = usd->FirstChildElement(ServiceAnnouncementXmlElements::DELIVERY_METHOD);
505  delivery_method != nullptr;
506  delivery_method = delivery_method->NextSiblingElement(ServiceAnnouncementXmlElements::DELIVERY_METHOD)) {
507  auto sdp_uri = delivery_method->Attribute(ServiceAnnouncementXmlElements::SESSION_DESCRIPTION_URI);
508  auto broadcast_app_service = delivery_method->FirstChildElement(
510  std::string broadcast_base_pattern = broadcast_app_service->FirstChildElement(
512 
513  if (broadcast_base_pattern == base) {
514  for (const auto &item: _items) {
515  if (item.uri == broadcast_base_pattern) {
516  cs->read_master_manifest(item.content);
517  }
518  if (item.content_type == ContentTypeConstants::SDP &&
519  item.uri == sdp_uri) {
520  broadcast_delivery_available = cs->configure_5gbc_delivery_from_sdp(item.content);
521  }
522  }
523  }
524  }
525  bool unicast_delivery_available = false;
526 
527  // When seamless switching is enabled we check for unicast endpoints as well
528  if (_seamless) {
529  if (!broadcast_delivery_available) {
530  // No 5G broadcast available. Assume the base pattern is a CDN endpoint.
531  std::dynamic_pointer_cast<SeamlessContentStream>(cs)->set_cdn_endpoint(base);
532  unicast_delivery_available = true;
533  } else {
534  // Check for identical content entries to find a CDN base pattern
535  for (auto *identical_content = app_service->FirstChildElement(
537  identical_content != nullptr;
538  identical_content = identical_content->NextSiblingElement(
540 
541  bool base_matched = false;
542  std::string found_identical_base;
543  for (auto *base_pattern = identical_content->FirstChildElement(
545  base_pattern != nullptr;
546  base_pattern = base_pattern->NextSiblingElement(ServiceAnnouncementXmlElements::BASE_PATTERN)) {
547  std::string identical_base = base_pattern->GetText();
548  if (base == identical_base) {
549  base_matched = true;
550  } else {
551  found_identical_base = identical_base;
552  }
553  }
554 
555  if (base_matched && found_identical_base.length()) {
556  std::dynamic_pointer_cast<SeamlessContentStream>(cs)->set_cdn_endpoint(found_identical_base);
557  }
558  }
559  }
560  }
561 
562  if (unicast_delivery_available || broadcast_delivery_available) {
563  service->add_and_start_content_stream(cs);
564  }
565  }
566  }
567 }
void _handleMbmsEnvelope(const Item &item)
Parses the MBMS envelope.
void _addServiceAnnouncementItems(const std::string &str)
Iterates through the service announcement file and adds the different sections/items to the the list ...
void _handleMbmbsUserServiceDescriptionBundle(const Item &item, const std::string &bootstrap_format)
Parses the MBMS USD.
void _handleAppService(tinyxml2::XMLElement *app_service, const std::shared_ptr< Service > &service)
Parse the appService element Spec: Presence of the r12:appService child element of userServiceDescrip...
void _setupBy5GMagConfig(tinyxml2::XMLElement *app_service, const std::shared_ptr< MBMS_RT::Service > &service, tinyxml2::XMLElement *usd)
void _setupBy5GMagLegacyFormat(tinyxml2::XMLElement *app_service, const std::shared_ptr< MBMS_RT::Service > &service, tinyxml2::XMLElement *usd)
Setup according to the format that was used for the first 5G-MAG sample recordings.
std::function< std::shared_ptr< Service >const std::string &service_id)> get_service_callback_t
void start_flute_receiver(const std::string &mcast_address)
Starts the FLUTE receiver at the specified multicast address.
std::tuple< std::shared_ptr< MBMS_RT::Service >, bool > _registerService(tinyxml2::XMLElement *usd, const std::string &service_id)
Creates a new service or finds an existing service for the specified service id.
std::function< void(const std::string &service_id, std::shared_ptr< Service >)> set_service_callback_t
void parse_bootstrap(const std::string &str)
Parse the service announcement/bootstrap file.
void _setupByAlternativeContentElement(tinyxml2::XMLElement *app_service, const std::shared_ptr< MBMS_RT::Service > &service, tinyxml2::XMLElement *usd)
Setup according to original SA format with an alternativeContentElement required to indicate that the...
ServiceAnnouncement(const libconfig::Config &cfg, std::string tmgi, const std::string &mcast, unsigned long long tsi, std::string iface, boost::asio::io_service &io_service, CacheManagement &cache, bool seamless_switching, get_service_callback_t get_service, set_service_callback_t set_service)
static Config cfg
Global configuration object.
Definition: main.cpp:111
static struct argp_option options[]
Definition: main.cpp:58
static char doc[]
Definition: main.cpp:56
const std::string MBMS_ENVELOPE
Definition: Constants.h:22
const std::string SDP
Definition: Constants.h:26
const std::string MBMS_USER_SERVICE_DESCRIPTION
Definition: Constants.h:23
const std::string DASH_MANIFEST
Definition: Constants.h:28
const std::string HLS_MANIFEST
Definition: Constants.h:27
const std::string FIVEG_MAG_BC_UC
Definition: Constants.h:33
const std::string FIVEG_MAG_LEGACY
Definition: Constants.h:34
const char *const ITEM
Definition: Constants.h:56
const char *const BASE_PATTERN
Definition: Constants.h:47
const char *const DELIVERY_METHOD
Definition: Constants.h:45
const char *const METADATA_ENVELOPE
Definition: Constants.h:54
const char *const APP_SERVICE_DESCRIPTION_URI
Definition: Constants.h:53
const char *const IDENTICAL_CONTENT
Definition: Constants.h:51
const char *const SERVICE_ID
Definition: Constants.h:43
const char *const UNICAST_APP_SERVICE
Definition: Constants.h:49
const char *const VERSION
Definition: Constants.h:57
const char *const ALTERNATIVE_CONTENT
Definition: Constants.h:50
const char *const BROADCAST_APP_SERVICE
Definition: Constants.h:48
const char *const LANG
Definition: Constants.h:41
const char *const NAME
Definition: Constants.h:40
const char *const USER_SERVICE_DESCRIPTION
Definition: Constants.h:42
const char *const SESSION_DESCRIPTION_URI
Definition: Constants.h:46
const char *const VALID_UNTIL
Definition: Constants.h:59
const char *const MIME_TYPE
Definition: Constants.h:52
const char *const VALID_FROM
Definition: Constants.h:58
const char *const APP_SERVICE
Definition: Constants.h:44
const char *const METADATA_URI
Definition: Constants.h:55
const char *const BUNDLE_DESCRIPTION
Definition: Constants.h:39