/* Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) This program 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. This program 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 this program. If not, see . dabplussnoop.cpp Extract MSC data and parse DAB+ frames from a ETI file Authors: Matthias P. Braendli */ /* From the spec: subchannel_index = MSC sub-channel size (kbps) / 8 audio_super_frame_size (bytes) = subchannel_index * 110 // Derived from // au_start[n] = au_start[n - 1] + au_size[n - 1] + 2; // 2 bytes for CRC au_size[n] = au_start[n+1] - au_start[n] - 2; he_aac_super_frame(subchannel_index) { he_aac_super_frame_header() { header_firecode 16 rfa 1 dac_rate 1 sbr_flag 1 aac_channel_mode 1 ps_flag 1 mpeg_surround_config 3 // end of audio parameters if ((dac_rate == 0) && (sbr_flag == 1)) num_aus = 2; // AAC core sampling rate 16 kHz if ((dac_rate == 1) && (sbr_flag == 1)) num_aus = 3; // AAC core sampling rate 24 kHz if ((dac_rate == 0) && (sbr_flag == 0)) num_aus = 4; // AAC core sampling rate 32 kHz if ((dac_rate == 1) && (sbr_flag == 0)) num_aus = 6; // AAC core sampling rate 48 kHz for (n = 1; n < num_aus; n++) { au_start[n]; 12 } if !((dac_rate == 1) && (sbr_flag == 1)) alignment 4 } for (n = 0; n < num_aus; n++) { au[n] 8 * au_size[n] au_crc[n] 16 } } */ #include #include #include #include #include #include #include #include "faad_decoder.hpp" #pragma once // DabPlusSnoop is responsible for decoding DAB+ audio class DabPlusSnoop { public: void set_subchannel_index(unsigned subchannel_index) { m_subchannel_index = subchannel_index; } void enable_wav_file_output(bool enable) { m_write_to_wav_file = enable; } void push(uint8_t* streamdata, size_t streamsize); audio_statistics_t get_audio_statistics(void) const; int subchid = -1; private: /* Data needed for FAAD */ FaadDecoder m_faad_decoder; bool m_write_to_wav_file = false; bool m_ps_flag = false; bool m_aac_channel_mode = false; bool m_dac_rate = false; bool m_sbr_flag = false; int m_mpeg_surround_config = false; /* Functions */ bool seek_valid_firecode(void); bool decode(void); bool extract_au(std::vector au_start); bool analyse_au(std::vector >& aus); unsigned m_subchannel_index = 0; std::vector m_data; }; // StreamSnoop is responsible for saving msc data into files, // and calling DabPlusSnoop's decode routine if it's a DAB+ subchannel class StreamSnoop { public: StreamSnoop(int subchid, bool dump_to_file) : dps(), m_raw_data_stream_fd(nullptr), m_dump_to_file(dump_to_file) { dps.subchid = subchid; dps.enable_wav_file_output(dump_to_file); } ~StreamSnoop(); StreamSnoop(StreamSnoop&& other); StreamSnoop(const StreamSnoop& other) = delete; StreamSnoop& operator=(const StreamSnoop& other) = delete; void set_subchannel_index(unsigned subchannel_index) { dps.set_subchannel_index(subchannel_index); } void push(uint8_t* streamdata, size_t streamsize); audio_statistics_t get_audio_statistics(void) const; int subchid = -1; int stream_index = -1; private: DabPlusSnoop dps; FILE* m_raw_data_stream_fd; bool m_dump_to_file; };