Skip to content
Merged
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
7 changes: 7 additions & 0 deletions include/nrsc5.h
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,12 @@ struct nrsc5_id3_comment_t {
*/
typedef struct nrsc5_id3_comment_t nrsc5_id3_comment_t;

enum
{
NRSC5_PKT_FLAGS_NONE = 0,
NRSC5_PKT_FLAGS_CRC_ERROR = 1 << 0, /** Failed the CRC check. Could be corrupted packet. */
};

/** Incoming event from receiver.
*
* This event structure is passed to your application supplied
Expand Down Expand Up @@ -407,6 +413,7 @@ struct nrsc5_event_t
unsigned int program;
const uint8_t *data;
size_t count;
unsigned int flags; /** The specific status of the hdc packet. Example `NRSC5_PKT_FLAGS_CRC_ERROR` **/
} hdc;
struct {
unsigned int program;
Expand Down
45 changes: 14 additions & 31 deletions src/frame.c
Original file line number Diff line number Diff line change
Expand Up @@ -616,37 +616,24 @@ void frame_process(frame_t *st, size_t length, logical_channel_t lc)
unsigned int cnt = start + locations[j] - offset;
uint8_t crc = crc8(st->buffer + offset, cnt + 1);

if (crc != 0)
log_warn("crc mismatch!");
packet_ref_t ref;
ref.program = prog;
ref.stream_id = hdr.stream_id;
ref.data = st->buffer + offset;
ref.size = cnt;
ref.seq = seq;
ref.flags = PACKET_FLAG_NONE;

if (crc != 0)
ref.flags |= PACKET_FLAG_CRC_ERROR;
if (j == 0 && hdr.pfirst)
{
unsigned int idx = st->pdu_idx[prog][hdr.stream_id];
if (idx)
{
if (crc == 0)
{
memcpy(&st->pdu[prog][hdr.stream_id][idx], st->buffer + offset, cnt);
output_push(st->input->output, st->pdu[prog][hdr.stream_id], cnt + idx, prog, hdr.stream_id, seq);
}
st->pdu_idx[prog][hdr.stream_id] = 0;
}
}
ref.shape = PACKET_HALF_BACK;
else if (j == hdr.nop - 1 && hdr.plast)
{
if (crc == 0)
{
memcpy(st->pdu[prog][hdr.stream_id], st->buffer + offset, cnt);
st->pdu_idx[prog][hdr.stream_id] = cnt;
}
}
ref.shape = PACKET_HALF_FRONT;
else
{
if (crc == 0)
{
output_push(st->input->output, st->buffer + offset, cnt, prog, hdr.stream_id, seq);
}
}
ref.shape = PACKET_FULL;

output_push(st->input->output, &ref);

offset += cnt + 1;
seq = (seq + 1) % ELASTIC_BUFFER_LEN;
Expand Down Expand Up @@ -742,10 +729,6 @@ void frame_reset(frame_t *st)
st->pci = 0;
for (int prog = 0; prog < MAX_PROGRAMS; prog++)
{
for (int stream_id = 0; stream_id < MAX_STREAMS; stream_id++)
{
st->pdu_idx[prog][stream_id] = 0;
}
st->psd_idx[prog] = -1;
}

Expand Down
2 changes: 0 additions & 2 deletions src/frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ typedef struct
struct input_t *input;
uint8_t buffer[MAX_PDU_LEN];
audio_service_t services[MAX_PROGRAMS];
uint8_t pdu[MAX_PROGRAMS][MAX_STREAMS][MAX_PDU_LEN];
unsigned int pdu_idx[MAX_PROGRAMS][MAX_STREAMS];
unsigned int pci;
unsigned int program;
uint8_t psd_buf[MAX_PROGRAMS][MAX_AAS_LEN];
Expand Down
20 changes: 17 additions & 3 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,10 @@ typedef struct {

unsigned int program;
unsigned int audio_ready;
unsigned int audio_packets_valid;
unsigned int audio_packets;
unsigned int audio_bytes;
unsigned int audio_errors;
int done;
} state_t;

Expand Down Expand Up @@ -344,11 +346,23 @@ static void callback(const nrsc5_event_t *evt, void *opaque)

st->audio_packets++;
st->audio_bytes += evt->hdc.count * sizeof(evt->hdc.data[0]);
if (st->audio_packets >= 32) {
log_info("Audio bit rate: %.1f kbps", (float)st->audio_bytes * 8 * NRSC5_SAMPLE_RATE_AUDIO / NRSC5_AUDIO_FRAME_SAMPLES / st->audio_packets / 1000);
st->audio_packets = 0;
if (evt->hdc.flags & NRSC5_PKT_FLAGS_CRC_ERROR)
st->audio_errors++;
else
st->audio_packets_valid++;

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;
st->audio_bytes = 0;
}
if (st->audio_packets >= 32)
{
if (st->audio_errors > 0)
log_warn("Audio packet CRC mismatches: %d", st->audio_errors);
st->audio_packets = 0;
st->audio_errors = 0;
}
}
break;
case NRSC5_EVENT_AUDIO:
Expand Down
16 changes: 13 additions & 3 deletions src/nrsc5.c
Original file line number Diff line number Diff line change
Expand Up @@ -702,14 +702,24 @@ void nrsc5_report_lost_sync(nrsc5_t *st)
nrsc5_report(st, &evt);
}

void nrsc5_report_hdc(nrsc5_t *st, unsigned int program, const uint8_t *data, size_t count)
void nrsc5_report_hdc(nrsc5_t *st, unsigned int program, const packet_t* pkt)
{
nrsc5_event_t evt;

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

if (pkt->shape == PACKET_FULL)
{
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;

nrsc5_report(st, &evt);
}

Expand Down
81 changes: 66 additions & 15 deletions src/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,67 @@ void output_align(output_t *st, unsigned int program, unsigned int stream_id, un
elastic->audio_offset = offset;
}

void output_push(output_t *st, uint8_t *pkt, unsigned int len, unsigned int program, unsigned int stream_id, unsigned int seq)
static int is_complete_pkt(const packet_t* pkt)
{
elastic_buffer_t *elastic = &st->elastic[program][stream_id];
return pkt->shape == PACKET_FULL;
}

static int is_crc_ok(const packet_t* pkt)
{
return !(pkt->flags & PACKET_FLAG_CRC_ERROR);
}

if (stream_id != 0)
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

if (elastic->packets[seq].size != 0)
log_warn("Packet %d already exists in elastic buffer for program %d, stream %d. Overwriting.", seq, program, stream_id);
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)
{
pkt->flags |= ref->flags;
pkt->shape = PACKET_FULL;

memcpy(elastic->packets[seq].data, pkt, len);
elastic->packets[seq].size = len;
if (is_crc_ok(pkt))
{
memcpy(pkt->data + pkt->size, ref->data, ref->size);
pkt->size += ref->size;
}
else
{
pkt->size = 0;
}
}
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;
}
}
}

static void pkt_reset(packet_t* pkt)
{
pkt->size = 0;
pkt->flags = PACKET_FLAG_NONE;
pkt->shape = PACKET_NONE;
}

void output_advance(output_t *st)
Expand All @@ -62,16 +111,18 @@ void output_advance(output_t *st)

for (frame = 0; frame < audio_frames; frame++)
{
unsigned int len = elastic->packets[elastic->audio_offset].size;
uint8_t *pkt = elastic->packets[elastic->audio_offset].data;
packet_t* pkt = &elastic->packets[elastic->audio_offset];
#ifdef USE_FAAD2
int produced_audio = 0;
#endif

if (len > 0)
if (is_complete_pkt(pkt))
{
nrsc5_report_hdc(st->radio, program, pkt, len);
nrsc5_report_hdc(st->radio, program, pkt);
}

if (is_complete_pkt(pkt) && is_crc_ok(pkt))
{
#ifdef USE_FAAD2
void *buffer;
NeAACDecFrameInfo info;
Expand All @@ -81,7 +132,7 @@ void output_advance(output_t *st)
NeAACDecInitHDC(&st->aacdec[program]);
}

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

Expand All @@ -91,8 +142,6 @@ void output_advance(output_t *st)
produced_audio = 1;
}
#endif

elastic->packets[elastic->audio_offset].size = 0;
}
else
{
Expand All @@ -106,6 +155,8 @@ 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);
Expand Down Expand Up @@ -160,7 +211,7 @@ void output_reset(output_t *st)
{
for (int k = 0; k < ELASTIC_BUFFER_LEN; k++)
{
st->elastic[i][j].packets[k].size = 0;
pkt_reset(&st->elastic[i][j].packets[k]);
}
st->elastic[i][j].audio_offset = -1;
}
Expand Down
29 changes: 28 additions & 1 deletion src/output.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,20 @@
#define MAX_FILE_BYTES 65536
#define MAX_LOT_FRAGMENTS (MAX_FILE_BYTES / LOT_FRAGMENT_SIZE)

enum
{
PACKET_FLAG_NONE = 0,
PACKET_FLAG_CRC_ERROR = 1 << 0,
};

enum
{
PACKET_NONE = 0,
PACKET_FULL,
PACKET_HALF_FRONT,
PACKET_HALF_BACK,
};

enum
{
SIG_COMPONENT_NONE,
Expand Down Expand Up @@ -77,10 +91,23 @@ typedef struct
sig_component_t component[MAX_SIG_COMPONENTS];
} sig_service_t;

typedef struct
{
uint8_t *data;
unsigned int size;
unsigned int program;
unsigned int stream_id;
unsigned int seq;
unsigned int flags;
unsigned int shape;
} packet_ref_t;

typedef struct
{
unsigned int size;
uint8_t data[MAX_PDU_LEN];
unsigned int flags;
unsigned int shape;
} packet_t;

typedef struct
Expand All @@ -103,7 +130,7 @@ typedef struct
} output_t;

void output_align(output_t *st, unsigned int program, unsigned int stream_id, unsigned int offset);
void output_push(output_t *st, uint8_t *pkt, unsigned int len, unsigned int program, unsigned int stream_id, unsigned int seq);
void output_push(output_t *st, const packet_ref_t* ref);
void output_advance(output_t *st);
void output_reset(output_t *st);
void output_init(output_t *st, nrsc5_t *);
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 uint8_t *data, size_t count);
void nrsc5_report_hdc(nrsc5_t *, unsigned int program, const packet_t* 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
18 changes: 15 additions & 3 deletions support/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ def __init__(self):
self.wav_output = None
self.raw_output = None
self.hdc_output = None
self.audio_packets_valid = 0
self.audio_packets = 0
self.audio_bytes = 0
self.audio_errors = 0
signal.signal(signal.SIGINT, self._signal_handler)

def _signal_handler(self, sig, frame):
Expand Down Expand Up @@ -226,11 +228,21 @@ def callback(self, evt_type, evt):

self.audio_packets += 1
self.audio_bytes += len(evt.data)
if self.audio_packets >= 32:
if evt.flags & nrsc5.PacketFlags.CRC_ERROR:
self.audio_errors += 1
else:
self.audio_packets_valid += 1

if self.audio_packets_valid >= 32:
logging.info("Audio bit rate: %.1f kbps", self.audio_bytes * 8 * nrsc5.SAMPLE_RATE_AUDIO
/ nrsc5.AUDIO_FRAME_SAMPLES / self.audio_packets / 1000)
self.audio_packets = 0
/ nrsc5.AUDIO_FRAME_SAMPLES / self.audio_packets_valid / 1000)
self.audio_packets_valid = 0
self.audio_bytes = 0
if self.audio_packets >= 32:
if self.audio_errors > 0:
logging.warning("Audio packet CRC mismatches: %d", self.audio_errors)
self.audio_packets = 0
self.audio_errors = 0
elif evt_type == nrsc5.EventType.AUDIO:
if evt.program == self.args.program:
if self.args.o:
Expand Down
Loading
Loading