Commit c57d9c24 authored by tommi's avatar tommi Committed by Commit bot

Fix issue with audio input streams where an error would not be reported

if an initialization error occurs while creating an audio stream.

BUG=678697
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel

Review-Url: https://codereview.chromium.org/2611063003
Cr-Commit-Position: refs/heads/master@{#441758}
parent 022c077e
......@@ -302,6 +302,7 @@ source_set("unit_tests") {
testonly = true
sources = [
"audio_input_controller_unittest.cc",
"audio_input_device_unittest.cc",
"audio_input_unittest.cc",
"audio_manager_unittest.cc",
"audio_output_controller_unittest.cc",
......
......@@ -178,18 +178,25 @@ void AudioInputDevice::OnStateChanged(
break;
case AUDIO_INPUT_IPC_DELEGATE_STATE_ERROR:
DLOG(WARNING) << "AudioInputDevice::OnStateChanged(ERROR)";
if (state_ == CREATING_STREAM) {
// At this point, we haven't attempted to start the audio thread.
// Accessing the hardware might have failed or we may have reached
// the limit of the number of allowed concurrent streams.
// We must report the error to the |callback_| so that a potential
// audio source object will enter the correct state (e.g. 'ended' for
// a local audio source).
callback_->OnCaptureError(
"Maximum allowed input device limit reached or OS failure.");
} else {
// Don't dereference the callback object if the audio thread
// is stopped or stopping. That could mean that the callback
// object has been deleted.
// TODO(tommi): Add an explicit contract for clearing the callback
// object. Possibly require calling Initialize again or provide
// a callback object via Start() and clear it in Stop().
{
base::AutoLock auto_lock_(audio_thread_lock_);
if (audio_thread_) {
callback_->OnCaptureError(
"AudioInputDevice::OnStateChanged - audio thread still running");
}
if (audio_thread_)
callback_->OnCaptureError("AUDIO_INPUT_IPC_DELEGATE_STATE_ERROR");
}
break;
default:
......
// Copyright (c) 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "media/audio/audio_input_device.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gmock_mutant.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
using testing::DoAll;
namespace media {
namespace {
class MockAudioInputIPC : public AudioInputIPC {
public:
MockAudioInputIPC() {}
~MockAudioInputIPC() override {}
MOCK_METHOD5(CreateStream,
void(AudioInputIPCDelegate* delegate,
int session_id,
const AudioParameters& params,
bool automatic_gain_control,
uint32_t total_segments));
MOCK_METHOD0(RecordStream, void());
MOCK_METHOD1(SetVolume, void(double volume));
MOCK_METHOD0(CloseStream, void());
};
class MockCaptureCallback : public AudioCapturerSource::CaptureCallback {
public:
MockCaptureCallback() {}
~MockCaptureCallback() override {}
MOCK_METHOD4(Capture,
void(const AudioBus* audio_source,
int audio_delay_milliseconds,
double volume,
bool key_pressed));
MOCK_METHOD1(OnCaptureError, void(const std::string& message));
};
// Used to terminate a loop from a different thread than the loop belongs to.
// |task_runner| should be a SingleThreadTaskRunner.
ACTION_P(QuitLoop, task_runner) {
task_runner->PostTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
}
} // namespace.
// Regular construction.
TEST(AudioInputDeviceTest, Noop) {
base::MessageLoopForIO io_loop;
MockAudioInputIPC* input_ipc = new MockAudioInputIPC();
scoped_refptr<AudioInputDevice> device(
new AudioInputDevice(base::WrapUnique(input_ipc), io_loop.task_runner()));
}
ACTION_P2(ReportStateChange, device, state) {
static_cast<AudioInputIPCDelegate*>(device)->OnStateChanged(state);
}
// Verify that we get an OnCaptureError() callback if CreateStream fails.
TEST(AudioInputDeviceTest, FailToCreateStream) {
AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY,
CHANNEL_LAYOUT_STEREO, 48000, 16, 480);
base::MessageLoopForIO io_loop;
MockCaptureCallback callback;
MockAudioInputIPC* input_ipc = new MockAudioInputIPC();
scoped_refptr<AudioInputDevice> device(
new AudioInputDevice(base::WrapUnique(input_ipc), io_loop.task_runner()));
device->Initialize(params, &callback, 1);
device->Start();
EXPECT_CALL(*input_ipc, CreateStream(_, _, _, _, _))
.WillOnce(ReportStateChange(device.get(),
AUDIO_INPUT_IPC_DELEGATE_STATE_ERROR));
EXPECT_CALL(callback, OnCaptureError(_))
.WillOnce(QuitLoop(io_loop.task_runner()));
base::RunLoop().Run();
}
} // namespace media.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment