In the past we support calling StartPlayingFileLocally() before StartPlayout(), then when playout is started, the file would be played out immediately.

Now we would get a failure if we do the same thing and the file would not be played out. Then GTalk/Hangout also reported this failure to us. 
This CL is to restore the original function. 

BUG = Issue 490
TEST = Manual test and voe_auto_test->FileBeforeStreamingTest
Review URL: https://webrtc-codereview.appspot.com/569016

git-svn-id: http://webrtc.googlecode.com/svn/trunk@2347 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
braveyao@webrtc.org 2012-06-04 03:26:39 +00:00
parent 899baa821b
commit ab12990b1b
4 changed files with 167 additions and 29 deletions

View File

@ -1601,6 +1601,10 @@ Channel::StartPlayout()
}
_playing = true;
if (RegisterFilePlayingToMixer() != 0)
return -1;
return 0;
}
@ -3409,22 +3413,9 @@ int Channel::StartPlayingFileLocally(const char* fileName,
_outputFilePlayerPtr->RegisterModuleFileCallback(this);
_outputFilePlaying = true;
}
// _fileCritSect cannot be taken while calling
// SetAnonymousMixabilityStatus() since as soon as the participant is added
// frames can be pulled by the mixer. Since the frames are generated from
// the file, _fileCritSect will be taken. This would result in a deadlock.
if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
{
CriticalSectionScoped cs(&_fileCritSect);
_outputFilePlaying = false;
_engineStatisticsPtr->SetLastError(
VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
"StartPlayingFile() failed to add participant as file to mixer");
_outputFilePlayerPtr->StopPlayingFile();
FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
_outputFilePlayerPtr = NULL;
if (RegisterFilePlayingToMixer() != 0)
return -1;
}
return 0;
}
@ -3500,21 +3491,9 @@ int Channel::StartPlayingFileLocally(InStream* stream,
_outputFilePlayerPtr->RegisterModuleFileCallback(this);
_outputFilePlaying = true;
}
// _fileCritSect cannot be taken while calling
// SetAnonymousMixibilityStatus. Refer to comments in
// StartPlayingFileLocally(const char* ...) for more details.
if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
{
CriticalSectionScoped cs(&_fileCritSect);
_outputFilePlaying = false;
_engineStatisticsPtr->SetLastError(
VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
"StartPlayingFile() failed to add participant as file to mixer");
_outputFilePlayerPtr->StopPlayingFile();
FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
_outputFilePlayerPtr = NULL;
if (RegisterFilePlayingToMixer() != 0)
return -1;
}
return 0;
}
@ -3570,6 +3549,36 @@ int Channel::IsPlayingFileLocally() const
return (WebRtc_Word32)_outputFilePlaying;
}
int Channel::RegisterFilePlayingToMixer()
{
// Return success for not registering for file playing to mixer if:
// 1. playing file before playout is started on that channel.
// 2. starting playout without file playing on that channel.
if (!_playing || !_outputFilePlaying)
{
return 0;
}
// |_fileCritSect| cannot be taken while calling
// SetAnonymousMixabilityStatus() since as soon as the participant is added
// frames can be pulled by the mixer. Since the frames are generated from
// the file, _fileCritSect will be taken. This would result in a deadlock.
if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
{
CriticalSectionScoped cs(&_fileCritSect);
_outputFilePlaying = false;
_engineStatisticsPtr->SetLastError(
VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
"StartPlayingFile() failed to add participant as file to mixer");
_outputFilePlayerPtr->StopPlayingFile();
FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
_outputFilePlayerPtr = NULL;
return -1;
}
return 0;
}
int Channel::ScaleLocalFilePlayout(const float scale)
{
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),

View File

@ -196,6 +196,7 @@ public:
const CodecInst* codecInst);
int StopPlayingFileLocally();
int IsPlayingFileLocally() const;
int RegisterFilePlayingToMixer();
int ScaleLocalFilePlayout(const float scale);
int GetLocalPlayoutPosition(int& positionMs);
int StartPlayingFileAsMicrophone(const char* fileName, const bool loop,

View File

@ -0,0 +1,127 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "after_initialization_fixture.h"
#include "test/testsupport/fileutils.h"
namespace {
const int kSampleRateHz = 16000;
const int kTestDurationMs = 1000;
const int16_t kInputValue = 15000;
const int16_t kSilenceValue = 0;
} // namespace
class FileBeforeStreamingTest : public AfterInitializationFixture {
protected:
FileBeforeStreamingTest()
: input_filename_(webrtc::test::OutputPath() + "file_test_input.pcm"),
output_filename_(webrtc::test::OutputPath() + "file_test_output.pcm") {
}
void SetUp() {
channel_ = voe_base_->CreateChannel();
}
void TearDown() {
voe_base_->DeleteChannel(channel_);
}
// TODO(andrew): consolidate below methods in a shared place?
// Generate input file with constant values as |kInputValue|. The file
// will be one second longer than the duration of the test.
void GenerateInputFile() {
FILE* input_file = fopen(input_filename_.c_str(), "wb");
ASSERT_TRUE(input_file != NULL);
for (int i = 0; i < kSampleRateHz / 1000 * (kTestDurationMs + 1000); i++) {
ASSERT_EQ(1u, fwrite(&kInputValue, sizeof(kInputValue), 1, input_file));
}
ASSERT_EQ(0, fclose(input_file));
}
void RecordOutput() {
// Start recording the mixed output for |kTestDurationMs| long.
EXPECT_EQ(0, voe_file_->StartRecordingPlayout(-1,
output_filename_.c_str()));
Sleep(kTestDurationMs);
EXPECT_EQ(0, voe_file_->StopRecordingPlayout(-1));
}
void VerifyOutput(int16_t target_value) {
FILE* output_file = fopen(output_filename_.c_str(), "rb");
ASSERT_TRUE(output_file != NULL);
int16_t output_value = 0;
int samples_read = 0;
while (fread(&output_value, sizeof(output_value), 1, output_file) == 1) {
samples_read++;
EXPECT_EQ(output_value, target_value);
}
// Ensure the recording length is close to the duration of the test.
ASSERT_GE((samples_read * 1000.0) / kSampleRateHz, 0.9 * kTestDurationMs);
// Ensure we read the entire file.
ASSERT_NE(0, feof(output_file));
ASSERT_EQ(0, fclose(output_file));
}
void VerifyEmptyOutput() {
FILE* output_file = fopen(output_filename_.c_str(), "rb");
ASSERT_TRUE(output_file != NULL);
ASSERT_EQ(0, fseek(output_file, 0, SEEK_END));
EXPECT_EQ(0, ftell(output_file));
ASSERT_EQ(0, fclose(output_file));
}
int channel_;
const std::string input_filename_;
const std::string output_filename_;
};
// This test case is to ensure that StartPlayingFileLocally() and
// StartPlayout() can be called in any order.
// A DC signal is used as input. And the output of mixer is supposed to be:
// 1. the same DC signal if file is played out,
// 2. total silence if file is not played out,
// 3. no output if playout is not started.
TEST_F(FileBeforeStreamingTest, TestStartPlayingFileLocallyWithStartPlayout) {
GenerateInputFile();
TEST_LOG("Playout is not started. File will not be played out.\n");
EXPECT_EQ(0, voe_file_->StartPlayingFileLocally(
channel_, input_filename_.c_str(), true));
EXPECT_EQ(1, voe_file_->IsPlayingFileLocally(channel_));
RecordOutput();
VerifyEmptyOutput();
TEST_LOG("Playout is now started. File will be played out.\n");
EXPECT_EQ(0, voe_base_->StartPlayout(channel_));
RecordOutput();
VerifyOutput(kInputValue);
TEST_LOG("Stop playing file. Only silence will be played out.\n");
EXPECT_EQ(0, voe_file_->StopPlayingFileLocally(channel_));
EXPECT_EQ(0, voe_file_->IsPlayingFileLocally(channel_));
RecordOutput();
VerifyOutput(kSilenceValue);
TEST_LOG("Start playing file again. File will be played out.\n");
EXPECT_EQ(0, voe_file_->StartPlayingFileLocally(
channel_, input_filename_.c_str(), true));
EXPECT_EQ(1, voe_file_->IsPlayingFileLocally(channel_));
RecordOutput();
VerifyOutput(kInputValue);
EXPECT_EQ(0, voe_base_->StopPlayout(channel_));
EXPECT_EQ(0, voe_file_->StopPlayingFileLocally(channel_));
}

View File

@ -49,6 +49,7 @@
'auto_test/standard/dtmf_test.cc',
'auto_test/standard/encryption_test.cc',
'auto_test/standard/external_media_test.cc',
'auto_test/standard/file_before_streaming_test.cc',
'auto_test/standard/file_test.cc',
'auto_test/standard/hardware_before_initializing_test.cc',
'auto_test/standard/hardware_before_streaming_test.cc',