blob: c7bf406aa3718fbc63e4c43e73a34d97714fefd4 [file] [log] [blame]
// Copyright 2018 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "starboard/shared/uwp/wasapi_audio.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace starboard {
namespace shared {
namespace uwp {
using ::testing::_;
using ::testing::Return;
using ::testing::SetArgPointee;
class IAudioClientMock : public IAudioClient2 {
public:
MOCK_METHOD1(SetClientProperties,
HRESULT(const AudioClientProperties* props));
MOCK_METHOD1(GetMixFormat, HRESULT(WAVEFORMATEX** format));
MOCK_METHOD2(QueryInterface, HRESULT(const IID& riid, void** obj));
MOCK_METHOD0(AddRef, ULONG());
MOCK_METHOD0(Release, ULONG());
MOCK_METHOD6(Initialize,
HRESULT(AUDCLNT_SHAREMODE s,
DWORD d,
REFERENCE_TIME t1,
REFERENCE_TIME t2,
const WAVEFORMATEX* w,
LPCGUID id));
MOCK_METHOD1(GetBufferSize, HRESULT(UINT32* n));
MOCK_METHOD1(GetStreamLatency, HRESULT(REFERENCE_TIME* t));
MOCK_METHOD1(GetCurrentPadding, HRESULT(UINT32* n));
MOCK_METHOD3(IsFormatSupported,
HRESULT(AUDCLNT_SHAREMODE, const WAVEFORMATEX*, WAVEFORMATEX**));
MOCK_METHOD2(GetDevicePeriod, HRESULT(REFERENCE_TIME*, REFERENCE_TIME*));
MOCK_METHOD0(Start, HRESULT());
MOCK_METHOD0(Stop, HRESULT());
MOCK_METHOD0(Reset, HRESULT());
MOCK_METHOD1(SetEventHandle, HRESULT(HANDLE h));
MOCK_METHOD2(GetService, HRESULT(const IID& riid, void** obj));
MOCK_METHOD2(IsOffloadCapable, HRESULT(AUDIO_STREAM_CATEGORY asc, BOOL* b));
MOCK_METHOD4(GetBufferSizeLimits,
HRESULT(const WAVEFORMATEX* w,
BOOL b,
REFERENCE_TIME* t1,
REFERENCE_TIME* t2));
};
class IUnknownMock : public IUnknown {
public:
MOCK_METHOD2(QueryInterface, HRESULT(const IID& riid, void** obj));
MOCK_METHOD0(AddRef, ULONG());
MOCK_METHOD0(Release, ULONG());
};
class AsyncOperationMock : public IActivateAudioInterfaceAsyncOperation {
public:
MOCK_METHOD2(GetActivateResult,
HRESULT(HRESULT* activateResult, IUnknown** activatedInterface));
MOCK_METHOD2(QueryInterface, HRESULT(const IID& riid, void** obj));
MOCK_METHOD0(AddRef, ULONG());
MOCK_METHOD0(Release, ULONG());
};
class WASAPIAudioDeviceTest : public testing::Test {
protected:
void InitAudioDevice() {
audio_device_->bitrate_ = -1;
audio_device_->channels_ = -1;
audio_device_->audio_client_ = nullptr;
audio_device_->activate_completed_ =
CreateEvent(nullptr, TRUE, FALSE, nullptr);
}
virtual void SetUp() {
audio_device_ = Microsoft::WRL::Make<WASAPIAudioDevice>();
InitAudioDevice();
}
void CallActivateCompleted() {
audio_device_->ActivateCompleted(&async_operation_);
}
bool IsInitializedAndNotChanged() {
CallActivateCompleted();
bool res = (audio_device_->GetBitrate() == -1);
res &= (audio_device_->GetNumChannels() == -1);
return res;
}
WAVEFORMATEX* CreateWAVEFORMATEX(int test_channels,
int test_samples_per_sec,
int test_bits_per_sample) {
WAVEFORMATEX* format =
reinterpret_cast<WAVEFORMATEX*>(CoTaskMemAlloc(sizeof(WAVEFORMATEX)));
EXPECT_NE(nullptr, format);
format->nChannels = test_channels;
format->nSamplesPerSec = test_samples_per_sec;
format->wBitsPerSample = test_bits_per_sample;
return format;
}
AsyncOperationMock async_operation_;
IAudioClientMock client_;
IUnknownMock audio_interface_;
Microsoft::WRL::ComPtr<WASAPIAudioDevice> audio_device_;
};
// GetActivateResult returns not S_OK, activateResult (first argument) is set to
// S_OK, activation fails, both GetNumChannels and GetBitrate should return -1
TEST_F(WASAPIAudioDeviceTest, GetActivateResultFailsReturnValue) {
EXPECT_CALL(async_operation_, GetActivateResult(_, _))
.WillRepeatedly(DoAll(SetArgPointee<0>(S_OK), Return(E_FAIL)));
EXPECT_TRUE(IsInitializedAndNotChanged());
}
// GetActivateResult returns S_OK, activateResult (first argument) is not S_OK,
// activation fails, both GetNumChannels and GetBitrate should return -1
TEST_F(WASAPIAudioDeviceTest, GetActivateResultFailsFirstArg) {
EXPECT_CALL(async_operation_, GetActivateResult(_, _))
.WillRepeatedly(DoAll(SetArgPointee<0>(E_ACCESSDENIED), Return(S_OK)));
EXPECT_TRUE(IsInitializedAndNotChanged());
}
// QueryInterface of audio_interface_ returns not S_OK as returned value,
// activation fails, both GetNumChannels and GetBitrate should return -1
TEST_F(WASAPIAudioDeviceTest, QueryInterfaceIsNotSupported) {
EXPECT_CALL(audio_interface_, QueryInterface(_, _))
.WillRepeatedly(Return(E_NOINTERFACE));
EXPECT_CALL(async_operation_, GetActivateResult(_, _))
.WillRepeatedly(DoAll(SetArgPointee<0>(S_OK),
SetArgPointee<1>(&audio_interface_), Return(S_OK)));
EXPECT_TRUE(IsInitializedAndNotChanged());
}
// QueryInterface of audio_interface_ returns null pointer to interface object,
// activation fails, both GetNumChannels and GetBitrate should return -1
TEST_F(WASAPIAudioDeviceTest, QueryInterfaceReturnsNullObj) {
IAudioClientMock* p_client = nullptr;
// If ppvObject of audio_interface_ is NULL, QueryInterface returns E_POINTER
EXPECT_CALL(audio_interface_, QueryInterface(_, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(p_client), Return(E_POINTER)));
EXPECT_CALL(async_operation_, GetActivateResult(_, _))
.WillRepeatedly(DoAll(SetArgPointee<0>(S_OK),
SetArgPointee<1>(&audio_interface_), Return(S_OK)));
EXPECT_TRUE(IsInitializedAndNotChanged());
}
// SetClientProperties of audio_client_ returns not S_OK,
// activation fails, both GetNumChannels and GetBitrate should return -1
TEST_F(WASAPIAudioDeviceTest, SetClientPropertiesFails) {
EXPECT_CALL(client_, SetClientProperties(_)).WillRepeatedly(Return(E_FAIL));
EXPECT_CALL(audio_interface_, QueryInterface(_, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(&client_), Return(S_OK)));
EXPECT_CALL(async_operation_, GetActivateResult(_, _))
.WillRepeatedly(DoAll(SetArgPointee<0>(S_OK),
SetArgPointee<1>(&audio_interface_), Return(S_OK)));
EXPECT_TRUE(IsInitializedAndNotChanged());
}
// GetMixFormat of audio_client_ returns not S_OK,
// activation fails, both GetNumChannels and GetBitrate should return -1
TEST_F(WASAPIAudioDeviceTest, GetMixFormatFails) {
EXPECT_CALL(client_, SetClientProperties(_)).WillRepeatedly(Return(S_OK));
EXPECT_CALL(client_, GetMixFormat(_))
.WillOnce(Return(E_POINTER))
.RetiresOnSaturation();
EXPECT_CALL(client_, GetMixFormat(_))
.WillOnce(Return(E_OUTOFMEMORY))
.RetiresOnSaturation();
EXPECT_CALL(client_, GetMixFormat(_))
.WillOnce(Return(AUDCLNT_E_SERVICE_NOT_RUNNING))
.RetiresOnSaturation();
EXPECT_CALL(client_, GetMixFormat(_))
.WillOnce(Return(AUDCLNT_E_DEVICE_INVALIDATED))
.RetiresOnSaturation();
EXPECT_CALL(audio_interface_, QueryInterface(_, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(&client_), Return(S_OK)));
EXPECT_CALL(async_operation_, GetActivateResult(_, _))
.WillRepeatedly(DoAll(SetArgPointee<0>(S_OK),
SetArgPointee<1>(&audio_interface_), Return(S_OK)));
for (int i = 0; i < 4; i++) {
InitAudioDevice();
EXPECT_TRUE(IsInitializedAndNotChanged());
}
}
// GetMixFormat of audio_client_ returns S_OK and sets some values,
// activation is OK, to check GetNumChannels and GetBitrate returns
// some numbers
TEST_F(WASAPIAudioDeviceTest, CheckValuesReturned) {
EXPECT_CALL(client_, SetClientProperties(_)).WillRepeatedly(Return(S_OK));
EXPECT_CALL(audio_interface_, QueryInterface(_, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(&client_), Return(S_OK)));
EXPECT_CALL(async_operation_, GetActivateResult(_, _))
.WillRepeatedly(DoAll(SetArgPointee<0>(S_OK),
SetArgPointee<1>(&audio_interface_), Return(S_OK)));
int test_channels_arr[] = {2, 6};
int test_samples_per_sec_arr[] = {44100, 48000, 96000};
int test_bits_per_sample_arr[] = {16, 24};
for (int test_channels : test_channels_arr) {
for (int test_samples_per_sec : test_samples_per_sec_arr) {
for (int test_bits_per_sample : test_bits_per_sample_arr) {
EXPECT_CALL(client_, GetMixFormat(_))
.WillRepeatedly(DoAll(
SetArgPointee<0>(CreateWAVEFORMATEX(
test_channels, test_samples_per_sec, test_bits_per_sample)),
Return(S_OK)));
InitAudioDevice();
CallActivateCompleted();
EXPECT_EQ(audio_device_->GetNumChannels(), test_channels);
EXPECT_EQ(audio_device_->GetBitrate(),
(test_samples_per_sec * test_bits_per_sample));
} // for k
} // for j
} // for i
}
} // namespace uwp
} // namespace shared
} // namespace starboard