diff options
Diffstat (limited to 'src/fig/FIG0_24.cpp')
-rw-r--r-- | src/fig/FIG0_24.cpp | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/src/fig/FIG0_24.cpp b/src/fig/FIG0_24.cpp new file mode 100644 index 0000000..a790440 --- /dev/null +++ b/src/fig/FIG0_24.cpp @@ -0,0 +1,184 @@ +/* + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, + 2011, 2012 Her Majesty the Queen in Right of Canada (Communications + Research Center Canada) + + Copyright (C) 2017 + Matthias P. Braendli, matthias.braendli@mpb.li + */ +/* + This file is part of ODR-DabMux. + + ODR-DabMux is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + ODR-DabMux is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ODR-DabMux. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "fig/FIG0structs.h" +#include "fig/FIG0_24.h" +#include "utils.h" + +/* FIG0/24 allows us to announce if a service is available in another ensemble. + * Things we do not support: + * + * - 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 { + +struct FIGtype0_24_audioservice { + uint16_t SId; + uint8_t Length:4; + uint8_t CAId:3; + uint8_t rfa:1; +} PACKED; + +struct FIGtype0_24_dataservice { + uint32_t SId; + uint8_t Length:4; + uint8_t CAId:3; + uint8_t rfa:1; +} PACKED; + + +FIG0_24::FIG0_24(FIGRuntimeInformation *rti) : + m_rti(rti), + m_initialised(false), + m_inserting_audio_not_data(false) +{ +} + +FillStatus FIG0_24::fill(uint8_t *buf, size_t max_size) +{ +#define FIG0_24_TRACE discard + using namespace std; + + FillStatus fs; + FIGtype0* fig0 = nullptr; + ssize_t remaining = max_size; + + const auto ensemble = m_rti->ensemble; + + etiLog.level(FIG0_24_TRACE) << "FIG0_24::fill init " << (m_initialised ? 1 : 0) << + " ********************************"; + + if (not m_initialised) { + serviceFIG0_24 = ensemble->services.begin(); + m_initialised = true; + } + + const auto last_service = ensemble->services.end(); + + // 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, + 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; + } + + const ssize_t required_size = + (isProgramme ? 2 : 4) + 1 + + (*serviceFIG0_24)->other_ensembles.size() * 2; + + + if (fig0 == nullptr) { + etiLog.level(FIG0_24_TRACE) << "FIG0_24::fill header"; + if (remaining < 2 + required_size) { + etiLog.level(FIG0_24_TRACE) << "FIG0_24::fill header no place" << + " rem=" << remaining << " req=" << 2 + required_size; + break; + } + fig0 = (FIGtype0*)buf; + + 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; + fig0->PD = isProgramme ? 0 : 1; + fig0->Extension = 24; + buf += 2; + remaining -= 2; + } + else if (remaining < required_size) { + etiLog.level(FIG0_24_TRACE) << "FIG0_24::fill no place" << + " rem=" << remaining << " req=" << required_size; + break; + } + + if (type == subchannel_type_t::Audio) { + auto fig0_2serviceAudio = (FIGtype0_24_audioservice*)buf; + + fig0_2serviceAudio->SId = htons((*serviceFIG0_24)->id); + fig0_2serviceAudio->rfa = 0; + fig0_2serviceAudio->CAId = 0; + 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); + } + else { + auto fig0_2serviceData = (FIGtype0_24_dataservice*)buf; + + fig0_2serviceData->SId = htonl((*serviceFIG0_24)->id); + fig0_2serviceData->rfa = 0; + fig0_2serviceData->CAId = 0; + 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); + } + + for (const uint16_t oe : (*serviceFIG0_24)->other_ensembles) { + buf[0] = oe >> 8; + buf[1] = oe & 0xFF; + + buf += 2; + fig0->Length += 2; + remaining -= 2; + } + } + + if (serviceFIG0_24 == last_service) { + etiLog.log(FIG0_24_TRACE, "FIG0_24::loop reached last"); + fs.complete_fig_transmitted = true; + m_initialised = false; + } + + etiLog.log(FIG0_24_TRACE, "FIG0_24::loop end complete=%d", + fs.complete_fig_transmitted ? 1 : 0); + + fs.num_bytes_written = max_size - remaining; + return fs; +} + +} |