iphone sdk 3.0 - CoreAudio - how to determine the end of the playing aac file -
i playing coreaudio on iphone, , unable find how know when song has finished play.
i put property listener on kaudioqueueproperty_isrunning
, working when starting playing not @ end of file. it's work when stop audioqueue...
do have idea ?
thanks lot.
ps : using sample code excellent book iphone cool projects : http://apress.com/book/downloadfile/4453
edit :
there’s bug in code went out book. fix requires small modification -[audioplayer audiorequestdidfinish:] calls [queue endofstream].
this class uli kusterer illustrates functionality clearly.
here's header:
// // uksound.h // mobilemoose // // created uli kusterer on 14.07.08. // copyright 2008 void software. rights reserved. // #import <uikit/uikit.h> #import <audiotoolbox/audiotoolbox.h> #define knumberbuffers 2 @class uksound; @protocol uksounddelegate @optional -(void) sound: (uksound*)sender didfinishplaying: (bool)state; @end @interface uksound : nsobject { audiofileid maudiofile; audiostreambasicdescription mdataformat; audioqueueref mqueue; audioqueuebufferref mbuffers[knumberbuffers]; uint64 mpacketindex; uint32 mnumpacketstoread; audiostreampacketdescription * mpacketdescs; bool mdone; id<uksounddelegate> delegate; int maxbuffersizebytes; } @property (assign) id<uksounddelegate> delegate; -(id) initwithcontentsofurl: (nsurl*)theurl; -(void) notifydelegateplaybackstatechanged: (id)sender; -(void) play; // private: -(void) audioqueue: (audioqueueref)inaq processbuffer: (audioqueuebufferref)incompleteaqbuffer; @end
here's implementation:
// // uksound.m // mobilemoose // // created uli kusterer on 14.07.08. // copyright 2008 void software. rights reserved. // #import "uksound.h" static void uksoundaqbuffercallback(void * inuserdata, audioqueueref inaq, audioqueuebufferref incompleteaqbuffer) { uksound* myself = (uksound*)inuserdata; [myself audioqueue: inaq processbuffer: incompleteaqbuffer]; } static void uksoundaqpropertylistenercallback( void * inuserdata, audioqueueref inaq, audioqueuepropertyid inid) { [(uksound*)inuserdata performselectoronmainthread: @selector(notifydelegateplaybackstatechanged:) withobject: nil waituntildone: no]; } @implementation uksound @synthesize delegate; -(id) initwithcontentsofurl: (nsurl*)theurl { self = [super init]; if( self ) { maxbuffersizebytes = 0x10000; osstatus err = audiofileopenurl( (cfurlref)theurl, kaudiofilereadpermission, 0, &maudiofile ); if( err != noerr ) nslog(@"couldn't open audiofile."); uint32 size = sizeof(mdataformat); err = audiofilegetproperty( maudiofile, kaudiofilepropertydataformat, &size, &mdataformat ); if( err != noerr ) nslog(@"couldn't determine audio file format."); err = audioqueuenewoutput( &mdataformat, uksoundaqbuffercallback, self, null, null, 0, &mqueue ); if( err != noerr ) nslog(@"couldn't create new output queue."); // have couple of things take care of // (1) setting conditions around vbr or cbr format - affects how read file // if format vbr need use packet table. if( mdataformat.mbytesperpacket == 0 || mdataformat.mframesperpacket == 0 ) { // first check see max size of packet - if bigger // our allocation default size, needs become larger uint32 maxpacketsize; size = sizeof(maxpacketsize); err = audiofilegetproperty( maudiofile, kaudiofilepropertypacketsizeupperbound, &size, &maxpacketsize); if( err != noerr ) nslog(@"couldn't max packet size of audio file."); if( maxpacketsize > maxbuffersizebytes ) maxbuffersizebytes = maxpacketsize; // need packet descpriptions file reading mnumpacketstoread = maxbuffersizebytes / maxpacketsize; mpacketdescs = malloc( sizeof(audiostreampacketdescription) * mnumpacketstoread ); } else { mnumpacketstoread = maxbuffersizebytes / mdataformat.mbytesperpacket; mpacketdescs = null; } // (2) if file has cookie, should , set on aq size = sizeof(uint32); err = audiofilegetpropertyinfo( maudiofile, kaudiofilepropertymagiccookiedata, &size, null ); if( !err && size ) { char* cookie = malloc( size ); err = audiofilegetproperty( maudiofile, kaudiofilepropertymagiccookiedata, &size, cookie ); if( err != noerr ) nslog(@"couldn't magic cookie of audio file."); err = audioqueuesetproperty( mqueue, kaudioqueueproperty_magiccookie, cookie, size ); if( err != noerr ) nslog(@"couldn't transfer magic cookie of audio file qudio queue."); free( cookie ); } err = audioqueueaddpropertylistener( mqueue, kaudioqueueproperty_isrunning, uksoundaqpropertylistenercallback, self ); if( err != noerr ) nslog(@"couldn't register playback state changes."); // prime queue data before starting mdone = false; mpacketindex = 0; for( int = 0; < knumberbuffers; ++i ) { err = audioqueueallocatebuffer( mqueue, maxbuffersizebytes, &mbuffers[i] ); if( err != noerr ) nslog(@"couldn't allocate buffer %d.", i); uksoundaqbuffercallback( self, mqueue, mbuffers[i] ); if( mdone ) break; } } return self; } -(void) dealloc { osstatus err = audioqueuedispose( mqueue, true ); err = audiofileclose( maudiofile ); if( mpacketdescs ) free( mpacketdescs ); [super dealloc]; } -(void) play { osstatus err = audioqueuestart( mqueue, null ); if( err != noerr ) nslog(@"couldn't start audio queue."); else [self retain]; } -(bool) isplaying { uint32 state = no, size = sizeof(uint32); osstatus err = audioqueuegetproperty( mqueue, kaudioqueueproperty_isrunning, &state, &size ); if( err != noerr ) nslog(@"couldn't play state of queue."); return state; } -(void) notifydelegateplaybackstatechanged: (id)sender; { if( ![self isplaying] ) { nslog(@"insert functionality here."); [delegate sound: self didfinishplaying: yes]; audioqueuestop( mqueue, false ); [self release]; } } -(void) audioqueue: (audioqueueref)inaq processbuffer: (audioqueuebufferref)incompleteaqbuffer { if( mdone ) return; uint32 numbytes; uint32 npackets = mnumpacketstoread; // read npackets worth of data buffer osstatus err = audiofilereadpackets( maudiofile, false, &numbytes, mpacketdescs, mpacketindex, &npackets, incompleteaqbuffer->maudiodata); if( err != noerr ) nslog(@"couldn't read buffer."); if (npackets > 0) { incompleteaqbuffer->maudiodatabytesize = numbytes; // queues buffer audio input/output. err = audioqueueenqueuebuffer( inaq, incompleteaqbuffer, (mpacketdescs ? npackets : 0), mpacketdescs ); if( err != noerr ) nslog(@"couldn't enqueue buffer."); mpacketindex += npackets; } else { uint32 state = no, size = sizeof(uint32); osstatus err = audioqueuegetproperty( mqueue, kaudioqueueproperty_isrunning, &state, &size ); // should calling following, makes app hang. if( state ) { err = audioqueuestop( mqueue, false ); if( err != noerr ) nslog(@"couldn't stop queue."); // reading npackets == 0 our eof condition } mdone = true; } } @end
when call initwithcontentsofurl: (nsurl*)theurl
method, uksoundaqpropertylistenercallback
added audio queue. set respond kaudioqueueproperty_isrunning
audio queue property. after play
method called , file finishes playing, uksoundaqpropertylistenercallback
called in turn calls notifydelegateplaybackstatechanged
method. have added nslog message method illustrate when file stops playing.
i'd happy share xcode project demonstrates functionality.
Comments
Post a Comment