Move RTCAudioSession* files  modules/audio_device/ -> sdk/Framework.

BUG=NONE

Review-Url: https://codereview.webrtc.org/2855023003
Cr-Commit-Position: refs/heads/master@{#18443}
diff --git a/webrtc/sdk/objc/Framework/UnitTests/RTCAudioSessionTest.mm b/webrtc/sdk/objc/Framework/UnitTests/RTCAudioSessionTest.mm
new file mode 100644
index 0000000..f932457
--- /dev/null
+++ b/webrtc/sdk/objc/Framework/UnitTests/RTCAudioSessionTest.mm
@@ -0,0 +1,338 @@
+/*
+ *  Copyright 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import <Foundation/Foundation.h>
+#import <OCMock/OCMock.h>
+
+#include "webrtc/base/gunit.h"
+
+#import "RTCAudioSession+Private.h"
+
+#import "WebRTC/RTCAudioSession.h"
+#import "WebRTC/RTCAudioSessionConfiguration.h"
+
+@interface RTCAudioSessionTestDelegate : NSObject <RTCAudioSessionDelegate>
+
+@property (nonatomic, readonly) float outputVolume;
+
+@end
+
+@implementation RTCAudioSessionTestDelegate
+
+@synthesize outputVolume = _outputVolume;
+
+- (instancetype)init {
+  if (self = [super init]) {
+    _outputVolume = -1;
+  }
+  return self;
+}
+
+- (void)audioSessionDidBeginInterruption:(RTCAudioSession *)session {
+}
+
+- (void)audioSessionDidEndInterruption:(RTCAudioSession *)session
+                   shouldResumeSession:(BOOL)shouldResumeSession {
+}
+
+- (void)audioSessionDidChangeRoute:(RTCAudioSession *)session
+           reason:(AVAudioSessionRouteChangeReason)reason
+    previousRoute:(AVAudioSessionRouteDescription *)previousRoute {
+}
+
+- (void)audioSessionMediaServerTerminated:(RTCAudioSession *)session {
+}
+
+- (void)audioSessionMediaServerReset:(RTCAudioSession *)session {
+}
+
+- (void)audioSessionShouldConfigure:(RTCAudioSession *)session {
+}
+
+- (void)audioSessionShouldUnconfigure:(RTCAudioSession *)session {
+}
+
+- (void)audioSession:(RTCAudioSession *)audioSession
+    didChangeOutputVolume:(float)outputVolume {
+  _outputVolume = outputVolume;
+}
+
+@end
+
+// A delegate that adds itself to the audio session on init and removes itself
+// in its dealloc.
+@interface RTCTestRemoveOnDeallocDelegate : RTCAudioSessionTestDelegate
+@end
+
+@implementation RTCTestRemoveOnDeallocDelegate
+
+- (instancetype)init {
+  if (self = [super init]) {
+    RTCAudioSession *session = [RTCAudioSession sharedInstance];
+    [session addDelegate:self];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RTCAudioSession *session = [RTCAudioSession sharedInstance];
+  [session removeDelegate:self];
+}
+
+@end
+
+
+@interface RTCAudioSessionTest : NSObject
+
+- (void)testLockForConfiguration;
+
+@end
+
+@implementation RTCAudioSessionTest
+
+- (void)testLockForConfiguration {
+  RTCAudioSession *session = [RTCAudioSession sharedInstance];
+
+  for (size_t i = 0; i < 2; i++) {
+    [session lockForConfiguration];
+    EXPECT_TRUE(session.isLocked);
+  }
+  for (size_t i = 0; i < 2; i++) {
+    EXPECT_TRUE(session.isLocked);
+    [session unlockForConfiguration];
+  }
+  EXPECT_FALSE(session.isLocked);
+}
+
+- (void)testAddAndRemoveDelegates {
+  RTCAudioSession *session = [RTCAudioSession sharedInstance];
+  NSMutableArray *delegates = [NSMutableArray array];
+  const size_t count = 5;
+  for (size_t i = 0; i < count; ++i) {
+    RTCAudioSessionTestDelegate *delegate =
+        [[RTCAudioSessionTestDelegate alloc] init];
+    [session addDelegate:delegate];
+    [delegates addObject:delegate];
+    EXPECT_EQ(i + 1, session.delegates.size());
+  }
+  [delegates enumerateObjectsUsingBlock:^(RTCAudioSessionTestDelegate *obj,
+                                          NSUInteger idx,
+                                          BOOL *stop) {
+    [session removeDelegate:obj];
+  }];
+  EXPECT_EQ(0u, session.delegates.size());
+}
+
+- (void)testPushDelegate {
+  RTCAudioSession *session = [RTCAudioSession sharedInstance];
+  NSMutableArray *delegates = [NSMutableArray array];
+  const size_t count = 2;
+  for (size_t i = 0; i < count; ++i) {
+    RTCAudioSessionTestDelegate *delegate =
+        [[RTCAudioSessionTestDelegate alloc] init];
+    [session addDelegate:delegate];
+    [delegates addObject:delegate];
+  }
+  // Test that it gets added to the front of the list.
+  RTCAudioSessionTestDelegate *pushedDelegate =
+      [[RTCAudioSessionTestDelegate alloc] init];
+  [session pushDelegate:pushedDelegate];
+  EXPECT_TRUE(pushedDelegate == session.delegates[0]);
+
+  // Test that it stays at the front of the list.
+  for (size_t i = 0; i < count; ++i) {
+    RTCAudioSessionTestDelegate *delegate =
+        [[RTCAudioSessionTestDelegate alloc] init];
+    [session addDelegate:delegate];
+    [delegates addObject:delegate];
+  }
+  EXPECT_TRUE(pushedDelegate == session.delegates[0]);
+
+  // Test that the next one goes to the front too.
+  pushedDelegate = [[RTCAudioSessionTestDelegate alloc] init];
+  [session pushDelegate:pushedDelegate];
+  EXPECT_TRUE(pushedDelegate == session.delegates[0]);
+}
+
+// Tests that delegates added to the audio session properly zero out. This is
+// checking an implementation detail (that vectors of __weak work as expected).
+- (void)testZeroingWeakDelegate {
+  RTCAudioSession *session = [RTCAudioSession sharedInstance];
+  @autoreleasepool {
+    // Add a delegate to the session. There should be one delegate at this
+    // point.
+    RTCAudioSessionTestDelegate *delegate =
+        [[RTCAudioSessionTestDelegate alloc] init];
+    [session addDelegate:delegate];
+    EXPECT_EQ(1u, session.delegates.size());
+    EXPECT_TRUE(session.delegates[0]);
+  }
+  // The previously created delegate should've de-alloced, leaving a nil ptr.
+  EXPECT_FALSE(session.delegates[0]);
+  RTCAudioSessionTestDelegate *delegate =
+      [[RTCAudioSessionTestDelegate alloc] init];
+  [session addDelegate:delegate];
+  // On adding a new delegate, nil ptrs should've been cleared.
+  EXPECT_EQ(1u, session.delegates.size());
+  EXPECT_TRUE(session.delegates[0]);
+}
+
+// Tests that we don't crash when removing delegates in dealloc.
+// Added as a regression test.
+- (void)testRemoveDelegateOnDealloc {
+  @autoreleasepool {
+    RTCTestRemoveOnDeallocDelegate *delegate =
+        [[RTCTestRemoveOnDeallocDelegate alloc] init];
+    EXPECT_TRUE(delegate);
+  }
+  RTCAudioSession *session = [RTCAudioSession sharedInstance];
+  EXPECT_EQ(0u, session.delegates.size());
+}
+
+- (void)testAudioSessionActivation {
+  RTCAudioSession *audioSession = [RTCAudioSession sharedInstance];
+  EXPECT_EQ(0, audioSession.activationCount);
+  [audioSession audioSessionDidActivate:[AVAudioSession sharedInstance]];
+  EXPECT_EQ(1, audioSession.activationCount);
+  [audioSession audioSessionDidDeactivate:[AVAudioSession sharedInstance]];
+  EXPECT_EQ(0, audioSession.activationCount);
+}
+
+// Hack - fixes OCMVerify link error
+// Link error is: Undefined symbols for architecture i386:
+// "OCMMakeLocation(objc_object*, char const*, int)", referenced from:
+// -[RTCAudioSessionTest testConfigureWebRTCSession] in RTCAudioSessionTest.o
+// ld: symbol(s) not found for architecture i386
+// REASON: https://github.com/erikdoe/ocmock/issues/238
+OCMLocation *OCMMakeLocation(id testCase, const char *fileCString, int line){
+  return [OCMLocation locationWithTestCase:testCase
+                                      file:[NSString stringWithUTF8String:fileCString]
+                                      line:line];
+}
+
+- (void)testConfigureWebRTCSession {
+  NSError *error = nil;
+
+  void (^setActiveBlock)(NSInvocation *invocation) = ^(NSInvocation *invocation) {
+    __autoreleasing NSError **retError;
+    [invocation getArgument:&retError atIndex:4];
+    *retError = [NSError errorWithDomain:@"AVAudioSession"
+                                    code:AVAudioSessionErrorInsufficientPriority
+                                userInfo:nil];
+    BOOL failure = NO;
+    [invocation setReturnValue:&failure];
+  };
+
+  id mockAVAudioSession = OCMPartialMock([AVAudioSession sharedInstance]);
+  OCMStub([[mockAVAudioSession ignoringNonObjectArgs]
+      setActive:YES withOptions:0 error:((NSError __autoreleasing **)[OCMArg anyPointer])]).
+      andDo(setActiveBlock);
+
+  id mockAudioSession = OCMPartialMock([RTCAudioSession sharedInstance]);
+  OCMStub([mockAudioSession session]).andReturn(mockAVAudioSession);
+
+  RTCAudioSession *audioSession = mockAudioSession;
+  EXPECT_EQ(0, audioSession.activationCount);
+  [audioSession lockForConfiguration];
+  EXPECT_TRUE([audioSession checkLock:nil]);
+  // configureWebRTCSession is forced to fail in the above mock interface,
+  // so activationCount should remain 0
+  OCMExpect([[mockAVAudioSession ignoringNonObjectArgs]
+      setActive:YES withOptions:0 error:((NSError __autoreleasing **)[OCMArg anyPointer])]).
+      andDo(setActiveBlock);
+  OCMExpect([mockAudioSession session]).andReturn(mockAVAudioSession);
+  EXPECT_FALSE([audioSession configureWebRTCSession:&error]);
+  EXPECT_EQ(0, audioSession.activationCount);
+
+  id session = audioSession.session;
+  EXPECT_EQ(session, mockAVAudioSession);
+  EXPECT_EQ(NO, [mockAVAudioSession setActive:YES withOptions:0 error:&error]);
+  [audioSession unlockForConfiguration];
+
+  OCMVerify([mockAudioSession session]);
+  OCMVerify([[mockAVAudioSession ignoringNonObjectArgs] setActive:YES withOptions:0 error:&error]);
+  OCMVerify([[mockAVAudioSession ignoringNonObjectArgs] setActive:NO withOptions:0 error:&error]);
+
+  [mockAVAudioSession stopMocking];
+  [mockAudioSession stopMocking];
+}
+
+- (void)testAudioVolumeDidNotify {
+  RTCAudioSession *session = [RTCAudioSession sharedInstance];
+  RTCAudioSessionTestDelegate *delegate =
+      [[RTCAudioSessionTestDelegate alloc] init];
+  [session addDelegate:delegate];
+
+  [session observeValueForKeyPath:@"outputVolume"
+                         ofObject:[AVAudioSession sharedInstance]
+                           change:
+        @{NSKeyValueChangeNewKey :
+            @([AVAudioSession sharedInstance].outputVolume) }
+                          context:nil];
+
+  EXPECT_NE(delegate.outputVolume, -1);
+  EXPECT_EQ([AVAudioSession sharedInstance].outputVolume, delegate.outputVolume);
+}
+
+@end
+
+namespace webrtc {
+
+class AudioSessionTest : public ::testing::Test {
+ protected:
+  void TearDown() {
+    RTCAudioSession *session = [RTCAudioSession sharedInstance];
+    for (id<RTCAudioSessionDelegate> delegate : session.delegates) {
+      [session removeDelegate:delegate];
+    }
+  }
+};
+
+TEST_F(AudioSessionTest, LockForConfiguration) {
+  RTCAudioSessionTest *test = [[RTCAudioSessionTest alloc] init];
+  [test testLockForConfiguration];
+}
+
+TEST_F(AudioSessionTest, AddAndRemoveDelegates) {
+  RTCAudioSessionTest *test = [[RTCAudioSessionTest alloc] init];
+  [test testAddAndRemoveDelegates];
+}
+
+TEST_F(AudioSessionTest, PushDelegate) {
+  RTCAudioSessionTest *test = [[RTCAudioSessionTest alloc] init];
+  [test testPushDelegate];
+}
+
+TEST_F(AudioSessionTest, ZeroingWeakDelegate) {
+  RTCAudioSessionTest *test = [[RTCAudioSessionTest alloc] init];
+  [test testZeroingWeakDelegate];
+}
+
+TEST_F(AudioSessionTest, RemoveDelegateOnDealloc) {
+  RTCAudioSessionTest *test = [[RTCAudioSessionTest alloc] init];
+  [test testRemoveDelegateOnDealloc];
+}
+
+TEST_F(AudioSessionTest, AudioSessionActivation) {
+  RTCAudioSessionTest *test = [[RTCAudioSessionTest alloc] init];
+  [test testAudioSessionActivation];
+}
+
+TEST_F(AudioSessionTest, ConfigureWebRTCSession) {
+  RTCAudioSessionTest *test = [[RTCAudioSessionTest alloc] init];
+  [test testConfigureWebRTCSession];
+}
+
+TEST_F(AudioSessionTest, AudioVolumeDidNotify) {
+  RTCAudioSessionTest *test = [[RTCAudioSessionTest alloc] init];
+  [test testAudioVolumeDidNotify];
+}
+
+}  // namespace webrtc