Skip to content

Commit

Permalink
Adds error codes to AudioInputController/AudioInputRendererHost nativ…
Browse files Browse the repository at this point in the history
…e logs

BUG=347433

Review URL: https://codereview.chromium.org/183023005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@254224 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
henrika@chromium.org committed Feb 28, 2014
1 parent 76ebbb8 commit 1fa826e
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 35 deletions.
46 changes: 26 additions & 20 deletions content/browser/renderer_host/media/audio_input_renderer_host.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "base/memory/shared_memory.h"
#include "base/metrics/histogram.h"
#include "base/process/process.h"
#include "base/strings/stringprintf.h"
#include "content/browser/media/capture/web_contents_audio_input_stream.h"
#include "content/browser/media/capture/web_contents_capture_util.h"
#include "content/browser/media/media_internals.h"
Expand Down Expand Up @@ -97,14 +98,16 @@ void AudioInputRendererHost::OnRecording(
make_scoped_refptr(controller)));
}

void AudioInputRendererHost::OnError(media::AudioInputController* controller) {
void AudioInputRendererHost::OnError(media::AudioInputController* controller,
media::AudioInputController::ErrorCode error_code) {
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(
&AudioInputRendererHost::DoHandleError,
this,
make_scoped_refptr(controller)));
make_scoped_refptr(controller),
error_code));
}

void AudioInputRendererHost::OnData(media::AudioInputController* controller,
Expand All @@ -123,13 +126,13 @@ void AudioInputRendererHost::DoCompleteCreation(

if (!PeerHandle()) {
NOTREACHED() << "Renderer process handle is invalid.";
DeleteEntryOnError(entry);
DeleteEntryOnError(entry, INVALID_PEER_HANDLE);
return;
}

if (!entry->controller->LowLatencyMode()) {
NOTREACHED() << "Only low-latency mode is supported.";
DeleteEntryOnError(entry);
DeleteEntryOnError(entry, INVALID_LATENCY_MODE);
return;
}

Expand All @@ -140,7 +143,7 @@ void AudioInputRendererHost::DoCompleteCreation(
&foreign_memory_handle)) {
// If we failed to map and share the shared memory then close the audio
// stream and send an error message.
DeleteEntryOnError(entry);
DeleteEntryOnError(entry, MEMORY_SHARING_FAILED);
return;
}

Expand All @@ -157,7 +160,7 @@ void AudioInputRendererHost::DoCompleteCreation(
// the construction of audio input stream.
if (!writer->PrepareForeignSocketHandle(PeerHandle(),
&foreign_socket_handle)) {
DeleteEntryOnError(entry);
DeleteEntryOnError(entry, SYNC_SOCKET_ERROR);
return;
}

Expand All @@ -175,17 +178,18 @@ void AudioInputRendererHost::DoSendRecordingMessage(
}

void AudioInputRendererHost::DoHandleError(
media::AudioInputController* controller) {
media::AudioInputController* controller,
media::AudioInputController::ErrorCode error_code) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
MediaStreamManager::SendMessageToNativeLog(
"The AudioInputController signalled an error.");
base::StringPrintf("AudioInputController error: %d", error_code));

AudioEntry* entry = LookupByController(controller);
if (!entry)
return;

audio_log_->OnError(entry->stream_id);
DeleteEntryOnError(entry);
DeleteEntryOnError(entry, AUDIO_INPUT_CONTROLLER_ERROR);
}

bool AudioInputRendererHost::OnMessageReceived(const IPC::Message& message,
Expand Down Expand Up @@ -217,7 +221,7 @@ void AudioInputRendererHost::OnCreateStream(

// media::AudioParameters is validated in the deserializer.
if (LookupById(stream_id) != NULL) {
SendErrorMessage(stream_id);
SendErrorMessage(stream_id, STREAM_ALREADY_EXISTS);
return;
}

Expand All @@ -237,7 +241,7 @@ void AudioInputRendererHost::OnCreateStream(
const StreamDeviceInfo* info = media_stream_manager_->
audio_input_device_manager()->GetOpenedDeviceInfoById(session_id);
if (!info) {
SendErrorMessage(stream_id);
SendErrorMessage(stream_id, PERMISSION_DENIED);
DLOG(WARNING) << "No permission has been granted to input stream with "
<< "session_id=" << session_id;
return;
Expand All @@ -258,7 +262,7 @@ void AudioInputRendererHost::OnCreateStream(
if (!entry->shared_memory.CreateAndMapAnonymous(
segment_size * entry->shared_memory_segment_count)) {
// If creation of shared memory failed then send an error message.
SendErrorMessage(stream_id);
SendErrorMessage(stream_id, SHARED_MEMORY_CREATE_FAILED);
return;
}

Expand All @@ -267,7 +271,7 @@ void AudioInputRendererHost::OnCreateStream(
entry->shared_memory_segment_count));

if (!writer->Init()) {
SendErrorMessage(stream_id);
SendErrorMessage(stream_id, SYNC_WRITER_INIT_FAILED);
return;
}

Expand Down Expand Up @@ -299,7 +303,7 @@ void AudioInputRendererHost::OnCreateStream(
}

if (!entry->controller.get()) {
SendErrorMessage(stream_id);
SendErrorMessage(stream_id, STREAM_CREATE_ERROR);
return;
}

Expand All @@ -323,7 +327,7 @@ void AudioInputRendererHost::OnRecordStream(int stream_id) {

AudioEntry* entry = LookupById(stream_id);
if (!entry) {
SendErrorMessage(stream_id);
SendErrorMessage(stream_id, INVALID_AUDIO_ENTRY);
return;
}

Expand All @@ -345,17 +349,18 @@ void AudioInputRendererHost::OnSetVolume(int stream_id, double volume) {

AudioEntry* entry = LookupById(stream_id);
if (!entry) {
SendErrorMessage(stream_id);
SendErrorMessage(stream_id, INVALID_AUDIO_ENTRY);
return;
}

entry->controller->SetVolume(volume);
audio_log_->OnSetVolume(stream_id, volume);
}

void AudioInputRendererHost::SendErrorMessage(int stream_id) {
void AudioInputRendererHost::SendErrorMessage(
int stream_id, ErrorCode error_code) {
MediaStreamManager::SendMessageToNativeLog(
"An error occurred in AudioInputRendererHost.");
base::StringPrintf("AudioInputRendererHost error: %d", error_code));
Send(new AudioInputMsg_NotifyStreamStateChanged(
stream_id, media::AudioInputIPCDelegate::kError));
}
Expand Down Expand Up @@ -390,12 +395,13 @@ void AudioInputRendererHost::DeleteEntry(AudioEntry* entry) {
audio_entries_.erase(entry->stream_id);
}

void AudioInputRendererHost::DeleteEntryOnError(AudioEntry* entry) {
void AudioInputRendererHost::DeleteEntryOnError(AudioEntry* entry,
ErrorCode error_code) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

// Sends the error message first before we close the stream because
// |entry| is destroyed in DeleteEntry().
SendErrorMessage(entry->stream_id);
SendErrorMessage(entry->stream_id, error_code);
CloseAndDeleteStream(entry);
}

Expand Down
53 changes: 49 additions & 4 deletions content/browser/renderer_host/media/audio_input_renderer_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,49 @@ class CONTENT_EXPORT AudioInputRendererHost
: public BrowserMessageFilter,
public media::AudioInputController::EventHandler {
public:

// Error codes to make native loggin more clear. These error codes are added
// to generic error strings to provide a higher degree of details.
// Changing these values can lead to problems when matching native debug
// logs with the actual cause of error.
enum ErrorCode {
// An unspecified error occured.
UNKNOWN_ERROR = 0,

// Failed to look up audio intry for the provided stream id.
INVALID_AUDIO_ENTRY, // = 1

// A stream with the specified stream id already exists.
STREAM_ALREADY_EXISTS, // = 2

// The page does not have permission to open the specified capture device.
PERMISSION_DENIED, // = 3

// Failed to create shared memory.
SHARED_MEMORY_CREATE_FAILED, // = 4

// Failed to initialize the AudioInputSyncWriter instance.
SYNC_WRITER_INIT_FAILED, // = 5

// Failed to create native audio input stream.
STREAM_CREATE_ERROR, // = 6

// Renderer process handle is invalid.
INVALID_PEER_HANDLE, // = 7

// Only low-latency mode is supported.
INVALID_LATENCY_MODE, // = 8

// Failed to map and share the shared memory.
MEMORY_SHARING_FAILED, // = 9

// Unable to prepare the foreign socket handle.
SYNC_SOCKET_ERROR, // = 10

// This error message comes from the AudioInputController instance.
AUDIO_INPUT_CONTROLLER_ERROR, // = 11
};

// Called from UI thread from the owner of this object.
// |user_input_monitor| is used for typing detection and can be NULL.
AudioInputRendererHost(media::AudioManager* audio_manager,
Expand All @@ -72,7 +115,8 @@ class CONTENT_EXPORT AudioInputRendererHost
// AudioInputController::EventHandler implementation.
virtual void OnCreated(media::AudioInputController* controller) OVERRIDE;
virtual void OnRecording(media::AudioInputController* controller) OVERRIDE;
virtual void OnError(media::AudioInputController* controller) OVERRIDE;
virtual void OnError(media::AudioInputController* controller,
media::AudioInputController::ErrorCode error_code) OVERRIDE;
virtual void OnData(media::AudioInputController* controller,
const uint8* data,
uint32 size) OVERRIDE;
Expand Down Expand Up @@ -120,10 +164,11 @@ class CONTENT_EXPORT AudioInputRendererHost
void DoSendRecordingMessage(media::AudioInputController* controller);

// Handle error coming from audio stream.
void DoHandleError(media::AudioInputController* controller);
void DoHandleError(media::AudioInputController* controller,
media::AudioInputController::ErrorCode error_code);

// Send an error message to the renderer.
void SendErrorMessage(int stream_id);
void SendErrorMessage(int stream_id, ErrorCode error_code);

// Delete all audio entry and all audio streams
void DeleteEntries();
Expand All @@ -136,7 +181,7 @@ class CONTENT_EXPORT AudioInputRendererHost
void DeleteEntry(AudioEntry* entry);

// Delete audio entry and close the related audio input stream.
void DeleteEntryOnError(AudioEntry* entry);
void DeleteEntryOnError(AudioEntry* entry, ErrorCode error_code);

// A helper method to look up a AudioEntry identified by |stream_id|.
// Returns NULL if not found.
Expand Down
3 changes: 2 additions & 1 deletion content/browser/speech/speech_recognizer_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,8 @@ SpeechRecognizerImpl::~SpeechRecognizerImpl() {
}

// Invoked in the audio thread.
void SpeechRecognizerImpl::OnError(AudioInputController* controller) {
void SpeechRecognizerImpl::OnError(AudioInputController* controller,
media::AudioInputController::ErrorCode error_code) {
FSMEventArgs event_args(EVENT_AUDIO_ERROR);
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&SpeechRecognizerImpl::DispatchEvent,
Expand Down
3 changes: 2 additions & 1 deletion content/browser/speech/speech_recognizer_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ class CONTENT_EXPORT SpeechRecognizerImpl
// AudioInputController::EventHandler methods.
virtual void OnCreated(media::AudioInputController* controller) OVERRIDE {}
virtual void OnRecording(media::AudioInputController* controller) OVERRIDE {}
virtual void OnError(media::AudioInputController* controller) OVERRIDE;
virtual void OnError(media::AudioInputController* controller,
media::AudioInputController::ErrorCode error_code) OVERRIDE;
virtual void OnData(media::AudioInputController* controller,
const uint8* data, uint32 size) OVERRIDE;

Expand Down
6 changes: 4 additions & 2 deletions content/browser/speech/speech_recognizer_impl_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,8 @@ TEST_F(SpeechRecognizerImplTest, AudioControllerErrorNoData) {
TestAudioInputController* controller =
audio_input_controller_factory_.controller();
ASSERT_TRUE(controller);
controller->event_handler()->OnError(controller);
controller->event_handler()->OnError(controller,
AudioInputController::UNKNOWN_ERROR);
base::MessageLoop::current()->RunUntilIdle();
EXPECT_TRUE(recognition_started_);
EXPECT_FALSE(audio_started_);
Expand All @@ -378,7 +379,8 @@ TEST_F(SpeechRecognizerImplTest, AudioControllerErrorWithData) {
ASSERT_TRUE(controller);
controller->event_handler()->OnData(controller, &audio_packet_[0],
audio_packet_.size());
controller->event_handler()->OnError(controller);
controller->event_handler()->OnError(controller,
AudioInputController::UNKNOWN_ERROR);
base::MessageLoop::current()->RunUntilIdle();
ASSERT_TRUE(url_fetcher_factory_.GetFetcherByID(0));
EXPECT_TRUE(recognition_started_);
Expand Down
8 changes: 4 additions & 4 deletions media/audio/audio_input_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -187,14 +187,14 @@ void AudioInputController::DoCreateForStream(
stream_ = stream_to_control;

if (!stream_) {
handler_->OnError(this);
handler_->OnError(this, STREAM_CREATE_ERROR);
return;
}

if (stream_ && !stream_->Open()) {
stream_->Close();
stream_ = NULL;
handler_->OnError(this);
handler_->OnError(this, STREAM_OPEN_ERROR);
return;
}

Expand Down Expand Up @@ -266,7 +266,7 @@ void AudioInputController::DoClose() {

void AudioInputController::DoReportError() {
DCHECK(task_runner_->BelongsToCurrentThread());
handler_->OnError(this);
handler_->OnError(this, STREAM_ERROR);
}

void AudioInputController::DoSetVolume(double volume) {
Expand Down Expand Up @@ -310,7 +310,7 @@ void AudioInputController::DoCheckForNoData() {
// The data-is-active marker will be false only if it has been more than
// one second since a data packet was recorded. This can happen if a
// capture device has been removed or disabled.
handler_->OnError(this);
handler_->OnError(this, NO_DATA_ERROR);
return;
}

Expand Down
26 changes: 25 additions & 1 deletion media/audio/audio_input_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,37 @@ class MEDIA_EXPORT AudioInputController
: public base::RefCountedThreadSafe<AudioInputController>,
public AudioInputStream::AudioInputCallback {
public:

// Error codes to make native loggin more clear. These error codes are added
// to generic error strings to provide a higher degree of details.
// Changing these values can lead to problems when matching native debug
// logs with the actual cause of error.
enum ErrorCode {
// An unspecified error occured.
UNKNOWN_ERROR = 0,

// Failed to create an audio input stream.
STREAM_CREATE_ERROR, // = 1

// Failed to open an audio input stream.
STREAM_OPEN_ERROR, // = 2

// Native input stream reports an error. Exact reason differs between
// platforms.
STREAM_ERROR, // = 3

// This can happen if a capture device has been removed or disabled.
NO_DATA_ERROR, // = 4
};

// An event handler that receives events from the AudioInputController. The
// following methods are all called on the audio thread.
class MEDIA_EXPORT EventHandler {
public:
virtual void OnCreated(AudioInputController* controller) = 0;
virtual void OnRecording(AudioInputController* controller) = 0;
virtual void OnError(AudioInputController* controller) = 0;
virtual void OnError(AudioInputController* controller,
ErrorCode error_code) = 0;
virtual void OnData(AudioInputController* controller, const uint8* data,
uint32 size) = 0;

Expand Down
6 changes: 4 additions & 2 deletions media/audio/audio_input_controller_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ class MockAudioInputControllerEventHandler

MOCK_METHOD1(OnCreated, void(AudioInputController* controller));
MOCK_METHOD1(OnRecording, void(AudioInputController* controller));
MOCK_METHOD1(OnError, void(AudioInputController* controller));
MOCK_METHOD2(OnError, void(AudioInputController* controller,
AudioInputController::ErrorCode error_code));
MOCK_METHOD3(OnData, void(AudioInputController* controller,
const uint8* data, uint32 size));

Expand Down Expand Up @@ -164,7 +165,8 @@ TEST_F(AudioInputControllerTest, RecordAndError) {

// OnError() will be called after the data stream stops while the
// controller is in a recording state.
EXPECT_CALL(event_handler, OnError(NotNull()))
EXPECT_CALL(event_handler, OnError(NotNull(),
AudioInputController::NO_DATA_ERROR))
.Times(Exactly(1))
.WillOnce(QuitMessageLoop(&message_loop_));

Expand Down

0 comments on commit 1fa826e

Please sign in to comment.