summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ConfigParser.cpp147
-rw-r--r--src/MuxElements.h12
-rw-r--r--src/fig/FIG0_24.cpp65
-rw-r--r--src/fig/FIG0_24.h4
4 files changed, 157 insertions, 71 deletions
diff --git a/src/ConfigParser.cpp b/src/ConfigParser.cpp
index 0ab3d43..a0bf97e 100644
--- a/src/ConfigParser.cpp
+++ b/src/ConfigParser.cpp
@@ -286,7 +286,7 @@ static void parse_freq_info(ptree& pt,
} break;
} // switch(rm)
}
- catch (ptree_error &e) {
+ catch (const ptree_error &e) {
throw runtime_error("invalid configuration for FI " + fle_uid);
}
@@ -312,6 +312,53 @@ static void parse_freq_info(ptree& pt,
} // if FI present
}
+static void parse_other_service_linking(ptree& pt,
+ std::shared_ptr<dabEnsemble> ensemble)
+{
+ auto pt_other_services = pt.get_child_optional("other-services");
+ if (pt_other_services)
+ {
+ for (const auto& it_service : *pt_other_services) {
+ const string srv_uid = it_service.first;
+ const ptree pt_srv = it_service.second;
+
+ ServiceOtherEnsembleInfo info;
+ try {
+ info.service_id = hexparse(pt_srv.get<string>("id"));
+
+ auto oelist = pt_srv.get<std::string>("other_ensembles", "");
+
+ if (not oelist.empty()) {
+ vector<string> oe_string_list;
+ boost::split(oe_string_list, oelist, boost::is_any_of(","));
+
+ for (const auto& oe_string : oe_string_list) {
+ if (oe_string == "") {
+ continue;
+ }
+ try {
+ info.other_ensembles.push_back(hexparse(oe_string));
+ }
+ catch (const std::exception& e) {
+ etiLog.level(warn) << "Cannot parse '" << oelist <<
+ "' other_ensembles for service " << srv_uid <<
+ ": " << e.what();
+ }
+ }
+
+ ensemble->service_other_ensemble.push_back(move(info));
+ }
+ }
+ catch (const std::exception &e) {
+ etiLog.level(warn) <<
+ "Cannot parse other_ensembles for service " << srv_uid <<
+ ": " << e.what();
+ }
+
+ } // for over services
+ } // if other-services present
+}
+
static void parse_general(ptree& pt,
std::shared_ptr<dabEnsemble> ensemble)
{
@@ -381,7 +428,7 @@ static void parse_general(ptree& pt,
ensemble_short_label = pt_ensemble.get<string>("shortlabel");
success = ensemble->label.setLabel(ensemble_label, ensemble_short_label);
}
- catch (ptree_error &e) {
+ catch (const ptree_error &e) {
etiLog.level(warn) << "Ensemble short label undefined, "
"truncating label " << ensemble_label;
@@ -430,9 +477,9 @@ static void parse_general(ptree& pt,
ensemble->clusters.push_back(cl);
}
}
- catch (ptree_error& e) {
- etiLog.level(info) << "No announcements defined in ensemble";
- etiLog.level(debug) << "because " << e.what();
+ catch (const ptree_error& e) {
+ etiLog.level(info) <<
+ "No announcements defined in ensemble because " << e.what();
}
}
@@ -490,7 +537,7 @@ void parse_ptree(
try {
service->clusters.push_back(hexparse(cluster_s));
}
- catch (std::logic_error& e) {
+ catch (const std::exception& e) {
etiLog.level(warn) << "Cannot parse '" << clusterlist <<
"' announcement clusters for service " << serviceuid <<
": " << e.what();
@@ -502,7 +549,7 @@ void parse_ptree(
"is empty, but announcements are defined";
}
}
- catch (ptree_error& e) {
+ catch (const ptree_error& e) {
service->ASu = 0;
service->clusters.clear();
@@ -510,30 +557,6 @@ void parse_ptree(
serviceuid;
}
- try {
- auto oelist = pt_service.get<std::string>("other_ensembles", "");
- vector<string> oe_string_list;
- boost::split(oe_string_list, oelist, boost::is_any_of(","));
-
- for (const auto& oe_string : oe_string_list) {
- if (oe_string == "") {
- continue;
- }
- try {
- service->other_ensembles.push_back(hexparse(oe_string));
- }
- catch (std::logic_error& e) {
- etiLog.level(warn) << "Cannot parse '" << oelist <<
- "' announcement clusters for service " << serviceuid <<
- ": " << e.what();
- }
- }
- }
- catch (ptree_error& e) {
- etiLog.level(info) << "No other_sensmbles information for Service " <<
- serviceuid;
- }
-
int success = -5;
string servicelabel = pt_service.get<string>("label");
@@ -542,7 +565,7 @@ void parse_ptree(
serviceshortlabel = pt_service.get<string>("shortlabel");
success = service->label.setLabel(servicelabel, serviceshortlabel);
}
- catch (ptree_error &e) {
+ catch (const ptree_error &e) {
etiLog.level(warn) << "Service short label undefined, "
"truncating label " << servicelabel;
@@ -587,6 +610,43 @@ void parse_ptree(
}
service->language = hexparse(pt_service.get("language", "0"));
+ try {
+ auto oelist = pt_service.get<std::string>("other_ensembles", "");
+
+ if (not oelist.empty()) {
+ etiLog.level(warn) <<
+ "You are using the deprecated other_ensembles inside "
+ "'services' specification. Please see doc/servicelinking.mux "
+ "for the new syntax.";
+
+ vector<string> oe_string_list;
+ boost::split(oe_string_list, oelist, boost::is_any_of(","));
+
+ ServiceOtherEnsembleInfo oe_info;
+ oe_info.service_id = service->id;
+
+ for (const auto& oe_string : oe_string_list) {
+ if (oe_string == "") {
+ continue;
+ }
+ try {
+ oe_info.other_ensembles.push_back(hexparse(oe_string));
+ }
+ catch (const std::exception& e) {
+ etiLog.level(warn) << "Cannot parse '" << oelist <<
+ "' other_ensembles for service " << serviceuid <<
+ ": " << e.what();
+ }
+ }
+
+ ensemble->service_other_ensemble.push_back(move(oe_info));
+ }
+ }
+ catch (const ptree_error& e) {
+ etiLog.level(info) << "No other_ensembles information for Service " <<
+ serviceuid;
+ }
+
allservices[serviceuid] = service;
// Set the service's SCIds to zero
@@ -612,7 +672,7 @@ void parse_ptree(
setup_subchannel_from_ptree(subchan, it->second, ensemble,
subchanuid);
}
- catch (runtime_error &e) {
+ catch (const runtime_error &e) {
etiLog.log(error,
"%s\n", e.what());
throw;
@@ -649,7 +709,7 @@ void parse_ptree(
}
service = allservices[service_uid];
}
- catch (ptree_error &e) {
+ catch (const ptree_error &e) {
stringstream ss;
ss << "Component with uid " << componentuid << " is missing service definition!";
throw runtime_error(ss.str());
@@ -666,7 +726,7 @@ void parse_ptree(
}
subchannel = allsubchans[subchan_uid];
}
- catch (ptree_error &e) {
+ catch (const ptree_error &e) {
stringstream ss;
ss << "Component with uid " << componentuid << " is missing subchannel definition!";
throw runtime_error(ss.str());
@@ -691,7 +751,7 @@ void parse_ptree(
componentshortlabel = pt_comp.get<string>("shortlabel");
success = component->label.setLabel(componentlabel, componentshortlabel);
}
- catch (ptree_error &e) {
+ catch (const ptree_error &e) {
if (not componentlabel.empty()) {
etiLog.level(warn) << "Component short label undefined, "
"truncating label " << componentlabel;
@@ -773,6 +833,7 @@ void parse_ptree(
parse_linkage(pt, ensemble);
parse_freq_info(pt, ensemble);
+ parse_other_service_linking(pt, ensemble);
}
static Inputs::dab_input_zmq_config_t setup_zmq_input(
@@ -784,7 +845,7 @@ static Inputs::dab_input_zmq_config_t setup_zmq_input(
try {
zmqconfig.buffer_size = pt.get<int>("zmq-buffer");
}
- catch (ptree_error &e) {
+ catch (const ptree_error &e) {
stringstream ss;
ss << "Subchannel " << subchanuid << ": " << "no zmq-buffer defined!";
throw runtime_error(ss.str());
@@ -792,7 +853,7 @@ static Inputs::dab_input_zmq_config_t setup_zmq_input(
try {
zmqconfig.prebuffering = pt.get<int>("zmq-prebuffering");
}
- catch (ptree_error &e) {
+ catch (const ptree_error &e) {
stringstream ss;
ss << "Subchannel " << subchanuid << ": " << "no zmq-prebuffer defined!";
throw runtime_error(ss.str());
@@ -817,7 +878,7 @@ static void setup_subchannel_from_ptree(shared_ptr<DabSubchannel>& subchan,
try {
type = pt.get<string>("type");
}
- catch (ptree_error &e) {
+ catch (const ptree_error &e) {
stringstream ss;
ss << "Subchannel with uid " << subchanuid << " has no type defined!";
throw runtime_error(ss.str());
@@ -832,7 +893,7 @@ static void setup_subchannel_from_ptree(shared_ptr<DabSubchannel>& subchan,
try {
inputUri = pt.get<string>("inputfile");
}
- catch (ptree_error &e) {
+ catch (const ptree_error &e) {
stringstream ss;
ss << "Subchannel with uid " << subchanuid << " has no inputUri defined!";
throw runtime_error(ss.str());
@@ -973,7 +1034,7 @@ static void setup_subchannel_from_ptree(shared_ptr<DabSubchannel>& subchan,
throw runtime_error(ss.str());
}
}
- catch (ptree_error &e) {
+ catch (const ptree_error &e) {
throw runtime_error("Error, no bitrate defined for subchannel " + subchanuid);
}
@@ -984,7 +1045,7 @@ static void setup_subchannel_from_ptree(shared_ptr<DabSubchannel>& subchan,
throw runtime_error("Invalid subchannel id " + to_string(subchan->id));
}
}
- catch (ptree_error &e) {
+ catch (const ptree_error &e) {
for (int i = 0; i < 64; ++i) { // Find first free subchannel
auto subchannel = getSubchannel(ensemble->subchannels, i);
if (subchannel == ensemble->subchannels.end()) {
@@ -1040,7 +1101,7 @@ static void setup_subchannel_from_ptree(shared_ptr<DabSubchannel>& subchan,
}
protection->level = level - 1;
}
- catch (ptree_error &e) {
+ catch (const ptree_error &e) {
stringstream ss;
ss << "Subchannel with uid " << subchanuid <<
": protection level undefined!";
diff --git a/src/MuxElements.h b/src/MuxElements.h
index b5d1285..6b8b718 100644
--- a/src/MuxElements.h
+++ b/src/MuxElements.h
@@ -196,6 +196,7 @@ class DabComponent;
class DabSubchannel;
class LinkageSet;
struct FrequencyInformation;
+struct ServiceOtherEnsembleInfo;
using vec_sp_component = std::vector<std::shared_ptr<DabComponent> >;
using vec_sp_service = std::vector<std::shared_ptr<DabService> >;
@@ -248,6 +249,7 @@ class dabEnsemble : public RemoteControllable {
std::vector<std::shared_ptr<AnnouncementCluster> > clusters;
std::vector<std::shared_ptr<LinkageSet> > linkagesets;
std::vector<std::shared_ptr<FrequencyInformation> > frequency_information;
+ std::vector<ServiceOtherEnsembleInfo> service_other_ensemble;
};
@@ -420,9 +422,6 @@ class DabService : public RemoteControllable
uint16_t ASu = 0;
std::vector<uint8_t> clusters;
- // Ensembles in which this service is also available, used for FIG0/24
- std::vector<uint16_t> other_ensembles;
-
subchannel_type_t getType(const std::shared_ptr<dabEnsemble> ensemble) const;
bool isProgramme(const std::shared_ptr<dabEnsemble>& ensemble) const;
unsigned char nbComponent(const vec_sp_component& components) const;
@@ -437,6 +436,13 @@ class DabService : public RemoteControllable
virtual const std::string get_parameter(const std::string& parameter) const;
};
+/* Represent an entry for FIG0/24 */
+struct ServiceOtherEnsembleInfo {
+ uint32_t service_id = 0;
+ // Ensembles in which this service is also available
+ std::vector<uint16_t> other_ensembles;
+};
+
enum class ServiceLinkType {DAB, FM, DRM, AMSS};
/* Represent one link inside a linkage set */
diff --git a/src/fig/FIG0_24.cpp b/src/fig/FIG0_24.cpp
index a790440..7dcefcd 100644
--- a/src/fig/FIG0_24.cpp
+++ b/src/fig/FIG0_24.cpp
@@ -32,7 +32,6 @@
*
* - The CEI using length=0, because this information is not available in the
* remote control, and there is no runtime changes.
- * - Announcing information about other ensembles (OE=1)
*/
namespace FIC {
@@ -61,7 +60,7 @@ FIG0_24::FIG0_24(FIGRuntimeInformation *rti) :
FillStatus FIG0_24::fill(uint8_t *buf, size_t max_size)
{
-#define FIG0_24_TRACE discard
+#define FIG0_24_TRACE debug
using namespace std;
FillStatus fs;
@@ -74,34 +73,52 @@ FillStatus FIG0_24::fill(uint8_t *buf, size_t max_size)
" ********************************";
if (not m_initialised) {
- serviceFIG0_24 = ensemble->services.begin();
+ serviceFIG0_24 = ensemble->service_other_ensemble.begin();
m_initialised = true;
}
- const auto last_service = ensemble->services.end();
+ const auto last_service = ensemble->service_other_ensemble.end();
+
+ bool last_oe = false;
// Rotate through the subchannels until there is no more
// space
for (; serviceFIG0_24 != last_service; ++serviceFIG0_24) {
- const auto type = (*serviceFIG0_24)->getType(ensemble);
- const auto isProgramme = (*serviceFIG0_24)->isProgramme(ensemble);
- etiLog.log(FIG0_24_TRACE, "FIG0_24::fill loop SId=%04x %s/%s",
- (*serviceFIG0_24)->id,
+ shared_ptr<DabService> service;
+ for (const auto& local_service : ensemble->services) {
+ if (local_service->id == serviceFIG0_24->service_id) {
+ service = local_service;
+ break;
+ }
+ }
+
+ subchannel_type_t type = subchannel_type_t::Audio;
+ bool isProgramme = true;
+ bool oe = true;
+
+ if (service) {
+ oe = false;
+ type = service->getType(ensemble);
+ isProgramme = service->isProgramme(ensemble);
+ }
+
+ etiLog.log(FIG0_24_TRACE, "FIG0_24::fill loop OE=%d SId=%04x %s/%s",
+ oe,
+ serviceFIG0_24->service_id,
m_inserting_audio_not_data ? "AUDIO" : "DATA",
type == subchannel_type_t::Audio ? "Audio" :
type == subchannel_type_t::Packet ? "Packet" :
type == subchannel_type_t::DataDmb ? "DataDmb" :
type == subchannel_type_t::Fidc ? "Fidc" : "?");
- // Skip services that are not in other ensembles
- if ((*serviceFIG0_24)->other_ensembles.empty()) {
- continue;
+ if (last_oe != oe) {
+ fig0 = nullptr;
}
const ssize_t required_size =
(isProgramme ? 2 : 4) + 1 +
- (*serviceFIG0_24)->other_ensembles.size() * 2;
+ serviceFIG0_24->other_ensembles.size() * 2;
if (fig0 == nullptr) {
@@ -116,8 +133,9 @@ FillStatus FIG0_24::fill(uint8_t *buf, size_t max_size)
fig0->FIGtypeNumber = 0;
fig0->Length = 1;
// CN according to ETSI TS 103 176, Clause 5.3.4.1
- fig0->CN = (serviceFIG0_24 == ensemble->services.begin() ? 0 : 1);
- fig0->OE = 0;
+ bool isFirst = serviceFIG0_24 == ensemble->service_other_ensemble.begin();
+ fig0->CN = (isFirst ? 0 : 1);
+ fig0->OE = oe;
fig0->PD = isProgramme ? 0 : 1;
fig0->Extension = 24;
buf += 2;
@@ -132,33 +150,33 @@ FillStatus FIG0_24::fill(uint8_t *buf, size_t max_size)
if (type == subchannel_type_t::Audio) {
auto fig0_2serviceAudio = (FIGtype0_24_audioservice*)buf;
- fig0_2serviceAudio->SId = htons((*serviceFIG0_24)->id);
+ fig0_2serviceAudio->SId = htons(serviceFIG0_24->service_id);
fig0_2serviceAudio->rfa = 0;
fig0_2serviceAudio->CAId = 0;
- fig0_2serviceAudio->Length = (*serviceFIG0_24)->other_ensembles.size();
+ fig0_2serviceAudio->Length = serviceFIG0_24->other_ensembles.size();
buf += 3;
fig0->Length += 3;
remaining -= 3;
etiLog.log(FIG0_24_TRACE, "FIG0_24::fill audio SId=%04x",
- (*serviceFIG0_24)->id);
+ serviceFIG0_24->service_id);
}
else {
auto fig0_2serviceData = (FIGtype0_24_dataservice*)buf;
- fig0_2serviceData->SId = htonl((*serviceFIG0_24)->id);
+ fig0_2serviceData->SId = htonl(serviceFIG0_24->service_id);
fig0_2serviceData->rfa = 0;
fig0_2serviceData->CAId = 0;
- fig0_2serviceData->Length = (*serviceFIG0_24)->other_ensembles.size();
+ fig0_2serviceData->Length = serviceFIG0_24->other_ensembles.size();
buf += 4;
fig0->Length += 4;
remaining -= 4;
etiLog.log(FIG0_24_TRACE, "FIG0_24::fill data SId=%04x",
- (*serviceFIG0_24)->id);
+ serviceFIG0_24->service_id);
}
- for (const uint16_t oe : (*serviceFIG0_24)->other_ensembles) {
+ for (const uint16_t oe : serviceFIG0_24->other_ensembles) {
buf[0] = oe >> 8;
buf[1] = oe & 0xFF;
@@ -174,8 +192,9 @@ FillStatus FIG0_24::fill(uint8_t *buf, size_t max_size)
m_initialised = false;
}
- etiLog.log(FIG0_24_TRACE, "FIG0_24::loop end complete=%d",
- fs.complete_fig_transmitted ? 1 : 0);
+ etiLog.log(FIG0_24_TRACE, "FIG0_24::loop end complete=%d %d",
+ fs.complete_fig_transmitted ? 1 : 0,
+ max_size - remaining);
fs.num_bytes_written = max_size - remaining;
return fs;
diff --git a/src/fig/FIG0_24.h b/src/fig/FIG0_24.h
index 1c17f6b..785e9bc 100644
--- a/src/fig/FIG0_24.h
+++ b/src/fig/FIG0_24.h
@@ -3,7 +3,7 @@
2011, 2012 Her Majesty the Queen in Right of Canada (Communications
Research Center Canada)
- Copyright (C) 2017
+ Copyright (C) 2018
Matthias P. Braendli, matthias.braendli@mpb.li
*/
/*
@@ -47,7 +47,7 @@ class FIG0_24 : public IFIG
FIGRuntimeInformation *m_rti;
bool m_initialised;
bool m_inserting_audio_not_data;
- vec_sp_service::iterator serviceFIG0_24;
+ std::vector<ServiceOtherEnsembleInfo>::iterator serviceFIG0_24;
};
}