chromium/media/audio/mac/audio_manager_mac_unittest.cc

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/audio/mac/audio_manager_mac.h"

#include "base/run_loop.h"
#include "base/test/test_message_loop.h"
#include "media/audio/audio_unittest_util.h"
#include "media/audio/fake_audio_log_factory.h"
#include "media/audio/fake_audio_manager.h"
#include "media/audio/test_audio_thread.h"
#include "testing/gmock/include/gmock/gmock.h"

using testing::Return;

namespace media {
// This class is used to mock audio devices and test their behavior in
// AudioManagerMac.
class AudioManagerMacUnderTest final : public AudioManagerMac {
 public:
  AudioManagerMacUnderTest(std::unique_ptr<AudioThread> audio_thread,
                           AudioLogFactory* audio_log_factory)
      : AudioManagerMac(std::move(audio_thread), audio_log_factory) {}

  MOCK_METHOD0(GetAllAudioDeviceIDs, std::vector<AudioObjectID>());
  MOCK_METHOD1(GetDeviceTransportType, std::optional<uint32_t>(AudioObjectID));
  MOCK_METHOD1(GetDeviceUniqueID, std::optional<std::string>(AudioObjectID));
  MOCK_METHOD1(GetRelatedNonBluetoothDeviceIDs,
               std::vector<AudioObjectID>(AudioObjectID));
};

class AudioManagerMacTest : public ::testing::Test {
 protected:
  AudioManagerMacTest() : message_loop_(base::MessagePumpType::IO) {
    audio_manager_ = std::make_unique<AudioManagerMacUnderTest>(
        std::make_unique<TestAudioThread>(), &fake_audio_log_factory_);
    base::RunLoop().RunUntilIdle();
  }
  ~AudioManagerMacTest() override { audio_manager_->Shutdown(); }

  base::TestMessageLoop message_loop_;
  FakeAudioLogFactory fake_audio_log_factory_;
  std::unique_ptr<AudioManagerMacUnderTest> audio_manager_;
};

// This creates a test which mocks the following input and output bluetooth
// device. The device configuration is as follows:
// Input: DeviceID: 1, uniqueID: "F3-A2-14-A9-1D-F8:input"
// Output: DeviceID: 2, uniqueID: "F3-A2-14-A9-1D-F8:output"
TEST_F(AudioManagerMacTest, SameGroupIdForBluetoothInputAndOutputDevice) {
  AudioManagerMacUnderTest& audio_manager_mock = *audio_manager_.get();
  EXPECT_CALL(audio_manager_mock, GetAllAudioDeviceIDs())
      .WillRepeatedly(Return(std::vector<AudioObjectID>{1, 2}));
  // DeviceID: 1
  EXPECT_CALL(audio_manager_mock, GetDeviceTransportType(/*device_id=*/1))
      .WillRepeatedly(Return(kAudioDeviceTransportTypeBluetooth));
  EXPECT_CALL(audio_manager_mock, GetDeviceUniqueID(/*device_id=*/1))
      .WillRepeatedly(Return("F3-A2-14-A9-1D-F8:input"));
  // DeviceID: 2
  EXPECT_CALL(audio_manager_mock, GetDeviceTransportType(/*device_id=*/2))
      .WillRepeatedly(Return(kAudioDeviceTransportTypeBluetooth));
  EXPECT_CALL(audio_manager_mock, GetDeviceUniqueID(/*device_id=*/2))
      .WillRepeatedly(Return("F3-A2-14-A9-1D-F8:output"));

  EXPECT_EQ(audio_manager_->GetRelatedDeviceIDs(/*device_id=*/1),
            std::vector<AudioObjectID>({1, 2}));
  EXPECT_EQ(audio_manager_->GetRelatedDeviceIDs(/*device_id=*/2),
            std::vector<AudioObjectID>({1, 2}));
}

// This creates a test which mocks 2 related built-in audio devices.
TEST_F(AudioManagerMacTest, SameGroupIdForNonBluetoothInputAndOutputDevice) {
  AudioManagerMacUnderTest& audio_manager_mock = *audio_manager_.get();
  // DeviceID: 1
  EXPECT_CALL(audio_manager_mock, GetDeviceTransportType(/*device_id=*/1))
      .WillRepeatedly(Return(kAudioDeviceTransportTypeBuiltIn));
  EXPECT_CALL(audio_manager_mock,
              GetRelatedNonBluetoothDeviceIDs(/*device_id=*/1))
      .WillRepeatedly(Return(std::vector<AudioObjectID>{1, 2}));

  EXPECT_EQ(audio_manager_->GetRelatedDeviceIDs(/*device_id=*/1),
            std::vector<AudioObjectID>({1, 2}));
}

// This creates a test which mocks the following unrelated input and output
// bluetooth device. The device configuration is as follows:
// Input: DeviceID: 1, uniqueID: "A3-C2-E3-19-D3-81:input"
// Output: DeviceID: 2, uniqueID: "F3-A2-14-A9-1D-F8:output"
TEST_F(AudioManagerMacTest,
       DifferentGroupIdForDifferentBluetoothInputAndOutputDevice) {
  AudioManagerMacUnderTest& audio_manager_mock = *audio_manager_.get();
  EXPECT_CALL(audio_manager_mock, GetAllAudioDeviceIDs())
      .WillRepeatedly(Return(std::vector<AudioObjectID>{1, 2}));
  // DeviceID: 1
  EXPECT_CALL(audio_manager_mock, GetDeviceTransportType(/*device_id=*/1))
      .WillRepeatedly(Return(kAudioDeviceTransportTypeBluetooth));
  EXPECT_CALL(audio_manager_mock, GetDeviceUniqueID(/*device_id=*/1))
      .WillRepeatedly(Return("A3-C2-E3-19-D3-81:input"));
  // DeviceID: 2
  EXPECT_CALL(audio_manager_mock, GetDeviceTransportType(/*device_id=*/2))
      .WillRepeatedly(Return(kAudioDeviceTransportTypeBluetooth));
  EXPECT_CALL(audio_manager_mock, GetDeviceUniqueID(/*device_id=*/2))
      .WillRepeatedly(Return("F3-A2-14-A9-1D-F8:output"));

  EXPECT_EQ(audio_manager_->GetRelatedDeviceIDs(/*device_id=*/1),
            std::vector<AudioObjectID>{1});
  EXPECT_EQ(audio_manager_->GetRelatedDeviceIDs(/*device_id=*/2),
            std::vector<AudioObjectID>{2});
}

// This creates a test which mocks the following unrelated input and output
// devices. The device configuration is as follows:
// Input: DeviceID: 1, uniqueID: "A3-C2-E3-19-D3-81:input"
// Input: DeviceID: 2, uniqueID: "default_input_device"
// Output: DeviceID: 3, uniqueID: "inbuilt_output_device"
TEST_F(AudioManagerMacTest, DifferentGroupIdForDifferentInputAndOutputDevices) {
  AudioManagerMacUnderTest& audio_manager_mock = *audio_manager_.get();
  EXPECT_CALL(audio_manager_mock, GetAllAudioDeviceIDs())
      .WillRepeatedly(Return(std::vector<AudioObjectID>{1, 2, 3}));
  // DeviceID: 1
  EXPECT_CALL(audio_manager_mock, GetDeviceTransportType(/*device_id=*/1))
      .WillRepeatedly(Return(kAudioDeviceTransportTypeBluetooth));
  EXPECT_CALL(audio_manager_mock, GetDeviceUniqueID(/*device_id=*/1))
      .WillRepeatedly(Return("A3-C2-E3-19-D3-81:input"));
  // DeviceID: 2
  EXPECT_CALL(audio_manager_mock, GetDeviceTransportType(/*device_id=*/2))
      .WillRepeatedly(Return(kAudioDeviceTransportTypeBuiltIn));
  EXPECT_CALL(audio_manager_mock, GetDeviceUniqueID(/*device_id=*/2))
      .WillRepeatedly(Return("default_input_device"));
  EXPECT_CALL(audio_manager_mock,
              GetRelatedNonBluetoothDeviceIDs(/*device_id=*/2))
      .WillRepeatedly(Return(std::vector<AudioObjectID>{2}));
  // DeviceID: 3
  EXPECT_CALL(audio_manager_mock, GetDeviceTransportType(/*device_id=*/3))
      .WillRepeatedly(Return(std::nullopt));
  EXPECT_CALL(audio_manager_mock, GetDeviceUniqueID(/*device_id=*/3))
      .WillRepeatedly(Return("inbuilt_output_device"));
  EXPECT_CALL(audio_manager_mock,
              GetRelatedNonBluetoothDeviceIDs(/*device_id=*/3))
      .WillRepeatedly(Return(std::vector<AudioObjectID>{3}));

  EXPECT_EQ(audio_manager_->GetRelatedDeviceIDs(/*device_id=*/1),
            std::vector<AudioObjectID>{1});
  EXPECT_EQ(audio_manager_->GetRelatedDeviceIDs(/*device_id=*/2),
            std::vector<AudioObjectID>{2});
  EXPECT_EQ(audio_manager_->GetRelatedDeviceIDs(/*device_id=*/3),
            std::vector<AudioObjectID>{3});
}
}  // namespace media