Add CriticalSection to fakeaudiocapturemodule to protect the variables which will be accessed from process_thread_ and the main thread.

TEST=try bots
BUG=1205
R=henrike@webrtc.org, kjellander@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/2419004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5019 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
wu@webrtc.org
2013-10-22 23:09:20 +00:00
parent 4d7116be7a
commit 8804a29951
3 changed files with 111 additions and 42 deletions

View File

@ -52,6 +52,7 @@ static const int kClockDriftMs = 0;
static const uint32_t kMaxVolume = 14392; static const uint32_t kMaxVolume = 14392;
enum { enum {
MSG_START_PROCESS,
MSG_RUN_PROCESS, MSG_RUN_PROCESS,
MSG_STOP_PROCESS, MSG_STOP_PROCESS,
}; };
@ -89,6 +90,7 @@ talk_base::scoped_refptr<FakeAudioCaptureModule> FakeAudioCaptureModule::Create(
} }
int FakeAudioCaptureModule::frames_received() const { int FakeAudioCaptureModule::frames_received() const {
talk_base::CritScope cs(&crit_);
return frames_received_; return frames_received_;
} }
@ -142,6 +144,7 @@ int32_t FakeAudioCaptureModule::RegisterEventObserver(
int32_t FakeAudioCaptureModule::RegisterAudioCallback( int32_t FakeAudioCaptureModule::RegisterAudioCallback(
webrtc::AudioTransport* audio_callback) { webrtc::AudioTransport* audio_callback) {
talk_base::CritScope cs(&crit_callback_);
audio_callback_ = audio_callback; audio_callback_ = audio_callback;
return 0; return 0;
} }
@ -245,18 +248,28 @@ int32_t FakeAudioCaptureModule::StartPlayout() {
if (!play_is_initialized_) { if (!play_is_initialized_) {
return -1; return -1;
} }
{
talk_base::CritScope cs(&crit_);
playing_ = true; playing_ = true;
UpdateProcessing(); }
bool start = true;
UpdateProcessing(start);
return 0; return 0;
} }
int32_t FakeAudioCaptureModule::StopPlayout() { int32_t FakeAudioCaptureModule::StopPlayout() {
bool start = false;
{
talk_base::CritScope cs(&crit_);
playing_ = false; playing_ = false;
UpdateProcessing(); start = ShouldStartProcessing();
}
UpdateProcessing(start);
return 0; return 0;
} }
bool FakeAudioCaptureModule::Playing() const { bool FakeAudioCaptureModule::Playing() const {
talk_base::CritScope cs(&crit_);
return playing_; return playing_;
} }
@ -264,18 +277,28 @@ int32_t FakeAudioCaptureModule::StartRecording() {
if (!rec_is_initialized_) { if (!rec_is_initialized_) {
return -1; return -1;
} }
{
talk_base::CritScope cs(&crit_);
recording_ = true; recording_ = true;
UpdateProcessing(); }
bool start = true;
UpdateProcessing(start);
return 0; return 0;
} }
int32_t FakeAudioCaptureModule::StopRecording() { int32_t FakeAudioCaptureModule::StopRecording() {
bool start = false;
{
talk_base::CritScope cs(&crit_);
recording_ = false; recording_ = false;
UpdateProcessing(); start = ShouldStartProcessing();
}
UpdateProcessing(start);
return 0; return 0;
} }
bool FakeAudioCaptureModule::Recording() const { bool FakeAudioCaptureModule::Recording() const {
talk_base::CritScope cs(&crit_);
return recording_; return recording_;
} }
@ -373,12 +396,14 @@ int32_t FakeAudioCaptureModule::MicrophoneVolumeIsAvailable(
return 0; return 0;
} }
int32_t FakeAudioCaptureModule::SetMicrophoneVolume(uint32_t /*volume*/) { int32_t FakeAudioCaptureModule::SetMicrophoneVolume(uint32_t volume) {
ASSERT(false); talk_base::CritScope cs(&crit_);
current_mic_level_ = volume;
return 0; return 0;
} }
int32_t FakeAudioCaptureModule::MicrophoneVolume(uint32_t* volume) const { int32_t FakeAudioCaptureModule::MicrophoneVolume(uint32_t* volume) const {
talk_base::CritScope cs(&crit_);
*volume = current_mic_level_; *volume = current_mic_level_;
return 0; return 0;
} }
@ -594,6 +619,9 @@ int32_t FakeAudioCaptureModule::GetLoudspeakerStatus(bool* /*enabled*/) const {
void FakeAudioCaptureModule::OnMessage(talk_base::Message* msg) { void FakeAudioCaptureModule::OnMessage(talk_base::Message* msg) {
switch (msg->message_id) { switch (msg->message_id) {
case MSG_START_PROCESS:
StartProcessP();
break;
case MSG_RUN_PROCESS: case MSG_RUN_PROCESS:
ProcessFrameP(); ProcessFrameP();
break; break;
@ -640,17 +668,25 @@ bool FakeAudioCaptureModule::CheckRecBuffer(int value) {
return false; return false;
} }
void FakeAudioCaptureModule::UpdateProcessing() { bool FakeAudioCaptureModule::ShouldStartProcessing() {
const bool process = recording_ || playing_; return recording_ || playing_;
if (process) { }
void FakeAudioCaptureModule::UpdateProcessing(bool start) {
if (start) {
process_thread_->Post(this, MSG_START_PROCESS);
} else {
process_thread_->Send(this, MSG_STOP_PROCESS);
}
}
void FakeAudioCaptureModule::StartProcessP() {
ASSERT(talk_base::Thread::Current() == process_thread_);
if (started_) { if (started_) {
// Already started. // Already started.
return; return;
} }
process_thread_->Post(this, MSG_RUN_PROCESS); ProcessFrameP();
} else {
process_thread_->Send(this, MSG_STOP_PROCESS);
}
} }
void FakeAudioCaptureModule::ProcessFrameP() { void FakeAudioCaptureModule::ProcessFrameP() {
@ -659,15 +695,22 @@ void FakeAudioCaptureModule::ProcessFrameP() {
next_frame_time_ = talk_base::Time(); next_frame_time_ = talk_base::Time();
started_ = true; started_ = true;
} }
bool playing;
bool recording;
{
talk_base::CritScope cs(&crit_);
playing = playing_;
recording = recording_;
}
// Receive and send frames every kTimePerFrameMs. // Receive and send frames every kTimePerFrameMs.
if (audio_callback_ != NULL) { if (playing) {
if (playing_) {
ReceiveFrameP(); ReceiveFrameP();
} }
if (recording_) { if (recording) {
SendFrameP(); SendFrameP();
} }
}
next_frame_time_ += kTimePerFrameMs; next_frame_time_ += kTimePerFrameMs;
const uint32 current_time = talk_base::Time(); const uint32 current_time = talk_base::Time();
@ -678,6 +721,11 @@ void FakeAudioCaptureModule::ProcessFrameP() {
void FakeAudioCaptureModule::ReceiveFrameP() { void FakeAudioCaptureModule::ReceiveFrameP() {
ASSERT(talk_base::Thread::Current() == process_thread_); ASSERT(talk_base::Thread::Current() == process_thread_);
{
talk_base::CritScope cs(&crit_callback_);
if (!audio_callback_) {
return;
}
ResetRecBuffer(); ResetRecBuffer();
uint32_t nSamplesOut = 0; uint32_t nSamplesOut = 0;
if (audio_callback_->NeedMorePlayData(kNumberSamples, kNumberBytesPerSample, if (audio_callback_->NeedMorePlayData(kNumberSamples, kNumberBytesPerSample,
@ -686,27 +734,38 @@ void FakeAudioCaptureModule::ReceiveFrameP() {
ASSERT(false); ASSERT(false);
} }
ASSERT(nSamplesOut == kNumberSamples); ASSERT(nSamplesOut == kNumberSamples);
}
// The SetBuffer() function ensures that after decoding, the audio buffer // The SetBuffer() function ensures that after decoding, the audio buffer
// should contain samples of similar magnitude (there is likely to be some // should contain samples of similar magnitude (there is likely to be some
// distortion due to the audio pipeline). If one sample is detected to // distortion due to the audio pipeline). If one sample is detected to
// have the same or greater magnitude somewhere in the frame, an actual frame // have the same or greater magnitude somewhere in the frame, an actual frame
// has been received from the remote side (i.e. faked frames are not being // has been received from the remote side (i.e. faked frames are not being
// pulled). // pulled).
if (CheckRecBuffer(kHighSampleValue)) ++frames_received_; if (CheckRecBuffer(kHighSampleValue)) {
talk_base::CritScope cs(&crit_);
++frames_received_;
}
} }
void FakeAudioCaptureModule::SendFrameP() { void FakeAudioCaptureModule::SendFrameP() {
ASSERT(talk_base::Thread::Current() == process_thread_); ASSERT(talk_base::Thread::Current() == process_thread_);
talk_base::CritScope cs(&crit_callback_);
if (!audio_callback_) {
return;
}
bool key_pressed = false; bool key_pressed = false;
uint32_t current_mic_level = 0;
MicrophoneVolume(&current_mic_level);
if (audio_callback_->RecordedDataIsAvailable(send_buffer_, kNumberSamples, if (audio_callback_->RecordedDataIsAvailable(send_buffer_, kNumberSamples,
kNumberBytesPerSample, kNumberBytesPerSample,
kNumberOfChannels, kNumberOfChannels,
kSamplesPerSecond, kTotalDelayMs, kSamplesPerSecond, kTotalDelayMs,
kClockDriftMs, current_mic_level_, kClockDriftMs, current_mic_level,
key_pressed, key_pressed,
current_mic_level_) != 0) { current_mic_level) != 0) {
ASSERT(false); ASSERT(false);
} }
SetMicrophoneVolume(current_mic_level);
} }
void FakeAudioCaptureModule::StopProcessP() { void FakeAudioCaptureModule::StopProcessP() {

View File

@ -38,6 +38,7 @@
#define TALK_APP_WEBRTC_TEST_FAKEAUDIOCAPTUREMODULE_H_ #define TALK_APP_WEBRTC_TEST_FAKEAUDIOCAPTUREMODULE_H_
#include "talk/base/basictypes.h" #include "talk/base/basictypes.h"
#include "talk/base/criticalsection.h"
#include "talk/base/messagehandler.h" #include "talk/base/messagehandler.h"
#include "talk/base/scoped_ref_ptr.h" #include "talk/base/scoped_ref_ptr.h"
#include "webrtc/common_types.h" #include "webrtc/common_types.h"
@ -88,6 +89,7 @@ class FakeAudioCaptureModule
virtual int32_t RegisterEventObserver( virtual int32_t RegisterEventObserver(
webrtc::AudioDeviceObserver* event_callback); webrtc::AudioDeviceObserver* event_callback);
// Note: Calling this method from a callback may result in deadlock.
virtual int32_t RegisterAudioCallback(webrtc::AudioTransport* audio_callback); virtual int32_t RegisterAudioCallback(webrtc::AudioTransport* audio_callback);
virtual int32_t Init(); virtual int32_t Init();
@ -225,10 +227,15 @@ class FakeAudioCaptureModule
// equal to |value|. // equal to |value|.
bool CheckRecBuffer(int value); bool CheckRecBuffer(int value);
// Starts or stops the pushing and pulling of audio frames depending on if // Returns true/false depending on if recording or playback has been
// recording or playback has been enabled/started. // enabled/started.
void UpdateProcessing(); bool ShouldStartProcessing();
// Starts or stops the pushing and pulling of audio frames.
void UpdateProcessing(bool start);
// Starts the periodic calling of ProcessFrame() in a thread safe way.
void StartProcessP();
// Periodcally called function that ensures that frames are pulled and pushed // Periodcally called function that ensures that frames are pulled and pushed
// periodically if enabled/started. // periodically if enabled/started.
void ProcessFrameP(); void ProcessFrameP();
@ -275,6 +282,13 @@ class FakeAudioCaptureModule
// indicate that the frames are not faked somewhere in the audio pipeline // indicate that the frames are not faked somewhere in the audio pipeline
// (e.g. by a jitter buffer). // (e.g. by a jitter buffer).
int frames_received_; int frames_received_;
// Protects variables that are accessed from process_thread_ and
// the main thread.
mutable talk_base::CriticalSection crit_;
// Protects |audio_callback_| that is accessed from process_thread_ and
// the main thread.
talk_base::CriticalSection crit_callback_;
}; };
#endif // TALK_APP_WEBRTC_TEST_FAKEAUDIOCAPTUREMODULE_H_ #endif // TALK_APP_WEBRTC_TEST_FAKEAUDIOCAPTUREMODULE_H_

View File

@ -11,10 +11,6 @@ race:webrtc/modules/audio_processing/aec/aec_rdft.c
# See https://code.google.com/p/webrtc/issues/detail?id=2484 for details. # See https://code.google.com/p/webrtc/issues/detail?id=2484 for details.
# race:webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc # race:webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc
# libjingle_peerconnection_unittest
# See https://code.google.com/p/webrtc/issues/detail?id=1205
race:talk/app/webrtc/test/fakeaudiocapturemodule.cc
# libjingle_p2p_unittest # libjingle_p2p_unittest
# See https://code.google.com/p/webrtc/issues/detail?id=2079 # See https://code.google.com/p/webrtc/issues/detail?id=2079
race:talk/base/messagequeue.cc race:talk/base/messagequeue.cc