}
}
-static bool is_pdu_valid(struct avtp_stream_pdu *pdu, uint64_t streamid,
- unsigned int data_len, unsigned int format,
- unsigned int nsr, unsigned int channels,
- unsigned int depth)
-{
- int res;
- uint64_t val64;
- uint32_t val32;
- struct avtp_common_pdu *common = (struct avtp_common_pdu *) pdu;
-
- res = avtp_pdu_get(common, AVTP_FIELD_SUBTYPE, &val32);
- if (res < 0)
- return false;
- if (val32 != AVTP_SUBTYPE_AAF) {
- pr_debug("Subtype mismatch: expected %u, got %u",
- AVTP_SUBTYPE_AAF, val32);
- return false;
- }
-
- res = avtp_pdu_get(common, AVTP_FIELD_VERSION, &val32);
- if (res < 0)
- return false;
- if (val32 != 0) {
- pr_debug("Version mismatch: expected %u, got %u", 0, val32);
- return false;
- }
-
- res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_STREAM_ID, &val64);
- if (res < 0)
- return false;
- if (val64 != streamid) {
- pr_debug("Streamid mismatch: expected %lu, got %lu", streamid,
- val64);
- return false;
- }
-
- res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_TV, &val64);
- if (res < 0)
- return false;
- if (val64 != 1) {
- pr_debug("TV mismatch: expected %u, got %lu", 1, val64);
- return false;
- }
-
- res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_SP, &val64);
- if (res < 0)
- return false;
- if (val64 != AVTP_AAF_PCM_SP_NORMAL) {
- pr_debug("SP mismatch: expected %u, got %lu",
- AVTP_AAF_PCM_SP_NORMAL, val64);
- return false;
- }
-
- res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_FORMAT, &val64);
- if (res < 0)
- return false;
- if (val64 != format) {
- pr_debug("Format mismatch: expected %u, got %lu", format,
- val64);
- return false;
- }
-
- res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_NSR, &val64);
- if (res < 0)
- return false;
- if (val64 != nsr) {
- pr_debug("NSR mismatch: expected %u, got %lu", nsr, val64);
- return false;
- }
-
- res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_CHAN_PER_FRAME, &val64);
- if (res < 0)
- return false;
- if (val64 != channels) {
- pr_debug("Channels mismatch: expected %u, got %lu", channels,
- val64);
- return false;
- }
-
- res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_BIT_DEPTH, &val64);
- if (res < 0)
- return false;
- if (val64 != depth) {
- pr_debug("Bit depth mismatch: expected %u, got %lu", depth,
- val64);
- return false;
- }
-
- res = avtp_aaf_pdu_get(pdu, AVTP_AAF_FIELD_STREAM_DATA_LEN, &val64);
- if (res < 0)
- return false;
- if (val64 != data_len) {
- pr_debug("Data len mismatch: expected %u, got %lu",
- data_len, val64);
- return false;
- }
-
- return true;
-}
-
static int aaf_load_config(snd_pcm_aaf_t *aaf, snd_config_t *conf)
{
snd_config_iterator_t cur, next;
return true;
}
-static int aaf_rx_pdu(snd_pcm_aaf_t *aaf)
+static bool is_pdu_valid(snd_pcm_aaf_t *aaf)
{
int res;
- ssize_t n;
- uint64_t seq, avtp_time;
- snd_pcm_uframes_t hw_avail;
+ uint64_t val64;
+ uint32_t val32;
snd_pcm_ioplug_t *io = &aaf->io;
snd_pcm_t *pcm = io->pcm;
+ const uint64_t data_len = snd_pcm_frames_to_bytes(pcm, aaf->frames_per_pdu);
+ const uint64_t format = alsa_to_avtp_format(io->format);
+ const uint64_t nsr = alsa_to_avtp_rate(io->rate);
+ const uint64_t depth = snd_pcm_format_width(io->format);
+ struct avtp_common_pdu *common = (struct avtp_common_pdu *) aaf->pdu;
- n = recv(aaf->sk_fd, aaf->pdu, aaf->pdu_size, 0);
- if (n < 0) {
- SNDERR("Failed to receive data");
- return -errno;
+ res = avtp_pdu_get(common, AVTP_FIELD_VERSION, &val32);
+ if (res < 0)
+ return false;
+ if (val32 != 0) {
+ pr_debug("Version mismatch: expected %u, got %u", 0, val32);
+ return false;
}
- if (n != aaf->pdu_size) {
- pr_debug("AVTPDU dropped: Invalid size");
- return 0;
+
+ res = avtp_aaf_pdu_get(aaf->pdu, AVTP_AAF_FIELD_STREAM_ID, &val64);
+ if (res < 0)
+ return false;
+ if (val64 != aaf->streamid) {
+ pr_debug("Streamid mismatch: expected %lu, got %lu",
+ aaf->streamid, val64);
+ return false;
}
- if (io->state == SND_PCM_STATE_DRAINING) {
- /* If device is in DRAIN state, we shouldn't copy any more data
- * to audio buffer. So we are done here.
- */
- return 0;
+ res = avtp_aaf_pdu_get(aaf->pdu, AVTP_AAF_FIELD_TV, &val64);
+ if (res < 0)
+ return false;
+ if (val64 != 1) {
+ pr_debug("TV mismatch: expected %u, got %lu", 1, val64);
+ return false;
}
- if (!is_pdu_valid(aaf->pdu, aaf->streamid,
- snd_pcm_frames_to_bytes(pcm, aaf->frames_per_pdu),
- alsa_to_avtp_format(io->format),
- alsa_to_avtp_rate(io->rate),
- io->channels, snd_pcm_format_width(io->format))) {
- pr_debug("AVTPDU dropped: Bad field(s)");
- return 0;
+ res = avtp_aaf_pdu_get(aaf->pdu, AVTP_AAF_FIELD_SP, &val64);
+ if (res < 0)
+ return false;
+ if (val64 != AVTP_AAF_PCM_SP_NORMAL) {
+ pr_debug("SP mismatch: expected %u, got %lu",
+ AVTP_AAF_PCM_SP_NORMAL, val64);
+ return false;
}
- res = avtp_aaf_pdu_get(aaf->pdu, AVTP_AAF_FIELD_SEQ_NUM, &seq);
+ res = avtp_aaf_pdu_get(aaf->pdu, AVTP_AAF_FIELD_FORMAT, &val64);
if (res < 0)
- return res;
- if (seq != aaf->pdu_seq) {
+ return false;
+ if (val64 != format) {
+ pr_debug("Format mismatch: expected %u, got %lu", format,
+ val64);
+ return false;
+ }
+
+ res = avtp_aaf_pdu_get(aaf->pdu, AVTP_AAF_FIELD_NSR, &val64);
+ if (res < 0)
+ return false;
+ if (val64 != nsr) {
+ pr_debug("NSR mismatch: expected %u, got %lu", nsr, val64);
+ return false;
+ }
+
+ res = avtp_aaf_pdu_get(aaf->pdu, AVTP_AAF_FIELD_CHAN_PER_FRAME, &val64);
+ if (res < 0)
+ return false;
+ if (val64 != io->channels) {
+ pr_debug("Channels mismatch: expected %u, got %lu",
+ io->channels, val64);
+ return false;
+ }
+
+ res = avtp_aaf_pdu_get(aaf->pdu, AVTP_AAF_FIELD_BIT_DEPTH, &val64);
+ if (res < 0)
+ return false;
+ if (val64 != depth) {
+ pr_debug("Bit depth mismatch: expected %u, got %lu", depth,
+ val64);
+ return false;
+ }
+
+ res = avtp_aaf_pdu_get(aaf->pdu, AVTP_AAF_FIELD_STREAM_DATA_LEN, &val64);
+ if (res < 0)
+ return false;
+ if (val64 != data_len) {
+ pr_debug("Data len mismatch: expected %u, got %lu",
+ data_len, val64);
+ return false;
+ }
+
+ res = avtp_aaf_pdu_get(aaf->pdu, AVTP_AAF_FIELD_SEQ_NUM, &val64);
+ if (res < 0)
+ return false;
+ if (val64 != aaf->pdu_seq) {
pr_debug("Sequence mismatch: expected %u, got %lu",
- aaf->pdu_seq, seq);
- aaf->pdu_seq = seq;
+ aaf->pdu_seq, val64);
+ aaf->pdu_seq = val64;
}
aaf->pdu_seq++;
- res = avtp_aaf_pdu_get(aaf->pdu, AVTP_AAF_FIELD_TIMESTAMP, &avtp_time);
- if (res < 0)
- return res;
+ if (aaf->timer_starttime) {
+ /* If media clock has started, it means we have already
+ * received an AVTPDU, so we are able to check if the
+ * Presentation Time from this AVTPDU is valid.
+ */
+ uint64_t avtp_time;
- if (aaf->timer_starttime == 0) {
- res = aaf_mclk_start_capture(aaf, avtp_time);
+ res = avtp_aaf_pdu_get(aaf->pdu, AVTP_AAF_FIELD_TIMESTAMP,
+ &avtp_time);
if (res < 0)
- return res;
- } else {
+ return false;
+
if (!is_ptime_valid(aaf, avtp_time)) {
pr_debug("Packet dropped: PT not valid");
- return 0;
+ return false;
}
}
+ return true;
+}
+
+static int aaf_copy_pdu_payload(snd_pcm_aaf_t *aaf)
+{
+ int res;
+ snd_pcm_uframes_t hw_avail;
+ snd_pcm_ioplug_t *io = &aaf->io;
+
hw_avail = snd_pcm_ioplug_hw_avail(io, aaf->hw_virt_ptr, io->appl_ptr);
if (hw_avail < aaf->frames_per_pdu) {
/* If there isn't enough space available on buffer to copy the
return 0;
}
+static int aaf_dispatch_pdu_aaf(snd_pcm_aaf_t *aaf)
+{
+ int res;
+
+ if (!is_pdu_valid(aaf)) {
+ pr_debug("AAF PDU dropped: Bad field(s)");
+ return 0;
+ }
+
+ res = aaf_copy_pdu_payload(aaf);
+ if (res < 0)
+ return res;
+
+ if (aaf->timer_starttime == 0) {
+ /* If the media clock has not been started yet (which means
+ * this is the first AAF PDU received by the plugin), we start
+ * it.
+ */
+ uint64_t avtp_time;
+
+ res = avtp_aaf_pdu_get(aaf->pdu, AVTP_AAF_FIELD_TIMESTAMP,
+ &avtp_time);
+ if (res < 0)
+ return res;
+
+ res = aaf_mclk_start_capture(aaf, avtp_time);
+ if (res < 0)
+ return res;
+ }
+
+ return 0;
+}
+
+static int aaf_dispatch_pdu(snd_pcm_aaf_t *aaf)
+{
+ int res;
+ uint32_t subtype;
+ struct avtp_common_pdu *common = (struct avtp_common_pdu *) aaf->pdu;
+
+ res = avtp_pdu_get(common, AVTP_FIELD_SUBTYPE, &subtype);
+ if (res < 0)
+ return res;
+
+ switch (subtype) {
+ case AVTP_SUBTYPE_AAF:
+ return aaf_dispatch_pdu_aaf(aaf);
+ default:
+ pr_debug("AVTPDU dropped: subtype not supported");
+ return 0;
+ }
+}
+
+static int aaf_socket_new_data(snd_pcm_aaf_t *aaf)
+{
+ ssize_t n;
+ snd_pcm_ioplug_t *io = &aaf->io;
+
+ n = recv(aaf->sk_fd, aaf->pdu, aaf->pdu_size, 0);
+ if (n < 0) {
+ SNDERR("Failed to receive data");
+ return -errno;
+ }
+ if (n != aaf->pdu_size) {
+ pr_debug("AVTPDU dropped: Invalid size");
+ return 0;
+ }
+
+ if (io->state == SND_PCM_STATE_DRAINING) {
+ /* If device is in DRAIN state, there is no point in
+ * dispatching the AVTPDU just received so we are done
+ * here.
+ */
+ return 0;
+ }
+
+ return aaf_dispatch_pdu(aaf);
+}
+
static int aaf_flush_rx_buf(snd_pcm_aaf_t *aaf)
{
char *tmp;
}
if (pfd[1].revents & POLLIN) {
- res = aaf_rx_pdu(aaf);
+ res = aaf_socket_new_data(aaf);
if (res < 0)
return res;
}