Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/nrsc5.h
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,9 @@ struct nrsc5_event_t
const uint8_t *data;
size_t count;
unsigned int flags; /** The specific status of the hdc packet. Example `NRSC5_PKT_FLAGS_CRC_ERROR` **/
const uint8_t *enh_data;
size_t enh_count;
unsigned int enh_flags;
} hdc;
struct {
unsigned int program;
Expand Down
7 changes: 7 additions & 0 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ typedef struct {
unsigned int audio_packets;
unsigned int audio_bytes;
unsigned int audio_errors;
unsigned int audio_errors_enh;
int done;
} state_t;

Expand Down Expand Up @@ -351,6 +352,9 @@ static void callback(const nrsc5_event_t *evt, void *opaque)
else
st->audio_packets_valid++;

if (evt->hdc.enh_flags & NRSC5_PKT_FLAGS_CRC_ERROR)
st->audio_errors_enh++;

if (st->audio_packets_valid >= 32) {
log_info("Audio bit rate: %.1f kbps", (float)st->audio_bytes * 8 * NRSC5_SAMPLE_RATE_AUDIO / NRSC5_AUDIO_FRAME_SAMPLES / st->audio_packets_valid / 1000);
st->audio_packets_valid = 0;
Expand All @@ -360,8 +364,11 @@ static void callback(const nrsc5_event_t *evt, void *opaque)
{
if (st->audio_errors > 0)
log_warn("Audio packet CRC mismatches: %d", st->audio_errors);
if (st->audio_errors_enh > 0)
log_warn("Audio packet CRC enhanced mismatch: %d", st->audio_errors);
st->audio_packets = 0;
st->audio_errors = 0;
st->audio_errors_enh = 0;
}
}
break;
Expand Down
22 changes: 17 additions & 5 deletions src/nrsc5.c
Original file line number Diff line number Diff line change
Expand Up @@ -702,23 +702,35 @@ void nrsc5_report_lost_sync(nrsc5_t *st)
nrsc5_report(st, &evt);
}

void nrsc5_report_hdc(nrsc5_t *st, unsigned int program, const packet_t* pkt)
{
void nrsc5_report_hdc(nrsc5_t *st, unsigned int program, const packet_ref_t* pkt, const packet_ref_t* enh_pkt){
nrsc5_event_t evt;

evt.event = NRSC5_EVENT_HDC;
evt.hdc.program = program;
evt.hdc.data = NULL;
evt.hdc.count = 0;
evt.hdc.flags = NRSC5_PKT_FLAGS_NONE;
evt.hdc.enh_data = NULL;
evt.hdc.enh_count = 0;
evt.hdc.enh_flags = NRSC5_PKT_FLAGS_NONE;

if (pkt->shape == PACKET_FULL)
if (pkt != NULL)
{
evt.hdc.data = pkt->data;
evt.hdc.count = pkt->size;

if (pkt->flags & PACKET_FLAG_CRC_ERROR)
evt.hdc.flags |= NRSC5_PKT_FLAGS_CRC_ERROR;
}

if (enh_pkt != NULL)
{
evt.hdc.enh_data = enh_pkt->data;
evt.hdc.enh_count = enh_pkt->size;

if (enh_pkt->flags & PACKET_FLAG_CRC_ERROR)
evt.hdc.enh_flags |= NRSC5_PKT_FLAGS_CRC_ERROR;
}
if (pkt->flags & PACKET_FLAG_CRC_ERROR)
evt.hdc.flags |= NRSC5_PKT_FLAGS_CRC_ERROR;

nrsc5_report(st, &evt);
}
Expand Down
121 changes: 75 additions & 46 deletions src/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,94 +34,115 @@ void output_align(output_t *st, unsigned int program, unsigned int stream_id, un
elastic->audio_offset = offset;
}

static int is_complete_pkt(const packet_t* pkt)
static int pkt_is_crc_ok(const unsigned int flags)
{
return pkt->shape == PACKET_FULL;
return !(flags & PACKET_FLAG_CRC_ERROR);
}

static int is_crc_ok(const packet_t* pkt)
static void pkt_reset(packet_t* pkt)
{
return !(pkt->flags & PACKET_FLAG_CRC_ERROR);
pkt->size = 0;
pkt->flags = PACKET_FLAG_NONE;
pkt->shape = PACKET_NONE;
}

void output_push(output_t *st, const packet_ref_t* ref)
{
elastic_buffer_t *elastic = &st->elastic[ref->program][ref->stream_id];
packet_t* pkt = &elastic->packets[ref->seq];

if (ref->stream_id != 0)
return; // TODO: Process enhanced stream
size_t offset = 0;

if (pkt->shape == PACKET_FULL)
log_warn("Packet %d already exists in elastic buffer for program %d, stream %d. Overwriting.", ref->seq, ref->program, ref->stream_id);

if (ref->shape == PACKET_HALF_BACK && pkt->shape == PACKET_HALF_FRONT)
if (ref->shape == PACKET_HALF_BACK)
{
if (pkt->shape != PACKET_HALF_FRONT)
return;

pkt->flags |= ref->flags;
pkt->shape = PACKET_FULL;

if (is_crc_ok(pkt))
{
memcpy(pkt->data + pkt->size, ref->data, ref->size);
pkt->size += ref->size;
}
else
{
pkt->size = 0;
}
offset = pkt->size;
}
else
{
if (ref->shape == PACKET_HALF_BACK)
return;

pkt->flags = ref->flags;
pkt->shape = ref->shape;

if (is_crc_ok(pkt))
{
memcpy(pkt->data, ref->data, ref->size);
pkt->size = ref->size;
}
else
{
pkt->size = 0;
}
offset = 0;
}

if (pkt_is_crc_ok(pkt->flags))
{
memcpy(pkt->data + offset, ref->data, ref->size);
pkt->size = offset + ref->size;
}
else
{
pkt->size = 0;
}
}

static void pkt_reset(packet_t* pkt)
static int is_core_running(output_t *st, unsigned int program)
{
pkt->size = 0;
pkt->flags = PACKET_FLAG_NONE;
pkt->shape = PACKET_NONE;
elastic_buffer_t *elastic = &st->elastic[program][0];
return elastic->audio_offset != -1;
}

static int collect_packet(output_t *st, packet_ref_t* ref, unsigned int program, unsigned int stream_id)
{
elastic_buffer_t *elastic = &st->elastic[program][stream_id];
if (elastic->audio_offset == -1)
return 0;

packet_t* pkt = &elastic->packets[elastic->audio_offset];
if (pkt->shape != PACKET_FULL)
return 0;

ref->program = program;
ref->stream_id = stream_id;
ref->seq = elastic->audio_offset;
ref->flags = pkt->flags;

if (pkt_is_crc_ok(pkt->flags))
{
ref->data = pkt->data;
ref->size = pkt->size;
}
else
{
ref->data = NULL;
ref->size = 0;
}
return 1;
}

void output_advance(output_t *st)
{
unsigned int program, frame;
unsigned int program, stream_id, frame;
unsigned int audio_frames = (st->radio->mode == NRSC5_MODE_FM ? 2 : 4);
packet_ref_t core, enh;

for (program = 0; program < MAX_PROGRAMS; program++)
{
elastic_buffer_t *elastic = &st->elastic[program][0]; // TODO: Process enhanced stream

if (elastic->audio_offset == -1)
if (!is_core_running(st, program))
continue;

for (frame = 0; frame < audio_frames; frame++)
{
packet_t* pkt = &elastic->packets[elastic->audio_offset];
int has_core = collect_packet(st, &core, program, 0);
int has_enh = collect_packet(st, &enh, program, 1);
#ifdef USE_FAAD2
int produced_audio = 0;
#endif

if (is_complete_pkt(pkt))
if (has_core)
{
nrsc5_report_hdc(st->radio, program, pkt);
nrsc5_report_hdc(st->radio, program, &core, has_enh ? &enh : NULL);
}

if (is_complete_pkt(pkt) && is_crc_ok(pkt))
if (has_core && core.size > 0)
{
#ifdef USE_FAAD2
void *buffer;
Expand All @@ -132,7 +153,7 @@ void output_advance(output_t *st)
NeAACDecInitHDC(&st->aacdec[program]);
}

buffer = NeAACDecDecode(st->aacdec[program], &info, pkt->data, pkt->size);
buffer = NeAACDecDecode(st->aacdec[program], &info, core.data, core.size);
if (info.error > 0)
log_error("Decode error: %s", NeAACDecGetErrorMessage(info.error));

Expand All @@ -155,14 +176,22 @@ void output_advance(output_t *st)
#endif
}

pkt_reset(pkt);

#ifdef USE_FAAD2
if (!produced_audio)
nrsc5_report_audio(st->radio, program, st->silence, NRSC5_AUDIO_FRAME_SAMPLES * 2);
#endif

elastic->audio_offset = (elastic->audio_offset + 1) % ELASTIC_BUFFER_LEN;

for (stream_id = 0; stream_id < MAX_STREAMS; stream_id++)
{
elastic_buffer_t *elastic = &st->elastic[program][stream_id];

if (elastic->audio_offset == -1)
continue;

pkt_reset(&elastic->packets[elastic->audio_offset]);
elastic->audio_offset = (elastic->audio_offset + 1) % ELASTIC_BUFFER_LEN;
}

}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/private.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ void nrsc5_report_sync(nrsc5_t *, float freq_offset, int psmi);
void nrsc5_report_lost_sync(nrsc5_t *);
void nrsc5_report_mer(nrsc5_t *, float lower, float upper);
void nrsc5_report_ber(nrsc5_t *, float cber);
void nrsc5_report_hdc(nrsc5_t *, unsigned int program, const packet_t* pkt);
void nrsc5_report_hdc(nrsc5_t *, unsigned int program, const packet_ref_t* pkt, const packet_ref_t* enh_pkt);
void nrsc5_report_audio(nrsc5_t *, unsigned int program, const int16_t *data, size_t count);
void nrsc5_report_stream(nrsc5_t *, uint16_t seq, unsigned int size, const uint8_t *data,
nrsc5_sig_service_t *service, nrsc5_sig_component_t *component);
Expand Down
6 changes: 6 additions & 0 deletions support/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def __init__(self):
self.audio_packets = 0
self.audio_bytes = 0
self.audio_errors = 0
self.audio_errors_enh = 0
signal.signal(signal.SIGINT, self._signal_handler)

def _signal_handler(self, sig, frame):
Expand Down Expand Up @@ -232,6 +233,8 @@ def callback(self, evt_type, evt):
self.audio_errors += 1
else:
self.audio_packets_valid += 1
if evt.enh_flags & nrsc5.PacketFlags.CRC_ERROR:
self.audio_errors_enh += 1

if self.audio_packets_valid >= 32:
logging.info("Audio bit rate: %.1f kbps", self.audio_bytes * 8 * nrsc5.SAMPLE_RATE_AUDIO
Expand All @@ -241,8 +244,11 @@ def callback(self, evt_type, evt):
if self.audio_packets >= 32:
if self.audio_errors > 0:
logging.warning("Audio packet CRC mismatches: %d", self.audio_errors)
if self.audio_errors_enh > 0:
logging.warning("Audio packet CRC enhanced mismatch: %d", self.audio_errors_enh)
self.audio_packets = 0
self.audio_errors = 0
self.audio_errors_enh = 0
elif evt_type == nrsc5.EventType.AUDIO:
if evt.program == self.args.program:
if self.args.o:
Expand Down
7 changes: 5 additions & 2 deletions support/nrsc5.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ class PacketFlags(enum.IntFlag):
Sync = collections.namedtuple("Sync", ["freq_offset", "psmi"])
MER = collections.namedtuple("MER", ["lower", "upper"])
BER = collections.namedtuple("BER", ["cber"])
HDC = collections.namedtuple("HDC", ["program", "data", "flags"])
HDC = collections.namedtuple("HDC", ["program", "data", "flags", "enh_data", "enh_flags"])
Audio = collections.namedtuple("Audio", ["program", "data"])
Comment = collections.namedtuple("Comment", ["lang", "short_content_desc", "full_text"])
UFID = collections.namedtuple("UFID", ["owner", "id"])
Expand Down Expand Up @@ -258,6 +258,9 @@ class _HDC(ctypes.Structure):
("data", ctypes.POINTER(ctypes.c_char)),
("count", ctypes.c_size_t),
("flags", ctypes.c_uint),
("enh_data", ctypes.POINTER(ctypes.c_char)),
("enh_count", ctypes.c_size_t),
("enh_flags", ctypes.c_uint),
]


Expand Down Expand Up @@ -680,7 +683,7 @@ def _callback_wrapper(self, c_evt):
evt = BER(ber.cber)
elif evt_type == EventType.HDC:
hdc = c_evt.u.hdc
evt = HDC(hdc.program, hdc.data[:hdc.count], PacketFlags(hdc.flags))
evt = HDC(hdc.program, hdc.data[:hdc.count], PacketFlags(hdc.flags), hdc.enh_data[:hdc.enh_count], PacketFlags(hdc.enh_flags))
elif evt_type == EventType.AUDIO:
audio = c_evt.u.audio
evt = Audio(audio.program, audio.data[:audio.count * 2])
Expand Down
Loading