On Fri, 12 Oct 2018 20:21:07 +0200, Brendan Shanks wrote: > > I'm working on an embedded system based on an Ambarella H1 SoC (32-bit ARM > Cortex A9). Audio playback through ALSA (and GStreamer) works fine when > playing to the raw hw device. When playing through dshare (my normal > configuration), playback stops after exactly 7 hours 16 minutes, for about > 3 minutes. During the 3 minutes, the playback thread consumes an entire CPU > core. After the 3 minutes, GStreamer reports an xrun, recovers from it, and > playback goes back to normal. > > After some debugging, the problem seems to be in > snd_pcm_dshare_sync_area(). When dshare->appl_ptr rolls over to 0, 'size' > becomes huge, 3036676576. 'slave_size' is also much bigger than it should > be, 1258291680. This is what 'size' is set to when the for loop starts, and > I believe the for loop then spends ~3 minutes copying a huge amount of > samples. > This also explains the 7h16m time, it's linked to the PCM boundary which is > 1258291200. At 48 kHz, 1258291200 samples takes 7h16m54s. > > I'm not sure what the fix should be though. Is this really a bug in dshare, > or are bad values being set somewhere else? GStreamer? Or maybe the > period/buffer size (480/9600) is causing problems? Maybe some 32bit boundary overflow? I vaguely remember of it. Takashi > Any advice is appreciated, my modified snd_pcm_dshare_sync_area() and the > output are below. > > Brendan Shanks > > > $ more /proc/asound/card0/pcm1p/sub0/hw_params > access: MMAP_INTERLEAVED > format: S16_LE > subformat: STD > channels: 4 > rate: 48000 (48000/1) > period_size: 480 > buffer_size: 9600 > $ more /proc/asound/card0/pcm1p/sub0/sw_params > tstamp_mode: ENABLE > period_step: 1 > avail_min: 480 > start_threshold: 1 > stop_threshold: 1258291200 > silence_threshold: 0 > silence_size: 1258291200 > boundary: 1258291200 > > --- output from running 'gst-launch-1.0 -e audiotestsrc ! alsasink' with > prints included as below > snd_pcm_dshare_sync_area size 3036676576, dshare->appl_ptr 0 > dshare->last_appl_ptr 1258290720 > slave_hw_ptr1 1258282080 slave_period_size 480 > slave_hw_ptr2 1258282080 slave_buffer_size 9600 > slave_hw_ptr3 1258291680 slave_boundary 1258291200 > slave_hw_ptr4 1258291680 slave_appl_ptr 0 > slave_size1 1258291680 > size 1258291680 > appl_ptr 9120 size 1258291680 boundary 1258291200 > last_appl_ptr 0 > slave_appl_ptr 0 > dshare->slave_appl_ptr 480 > exiting > > snd_pcm_dshare_sync_area size 3036676576, dshare->appl_ptr 0 > dshare->last_appl_ptr 1258290720 > slave_hw_ptr1 8965920 slave_period_size 480 > slave_hw_ptr2 8965920 slave_buffer_size 9600 > slave_hw_ptr3 8975520 slave_boundary 1258291200 > slave_hw_ptr4 8975520 slave_appl_ptr 8975040 > slave_size1 480 > size 480 > appl_ptr 9120 size 480 boundary 1258291200 > last_appl_ptr 0 > slave_appl_ptr 8640 > dshare->slave_appl_ptr 8975520 > exiting > > --- snd_pcm_dshare_sync_area() from alsa-lib-1.1.6 with prints added: > static void snd_pcm_dshare_sync_area(snd_pcm_t *pcm) > { > snd_pcm_direct_t *dshare = pcm->private_data; > snd_pcm_uframes_t slave_hw_ptr, slave_appl_ptr, slave_size; > snd_pcm_uframes_t appl_ptr, size; > const snd_pcm_channel_area_t *src_areas, *dst_areas; > int print = 0; > > /* calculate the size to transfer */ > size = dshare->appl_ptr - dshare->last_appl_ptr; > if (! size) > return; > if (size > 9600) > { > printf("snd_pcm_dshare_sync_area size %lu, dshare->appl_ptr > %lu dshare->last_appl_ptr %lu\n", > size, dshare->appl_ptr, dshare->last_appl_ptr); > print = 1; > } > slave_hw_ptr = dshare->slave_hw_ptr; > if (print) printf("slave_hw_ptr1 %lu slave_period_size %lu", slave_hw_ptr, > dshare->slave_period_size); > /* don't write on the last active period - this area may be cleared > * by the driver during write operation... > */ > slave_hw_ptr -= slave_hw_ptr % dshare->slave_period_size; > if (print) printf("slave_hw_ptr2 %lu slave_buffer_size %lu", slave_hw_ptr, > dshare->slave_buffer_size); > slave_hw_ptr += dshare->slave_buffer_size; > if (print) printf("slave_hw_ptr3 %lu slave_boundary %lu", slave_hw_ptr, > dshare->slave_boundary); > if (dshare->slave_hw_ptr > dshare->slave_boundary) > slave_hw_ptr -= dshare->slave_boundary; > if (print) printf("slave_hw_ptr4 %lu slave_appl_ptr %lu", slave_hw_ptr, > dshare->slave_appl_ptr); > if (slave_hw_ptr < dshare->slave_appl_ptr) > slave_size = slave_hw_ptr + (dshare->slave_boundary - > dshare->slave_appl_ptr); > else > slave_size = slave_hw_ptr - dshare->slave_appl_ptr; > if (print) printf("slave_size1 %lu", slave_size); > if (slave_size < size) > size = slave_size; > if (! size) > return; > if (print) printf("size %lu", size); > > /* add sample areas here */ > src_areas = snd_pcm_mmap_areas(pcm); > dst_areas = snd_pcm_mmap_areas(dshare->spcm); > appl_ptr = dshare->last_appl_ptr % pcm->buffer_size; > if (print) printf("appl_ptr %lu size %lu boundary %lu", appl_ptr, size, > pcm->boundary); > dshare->last_appl_ptr += size; > dshare->last_appl_ptr %= pcm->boundary; > if (print) printf("last_appl_ptr %lu", dshare->last_appl_ptr); > slave_appl_ptr = dshare->slave_appl_ptr % dshare->slave_buffer_size; > if (print) printf("slave_appl_ptr %lu", slave_appl_ptr); > dshare->slave_appl_ptr += size; > dshare->slave_appl_ptr %= dshare->slave_boundary; > if (print) printf("dshare->slave_appl_ptr %lu", dshare->slave_appl_ptr); > for (;;) { > snd_pcm_uframes_t transfer = size; > if (appl_ptr + transfer > pcm->buffer_size) > transfer = pcm->buffer_size - appl_ptr; > if (slave_appl_ptr + transfer > dshare->slave_buffer_size) > transfer = dshare->slave_buffer_size - > slave_appl_ptr; > share_areas(dshare, src_areas, dst_areas, appl_ptr, > slave_appl_ptr, transfer); > size -= transfer; > if (! size) > break; > slave_appl_ptr += transfer; > slave_appl_ptr %= dshare->slave_buffer_size; > appl_ptr += transfer; > appl_ptr %= pcm->buffer_size; > } > if (print) printf("exiting"); > _______________________________________________ > Alsa-devel mailing list > Alsa-devel@xxxxxxxxxxxxxxxx > http://mailman.alsa-project.org/mailman/listinfo/alsa-devel > _______________________________________________ Alsa-devel mailing list Alsa-devel@xxxxxxxxxxxxxxxx http://mailman.alsa-project.org/mailman/listinfo/alsa-devel