ios - Why does this audio session fail to recognise an interruption? -


my app synthesises audio lookup table. plays audio crashes moment try stop playing. audio playback needs exit without restarting requirements handling interruption basic. reread apple’s audio session programming guide including section responding interruptions. method handleaudiosessioninterruption not seem register interrupt i’m missing something.


edit see answer. when began work on knew next nothing nsnotificationcenter welcome suggestion improvement.


two methods set audio session play in foreground.

- (void)setupaudio {     if (_playqueue == null)     {         if ([self setupaudiosession] == true)         {             [self setupplayqueue];             [self setupplayqueuebuffers];         }     } }   - (bool)setupaudiosession {     bool success                        = no;     nserror *audiosessionerror          = nil;      avaudiosession *session             = [avaudiosession sharedinstance];      // set notifications      [[nsnotificationcenter defaultcenter] addobserver:self                                              selector:@selector(handleaudiosessioninterruption:)                                                  name:avaudiosessioninterruptionnotification                                                object:session];      // set category      success                             = [session setcategory:avaudiosessioncategoryplayback                                                          error:&audiosessionerror];     if (!success)     {         nslog(@"%@ error setting category: %@",               nsstringfromselector(_cmd), [audiosessionerror localizeddescription]);          // exit         return success;     }      // set mode      success                             = [session setmode:avaudiosessionmodedefault                                                      error:&audiosessionerror];     if (!success)     {         nslog(@"%@ error setting mode: %@",               nsstringfromselector(_cmd), [audiosessionerror localizeddescription]);          // exit         return success;     }      // set preferred values      nstimeinterval bufferduration       = .005; // prefer 5ms buffer duration      success                             = [session setpreferrediobufferduration:bufferduration                                                                           error:&audiosessionerror];     if (audiosessionerror)     {         nslog(@"error %ld, %@ %i", (long)audiosessionerror.code, audiosessionerror.localizeddescription, success);     }      double samplerate                   = _audioformat.msamplerate; // prefer sample rate of 44.1khz      success                             = [session setpreferredsamplerate:samplerate                                                                     error:&audiosessionerror];     if (audiosessionerror)     {         nslog(@"error %ld, %@ %i", (long)audiosessionerror.code, audiosessionerror.localizeddescription, success);     }      success                             = [session setactive:yes                                                        error:&audiosessionerror];     if (!success)     {         nslog(@"%@ error activating %@",               nsstringfromselector(_cmd), [audiosessionerror localizeddescription]);     }      // current values      samplerate                          = session.samplerate;     bufferduration                      = session.iobufferduration;     nslog(@"sample rate:%0.0fhz i/o buffer duration:%f", samplerate, bufferduration);      return success; } 

and here method handles interruption when press stop button. not respond.


edit correct method needs block, not selector. see answer.


- (void)handleaudiosessioninterruption:(nsnotification*)notification {     if (_playqueue)     {         nsnumber *interruptiontype      = [[notification userinfo] objectforkey:avaudiosessioninterruptiontypekey];         nsnumber *interruptionoption    = [[notification userinfo] objectforkey:avaudiosessioninterruptionoptionkey];          nslog(@"in-app audio playback stopped %@ %lu", notification.name, (unsigned long)interruptiontype.unsignedintegervalue);          switch (interruptiontype.unsignedintegervalue)         {             case avaudiosessioninterruptiontypebegan:             {                 if (interruptionoption.unsignedintegervalue == avaudiosessionsetactiveoptionnotifyothersondeactivation)                 {                     nslog(@"notify other apps audio available");                 }             }                 break;              default:                 break;         }     } } 

answer method handle audiosessioninterruption did not subscribe observer correctly nsnotificationcentre. has been fixed adding observer using block, not selector.

the solution replaces deprecated avaudiosession delegate methods in audiobufferplayer, extremely fit purpose audio player developed direct audio synthesis matthias hollejmans. several deprecated functions including interruptionlistenercallback later upgraded mario diana. solution (below) uses nsnotification allowing users exit avaudiosession gracefully pressing button.

here relevant code.

playviewcontroller.m

uibutton action performs orderly shutdown of synth, invalidates timer , posts notification exit avaudiosession

- (void)fromescbutton:(uibutton*)button {     [self stopconcertclock];      ...                            // code exit playviewcontroller not shown }  - (void)stopconcertclock {     [_synthlock lock];     [_synth stopallnotes];     [_synthlock unlock];     [timer invalidate];     timer = nil;     [self postavaudiosessioninterruptionnotification];     nslog(@"esc button pressed or sequence ended. exit playviewcontroller "); }   - (void) postavaudiosessioninterruptionnotification {     [[nsnotificationcenter defaultcenter]      postnotificationname:@"avaudiosessioninterruptionnotification"      object:self]; } 

initialising avaudiosession includes subscribing single interruption notification before starting startaudioplayer in audiobufferplayer

- (id)init {     if (self = [super init])     {         nslog(@"playviewcontroller starts motionlistener , audiosession");          [self startaudiosession];     }     return self; }   - (void)startaudiosession     {     // synth , audiobufferplayer must use same sample rate.      _synthlock = [[nslock alloc] init];      float samplerate = 44100.0f;      // initialise synth fill audio buffer audio samples.      _synth = [[synth alloc] initwithsamplerate:samplerate];      // initialise audio buffer.      _player = [[audiobufferplayer alloc] initwithsamplerate:samplerate                                                     channels:1                                              bitsperchannel:16                                            packetsperbuffer:1024];     _player.gain = 0.9f;      __block __weak playviewcontroller *weakself = self;       _player.block = ^(audioqueuebufferref buffer, audiostreambasicdescription audioformat) {     playviewcontroller *blockself   = weakself;      if (blockself != nil)     {         // lock access synth. callback runs on internal audio queue thread , don't         // want thread change synth's state while we're still filling audio buffer.      [blockself -> _synthlock lock];          // calculate how many packets fit buffer. remember packet equals 1 frame         // because dealing uncompressed audio; frame set of left+right samples         // stereo sound, or single sample mono sound. each sample consists of 1 or more         // bytes. 16-bit mono sound, each packet 2 bytes. stereo 4 bytes.      int packetsperbuffer = buffer -> maudiodatabytescapacity / audioformat.mbytesperpacket;          // let synth write buffer. synth knows how fill buffers         // in particular format , not care come from.      int packetswritten              = [blockself -> _synth fillbuffer:buffer->maudiodata frames:packetsperbuffer];          // have tell buffer how many bytes wrote it.      buffer -> maudiodatabytesize    = packetswritten * audioformat.mbytesperpacket;      [blockself -> _synthlock unlock];     } };  // set notifications      [self subscribeforblocknotification];      [_player startaudioplayer]; }   - (void)subscribeforblocknotification {     nsnotificationcenter * __weak center = [nsnotificationcenter defaultcenter];      id __block token = [center addobserverforname:@"avaudiosessioninterruptionnotification"                                         object:nil                                         queue:[nsoperationqueue mainqueue]                                    usingblock:^(nsnotification *note) {                                        nslog(@"received notification!");                                        [_player stopaudioplayer];                                        [center removeobserver:token];                                    }]; } 

playviewcontroller.h

these relevant interface settings

@interface playviewcontroller : uiviewcontroller <escbuttondelegate>  {         ...       // initialisation of audio player , synth      audiobufferplayer* player;     synth*             synth;     nslock*            synthlock; }      ...      - (audiobufferplayer*)player;     - (synth*)synth;  @end 

audiobufferplayer.m

- (void)stopaudioplayer {     [self stopplayqueue];     [self teardownplayqueue];     [self teardownaudiosession]; }   - (void)stopplayqueue {     if (_audioplaybackqueue != null)     {         audioqueuepause(_audioplaybackqueue);         audioqueuereset(_audioplaybackqueue);         _playing = no;     } }   - (void)teardownplayqueue {     audioqueuedispose(_audioplaybackqueue, no);     _audioplaybackqueue = null; }   - (bool)teardownaudiosession {     nserror *deactivationerror = nil;     bool success = [[avaudiosession sharedinstance] setactive:no                                                   withoptions:avaudiosessionsetactiveoptionnotifyothersondeactivation                                                         error:nil];     if (!success)     {         nslog(@"%s avaudiosession error: %@", __function__, deactivationerror);     }     return success; } 

Comments

Popular posts from this blog

angular - Ionic slides - dynamically add slides before and after -

minify - Minimizing css files -

Add a dynamic header in angular 2 http provider -