Package: libarts1 Version: 1.2.2 Severity: important Tags: patch When playing audio trough arts the reaction time of artsd can increase to around 1s if the alsa output plugin is used together with dmix.
Attached is a fix from Allen Sandfeld. This fix is already in kde cvs. The patch must be applied in the arts-1.2.2/flow directory and does not interfere with arts_1.2.2-1.diff.gz. Full information on the bug is available on http://bugs.kde.org/show_bug.cgi?id=81095 -- lg, Chris
Index: audioioalsa9.cc =================================================================== RCS file: /home/kde/arts/flow/audioioalsa9.cc,v retrieving revision 1.4.2.3 diff -u -3 -p -r1.4.2.3 audioioalsa9.cc --- audioioalsa9.cc 2 Apr 2004 11:21:49 -0000 1.4.2.3 +++ audioioalsa9.cc 7 May 2004 19:29:35 -0000 @@ -63,20 +63,18 @@ namespace Arts { class AudioIOALSA : public AudioIO, public IONotify { protected: - int audio_read_fd; - int audio_write_fd; + struct pollfd m_audio_read_pfd, m_audio_write_pfd; snd_pcm_t *m_pcm_playback; snd_pcm_t *m_pcm_capture; snd_pcm_format_t m_format; int m_period_size, m_periods; - bool inProgress; - bool restartIOHandling; void startIO(); - int poll2iomanager(int pollTypes); + static int poll2iomanager(int pollTypes); + static int iomanager2poll(int pollTypes); int setPcmParams(snd_pcm_t *pcm); - int watchDescriptor(snd_pcm_t *pcm); + void watchDescriptor(snd_pcm_t *pcm, struct pollfd *pfd); void notifyIO(int fd, int types); @@ -118,9 +116,6 @@ AudioIOALSA::AudioIOALSA() m_format = SND_PCM_FORMAT_S16_LE; m_pcm_playback = NULL; m_pcm_capture = NULL; - inProgress = false; - restartIOHandling = false; - audio_read_fd = audio_write_fd = -1; } bool AudioIOALSA::open() @@ -309,10 +304,10 @@ void AudioIOALSA::startIO() { /* watch PCM file descriptor(s) */ if (m_pcm_playback) { - audio_write_fd = watchDescriptor(m_pcm_playback); + watchDescriptor(m_pcm_playback, &m_audio_write_pfd); } if (m_pcm_capture) { - audio_read_fd = watchDescriptor(m_pcm_capture); + watchDescriptor(m_pcm_capture, &m_audio_read_pfd); } } @@ -328,28 +323,40 @@ int AudioIOALSA::poll2iomanager(int poll if(pollTypes & POLLERR) types |= IOType::except; - return types | IOType::reentrant; + return types; } -int AudioIOALSA::watchDescriptor(snd_pcm_t *pcm) +int AudioIOALSA::iomanager2poll(int pollTypes) +{ + int types = 0; + + if(pollTypes & IOType::read) + types |= POLLIN; + if(pollTypes & IOType::write) + types |= POLLOUT; + if(pollTypes & IOType::except) + types |= POLLERR; + + return types; +} + +void AudioIOALSA::watchDescriptor(snd_pcm_t *pcm, struct pollfd *pfd) { - struct pollfd pfds; if (snd_pcm_poll_descriptors_count(pcm) != 1) { - arts_info("Can't handle more than one poll descriptor\n"); - return -1; + arts_fatal("Can't handle more than one poll descriptor\n"); + return; } - if (snd_pcm_poll_descriptors(pcm, &pfds, 1) != 1) { - arts_info("Cannot get poll descriptor\n"); - return -1; + if (snd_pcm_poll_descriptors(pcm, pfd, 1) != 1) { + arts_fatal("Cannot get poll descriptor\n"); + return; } // See though the crack-fumes from the ALSA-developers and try to // figure out which way this handle is supposed to be polled. - int types = poll2iomanager(pfds.events); + int types = poll2iomanager(pfd->events); - Dispatcher::the()->ioManager()->watchFD(pfds.fd, types, this); + Dispatcher::the()->ioManager()->watchFD(pfd->fd, types, this); - return pfds.fd; } int AudioIOALSA::xrun(snd_pcm_t *pcm) @@ -399,9 +406,6 @@ int AudioIOALSA::read(void *buffer, int int AudioIOALSA::write(void *buffer, int size) { - // DMix has an annoying habit of returning instantantly on the returned - // poll-descriptor. So we block here to avoid an infinity loop. - snd_pcm_wait(m_pcm_playback, 5); int frames = snd_pcm_bytes_to_frames(m_pcm_playback, size); int length; @@ -428,29 +432,28 @@ void AudioIOALSA::notifyIO(int fd, int t { int todo = 0; - if(inProgress) - { - if(!restartIOHandling) - { - Dispatcher::the()->ioManager()->remove(this,IOType::all); - restartIOHandling = true; - } - return; + // Call pcm_poll_desciptors_revents to translate the event safely for us. + // This is necassary even if we know what the event is, because _revents + // might have side-effects (dmix have) + unsigned short revents; + if(fd == m_audio_write_pfd.fd) { + m_audio_write_pfd.revents = iomanager2poll(type); + snd_pcm_poll_descriptors_revents(m_pcm_playback, &m_audio_write_pfd, 1, &revents); + if (revents & POLLOUT) + todo |= AudioSubSystem::ioWrite; + + } + if(fd == m_audio_read_pfd.fd) { + m_audio_read_pfd.revents = iomanager2poll(type); + snd_pcm_poll_descriptors_revents(m_pcm_capture, &m_audio_read_pfd, 1, &revents); + if (revents & POLLIN) + todo |= AudioSubSystem::ioRead; } - // We can't trust the type as ALSA might have read-type events, - // that are really meant to be write-type event! - if(fd == audio_write_fd) todo |= AudioSubSystem::ioWrite; - if(fd == audio_read_fd) todo |= AudioSubSystem::ioRead; - if (type & IOType::except) todo |= AudioSubSystem::ioExcept; - restartIOHandling = false; - inProgress = true; - AudioSubSystem::the()->handleIO(todo); - inProgress = false; + if (todo) AudioSubSystem::the()->handleIO(todo); - if (restartIOHandling) startIO(); } int AudioIOALSA::setPcmParams(snd_pcm_t *pcm) Index: audiosubsys.cc =================================================================== RCS file: /home/kde/arts/flow/audiosubsys.cc,v retrieving revision 1.46 diff -u -3 -p -r1.46 audiosubsys.cc --- audiosubsys.cc 29 Aug 2003 21:02:06 -0000 1.46 +++ audiosubsys.cc 7 May 2004 19:29:36 -0000 @@ -7,12 +7,12 @@ modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. - + You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, @@ -100,7 +100,7 @@ AudioSubSystem::AudioSubSystem() d = new AudioSubSystemPrivate; d->audioIO = 0; d->audioIOInit = false; - + _running = false; consumer = 0; producer = 0; @@ -338,7 +338,7 @@ int AudioSubSystem::selectWriteFD() bool AudioSubSystem::check() { - bool ok = open(); + bool ok = open(); if(ok) close(); return ok; @@ -353,7 +353,7 @@ bool AudioSubSystem::open() { if(d->audioIOName == "") _error = "couldn't auto detect which audio I/O method to use"; - else + else _error = "unable to select '"+d->audioIOName+"' style audio I/O"; return false; } @@ -422,6 +422,7 @@ void AudioSubSystem::handleIO(int type) /* * make sure that we have a fragment full of data at least */ +Rewrite: while(wBuffer.size() < _fragmentSize) { long wbsz = wBuffer.size(); @@ -477,6 +478,9 @@ void AudioSubSystem::handleIO(int type) } } } + + // If we can write a fragment more, then do so right now: + if (space >= _fragmentSize*2) goto Rewrite; } assert((type & ioExcept) == 0);