Adding a KVO context to avoid issues with future super/sub-classing.

Bug: webrtc:8342
Change-Id: I457858056ffc7f33bbfb261153301ea2ccd71a51
Reviewed-on: https://webrtc-review.googlesource.com/6440
Commit-Queue: Peter Hanspers <peterhanspers@webrtc.org>
Reviewed-by: Anders Carlsson <andersc@webrtc.org>
Reviewed-by: Daniela Jovanoska Petrenko <denicija@webrtc.org>
Reviewed-by: Kári Helgason <kthelgason@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20389}
diff --git a/sdk/objc/Framework/Classes/Audio/RTCAudioSession.mm b/sdk/objc/Framework/Classes/Audio/RTCAudioSession.mm
index 43575b9..67a70da 100644
--- a/sdk/objc/Framework/Classes/Audio/RTCAudioSession.mm
+++ b/sdk/objc/Framework/Classes/Audio/RTCAudioSession.mm
@@ -56,8 +56,13 @@
 }
 
 - (instancetype)init {
+  return [self initWithAudioSession:[AVAudioSession sharedInstance]];
+}
+
+/** This initializer provides a way for unit tests to inject a fake/mock audio session. */
+- (instancetype)initWithAudioSession:(id)audioSession {
   if (self = [super init]) {
-    _session = [AVAudioSession sharedInstance];
+    _session = audioSession;
 
     NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
     [center addObserver:self
@@ -91,7 +96,7 @@
     [_session addObserver:self
                forKeyPath:kRTCAudioSessionOutputVolumeSelector
                   options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
-                  context:nil];
+                  context:(__bridge void*)RTCAudioSession.class];
 
     RTCLog(@"RTCAudioSession (%p): init.", self);
   }
@@ -100,7 +105,9 @@
 
 - (void)dealloc {
   [[NSNotificationCenter defaultCenter] removeObserver:self];
-  [_session removeObserver:self forKeyPath:kRTCAudioSessionOutputVolumeSelector context:nil];
+  [_session removeObserver:self
+                forKeyPath:kRTCAudioSessionOutputVolumeSelector
+                   context:(__bridge void*)RTCAudioSession.class];
   RTCLog(@"RTCAudioSession (%p): dealloc.", self);
 }
 
@@ -815,10 +822,12 @@
                       ofObject:(id)object
                         change:(NSDictionary *)change
                        context:(void *)context {
-  if (object == _session) {
-    NSNumber *newVolume = change[NSKeyValueChangeNewKey];
-    RTCLog(@"OutputVolumeDidChange to %f", newVolume.floatValue);
-    [self notifyDidChangeOutputVolume:newVolume.floatValue];
+  if (context == (__bridge void*)RTCAudioSession.class) {
+    if (object == _session) {
+      NSNumber *newVolume = change[NSKeyValueChangeNewKey];
+      RTCLog(@"OutputVolumeDidChange to %f", newVolume.floatValue);
+      [self notifyDidChangeOutputVolume:newVolume.floatValue];
+    }
   } else {
     [super observeValueForKeyPath:keyPath
                          ofObject:object
diff --git a/sdk/objc/Framework/UnitTests/RTCAudioSessionTest.mm b/sdk/objc/Framework/UnitTests/RTCAudioSessionTest.mm
index d94c635..951b5ea 100644
--- a/sdk/objc/Framework/UnitTests/RTCAudioSessionTest.mm
+++ b/sdk/objc/Framework/UnitTests/RTCAudioSessionTest.mm
@@ -18,6 +18,22 @@
 #import "WebRTC/RTCAudioSession.h"
 #import "WebRTC/RTCAudioSessionConfiguration.h"
 
+@interface RTCAudioSession (UnitTesting)
+
+- (instancetype)initWithAudioSession:(id)audioSession;
+
+@end
+
+@interface MockAVAudioSession : NSObject
+
+@property (nonatomic, readwrite, assign) float outputVolume;
+
+@end
+
+@implementation MockAVAudioSession
+@synthesize outputVolume = _outputVolume;
+@end
+
 @interface RTCAudioSessionTestDelegate : NSObject <RTCAudioSessionDelegate>
 
 @property (nonatomic, readonly) float outputVolume;
@@ -265,20 +281,16 @@
 }
 
 - (void)testAudioVolumeDidNotify {
-  RTCAudioSession *session = [RTCAudioSession sharedInstance];
+  MockAVAudioSession *mockAVAudioSession = [[MockAVAudioSession alloc] init];
+  RTCAudioSession *session = [[RTCAudioSession alloc] initWithAudioSession:mockAVAudioSession];
   RTCAudioSessionTestDelegate *delegate =
       [[RTCAudioSessionTestDelegate alloc] init];
   [session addDelegate:delegate];
 
-  [session observeValueForKeyPath:@"outputVolume"
-                         ofObject:[AVAudioSession sharedInstance]
-                           change:
-        @{NSKeyValueChangeNewKey :
-            @([AVAudioSession sharedInstance].outputVolume) }
-                          context:nil];
+  float expectedVolume = 0.75;
+  mockAVAudioSession.outputVolume = expectedVolume;
 
-  EXPECT_NE(delegate.outputVolume, -1);
-  EXPECT_EQ([AVAudioSession sharedInstance].outputVolume, delegate.outputVolume);
+  EXPECT_EQ(expectedVolume, delegate.outputVolume);
 }
 
 @end