In order to implement the transmission offload mechanism, we need to change the way the plugin behaves so, instead of sending only one AVTPDU, it sends several AVTPDUs at every media clock tick.
To achieve that, this patch changes the plugin so it consumes the audio buffer in chunks of period size instead of in frames_per_pdu. The number of AVTPDUs sent at every media clock tick is calculated by dividing the period size by the number of frames per AVTPDU. To ensure that number is not fractional, the plugin requires that the period size is multiple of the plugin configuration 'frames_per_pdu'.
For the sake of consistency, the capture mode is also changed so the plugin presents audio frames to the alsa-lib layer in chunks of period size as well.
Signed-off-by: Andre Guedes andre.guedes@intel.com --- aaf/pcm_aaf.c | 44 +++++++++++++++++++++++++++++++------------- doc/aaf.txt | 7 ++++--- 2 files changed, 35 insertions(+), 16 deletions(-)
diff --git a/aaf/pcm_aaf.c b/aaf/pcm_aaf.c index 1d7ebca..284cbfd 100644 --- a/aaf/pcm_aaf.c +++ b/aaf/pcm_aaf.c @@ -83,6 +83,8 @@ typedef struct { snd_pcm_uframes_t boundary;
uint64_t prev_ptime; + + int pdu_period; } snd_pcm_aaf_t;
static unsigned int alsa_to_avtp_format(snd_pcm_format_t format) @@ -489,7 +491,7 @@ static int aaf_mclk_start_playback(snd_pcm_aaf_t *aaf) return -errno; }
- period = (uint64_t)NSEC_PER_SEC * aaf->frames_per_pdu / io->rate; + period = (uint64_t)NSEC_PER_SEC * io->period_size / io->rate; time = now.tv_sec * NSEC_PER_SEC + now.tv_nsec + period; res = aaf_mclk_start(aaf, time, period); if (res < 0) @@ -502,7 +504,7 @@ static int aaf_mclk_start_capture(snd_pcm_aaf_t *aaf, uint32_t avtp_time) { int res; struct timespec tspec; - uint64_t now, ptime, period; + uint64_t now, ptime, time, period; snd_pcm_ioplug_t *io = &aaf->io;
res = clock_gettime(CLOCK_TAI, &tspec); @@ -526,8 +528,9 @@ static int aaf_mclk_start_capture(snd_pcm_aaf_t *aaf, uint32_t avtp_time) if (ptime < now) ptime += (1ULL << 32);
- period = (uint64_t)NSEC_PER_SEC * aaf->frames_per_pdu / io->rate; - res = aaf_mclk_start(aaf, ptime, period); + period = (uint64_t)NSEC_PER_SEC * io->period_size / io->rate; + time = ptime + period; + res = aaf_mclk_start(aaf, time, period); if (res < 0) return res;
@@ -613,7 +616,7 @@ static int aaf_tx_pdus(snd_pcm_aaf_t *aaf, int pdu_count) if (res < 0) return res;
- ptime += aaf->timer_period; + ptime += aaf->pdu_period; ptr += aaf->frames_per_pdu; }
@@ -622,7 +625,7 @@ static int aaf_tx_pdus(snd_pcm_aaf_t *aaf, int pdu_count)
static bool is_ptime_valid(snd_pcm_aaf_t *aaf, uint32_t avtp_time) { - const uint64_t exp_ptime = aaf->prev_ptime + aaf->timer_period; + const uint64_t exp_ptime = aaf->prev_ptime + aaf->pdu_period; const uint64_t lower_bound = exp_ptime - aaf->ptime_tolerance; const uint64_t upper_bound = exp_ptime + aaf->ptime_tolerance; const uint64_t ptime = (exp_ptime & 0xFFFFFFFF00000000ULL) | avtp_time; @@ -899,22 +902,23 @@ static int aaf_tx_frames(snd_pcm_aaf_t *aaf) { int res; snd_pcm_uframes_t hw_avail; + int pdu_count; snd_pcm_ioplug_t *io = &aaf->io;
hw_avail = snd_pcm_ioplug_hw_avail(io, aaf->hw_ptr, io->appl_ptr); - if (hw_avail < aaf->frames_per_pdu) { - /* If the number of available frames is less than number of - * frames needed to fill an AVTPDU, we reached an underrun - * state. + if (hw_avail < io->period_size) { + /* If the number of available frames is less than the period + * size, we reached an underrun state. */ return -EPIPE; }
- res = aaf_tx_pdus(aaf, 1); + pdu_count = io->period_size / aaf->frames_per_pdu; + res = aaf_tx_pdus(aaf, pdu_count); if (res < 0) return res;
- aaf_inc_ptr(&aaf->hw_ptr, aaf->frames_per_pdu, aaf->boundary); + aaf_inc_ptr(&aaf->hw_ptr, io->period_size, aaf->boundary); return 0; }
@@ -935,7 +939,7 @@ static int aaf_present_frames(snd_pcm_aaf_t *aaf) return -EPIPE; }
- aaf_inc_ptr(&aaf->hw_ptr, aaf->frames_per_pdu, aaf->boundary); + aaf_inc_ptr(&aaf->hw_ptr, io->period_size, aaf->boundary); return 0; }
@@ -1071,8 +1075,22 @@ static int aaf_hw_params(snd_pcm_ioplug_t *io, if (res < 0) goto err_free_pdu;
+ if (io->period_size % aaf->frames_per_pdu) { + /* The plugin requires that the period size is multiple of the + * configuration frames_per_pdu. Return error if this + * requirement isn't satisfied. + */ + SNDERR("Period size must be multiple of frames_per_pdu"); + res = -EINVAL; + goto err_free_areas; + } + + aaf->pdu_period = (uint64_t)NSEC_PER_SEC * aaf->frames_per_pdu / + io->rate; return 0;
+err_free_areas: + free(aaf->payload_areas); err_free_pdu: free(aaf->pdu); err_close_timer: diff --git a/doc/aaf.txt b/doc/aaf.txt index e72eba2..e12a6f6 100644 --- a/doc/aaf.txt +++ b/doc/aaf.txt @@ -147,16 +147,17 @@ below: }
Put the above to ~/.asoundrc (or /etc/asound.conf), and use the AAF PCM virtual -device 'aaf0' with your favorite alsa-utils tool. +device 'aaf0' with your favorite alsa-utils tool. Note that the plugin requires +the period size is multiple of the 'frames_per_pdu' configuration.
For example, to stream the pink noise generated by 'speaker-test', run:
- $ speaker-test -F S16_BE -c 2 -r 48000 -D aaf0 + $ speaker-test -F S16_BE -c 2 -r 48000 -D aaf0 -p 12500
To receive the AAF stream generated by the command above, run the following command in another host:
- $ arecord -t raw -f S16_BE -c 2 -r 48000 -D aaf0 -vv /dev/null + $ arecord -t raw -f S16_BE -c 2 -r 48000 -D aaf0 -vv /dev/null -F 12500
If you want to playback the contents of the AAF stream, change the command-line above so the output from 'arecord' is redirected to 'aplay', or simply use the