mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-06-08 03:01:52 -04:00
milan-avb: UNSUPPORTED_FORMAT per-PDU vs current format from descriptor
This commit is contained in:
parent
5fe0a7e575
commit
5b8fa0a9b6
3 changed files with 69 additions and 31 deletions
|
|
@ -79,4 +79,22 @@ struct avb_packet_aaf {
|
|||
uint8_t payload[0];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
/* IEEE 1722-2016 Table 18: AAF nsr code to rate in Hz, 0 if user/reserved. */
|
||||
static inline uint32_t avb_aaf_nsr_to_rate(uint8_t nsr)
|
||||
{
|
||||
switch (nsr) {
|
||||
case AVB_AAF_PCM_NSR_8KHZ: return 8000;
|
||||
case AVB_AAF_PCM_NSR_16KHZ: return 16000;
|
||||
case AVB_AAF_PCM_NSR_24KHZ: return 24000;
|
||||
case AVB_AAF_PCM_NSR_32KHZ: return 32000;
|
||||
case AVB_AAF_PCM_NSR_44_1KHZ: return 44100;
|
||||
case AVB_AAF_PCM_NSR_48KHZ: return 48000;
|
||||
case AVB_AAF_PCM_NSR_88_2KHZ: return 88200;
|
||||
case AVB_AAF_PCM_NSR_96KHZ: return 96000;
|
||||
case AVB_AAF_PCM_NSR_176_4KHZ: return 176400;
|
||||
case AVB_AAF_PCM_NSR_192KHZ: return 192000;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* AVB_AAF_H */
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include "aecp.h"
|
||||
#include "aecp-aem-types.h"
|
||||
#include "packets.h"
|
||||
#include "aaf.h"
|
||||
|
||||
/* AVDECC stream_format decoder.
|
||||
*
|
||||
|
|
@ -23,12 +24,8 @@
|
|||
* plane plus an `is_audio` shortcut so callers can skip non-media streams
|
||||
* (CRF). Fields are 0 when not applicable.
|
||||
*
|
||||
* NOTE: bit-level decoding inside each subtype is incomplete. Today the
|
||||
* decoder identifies the subtype reliably and falls back to the historical
|
||||
* 8 ch / 48 kHz / 24-bit defaults for audio — sufficient for current Milan
|
||||
* builds where every stream_input_0 / stream_output_0 uses one of those
|
||||
* formats. TODO Section H.1 (AAF) and Section F (IEC 61883-6 AM824) fields once a real
|
||||
* conformance run needs other rates / channel counts. */
|
||||
* AAF (Section H.1) decodes each field. IEC 61883-6 (Section F) still uses the
|
||||
* historical 8 ch / 48 kHz defaults, TODO decode it. */
|
||||
enum avb_aem_stream_format_kind {
|
||||
AVB_AEM_STREAM_FORMAT_KIND_UNKNOWN = 0,
|
||||
AVB_AEM_STREAM_FORMAT_KIND_AAF,
|
||||
|
|
@ -44,6 +41,9 @@ struct avb_aem_stream_format_info {
|
|||
uint16_t channels;
|
||||
uint8_t bit_depth;
|
||||
uint16_t samples_per_frame;
|
||||
uint8_t format;
|
||||
uint8_t nsr;
|
||||
uint8_t sparse;
|
||||
};
|
||||
|
||||
static inline void avb_aem_stream_format_decode(uint64_t fmt_be,
|
||||
|
|
@ -57,15 +57,23 @@ static inline void avb_aem_stream_format_decode(uint64_t fmt_be,
|
|||
out->channels = 0;
|
||||
out->bit_depth = 0;
|
||||
out->samples_per_frame = 0;
|
||||
out->format = 0;
|
||||
out->nsr = 0;
|
||||
out->sparse = 0;
|
||||
|
||||
switch (out->subtype) {
|
||||
case AVB_SUBTYPE_AAF:
|
||||
/* Section H.1 quadlet: nsr[51:48] format[47:40] bit_depth[39:32]
|
||||
* channels[31:22] samples_per_frame[21:12]. */
|
||||
out->kind = AVB_AEM_STREAM_FORMAT_KIND_AAF;
|
||||
out->is_audio = true;
|
||||
out->rate = 48000;
|
||||
out->channels = 8;
|
||||
out->bit_depth = 24;
|
||||
out->samples_per_frame = 6;
|
||||
out->nsr = (uint8_t)((f >> 48) & 0x0F);
|
||||
out->format = (uint8_t)((f >> 40) & 0xFF);
|
||||
out->bit_depth = (uint8_t)((f >> 32) & 0xFF);
|
||||
out->channels = (uint16_t)((f >> 22) & 0x3FF);
|
||||
out->samples_per_frame = (uint16_t)((f >> 12) & 0x3FF);
|
||||
out->sparse = AVB_AAF_PCM_SP_NORMAL;
|
||||
out->rate = avb_aaf_nsr_to_rate(out->nsr);
|
||||
break;
|
||||
case AVB_SUBTYPE_61883_IIDC:
|
||||
out->kind = AVB_AEM_STREAM_FORMAT_KIND_IEC_61883_6;
|
||||
|
|
|
|||
|
|
@ -92,8 +92,8 @@
|
|||
* MEDIA_RESET_IN TODO: tick when AVTPDU header sets the mr bit
|
||||
* (header reset notification)
|
||||
* TIMESTAMP_UNCERTAIN_IN TODO: tick when AVTPDU tu bit is set in the header
|
||||
* UNSUPPORTED_FORMAT live: handle_aaf_packet drops + ticks any AAF PDU
|
||||
* whose media format is not the Milan base format
|
||||
* UNSUPPORTED_FORMAT live: handle_aaf_packet drops + ticks per PDU any AAF PDU
|
||||
* whose format != the Stream Input current format
|
||||
* LATE_TIMESTAMP TODO: tick when p->timestamp < CLOCK_TAI now
|
||||
* (frame missed its presentation deadline)
|
||||
* EARLY_TIMESTAMP TODO: tick when p->timestamp > now + max_transit_time
|
||||
|
|
@ -1064,17 +1064,31 @@ static void stream_mc_recover(struct stream *stream, const struct avb_packet_aaf
|
|||
* a Listener that joins mid-stream. Small, so genuine ongoing loss still counts. */
|
||||
#define AVB_STREAM_SEQ_SETTLE 8
|
||||
|
||||
/* Milan v1.2 Section 5.4: the listener supports only the Milan base stream
|
||||
* format for decode — AAF PCM, 32-bit integer, 48 kHz, non-sparse. The channel
|
||||
* count is checked separately by handle_aaf_packet against the stream's
|
||||
* negotiated channel count (a frame from a mismatched talker is rejected). */
|
||||
static inline bool aaf_is_milan_format(const struct avb_packet_aaf *p)
|
||||
/* Milan v1.2 Section 5.4: a received AAF AVTPDU matches the current format when
|
||||
* subtype, format, nsr, bit depth, channels and sparse all match. */
|
||||
static inline bool aaf_pdu_format_matches(const struct avb_packet_aaf *p,
|
||||
const struct avb_aem_stream_format_info *fi)
|
||||
{
|
||||
return p->subtype == AVB_SUBTYPE_AAF &&
|
||||
p->format == AVB_AAF_FORMAT_INT_32BIT &&
|
||||
p->nsr == AVB_AAF_PCM_NSR_48KHZ &&
|
||||
p->bit_depth == 32 &&
|
||||
p->sp == AVB_AAF_PCM_SP_NORMAL;
|
||||
return p->subtype == fi->subtype &&
|
||||
p->format == fi->format &&
|
||||
p->nsr == fi->nsr &&
|
||||
p->bit_depth == fi->bit_depth &&
|
||||
p->chan_per_frame == fi->channels &&
|
||||
p->sp == fi->sparse;
|
||||
}
|
||||
|
||||
/* Read the current format from the Stream Input descriptor. SET_STREAM_FORMAT
|
||||
* updates it there, so this is always the current one. */
|
||||
static void stream_in_current_format(struct stream *stream,
|
||||
struct avb_aem_stream_format_info *out)
|
||||
{
|
||||
struct descriptor *desc;
|
||||
struct avb_aem_desc_stream *body;
|
||||
|
||||
desc = server_find_descriptor(stream->server, AVB_AEM_DESC_STREAM_INPUT,
|
||||
stream->index);
|
||||
body = desc ? descriptor_body(desc) : NULL;
|
||||
avb_aem_stream_format_decode(body ? body->current_format : 0, out);
|
||||
}
|
||||
|
||||
static void handle_aaf_packet(struct stream *stream,
|
||||
|
|
@ -1082,6 +1096,7 @@ static void handle_aaf_packet(struct stream *stream,
|
|||
{
|
||||
struct aecp_aem_stream_input_state *si = stream_in_state(stream);
|
||||
struct aecp_aem_stream_input_counters *cnt = &si->counters;
|
||||
struct avb_aem_stream_format_info cur;
|
||||
struct timespec now_ts;
|
||||
uint32_t index, n_bytes;
|
||||
int32_t filled;
|
||||
|
|
@ -1089,15 +1104,10 @@ static void handle_aaf_packet(struct stream *stream,
|
|||
filled = spa_ringbuffer_get_write_index(&stream->ring, &index);
|
||||
n_bytes = ntohs(p->data_len);
|
||||
|
||||
/* milan-avb: accept ONLY frames matching this stream's negotiated format.
|
||||
* EVERY received frame that is not a well-formed Milan AAF PDU — bad length,
|
||||
* subtype/format/sample-rate/bit-depth/sparse not the Milan base format, or
|
||||
* whose channel count differs from this stream's negotiated channel count —
|
||||
* bumps UNSUPPORTED_FORMAT and is dropped, per frame: not counted as a valid
|
||||
* frame, not media-locked, not written. The channel check rejects frames from
|
||||
* a different talker/format sharing the VLAN (Milan Section 5.5.1.2). */
|
||||
if (n_bytes > (uint32_t)(len - (int)sizeof(*p)) || !aaf_is_milan_format(p) ||
|
||||
p->chan_per_frame != stream->info.info.raw.channels) {
|
||||
/* IEEE 1722.1-2021 Table 7-156: per-PDU, bump UNSUPPORTED_FORMAT on any AVTPDU
|
||||
* whose format != the Stream Input current format (from descriptor), or malformed. */
|
||||
stream_in_current_format(stream, &cur);
|
||||
if (n_bytes > (uint32_t)(len - (int)sizeof(*p)) || !aaf_pdu_format_matches(p, &cur)) {
|
||||
cnt->unsupported_format++;
|
||||
stream_in_mark_counters_dirty(stream);
|
||||
return;
|
||||
|
|
@ -1267,6 +1277,8 @@ static void handle_iec61883_packet(struct stream *stream,
|
|||
}
|
||||
}
|
||||
|
||||
/* TODO: RX is on the main loop, not the RT data_loop — preemption can drop PDUs
|
||||
* (SEQ_NUM_MISMATCH). Move it to data_loop + a big SO_RCVBUF, like the flush_timer. */
|
||||
static void on_socket_data(void *data, int fd, uint32_t mask)
|
||||
{
|
||||
struct stream *stream = data;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue