Resolves threading issues when audio is interrupted on iOS.

Before this change we could crash in Debug when WebRTC audio was first
interrupted and then resumed again. The reason was that the new audio
stream stems from a new native I/O thread and that triggered thread
checkers. With this change, failing thread checkers are detached when
audio is interrupted to ensure that they don't fail when audio is restarted.

NOTRY=TRUE

Bug: webrtc:8126
Change-Id: Ib36ff6bc942477730aba60066f049ed0c43d3901
Reviewed-on: https://chromium-review.googlesource.com/628716
Commit-Queue: Henrik Andreasson <henrika@webrtc.org>
Reviewed-by: Per Ã…hgren <peah@webrtc.org>
Cr-Original-Commit-Position: refs/heads/master@{#19465}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: 09a76193f5fa87bfacefd2ea15249338792aad1d
diff --git a/modules/audio_device/audio_device_buffer.cc b/modules/audio_device/audio_device_buffer.cc
index 8227d5b..905c696 100644
--- a/modules/audio_device/audio_device_buffer.cc
+++ b/modules/audio_device/audio_device_buffer.cc
@@ -260,6 +260,12 @@
   return 0;
 }
 
+void AudioDeviceBuffer::NativeAudioInterrupted() {
+  RTC_DCHECK(main_thread_checker_.CalledOnValidThread());
+  playout_thread_checker_.DetachFromThread();
+  recording_thread_checker_.DetachFromThread();
+}
+
 uint32_t AudioDeviceBuffer::NewMicLevel() const {
   RTC_DCHECK_RUN_ON(&recording_thread_checker_);
   return new_mic_level_;
diff --git a/modules/audio_device/audio_device_buffer.h b/modules/audio_device/audio_device_buffer.h
index 04e1be8..2a5a84b 100644
--- a/modules/audio_device/audio_device_buffer.h
+++ b/modules/audio_device/audio_device_buffer.h
@@ -118,6 +118,12 @@
 
   int32_t SetTypingStatus(bool typing_status);
 
+  // Called on iOS where the native audio layer can be interrupted by other
+  // audio applications. This method can then be used to reset internal
+  // states and detach thread checkers to allow for a new audio session where
+  // native callbacks may come from a new set of I/O threads.
+  void NativeAudioInterrupted();
+
  private:
   // Starts/stops periodic logging of audio stats.
   void StartPeriodicLogging();
diff --git a/modules/audio_device/ios/audio_device_ios.mm b/modules/audio_device/ios/audio_device_ios.mm
index 1d59aff..fb2f65d 100644
--- a/modules/audio_device/ios/audio_device_ios.mm
+++ b/modules/audio_device/ios/audio_device_ios.mm
@@ -554,6 +554,15 @@
     RTCLog(@"Stopping the audio unit due to interruption begin.");
     if (!audio_unit_->Stop()) {
       RTCLogError(@"Failed to stop the audio unit for interruption begin.");
+    } else {
+      // The audio unit has been stopped but will be restarted when the
+      // interruption ends in HandleInterruptionEnd(). It will result in audio
+      // callbacks from a new native I/O thread which means that we must detach
+      // thread checkers here to be prepared for an upcoming new audio stream.
+      io_thread_checker_.DetachFromThread();
+      // The audio device buffer must also be informed about the interrupted
+      // state so it can detach its thread checkers as well.
+      audio_device_buffer_->NativeAudioInterrupted();
     }
   }
   is_interrupted_ = true;