(*** This bug was imported into bugs.kde.org ***) Package: noatun Version: 1.8.0 (using KDE 2.9.0 2 (CVS >= 20020104)) Severity: wishlist Installed from: compiled sources Compiler: gcc version 2.95.3 20010315 (SuSE) OS: Linux (i686) release 2.4.17-rc1-update_page_usage OS/Compiler notes: Earlier versions of ogg does not handle (encode nor decode) originals with frequencies that differ from 44100 or 48000 in stereo... With the release of rc3 it can. ktuberlings translations were recoded from various original qualities. But the problem is that arts does not replay it correctly or at all - maybe it assumes some specific frequency or stereo? (the german translation is a specific example) Recompiling kdemultimedia does not work. The applicatoin xmms can replay the files with no recompiling necessary... (Submitted via bugs.kde.org) (Called from KBugReport dialog)
--------------Boundary-00=_RC2QVUOBMEA14N0LWUWB Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 8bit [found the list and remembered my wish list item] Hi all (since I have no idea who is responsible for the code) I have made "some" modifications to oggvorbis_artsplugin to make it handle non 44100 Hz files. 44100 Hz files is a lot easier since you decode to the same frequency as arts uses internally... The possibility to use other sampling frequencies and mono was added in ogg rc3. wav(f Hz c Channels) => encode => ogg rc3 => decode => wav(f Hz c Channels) This gives some problems when trying to handle the standard arts frequency. You basically need to resample - I have included a simple resampler. Audio quality has not been my priority up to this point - now it gives right audio for the correct time. (it works but gives bad audio quality - overtones a filter with the band width of the original sound will help...) My feeling is that there are probably working resamplers included somewere in the arts libraries... Help please? BUT: I think I detected quite a number of races while working with the code. As an example: when the file is read to end then this code was executed... ! //signal completion ! foo.val = 0; ! // no more data available ! semctl(buflen_sem 0 SETVAL foo); ! // and no room either (ie none coming) ! semctl(buflen_sem 1 SETVAL foo); Two problems: * writing zero to sem 0 will not let the audio file play to the end. all samples that were buffered got removed in one stroke. * writing zero to sem 1 might race with main process updating sem 1 and the expected condition will never happen... /RogerL -- Roger Larsson SkellefteÃ¥ Sweden --------------Boundary-00=_RC2QVUOBMEA14N0LWUWB Content-Type: text/x-diff; charset="iso-8859-1"; name="kde_oggvorbis_artsplugin.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kde_oggvorbis_artsplugin.patch" ? oggarts.mcoptype ? oggarts.h ? oggarts.cc ? oggarts.mcopclass Index: oggPlayObject_impl.cpp =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /home/kde/kdemultimedia/oggvorbis_artsplugin/oggPlayObject_impl.c= ppv retrieving revision 1.3 diff -c -r1.3 oggPlayObject_impl.cpp *** oggPlayObject_impl.cpp2001/12/14 20:54:431.3 --- oggPlayObject_impl.cpp2002/01/29 22:02:00 *************** *** 3241 **** --- 3243 ---- =20=20 =20=20 #include "oggPlayObject_impl.h" + #define SAMPLESIZE sizeof(short) =20=20 using namespace Arts; =20=20 oggPlayObject_impl::oggPlayObject_impl() + : fract_bufpos(0) reserved(0) { struct shmid_ds bleh; shm_id =3D shmget(IPC_PRIVATE sizeof(*shm_buf) 0600); *************** *** 95114 **** =20=20 FILE *ogg_fp; ogg_fp =3D fopen(filename.c_str() "r"); int current_section=3D0; =20=20 ov_open(ogg_fp &vf NULL 0); if (!(child_pid =3D fork())) { arts_debug("oggvorbis: child process"); do { ! // get more data =20=20 int seekTo =3D semctl(buflen_sem 2 GETVAL foo); if (seekTo) { arts_debug("oggvorbis: seeking to %d" seekTo); // we have a seek command int ret =3D ov_time_seek(&vf (double)seekTo-1); ! arts_debug("oggvorbis: ov_time_seek returned: %d\n" ret); foo.val=3D0; semctl(buflen_sem 2 SETVAL foo); // we've done it } --- 97135 ---- =20=20 FILE *ogg_fp; ogg_fp =3D fopen(filename.c_str() "r"); + if (ogg_fp =3D=3D NULL) { + perror(filename.c_str()); + return false; + } +=20 int current_section=3D0; =20=20 ov_open(ogg_fp &vf NULL 0); + arts_debug("oggvorbis: Encoded by: %s"ov_comment(&vf-1)->vendor); +=20=20 + // Check user comments and info + char **ptr=3Dov_comment(&vf-1)->user_comments; + while(*ptr){ + arts_debug("oggvorbis: %s"*ptr); + ++ptr; + } +=20 + vorbis_info *vi=3Dov_info(&vf-1); + arts_debug("\noggvorbis: Bitstream is %d channel %ldHz (hw %d Hz)"vi-= >channelsvi->rate samplingRate); + shm_buf->rate =3D vi->rate; +=20=20=20=20 +=20=20 if (!(child_pid =3D fork())) { arts_debug("oggvorbis: child process"); do { ! // seek and indicate position =20=20 int seekTo =3D semctl(buflen_sem 2 GETVAL foo); if (seekTo) { arts_debug("oggvorbis: seeking to %d" seekTo); // we have a seek command int ret =3D ov_time_seek(&vf (double)seekTo-1); ! arts_debug("oggvorbis: ov_time_seek returned: %d" ret); foo.val=3D0; semctl(buflen_sem 2 SETVAL foo); // we've done it } *************** *** 116135 **** if (foo.val =3D=3D -1) foo.val=3D0; semctl(buflen_sem 3 SETVAL foo); =20=20 ! int thisPass =3D ov_read(&vf (char *)decode_buf BACKBUFSIZ*sizeof(sh= ort) 0 2 1 ¤t_section); ! if (thisPass =3D=3D 0) { // we're done or we errored (in which case we're done) break; } ! thisPass =3D (thisPass / 4); =20=20 =20=20 semoper.sem_num =3D 1; semoper.sem_op =3D -thisPass; semop(buflen_sem &semoper 1); =20=20 ! // block until there's enough space to stick in this frame int roomFor =3D semctl(buflen_sem 1 GETVAL foo); if (roomFor > BACKBUFSIZ) { arts_debug("oggvorbis: exit requested bye!"); // this can never go above BACKBUFSIZ in normal operation --- 137162 ---- if (foo.val =3D=3D -1) foo.val=3D0; semctl(buflen_sem 3 SETVAL foo); =20=20 ! // get more data !=20 ! // ALWAYS read 16 bit little endian that specific format will be conv= erted to float later... ! int thisPass =3D ov_read(&vf (char *)decode_buf sizeof(decode_buf) = 0 SAMPLESIZE 1 ¤t_section); ! if (thisPass <=3D 0) { // we're done or we errored (in which case we're done) + arts_debug("oggvorbis: ov_read returned: thisPass=3D%d" thisPass); break; } ! thisPass =3D (thisPass / (SAMPLESIZE * vi->channels)); =20=20 =20=20 + // block until there's enough space to stick in this frame semoper.sem_num =3D 1; semoper.sem_op =3D -thisPass; semop(buflen_sem &semoper 1); =20=20 ! // check if exit is requested - non blocking int roomFor =3D semctl(buflen_sem 1 GETVAL foo); +=20 if (roomFor > BACKBUFSIZ) { arts_debug("oggvorbis: exit requested bye!"); // this can never go above BACKBUFSIZ in normal operation *************** *** 138145 **** } =20=20 for (int i=3D0 ; i <thisPass ; ++i buf_pos =3D ((buf_pos + 1) % BACKB= UFSIZ)) { ! shm_buf->left[buf_pos] =3D conv_16le_float(decode_buf[2*i]); ! shm_buf->right[buf_pos] =3D conv_16le_float(decode_buf[2*i+1]); } =20=20 //arts_debug("oggvorbis: enqueued them"); --- 165174 ---- } =20=20 for (int i=3D0 ; i <thisPass ; ++i buf_pos =3D ((buf_pos + 1) % BACKB= UFSIZ)) { ! // Sort of works for all number of channels... ! // TODO: proper handling of multichannel do not waste work from mono ! shm_buf->left[buf_pos] =3D conv_16le_float(decode_buf[vi->channels*i]= ); ! shm_buf->right[buf_pos] =3D conv_16le_float(decode_buf[vi->channels*i= +(vi->channels-1)]); } =20=20 //arts_debug("oggvorbis: enqueued them"); *************** *** 150161 **** //arts_debug("oggvorbis: calculated %d more samples"shm_buf->back$ } while(1); =20=20 ! //signal completion ! foo.val =3D 0; ! // no more data available ! semctl(buflen_sem 0 SETVAL foo); ! // and no room either (ie none coming) ! semctl(buflen_sem 1 SETVAL foo); =20=20 arts_debug("oggvorbis: decoder process exiting"); exit(0); --- 179189 ---- //arts_debug("oggvorbis: calculated %d more samples"shm_buf->back$ } while(1); =20=20 ! // block until all produced data has been consumed ! arts_debug("oggvorbis: decoder process waiting"); ! semoper.sem_num =3D 0; ! semoper.sem_op =3D 0; ! semop(buflen_sem &semoper 1); =20=20 arts_debug("oggvorbis: decoder process exiting"); exit(0); *************** *** 177183 **** if (time.seconds =3D=3D -1) time.seconds =3D 0; // Eek infinite loop time. time.ms=3D0; ! //arts_debug("oggvorbis: time is now %d\n" time.seconds); return time; } =20=20 --- 205211 ---- if (time.seconds =3D=3D -1) time.seconds =3D 0; // Eek infinite loop time. time.ms=3D0; ! //arts_debug("oggvorbis: time is now %d" time.seconds); return time; } =20=20 *************** *** 210215 **** --- 238244 ---- mState =3D posIdle; union semun foo; =20=20 + arts_debug("oggvorbis: halt"); if (child_pid) { arts_debug("oggvorbis: killing decoder process"); foo.val =3D 2*BACKBUFSIZ; *************** *** 222227 **** --- 251265 ---- // mainly this is to ensure that the decoder wakes up to notice } =20=20 + void oggPlayObject_impl::halt_on_decoderTerminated() { + if (child_pid &&=20 + waitpid(child_pid NULL WNOHANG)) { // child has already terminated! + child_pid =3D 0; + halt(); + } + } +=20 +=20 void oggPlayObject_impl::seek(const class poTime &t) { union semun foo; *************** *** 249255 **** =20=20 void oggPlayObject_impl::calculateBlock(unsigned long samples) { ! int samplesAvailable =3D 0; =20=20 //arts_debug("oggvorbis: calculateBlock"); =20=20 --- 287293 ---- =20=20 void oggPlayObject_impl::calculateBlock(unsigned long samples) { ! unsigned long samplesWritten =3D 0; =20=20 //arts_debug("oggvorbis: calculateBlock"); =20=20 *************** *** 257306 **** //arts_debug("oggvorbis: calculateBlock %d(%d) of %d samples in buffer= " //shm_buf->buflen - bufpos shm_buf->backbuflensamples); =20=20 ! struct sembuf bleh; =20=20 ! bleh.sem_num =3D 0; ! bleh.sem_flg =3D IPC_NOWAIT; ! //arts_debug("oggvorbis: %d samples wanted" samplesAvailable); ! bleh.sem_op =3D -samples; // does the buffer have sufficient samples? ! if (semop(buflen_sem &bleh 1) =3D=3D -1) { ! if (errno =3D=3D EAGAIN) { ! union semun foo; arts_debug("oggvorbis: buffer underrun"); ! samplesAvailable =3D semctl(buflen_sem 0 GETVAL foo); ! // no samples AND no room is the decoder's way of signalling completi= on ! if (semctl(buflen_sem 1 GETVAL foo) =3D=3D 0) { ! halt(); ! samplesAvailable =3D 0; } } else { ! // something awful has happened halt(); ! samplesAvailable =3D 0; } - } else { - samplesAvailable =3D samples; // number of samples we pushed from buff= ers - // used to calculate the number we should zero out for an underrun } - bleh.sem_flg =3D 0; // back to normal now -=20 - //arts_debug("oggvorbis: %d samples available"samplesAvailable); - for (int i =3D 0; i < samplesAvailable; - ++i buf_pos =3D ((buf_pos + 1) % BACKBUFSIZ)) { =20=20 ! left[i] =3D shm_buf->left[buf_pos]; ! right[i] =3D shm_buf->right[buf_pos]; } =20=20 ! bleh.sem_num =3D 1; ! bleh.sem_op =3D samplesAvailable; ! semop(buflen_sem &bleh 1); // mark the now-free space } // zero out any samples we didn't have enough to complete ! while(static_cast<unsigned long>(samplesAvailable) < samples) { ! left[samplesAvailable] =3D 0.0; ! right[samplesAvailable] =3D 0.0; ! samplesAvailable++; } } =20=20 --- 295378 ---- //arts_debug("oggvorbis: calculateBlock %d(%d) of %d samples in buffer= " //shm_buf->buflen - bufpos shm_buf->backbuflensamples); =20=20 ! int additional_reserve; ! if (shm_buf->rate =3D=3D samplingRate) { ! additional_reserve =3D samples; ! } else { ! additional_reserve =3D samples*shm_buf->rate/samplingRate + 1 - reserv= ed; ! } =20=20 ! while (additional_reserve > 0) { !=20 ! struct sembuf bleh; !=20 ! bleh.sem_num =3D 0; ! bleh.sem_flg =3D IPC_NOWAIT; ! bleh.sem_op =3D -additional_reserve; ! if (semop(buflen_sem &bleh 1) =3D=3D 0) { // likely ! // Success! ! reserved +=3D additional_reserve; ! additional_reserve =3D 0; ! } else if (errno =3D=3D EAGAIN) { arts_debug("oggvorbis: buffer underrun"); !=20 ! // Check the number of samples available this does not reserve them! ! union semun foo; ! int samplesAvailable =3D semctl(buflen_sem 0 GETVAL foo); !=20 ! // No samples! Why? Has decoder terminated? ! if (samplesAvailable =3D=3D 0) { ! halt_on_decoderTerminated(); } +=20 + additional_reserve =3D samplesAvailable; } else { ! // something awful/unexpected has happened halt(); ! additional_reserve =3D 0; } } =20=20 ! //////////////////////// ! // use from reserved ! // ! int used =3D 0; ! while (samplesWritten < samples && used < reserved) { !=20 ! left[samplesWritten] =3D shm_buf->left[buf_pos]; ! right[samplesWritten] =3D shm_buf->right[buf_pos]; ! samplesWritten++; !=20 ! fract_bufpos +=3D shm_buf->rate; !=20 ! if (fract_bufpos >=3D samplingRate) { ! fract_bufpos -=3D samplingRate; ! buf_pos =3D ((buf_pos + 1) % BACKBUFSIZ); ! used++; ! } } =20=20 ! /////////////////////////////////////////////////////// ! // finalize avoid semop with sem_op=3D=3D0 =3D> will sleep ! // ! reserved -=3D used; ! artsdebug("reserved=3D%d used=3D%d\n" reserved used); !=20 ! if (used > 0) { ! struct sembuf freesem; ! freesem.sem_num =3D 1; ! freesem.sem_op =3D +used; ! semop(buflen_sem &freesem 1); // mark the now-free space ! } } +=20 + //////////////////////////////////////////////////////////// // zero out any samples we didn't have enough to complete ! // ! while(samplesWritten < samples) { ! left[samplesWritten] =3D 0.0; ! right[samplesWritten] =3D 0.0; ! samplesWritten++; } } =20=20 *************** *** 310312 **** --- 382390 ---- } =20=20 REGISTER_IMPLEMENTATION(oggPlayObject_impl); +=20 +=20 +=20 +=20 +=20 +=20 Index: oggPlayObject_impl.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /home/kde/kdemultimedia/oggvorbis_artsplugin/oggPlayObject_impl.h= v retrieving revision 1.2 diff -c -r1.2 oggPlayObject_impl.h *** oggPlayObject_impl.h2001/12/14 20:54:431.2 --- oggPlayObject_impl.h2002/01/29 22:02:00 *************** *** 5060 **** --- 5075 ---- struct buf_t{ float left[BACKBUFSIZ]; float right[BACKBUFSIZ]; + int rate; } *shm_buf; int shm_id child_pid; int buflen_sem; +=20 + private: + int reserved; // reserved but unused input (shm_buf) + int fract_bufpos; // per samplingRate initialized to 0 +=20 + void halt_on_decoderTerminated(); }; =20=20 }; =20=20 #endif +=20 +=20 +=20 +=20 +=20 +=20 +=20 +=20 --------------Boundary-00=_RC2QVUOBMEA14N0LWUWB--
After some tweaking it works. Problem is that we have several competing OGG vorbis handling currently... arts, mpeglib, and oggvorbis_artsplugin I have done nothing special in my configuration but I get two .mcopclass'es installed that handles OGG: [use: "grep -r -i ogg /opt/kdecvs/lib/mcop/" to find out] /opt/kdecvs/lib/mcop/Arts/GSLPlayObject.mcopclass /opt/kdecvs/lib/mcop/OGGPlayObject.mcopclass If I remove OGGPlayObject.mcopclass (or move away) and then restart arts sound server - I get sound for all strange ogg files (like encoded 8000 Hz, mono) Should oggPlayObject and ogg support from mpeglib be removed?
fixed with a hack to vorbisPlugin. Tested with a short 8Khz file. case _STREAM_STATE_WAIT_FOR_END: // exit while loop lDecoderLoop=false; + usleep(2000000); break; default: cout << "unknown stream state vorbis decoder:"<<streamState<<endl;
*** Bug has been marked as fixed ***.
Subject: Re: can not play all files encoded with ogg vorbis rc3 Martin, is the usleep the only change you made? You do not have this patch applied? from Matthias Welwarsky (when only using the usleep does not work for me, I get no sound, speedy sound, or crashes - indicates that something is wrong - I will recompile and retry) /RogerL Index: GSLPlayObject.mcopclass =================================================================== RCS file: /cvs/arts/soundserver/GSLPlayObject.mcopclass,v retrieving revision 1.5 diff -u -3 -p -r1.5 GSLPlayObject.mcopclass --- GSLPlayObject.mcopclass 2002/07/31 11:33:43 1.5 +++ GSLPlayObject.mcopclass 2002/10/21 20:16:47 @@ -5,3 +5,4 @@ Extension=wav,mp3,ogg Language=C++ Library=libartsgslplayobject.la MimeType=audio/wav,audio/x-wav,audio/x-mp3,audio/x-mp1,audio/x-mp2,audio/x-ogg,application/x-ogg +Preference=4
Subject: Re: can not play all files encoded with ogg vorbis rc3 On Tuesday 22 October 2002 13.34, Martin Vogt wrote: > On Mon, Oct 21, 2002 at 08:22:52PM -0000, Roger Larsson wrote: > > > > ------- Additional Comments From roger.larsson@norran.net 2002-10-21 22:22 ------- > > Subject: Re: can not play all files encoded with ogg vorbis rc3 > > > > Martin, is the usleep the only change you made? > > > > You do not have this patch applied? from Matthias Welwarsky > > (when only using the usleep does not work for me, I get no sound, speedy > > sound, or crashes - indicates that something is wrong - I will recompile and > > retry) > > > Do you have such a file? > I have currently only 1.0 installed. > Can you please try > > yaf-vorbis > > the command line player. This helps to find > where a possible problem is. > > Martin > > > The file ohr.ogg that you already got is one of the problematic files. I have now recognized what happens. It plays only the initial part of the file (sound of taperecorder turning on...) The usleep that you added should help but it does not... usleep(2000000); Possible problems: usleep(1000000) can give errors and no sleep (see man pages), tried with sleep(2) but no difference my computer might be faster than your (933 MHz) so the file might be read and decoded before play even starts... using sleeps is bad practice. You should not sleep but wait on notification that file is played. Note: The patch from Matthias Welwarsky works. Altering preference orders. Playing with ogg123 works. I have recompiled everything, but I still get crashes (Qt)... So I am not 100% that everything works as expected - will investigate this further... roger@jeloin:~/KDE/sounds/de> yaf-vorbis ohr.ogg Command:0 Msg:protocol yaf-0.1 Command:0 Msg:implements xplayer Command:0 Msg:decoder vorbis Version:20000223 Command:0 Msg:mimetypes audio/ogg; Command:0 Msg:comment vorbis by Monty http://www.xiph.org/ Command:0 Msg:comment yaf port by mvogt@rhrk.uni-kl.de Command:0 Msg:comment based on sources from vorbis Command:0 Msg:comment enter 'help' Command:0 Msg:player-status on Command:0 Msg:player-status open Command:0 Msg:player-status playing Command:0 Msg:musicinfo-Start Command:0 Msg:song_filename Command:0 Msg:song_name noname Command:0 Msg:song_len 3 Command:0 Msg:song_jumps 0 Command:0 Msg:musicinfo-End Command:43 Ret:(ok) Msg:open ohr.ogg Command:0 Msg:streamInfo-Start Command:0 Msg:streamInfo-Channels 1 Command:0 Msg:streamInfo-SampleSize 16 Command:0 Msg:streamInfo-Speed 8000 Command:0 Msg:streamInfo-End Command:0 Msg:player-status pause Command:0 Msg:player-status close Command:0 Msg:player-status off 23680 23680 Command:44 Ret:(ok) Msg:update roger@jeloin:~/KDE/sounds/de> ogg123 ohr.ogg Audio Device: Advanced Linux Sound Architecture (ALSA) output Spelar: ohr.ogg Klar.
It plays alright but it truncates the end of the audio. Short files will not play anything. This patch, from Matthias Welwarsky works around the problem by using GSLPlayObject instead (but it does not fix the bug that is in mpeglib. Index: GSLPlayObject.mcopclass =================================================================== RCS file: /home/kde/arts/soundserver/GSLPlayObject.mcopclass,v retrieving revision 1.5 diff -u -3 -p -r1.5 GSLPlayObject.mcopclass --- GSLPlayObject.mcopclass 2002/07/31 11:33:43 1.5 +++ GSLPlayObject.mcopclass 2002/10/19 18:57:19 @@ -5,3 +5,4 @@ Extension=wav,mp3,ogg Language=C++ Library=libartsgslplayobject.la MimeType=audio/wav,audio/x-wav,audio/x-mp3,audio/x-mp1,audio/x-mp2,audio/x-ogg,application/x-ogg +Preference=4
This now works for me. But should not the usleep(2000000); be replaced with sleep(2); for compatibility reasons? see > man 3 usleep EINVAL usec is not smaller than 1000000. (On systems where that is considered an error.)
Sorry, I noticed that I had the other patch applied. (Preference=4) Removing that patch results in a non working ohr.ogg again... :-(
what is the current status on this, is this different in 3.1?
Subject: Re: can not play all files encoded with ogg vorbis rc3 It still does not work in CVS (-> KDE 3.2)
No go with recent CVS (~3.2 alpha)
This works with recent CVS!