title: How to consistently stop AVAudioSession after AVSpeechUtterance
body: <p>What I want to do is allow my app to speak an utterance using <code>AVSpeechSynthesizer</code> while background audio apps are playing audio. While my app is speaking, I'd like the background apps' audio to "dim" and then return to their original volume after my app has finished speaking.</p>
  
  <p>In my <code>AudioFeedback</code> class, I initialize I setup the <code>AVAudioSessions</code> like so:</p>
  
  <pre><code>    self.session = [AVAudioSession sharedInstance];
      NSError *error;
      [self.session setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionDuckOthers error:&amp;error];
  </code></pre>
  
  <p>Whenever I want to speak a new utterance, I do the following. I followed the suggestion from <a href="https://stackoverflow.com/questions/19672814/an-issue-with-avspeechsynthesizer-any-workarounds">An issue with AVSpeechSynthesizer, Any workarounds?</a> to create a new AVSpeechSynthesizer every time to "make sure" that cancelations are always received (it just seems to work, I'm not sure why).</p>
  
  <pre><code>- (AVSpeechUtterance *) utteranceWithString: (NSString *) string
  {
      AVSpeechUtterance *utterance = [AVSpeechUtterance  speechUtteranceWithString:string];
      utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:@"en-ES"];
      [utterance setRate:(AVSpeechUtteranceDefaultSpeechRate+AVSpeechUtteranceMinimumSpeechRate)/2.0];
      return utterance;
  }
  
  - (void) sayString: (NSString *) string cancelPrevious: (BOOL) cancelPrevious
  {
      [self.session setActive:enabled error:nil];
      if (cancelPrevious) {
          AVSpeechSynthesizer *oldSynthesizer = self.voice;
          self.voice = nil;
          [oldSynthesizer stopSpeakingAtBoundary:AVSpeechBoundaryImmediate];
          self.voice = [[AVSpeechSynthesizer alloc] init];
          self.voice.delegate = self;
      }
  
      // Keep track of the final utterance, we'll use this to determine whether or not we should stop the audio session
      self.finalUtterance = [self utteranceWithString:string];
      [self.voice speakUtterance:self.finalUtterance];
  }
  </code></pre>
  
  <p>In my AVSpeechSynthesizer delegate method, I check to see if I should stop the audio session to return the background audio to normal volume if the current AVSpeechSynthesizer and the current AVSpeechUtterance match the last known synthesizer and utterance.</p>
  
  <pre><code>-(void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didFinishSpeechUtterance:(AVSpeechUtterance *)utterance
  {
      NSError *error;
      // Only stop the audio session if this is the last created synthesizer
      if (synthesizer == self.voice  &amp;&amp; self.finalUtterance == utterance) {
          if ([self.session setActive:enabled error:&amp;error]]) {
              NSLog(@"Stopped the audio session: Speech synthesizer still speaking %d", synthesizer.speaking);
          } else {
              NSLog(@"ERROR failed to stop the audio session: %@. Speech synthesizer still speaking %d", error, synthesizer.speaking);
          }
      }
  }
  </code></pre>
  
  <p>The problem I'm having is that sometimes, the audio session will stop without issues, and other times, the audio session will fail to stop with the following error:</p>
  
  <blockquote>
    <p>Error Domain=NSOSStatusErrorDomain Code=2003329396 "The operation couldn’t be completed. (OSStatus error 2003329396.)"</p>
  </blockquote>
  
  <p>I am not sure how to guarantee that I can stop the AVAudioSession. I've tried to keep calling <code>[[AVAudioSession sharedInstance] setActive:NO error:&amp;error]</code> for as long as I am unable to stop the audio session, but that just doesn't seem to work. Any help would be greatly appreciated. Thank you!</p>