/*
Copyright (C) 2014 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
Parse DAB+ frames from a ETI file
Authors:
Matthias P. Braendli
*/
#include
#include
#include
#include
#include
#include
#include "dabplussnoop.h"
#include "firecode.h"
#define DPS_INDENT "\t\t"
#define DPS_PREFIX "DABPLUS:"
using namespace std;
void DabPlusSnoop::push(uint8_t* streamdata, size_t streamsize)
{
size_t original_size = m_data.size();
m_data.resize(original_size + streamsize);
memcpy(&m_data[original_size], streamdata, streamsize);
check();
}
// Idea and some code taken from Xpadxpert
int DabPlusSnoop::check()
{
if (m_data.size() < 10) {
// Not enough data
return -1;
}
bool crc_ok = false;
int i;
for (i = 0; i < m_data.size() - 10; i++) {
uint8_t* b = &m_data[i];
// the three bytes after the firecode must not be zero
// (simple plausibility check to avoid sync in zero byte region)
if (b[3] != 0x00 || (b[4] & 0xF0) != 0x00) {
uint16_t header_firecode = (b[0] << 8) | b[1];
uint16_t calculated_firecode = firecode_crc(b+2, 9);
if (header_firecode == calculated_firecode) {
crc_ok = true;
break;
}
}
}
if (crc_ok) {
fprintf(stderr, DPS_PREFIX " Found valid FireCode at %d\n", i);
m_data.erase(m_data.begin(), m_data.begin() + i);
return decode();
}
else {
fprintf(stderr, DPS_PREFIX " No valid FireCode found\n");
return -1;
}
}
int DabPlusSnoop::decode()
{
if (m_subchannel_index && m_data.size() >= m_subchannel_index * 110) {
fprintf(stderr, DPS_PREFIX " We have %zu bytes of data\n", m_data.size());
uint8_t* b = &m_data[0];
// -- Parse he_aac_super_frame
// ---- Parse he_aac_super_frame_header
// ------ Parse firecode and audio params
uint16_t header_firecode = (b[0] << 8) | b[1];
uint8_t audio_params = b[2];
int rfa = (audio_params & 0x80) ? 1 : 0;
int dac_rate = (audio_params & 0x40) ? 1 : 0;
int sbr_flag = (audio_params & 0x20) ? 1 : 0;
int aac_channel_mode = (audio_params & 0x10) ? 1 : 0;
int ps_flag = (audio_params & 0x08) ? 1 : 0;
int mpeg_surround_config = (audio_params & 0x07) ? 1 : 0;
int num_aus;
if ((dac_rate == 0) && (sbr_flag == 1)) num_aus = 2;
// AAC core sampling rate 16 kHz
else if ((dac_rate == 1) && (sbr_flag == 1)) num_aus = 3;
// AAC core sampling rate 24 kHz
else if ((dac_rate == 0) && (sbr_flag == 0)) num_aus = 4;
// AAC core sampling rate 32 kHz
else if ((dac_rate == 1) && (sbr_flag == 0)) num_aus = 6;
// AAC core sampling rate 48 kHz
fprintf(stderr,
DPS_INDENT DPS_PREFIX "\n"
DPS_INDENT "\tfirecode 0x%x\n"
DPS_INDENT "\trfa %d\n"
DPS_INDENT "\tdac_rate %d\n"
DPS_INDENT "\tsbr_flag %d\n"
DPS_INDENT "\taac_channel_mode %d\n"
DPS_INDENT "\tps_flag %d\n"
DPS_INDENT "\tmpeg_surround_config %d\n"
DPS_INDENT "\tnum_aus %d\n",
header_firecode, rfa, dac_rate, sbr_flag, aac_channel_mode,
ps_flag, mpeg_surround_config, num_aus);
// ------ Parse au_start
b += 3;
vector au_start_nibbles(3*(num_aus-1));
size_t nib = 0;
for (int i = 0; i < (num_aus-1)*3/2; i++) {
au_start_nibbles[nib] = b[i] >> 4;
au_start_nibbles[nib+1] = 0x0F & (b[i]);
nib += 2;
fprintf(stderr, "0x%1x 0x%1x ", b[i] >> 4, 0x0F & b[i]);
}
fprintf(stderr, "\n");
vector au_start(num_aus);
if (num_aus == 2)
au_start[0] = 5;
else if (num_aus == 3)
au_start[0] = 6;
else if (num_aus == 4)
au_start[0] = 8;
else if (num_aus == 6)
au_start[0] = 11;
nib = 0;
fprintf(stderr, DPS_INDENT DPS_PREFIX " AU start\n");
for (int au = 1; au < num_aus; au++) {
au_start[au] = au_start_nibbles[nib] << 8 | \
au_start_nibbles[nib+1] << 4 | \
au_start_nibbles[nib+2];
nib += 3;
}
for (int au = 0; au < num_aus; au++) {
fprintf(stderr, DPS_INDENT "\tAU[%d] %d 0x%x\n", au,
au_start[au],
au_start[au]);
}
m_data.clear();
return 0;
}
else {
return -1;
}
}