diff options
Diffstat (limited to 'src/fig/FIG0_2.cpp')
-rw-r--r-- | src/fig/FIG0_2.cpp | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/src/fig/FIG0_2.cpp b/src/fig/FIG0_2.cpp new file mode 100644 index 0000000..04bff60 --- /dev/null +++ b/src/fig/FIG0_2.cpp @@ -0,0 +1,266 @@ +/* + 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) 2016 + 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/FIG0_2.h" +#include "utils.h" + +namespace FIC { + +FIG0_2::FIG0_2(FIGRuntimeInformation *rti) : + m_rti(rti), + m_initialised(false), + m_inserting_audio_not_data(false) +{ +} + +FillStatus FIG0_2::fill(uint8_t *buf, size_t max_size) +{ +#define FIG0_2_TRACE discard + using namespace std; + + FillStatus fs; + FIGtype0_2 *fig0_2 = NULL; + int cur = 0; + ssize_t remaining = max_size; + + const auto ensemble = m_rti->ensemble; + + etiLog.level(FIG0_2_TRACE) << "FIG0_2::fill init " << (m_initialised ? 1 : 0) << + " ********************************"; + + for (const auto& s : ensemble->services) { + // Exclude Fidc type services, TODO unsupported + auto type = s->getType(ensemble); + if (type == subchannel_type_t::Fidc) { + throw invalid_argument("FIG0/2 does not support FIDC"); + } + } + + if (not m_initialised) { + m_audio_services.clear(); + copy_if(ensemble->services.begin(), + ensemble->services.end(), + back_inserter(m_audio_services), + [&](shared_ptr<DabService>& s) { + return s->isProgramme(ensemble); + } ); + + m_data_services.clear(); + copy_if(ensemble->services.begin(), + ensemble->services.end(), + back_inserter(m_data_services), + [&](shared_ptr<DabService>& s) { + return not s->isProgramme(ensemble); + } ); + + m_initialised = true; + m_inserting_audio_not_data = !m_inserting_audio_not_data; + + if (m_inserting_audio_not_data) { + serviceFIG0_2 = m_audio_services.begin(); + } + else { + serviceFIG0_2 = m_data_services.begin(); + } + + etiLog.level(FIG0_2_TRACE) << "FIG0_2::fill we have " << + m_audio_services.size() << " audio and " << + m_data_services.size() << " data services. Inserting " << + (m_inserting_audio_not_data ? "AUDIO" : "DATA"); + } + + const auto last_service = m_inserting_audio_not_data ? + m_audio_services.end() : m_data_services.end(); + + // Rotate through the subchannels until there is no more + // space + for (; serviceFIG0_2 != last_service; ++serviceFIG0_2) { + const auto type = (*serviceFIG0_2)->getType(ensemble); + const auto isProgramme = (*serviceFIG0_2)->isProgramme(ensemble); + + etiLog.log(FIG0_2_TRACE, "FIG0_2::fill loop SId=%04x %s/%s", + (*serviceFIG0_2)->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" : "?"); + + // filter out services which have no components + if ((*serviceFIG0_2)->nbComponent(ensemble->components) == 0) { + etiLog.level(FIG0_2_TRACE) << "FIG0_2::fill no components "; + continue; + } + + ++cur; + + const int required_size = isProgramme ? + 3 + 2 * (*serviceFIG0_2)->nbComponent(ensemble->components) : + 5 + 2 * (*serviceFIG0_2)->nbComponent(ensemble->components); + + if (fig0_2 == NULL) { + etiLog.level(FIG0_2_TRACE) << "FIG0_2::fill header"; + if (remaining < 2 + required_size) { + etiLog.level(FIG0_2_TRACE) << "FIG0_2::fill header no place" << + " rem=" << remaining << " req=" << 2 + required_size; + break; + } + fig0_2 = (FIGtype0_2 *)buf; + + fig0_2->FIGtypeNumber = 0; + fig0_2->Length = 1; + fig0_2->CN = 0; + fig0_2->OE = 0; + fig0_2->PD = isProgramme ? 0 : 1; + fig0_2->Extension = 2; + buf += 2; + remaining -= 2; + } + else if (remaining < required_size) { + etiLog.level(FIG0_2_TRACE) << "FIG0_2::fill no place" << + " rem=" << remaining << " req=" << required_size; + break; + } + + if (type == subchannel_type_t::Audio) { + auto fig0_2serviceAudio = (FIGtype0_2_Service*)buf; + + fig0_2serviceAudio->SId = htons((*serviceFIG0_2)->id); + fig0_2serviceAudio->Local_flag = 0; + fig0_2serviceAudio->CAId = 0; + fig0_2serviceAudio->NbServiceComp = + (*serviceFIG0_2)->nbComponent(ensemble->components); + buf += 3; + fig0_2->Length += 3; + remaining -= 3; + + etiLog.log(FIG0_2_TRACE, "FIG0_2::fill audio SId=%04x", + (*serviceFIG0_2)->id); + } + else { + auto fig0_2serviceData = (FIGtype0_2_Service_data*)buf; + + fig0_2serviceData->SId = htonl((*serviceFIG0_2)->id); + fig0_2serviceData->Local_flag = 0; + fig0_2serviceData->CAId = 0; + fig0_2serviceData->NbServiceComp = + (*serviceFIG0_2)->nbComponent(ensemble->components); + buf += 5; + fig0_2->Length += 5; + remaining -= 5; + + etiLog.log(FIG0_2_TRACE, "FIG0_2::fill data SId=%04x", + (*serviceFIG0_2)->id); + } + + int curCpnt = 0; + for (auto component = getComponent( + ensemble->components, (*serviceFIG0_2)->id ); + component != ensemble->components.end(); + component = getComponent( + ensemble->components, + (*serviceFIG0_2)->id, + component ) + ) { + auto subchannel = getSubchannel( + ensemble->subchannels, (*component)->subchId); + + etiLog.log(FIG0_2_TRACE, "FIG0_2::fill comp sub=%04x srv=%04x", + (*component)->subchId, (*component)->serviceId); + + if (subchannel == ensemble->subchannels.end()) { + etiLog.log(error, + "Subchannel %i does not exist for component " + "of service %i\n", + (*component)->subchId, (*component)->serviceId); + throw MuxInitException(); + } + + switch ((*subchannel)->type) { + case subchannel_type_t::Audio: + { + auto audio_description = (FIGtype0_2_audio_component*)buf; + audio_description->TMid = 0; + audio_description->ASCTy = (*component)->type; + audio_description->SubChId = (*subchannel)->id; + audio_description->PS = ((curCpnt == 0) ? 1 : 0); + audio_description->CA_flag = 0; + } + break; + case subchannel_type_t::DataDmb: + { + auto data_description = (FIGtype0_2_data_component*)buf; + data_description->TMid = 1; + data_description->DSCTy = (*component)->type; + data_description->SubChId = (*subchannel)->id; + data_description->PS = ((curCpnt == 0) ? 1 : 0); + data_description->CA_flag = 0; + } + break; + case subchannel_type_t::Packet: + { + auto packet_description = (FIGtype0_2_packet_component*)buf; + packet_description->TMid = 3; + packet_description->setSCId((*component)->packet.id); + packet_description->PS = ((curCpnt == 0) ? 1 : 0); + packet_description->CA_flag = 0; + } + break; + default: + etiLog.log(error, + "Component type not supported\n"); + throw MuxInitException(); + } + buf += 2; + fig0_2->Length += 2; + remaining -= 2; + if (remaining < 0) { + etiLog.log(error, + "Sorry, no space left in FIG 0/2 to insert " + "component %i of program service %i.\n", + curCpnt, cur); + throw MuxInitException(); + } + ++curCpnt; + + etiLog.log(FIG0_2_TRACE, "FIG0_2::fill comp length=%d", + fig0_2->Length); + } + } + + if (serviceFIG0_2 == last_service) { + etiLog.log(FIG0_2_TRACE, "FIG0_2::loop reached last"); + m_initialised = false; + fs.complete_fig_transmitted = !m_inserting_audio_not_data; + } + + etiLog.log(FIG0_2_TRACE, "FIG0_2::loop end complete=%d", + fs.complete_fig_transmitted ? 1 : 0); + + fs.num_bytes_written = max_size - remaining; + return fs; +} + +} |