Update libjingle 62364298->62472237

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5632 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
henrike@webrtc.org 2014-03-03 18:30:11 +00:00
parent 1bbfb57d71
commit 40b3b68cdf
18 changed files with 678 additions and 128 deletions

View File

@ -41,17 +41,21 @@ class AudioTrack : public MediaStreamTrack<AudioTrackInterface> {
static talk_base::scoped_refptr<AudioTrack> Create(
const std::string& id, AudioSourceInterface* source);
virtual AudioSourceInterface* GetSource() const {
// AudioTrackInterface implementation.
virtual AudioSourceInterface* GetSource() const OVERRIDE {
return audio_source_.get();
}
// This method is used for supporting multiple sources/sinks for AudioTracks.
virtual cricket::AudioRenderer* GetRenderer() {
// TODO(xians): Implement these methods.
virtual void AddSink(AudioTrackSinkInterface* sink) OVERRIDE {}
virtual void RemoveSink(AudioTrackSinkInterface* sink) OVERRIDE {}
virtual bool GetSignalLevel(int* level) OVERRIDE { return false; }
virtual AudioProcessorInterface* GetAudioProcessor() OVERRIDE { return NULL; }
virtual cricket::AudioRenderer* GetRenderer() OVERRIDE {
return NULL;
}
// Implement MediaStreamTrack
virtual std::string kind() const;
// MediaStreamTrack implementation.
virtual std::string kind() const OVERRIDE;
protected:
AudioTrack(const std::string& label, AudioSourceInterface* audio_source);

View File

@ -174,18 +174,55 @@ class AudioTrackSinkInterface {
virtual ~AudioTrackSinkInterface() {}
};
// Interface of the audio processor used by the audio track to collect
// statistics.
class AudioProcessorInterface : public talk_base::RefCountInterface {
public:
struct AudioProcessorStats {
AudioProcessorStats() : typing_noise_detected(false),
echo_return_loss(0),
echo_return_loss_enhancement(0),
echo_delay_median_ms(0),
aec_quality_min(0.0),
echo_delay_std_ms(0) {}
~AudioProcessorStats() {}
bool typing_noise_detected;
int echo_return_loss;
int echo_return_loss_enhancement;
int echo_delay_median_ms;
float aec_quality_min;
int echo_delay_std_ms;
};
// Get audio processor statistics.
virtual void GetStats(AudioProcessorStats* stats) = 0;
protected:
virtual ~AudioProcessorInterface() {}
};
class AudioTrackInterface : public MediaStreamTrackInterface {
public:
// TODO(xians): Figure out if the following interface should be const or not.
virtual AudioSourceInterface* GetSource() const = 0;
// Adds/Removes a sink that will receive the audio data from the track.
// TODO(xians): Make them pure virtual after Chrome implements these
// interfaces.
virtual void AddSink(AudioTrackSinkInterface* sink) {}
virtual void RemoveSink(AudioTrackSinkInterface* sink) {}
// Add/Remove a sink that will receive the audio data from the track.
virtual void AddSink(AudioTrackSinkInterface* sink) = 0;
virtual void RemoveSink(AudioTrackSinkInterface* sink) = 0;
// Gets a pointer to the audio renderer of this AudioTrack.
// Get the signal level from the audio track.
// Return true on success, otherwise false.
// TODO(xians): Change the interface to int GetSignalLevel() and pure virtual
// after Chrome has the correct implementation of the interface.
virtual bool GetSignalLevel(int* level) { return false; }
// Get the audio processor used by the audio track. Return NULL if the track
// does not have any processor.
// TODO(xians): Make the interface pure virtual.
virtual AudioProcessorInterface* GetAudioProcessor() { return NULL; }
// Get a pointer to the audio renderer of this AudioTrack.
// The pointer is valid for the lifetime of this AudioTrack.
// TODO(xians): Remove the following interface after Chrome switches to
// AddSink() and RemoveSink() interfaces.

View File

@ -321,8 +321,29 @@ bool MediaStreamSignaling::AddLocalStream(MediaStreamInterface* local_stream) {
void MediaStreamSignaling::RemoveLocalStream(
MediaStreamInterface* local_stream) {
local_streams_->RemoveStream(local_stream);
AudioTrackVector audio_tracks = local_stream->GetAudioTracks();
for (AudioTrackVector::const_iterator it = audio_tracks.begin();
it != audio_tracks.end(); ++it) {
const TrackInfo* track_info = FindTrackInfo(local_audio_tracks_,
local_stream->label(),
(*it)->id());
if (track_info) {
stream_observer_->OnRemoveLocalAudioTrack(local_stream, *it,
track_info->ssrc);
}
}
VideoTrackVector video_tracks = local_stream->GetVideoTracks();
for (VideoTrackVector::const_iterator it = video_tracks.begin();
it != video_tracks.end(); ++it) {
const TrackInfo* track_info = FindTrackInfo(local_video_tracks_,
local_stream->label(),
(*it)->id());
if (track_info) {
stream_observer_->OnRemoveLocalVideoTrack(local_stream, *it);
}
}
local_streams_->RemoveStream(local_stream);
stream_observer_->OnRemoveLocalStream(local_stream);
}
@ -725,7 +746,8 @@ void MediaStreamSignaling::UpdateLocalTracks(
cricket::StreamParams params;
if (!cricket::GetStreamBySsrc(streams, info.ssrc, &params) ||
params.id != info.track_id || params.sync_label != info.stream_label) {
OnLocalTrackRemoved(info.stream_label, info.track_id, media_type);
OnLocalTrackRemoved(info.stream_label, info.track_id, info.ssrc,
media_type);
track_it = current_tracks->erase(track_it);
} else {
++track_it;
@ -787,6 +809,7 @@ void MediaStreamSignaling::OnLocalTrackSeen(
void MediaStreamSignaling::OnLocalTrackRemoved(
const std::string& stream_label,
const std::string& track_id,
uint32 ssrc,
cricket::MediaType media_type) {
MediaStreamInterface* stream = local_streams_->find(stream_label);
if (!stream) {
@ -803,7 +826,7 @@ void MediaStreamSignaling::OnLocalTrackRemoved(
if (!audio_track) {
return;
}
stream_observer_->OnRemoveLocalAudioTrack(stream, audio_track);
stream_observer_->OnRemoveLocalAudioTrack(stream, audio_track, ssrc);
} else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
VideoTrackInterface* video_track = stream->FindVideoTrack(track_id);
if (!video_track) {

View File

@ -92,7 +92,8 @@ class MediaStreamSignalingObserver {
// Triggered when the local SessionDescription has removed an audio track.
virtual void OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
AudioTrackInterface* audio_track) = 0;
AudioTrackInterface* audio_track,
uint32 ssrc) = 0;
// Triggered when the local SessionDescription has removed a video track.
virtual void OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
@ -354,6 +355,7 @@ class MediaStreamSignaling {
// MediaStreamTrack in a MediaStream in |local_streams_|.
void OnLocalTrackRemoved(const std::string& stream_label,
const std::string& track_id,
uint32 ssrc,
cricket::MediaType media_type);
void UpdateLocalRtpDataChannels(const cricket::StreamParamsVec& streams);

View File

@ -298,7 +298,8 @@ class MockSignalingObserver : public webrtc::MediaStreamSignalingObserver {
}
virtual void OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
AudioTrackInterface* audio_track) {
AudioTrackInterface* audio_track,
uint32 ssrc) {
RemoveTrack(&local_audio_tracks_, stream, audio_track);
}

View File

@ -42,6 +42,10 @@ BEGIN_PROXY_MAP(AudioTrack)
PROXY_CONSTMETHOD0(TrackState, state)
PROXY_CONSTMETHOD0(bool, enabled)
PROXY_CONSTMETHOD0(AudioSourceInterface*, GetSource)
PROXY_METHOD1(void, AddSink, AudioTrackSinkInterface*)
PROXY_METHOD1(void, RemoveSink, AudioTrackSinkInterface*)
PROXY_METHOD1(bool, GetSignalLevel, int*)
PROXY_METHOD0(AudioProcessorInterface*, GetAudioProcessor)
PROXY_METHOD0(cricket::AudioRenderer*, GetRenderer)
PROXY_METHOD1(bool, set_enabled, bool)

View File

@ -706,6 +706,7 @@ void PeerConnection::OnAddLocalAudioTrack(MediaStreamInterface* stream,
AudioTrackInterface* audio_track,
uint32 ssrc) {
stream_handler_container_->AddLocalAudioTrack(stream, audio_track, ssrc);
stats_.AddLocalAudioTrack(audio_track, ssrc);
}
void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream,
VideoTrackInterface* video_track,
@ -714,8 +715,10 @@ void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream,
}
void PeerConnection::OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
AudioTrackInterface* audio_track) {
AudioTrackInterface* audio_track,
uint32 ssrc) {
stream_handler_container_->RemoveLocalTrack(stream, audio_track);
stats_.RemoveLocalAudioTrack(audio_track, ssrc);
}
void PeerConnection::OnRemoveLocalVideoTrack(MediaStreamInterface* stream,

View File

@ -136,7 +136,8 @@ class PeerConnection : public PeerConnectionInterface,
uint32 ssrc) OVERRIDE;
virtual void OnRemoveLocalAudioTrack(
MediaStreamInterface* stream,
AudioTrackInterface* audio_track) OVERRIDE;
AudioTrackInterface* audio_track,
uint32 ssrc) OVERRIDE;
virtual void OnRemoveLocalVideoTrack(
MediaStreamInterface* stream,
VideoTrackInterface* video_track) OVERRIDE;

View File

@ -201,6 +201,19 @@ void StatsReport::AddBoolean(const std::string& name, bool value) {
AddValue(name, value ? "true" : "false");
}
void StatsReport::ReplaceValue(const std::string& name,
const std::string& value) {
for (Values::iterator it = values.begin(); it != values.end(); ++it) {
if ((*it).name == name) {
it->value = value;
return;
}
}
// It is not reachable here, add an ASSERT to make sure the overwriting is
// always a success.
ASSERT(false);
}
namespace {
typedef std::map<std::string, StatsReport> StatsMap;
@ -458,6 +471,32 @@ void StatsCollector::AddStream(MediaStreamInterface* stream) {
&reports_);
}
void StatsCollector::AddLocalAudioTrack(AudioTrackInterface* audio_track,
uint32 ssrc) {
ASSERT(audio_track != NULL);
#ifdef _DEBUG
for (LocalAudioTrackVector::iterator it = local_audio_tracks_.begin();
it != local_audio_tracks_.end(); ++it) {
ASSERT(it->first != audio_track || it->second != ssrc);
}
#endif
local_audio_tracks_.push_back(std::make_pair(audio_track, ssrc));
}
void StatsCollector::RemoveLocalAudioTrack(AudioTrackInterface* audio_track,
uint32 ssrc) {
ASSERT(audio_track != NULL);
for (LocalAudioTrackVector::iterator it = local_audio_tracks_.begin();
it != local_audio_tracks_.end(); ++it) {
if (it->first == audio_track && it->second == ssrc) {
local_audio_tracks_.erase(it);
return;
}
}
ASSERT(false);
}
bool StatsCollector::GetStats(MediaStreamTrackInterface* track,
StatsReports* reports) {
ASSERT(reports != NULL);
@ -784,6 +823,8 @@ void StatsCollector::ExtractVoiceInfo() {
}
ExtractStatsFromList(voice_info.receivers, transport_id, this);
ExtractStatsFromList(voice_info.senders, transport_id, this);
UpdateStatsFromExistingLocalAudioTracks();
}
void StatsCollector::ExtractVideoInfo(
@ -840,19 +881,86 @@ bool StatsCollector::GetTransportIdFromProxy(const std::string& proxy,
return true;
}
StatsReport* StatsCollector::GetOrCreateReport(const std::string& type,
const std::string& id) {
StatsReport* StatsCollector::GetReport(const std::string& type,
const std::string& id) {
std::string statsid = StatsId(type, id);
StatsReport* report = NULL;
std::map<std::string, StatsReport>::iterator it = reports_.find(statsid);
if (it == reports_.end()) {
report = &reports_[statsid]; // Create new element.
report->id = statsid;
report->type = type;
} else {
if (it != reports_.end())
report = &(it->second);
}
return report;
}
StatsReport* StatsCollector::GetOrCreateReport(const std::string& type,
const std::string& id) {
StatsReport* report = GetReport(type, id);
if (report == NULL) {
std::string statsid = StatsId(type, id);
report = &reports_[statsid]; // Create new element.
report->id = statsid;
report->type = type;
}
return report;
}
void StatsCollector::UpdateStatsFromExistingLocalAudioTracks() {
// Loop through the existing local audio tracks.
for (LocalAudioTrackVector::const_iterator it = local_audio_tracks_.begin();
it != local_audio_tracks_.end(); ++it) {
AudioTrackInterface* track = it->first;
uint32 ssrc = it->second;
std::string ssrc_id = talk_base::ToString<uint32>(ssrc);
StatsReport* report = GetReport(StatsReport::kStatsReportTypeSsrc,
ssrc_id);
ASSERT(report != NULL);
// The same ssrc can be used by both local and remote audio tracks.
std::string track_id;
if (!ExtractValueFromReport(*report,
StatsReport::kStatsValueNameTrackId,
&track_id) ||
track_id != track->id()) {
continue;
}
UpdateReportFromAudioTrack(track, report);
}
}
void StatsCollector::UpdateReportFromAudioTrack(AudioTrackInterface* track,
StatsReport* report) {
ASSERT(track != NULL);
if (report == NULL)
return;
int signal_level = 0;
if (track->GetSignalLevel(&signal_level)) {
report->ReplaceValue(StatsReport::kStatsValueNameAudioInputLevel,
talk_base::ToString<int>(signal_level));
}
talk_base::scoped_refptr<AudioProcessorInterface> audio_processor(
track->GetAudioProcessor());
if (audio_processor.get() == NULL)
return;
AudioProcessorInterface::AudioProcessorStats stats;
audio_processor->GetStats(&stats);
report->ReplaceValue(StatsReport::kStatsValueNameTypingNoiseState,
stats.typing_noise_detected ? "true" : "false");
report->ReplaceValue(StatsReport::kStatsValueNameEchoReturnLoss,
talk_base::ToString<int>(stats.echo_return_loss));
report->ReplaceValue(
StatsReport::kStatsValueNameEchoReturnLossEnhancement,
talk_base::ToString<int>(stats.echo_return_loss_enhancement));
report->ReplaceValue(StatsReport::kStatsValueNameEchoDelayMedian,
talk_base::ToString<int>(stats.echo_delay_median_ms));
report->ReplaceValue(StatsReport::kStatsValueNameEchoCancellationQualityMin,
talk_base::ToString<float>(stats.aec_quality_min));
report->ReplaceValue(StatsReport::kStatsValueNameEchoDelayStdDev,
talk_base::ToString<int>(stats.echo_delay_std_ms));
}
} // namespace webrtc

View File

@ -31,8 +31,9 @@
#ifndef TALK_APP_WEBRTC_STATSCOLLECTOR_H_
#define TALK_APP_WEBRTC_STATSCOLLECTOR_H_
#include <string>
#include <map>
#include <string>
#include <vector>
#include "talk/app/webrtc/mediastreaminterface.h"
#include "talk/app/webrtc/peerconnectioninterface.h"
@ -57,6 +58,13 @@ class StatsCollector {
// to GetStats.
void AddStream(MediaStreamInterface* stream);
// Adds a local audio track that is used for getting some voice statistics.
void AddLocalAudioTrack(AudioTrackInterface* audio_track, uint32 ssrc);
// Removes a local audio tracks that is used for getting some voice
// statistics.
void RemoveLocalAudioTrack(AudioTrackInterface* audio_track, uint32 ssrc);
// Gather statistics from the session and store them for future use.
void UpdateStats(PeerConnectionInterface::StatsOutputLevel level);
@ -95,6 +103,13 @@ class StatsCollector {
WebRtcSession* session() { return session_; }
webrtc::StatsReport* GetOrCreateReport(const std::string& type,
const std::string& id);
webrtc::StatsReport* GetReport(const std::string& type,
const std::string& id);
// Helper method to get stats from the local audio tracks.
void UpdateStatsFromExistingLocalAudioTracks();
void UpdateReportFromAudioTrack(AudioTrackInterface* track,
StatsReport* report);
// A map from the report id to the report.
std::map<std::string, StatsReport> reports_;
@ -103,6 +118,10 @@ class StatsCollector {
double stats_gathering_started_;
talk_base::Timing timing_;
cricket::ProxyTransportMap proxy_to_transport_;
typedef std::vector<std::pair<AudioTrackInterface*, uint32> >
LocalAudioTrackVector;
LocalAudioTrackVector local_audio_tracks_;
};
} // namespace webrtc

View File

@ -29,6 +29,8 @@
#include "talk/app/webrtc/statscollector.h"
#include "talk/app/webrtc/mediastream.h"
#include "talk/app/webrtc/mediastreaminterface.h"
#include "talk/app/webrtc/mediastreamtrack.h"
#include "talk/app/webrtc/videotrack.h"
#include "talk/base/base64.h"
#include "talk/base/fakesslidentity.h"
@ -47,6 +49,8 @@ using testing::Return;
using testing::ReturnNull;
using testing::SetArgPointee;
using webrtc::PeerConnectionInterface;
using webrtc::StatsReport;
using webrtc::StatsReports;
namespace cricket {
@ -63,6 +67,7 @@ const char kNoReports[] = "NO REPORTS";
// Constant names for track identification.
const char kTrackId[] = "somename";
const char kAudioTrackId[] = "audio_track_id";
const uint32 kSsrcOfTrack = 1234;
class MockWebRtcSession : public webrtc::WebRtcSession {
@ -71,6 +76,7 @@ class MockWebRtcSession : public webrtc::WebRtcSession {
: WebRtcSession(channel_manager, talk_base::Thread::Current(),
talk_base::Thread::Current(), NULL, NULL) {
}
MOCK_METHOD0(voice_channel, cricket::VoiceChannel*());
MOCK_METHOD0(video_channel, cricket::VideoChannel*());
MOCK_METHOD2(GetTrackIdBySsrc, bool(uint32, std::string*));
MOCK_METHOD1(GetStats, bool(cricket::SessionStats*));
@ -86,10 +92,60 @@ class MockVideoMediaChannel : public cricket::FakeVideoMediaChannel {
MOCK_METHOD2(GetStats, bool(const StatsOptions&, cricket::VideoMediaInfo*));
};
bool GetValue(const webrtc::StatsReport* report,
class MockVoiceMediaChannel : public cricket::FakeVoiceMediaChannel {
public:
MockVoiceMediaChannel() : cricket::FakeVoiceMediaChannel(NULL) {
}
MOCK_METHOD1(GetStats, bool(cricket::VoiceMediaInfo*));
};
class FakeAudioProcessor : public webrtc::AudioProcessorInterface {
public:
FakeAudioProcessor() {}
~FakeAudioProcessor() {}
private:
virtual void GetStats(
AudioProcessorInterface::AudioProcessorStats* stats) OVERRIDE {
stats->typing_noise_detected = true;
stats->echo_return_loss = 2;
stats->echo_return_loss_enhancement = 3;
stats->echo_delay_median_ms = 4;
stats->aec_quality_min = 5.1f;
stats->echo_delay_std_ms = 6;
}
};
class FakeLocalAudioTrack
: public webrtc::MediaStreamTrack<webrtc::AudioTrackInterface> {
public:
explicit FakeLocalAudioTrack(const std::string& id)
: webrtc::MediaStreamTrack<webrtc::AudioTrackInterface>(id),
processor_(new talk_base::RefCountedObject<FakeAudioProcessor>()) {}
std::string kind() const OVERRIDE {
return "audio";
}
virtual webrtc::AudioSourceInterface* GetSource() const OVERRIDE {
return NULL;
}
virtual void AddSink(webrtc::AudioTrackSinkInterface* sink) OVERRIDE {}
virtual void RemoveSink(webrtc::AudioTrackSinkInterface* sink) OVERRIDE {}
virtual bool GetSignalLevel(int* level) OVERRIDE {
*level = 1;
return true;
}
virtual webrtc::AudioProcessorInterface* GetAudioProcessor() OVERRIDE {
return processor_.get();
}
private:
talk_base::scoped_refptr<FakeAudioProcessor> processor_;
};
bool GetValue(const StatsReport* report,
const std::string& name,
std::string* value) {
webrtc::StatsReport::Values::const_iterator it = report->values.begin();
StatsReport::Values::const_iterator it = report->values.begin();
for (; it != report->values.end(); ++it) {
if (it->name == name) {
*value = it->value;
@ -100,7 +156,7 @@ bool GetValue(const webrtc::StatsReport* report,
}
std::string ExtractStatsValue(const std::string& type,
const webrtc::StatsReports& reports,
const StatsReports& reports,
const std::string name) {
if (reports.empty()) {
return kNoReports;
@ -119,8 +175,8 @@ std::string ExtractStatsValue(const std::string& type,
// Finds the |n|-th report of type |type| in |reports|.
// |n| starts from 1 for finding the first report.
const webrtc::StatsReport* FindNthReportByType(
const webrtc::StatsReports& reports, const std::string& type, int n) {
const StatsReport* FindNthReportByType(
const StatsReports& reports, const std::string& type, int n) {
for (size_t i = 0; i < reports.size(); ++i) {
if (reports[i].type == type) {
n--;
@ -131,8 +187,8 @@ const webrtc::StatsReport* FindNthReportByType(
return NULL;
}
const webrtc::StatsReport* FindReportById(const webrtc::StatsReports& reports,
const std::string& id) {
const StatsReport* FindReportById(const StatsReports& reports,
const std::string& id) {
for (size_t i = 0; i < reports.size(); ++i) {
if (reports[i].id == id) {
return &reports[i];
@ -141,16 +197,16 @@ const webrtc::StatsReport* FindReportById(const webrtc::StatsReports& reports,
return NULL;
}
std::string ExtractSsrcStatsValue(webrtc::StatsReports reports,
std::string ExtractSsrcStatsValue(StatsReports reports,
const std::string& name) {
return ExtractStatsValue(
webrtc::StatsReport::kStatsReportTypeSsrc, reports, name);
StatsReport::kStatsReportTypeSsrc, reports, name);
}
std::string ExtractBweStatsValue(webrtc::StatsReports reports,
std::string ExtractBweStatsValue(StatsReports reports,
const std::string& name) {
return ExtractStatsValue(
webrtc::StatsReport::kStatsReportTypeBwe, reports, name);
StatsReport::kStatsReportTypeBwe, reports, name);
}
std::string DerToPem(const std::string& der) {
@ -167,18 +223,18 @@ std::vector<std::string> DersToPems(
return pems;
}
void CheckCertChainReports(const webrtc::StatsReports& reports,
void CheckCertChainReports(const StatsReports& reports,
const std::vector<std::string>& ders,
const std::string& start_id) {
std::string certificate_id = start_id;
size_t i = 0;
while (true) {
const webrtc::StatsReport* report = FindReportById(reports, certificate_id);
const StatsReport* report = FindReportById(reports, certificate_id);
ASSERT_TRUE(report != NULL);
std::string der_base64;
EXPECT_TRUE(GetValue(
report, webrtc::StatsReport::kStatsValueNameDer, &der_base64));
report, StatsReport::kStatsValueNameDer, &der_base64));
std::string der = talk_base::Base64::Decode(der_base64,
talk_base::Base64::DO_STRICT);
EXPECT_EQ(ders[i], der);
@ -186,7 +242,7 @@ void CheckCertChainReports(const webrtc::StatsReports& reports,
std::string fingerprint_algorithm;
EXPECT_TRUE(GetValue(
report,
webrtc::StatsReport::kStatsValueNameFingerprintAlgorithm,
StatsReport::kStatsValueNameFingerprintAlgorithm,
&fingerprint_algorithm));
// The digest algorithm for a FakeSSLCertificate is always SHA-1.
std::string sha_1_str = talk_base::DIGEST_SHA_1;
@ -195,17 +251,68 @@ void CheckCertChainReports(const webrtc::StatsReports& reports,
std::string dummy_fingerprint; // Value is not checked.
EXPECT_TRUE(GetValue(
report,
webrtc::StatsReport::kStatsValueNameFingerprint,
StatsReport::kStatsValueNameFingerprint,
&dummy_fingerprint));
++i;
if (!GetValue(
report, webrtc::StatsReport::kStatsValueNameIssuerId, &certificate_id))
report, StatsReport::kStatsValueNameIssuerId, &certificate_id))
break;
}
EXPECT_EQ(ders.size(), i);
}
void VerifyVoiceSenderInfoReport(const StatsReport* report,
const cricket::VoiceSenderInfo& sinfo) {
std::string value_in_report;
EXPECT_TRUE(GetValue(
report, StatsReport::kStatsValueNameCodecName, &value_in_report));
EXPECT_EQ(sinfo.codec_name, value_in_report);
EXPECT_TRUE(GetValue(
report, StatsReport::kStatsValueNameBytesSent, &value_in_report));
EXPECT_EQ(talk_base::ToString<int64>(sinfo.bytes_sent), value_in_report);
EXPECT_TRUE(GetValue(
report, StatsReport::kStatsValueNamePacketsSent, &value_in_report));
EXPECT_EQ(talk_base::ToString<int>(sinfo.packets_sent), value_in_report);
EXPECT_TRUE(GetValue(
report, StatsReport::kStatsValueNameRtt, &value_in_report));
EXPECT_EQ(talk_base::ToString<int>(sinfo.rtt_ms), value_in_report);
EXPECT_TRUE(GetValue(
report, StatsReport::kStatsValueNameRtt, &value_in_report));
EXPECT_EQ(talk_base::ToString<int>(sinfo.rtt_ms), value_in_report);
EXPECT_TRUE(GetValue(
report, StatsReport::kStatsValueNameJitterReceived, &value_in_report));
EXPECT_EQ(talk_base::ToString<int>(sinfo.jitter_ms), value_in_report);
EXPECT_TRUE(GetValue(
report, StatsReport::kStatsValueNameEchoCancellationQualityMin,
&value_in_report));
EXPECT_EQ(talk_base::ToString<float>(sinfo.aec_quality_min), value_in_report);
EXPECT_TRUE(GetValue(
report, StatsReport::kStatsValueNameEchoDelayMedian, &value_in_report));
EXPECT_EQ(talk_base::ToString<int>(sinfo.echo_delay_median_ms),
value_in_report);
EXPECT_TRUE(GetValue(
report, StatsReport::kStatsValueNameEchoDelayStdDev, &value_in_report));
EXPECT_EQ(talk_base::ToString<int>(sinfo.echo_delay_std_ms),
value_in_report);
EXPECT_TRUE(GetValue(
report, StatsReport::kStatsValueNameEchoReturnLoss, &value_in_report));
EXPECT_EQ(talk_base::ToString<int>(sinfo.echo_return_loss),
value_in_report);
EXPECT_TRUE(GetValue(
report, StatsReport::kStatsValueNameEchoReturnLossEnhancement,
&value_in_report));
EXPECT_EQ(talk_base::ToString<int>(sinfo.echo_return_loss_enhancement),
value_in_report);
EXPECT_TRUE(GetValue(
report, StatsReport::kStatsValueNameAudioInputLevel, &value_in_report));
EXPECT_EQ(talk_base::ToString<int>(sinfo.audio_level), value_in_report);
EXPECT_TRUE(GetValue(
report, StatsReport::kStatsValueNameTypingNoiseState, &value_in_report));
std::string typing_detected = sinfo.typing_noise_detected ? "true" : "false";
EXPECT_EQ(typing_detected, value_in_report);
}
class StatsCollectorTest : public testing::Test {
protected:
StatsCollectorTest()
@ -245,12 +352,25 @@ class StatsCollectorTest : public testing::Test {
Return(true)));
}
// Adds a local audio track with a given SSRC into the stats.
void AddLocalAudioTrackStats() {
if (stream_ == NULL)
stream_ = webrtc::MediaStream::Create("streamlabel");
audio_track_ =
new talk_base::RefCountedObject<FakeLocalAudioTrack>(kAudioTrackId);
stream_->AddTrack(audio_track_);
EXPECT_CALL(session_, GetTrackIdBySsrc(kSsrcOfTrack, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(kAudioTrackId),
Return(true)));
}
void TestCertificateReports(const talk_base::FakeSSLCertificate& local_cert,
const std::vector<std::string>& local_ders,
const talk_base::FakeSSLCertificate& remote_cert,
const std::vector<std::string>& remote_ders) {
webrtc::StatsCollector stats; // Implementation under test.
webrtc::StatsReports reports; // returned values.
StatsReports reports; // returned values.
stats.set_session(&session_);
// Fake stats to process.
@ -289,22 +409,22 @@ class StatsCollectorTest : public testing::Test {
EXPECT_CALL(session_, GetStats(_))
.WillOnce(DoAll(SetArgPointee<0>(session_stats),
Return(true)));
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(ReturnNull());
EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
const webrtc::StatsReport* channel_report = FindNthReportByType(
reports, webrtc::StatsReport::kStatsReportTypeComponent, 1);
const StatsReport* channel_report = FindNthReportByType(
reports, StatsReport::kStatsReportTypeComponent, 1);
EXPECT_TRUE(channel_report != NULL);
// Check local certificate chain.
std::string local_certificate_id = ExtractStatsValue(
webrtc::StatsReport::kStatsReportTypeComponent,
StatsReport::kStatsReportTypeComponent,
reports,
webrtc::StatsReport::kStatsValueNameLocalCertificateId);
StatsReport::kStatsValueNameLocalCertificateId);
if (local_ders.size() > 0) {
EXPECT_NE(kNotFound, local_certificate_id);
CheckCertChainReports(reports, local_ders, local_certificate_id);
@ -314,9 +434,9 @@ class StatsCollectorTest : public testing::Test {
// Check remote certificate chain.
std::string remote_certificate_id = ExtractStatsValue(
webrtc::StatsReport::kStatsReportTypeComponent,
StatsReport::kStatsReportTypeComponent,
reports,
webrtc::StatsReport::kStatsValueNameRemoteCertificateId);
StatsReport::kStatsValueNameRemoteCertificateId);
if (remote_ders.size() > 0) {
EXPECT_NE(kNotFound, remote_certificate_id);
CheckCertChainReports(reports, remote_ders, remote_certificate_id);
@ -331,6 +451,7 @@ class StatsCollectorTest : public testing::Test {
cricket::SessionStats session_stats_;
talk_base::scoped_refptr<webrtc::MediaStream> stream_;
talk_base::scoped_refptr<webrtc::VideoTrack> track_;
talk_base::scoped_refptr<FakeLocalAudioTrack> audio_track_;
std::string track_id_;
};
@ -340,7 +461,7 @@ TEST_F(StatsCollectorTest, BytesCounterHandles64Bits) {
MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
cricket::VideoChannel video_channel(talk_base::Thread::Current(),
media_engine_, media_channel, &session_, "", false, NULL);
webrtc::StatsReports reports; // returned values.
StatsReports reports; // returned values.
cricket::VideoSenderInfo video_sender_info;
cricket::VideoMediaInfo stats_read;
// The number of bytes must be larger than 0xFFFFFFFF for this test.
@ -356,8 +477,8 @@ TEST_F(StatsCollectorTest, BytesCounterHandles64Bits) {
video_sender_info.bytes_sent = kBytesSent;
stats_read.senders.push_back(video_sender_info);
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(Return(&video_channel));
EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel));
EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
EXPECT_CALL(*media_channel, GetStats(_, _))
.WillOnce(DoAll(SetArgPointee<1>(stats_read),
Return(true)));
@ -373,7 +494,7 @@ TEST_F(StatsCollectorTest, BandwidthEstimationInfoIsReported) {
MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
cricket::VideoChannel video_channel(talk_base::Thread::Current(),
media_engine_, media_channel, &session_, "", false, NULL);
webrtc::StatsReports reports; // returned values.
StatsReports reports; // returned values.
cricket::VideoSenderInfo video_sender_info;
cricket::VideoMediaInfo stats_read;
// Set up an SSRC just to test that we get both kinds of stats back: SSRC and
@ -395,8 +516,8 @@ TEST_F(StatsCollectorTest, BandwidthEstimationInfoIsReported) {
bwe.target_enc_bitrate = kTargetEncBitrate;
stats_read.bw_estimations.push_back(bwe);
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(Return(&video_channel));
EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel));
EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
EXPECT_CALL(*media_channel, GetStats(_, _))
.WillOnce(DoAll(SetArgPointee<1>(stats_read),
Return(true)));
@ -413,14 +534,14 @@ TEST_F(StatsCollectorTest, BandwidthEstimationInfoIsReported) {
// exists in the returned stats.
TEST_F(StatsCollectorTest, SessionObjectExists) {
webrtc::StatsCollector stats; // Implementation under test.
webrtc::StatsReports reports; // returned values.
StatsReports reports; // returned values.
stats.set_session(&session_);
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(ReturnNull());
EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
const webrtc::StatsReport* session_report = FindNthReportByType(
reports, webrtc::StatsReport::kStatsReportTypeSession, 1);
const StatsReport* session_report = FindNthReportByType(
reports, StatsReport::kStatsReportTypeSession, 1);
EXPECT_FALSE(session_report == NULL);
}
@ -428,18 +549,18 @@ TEST_F(StatsCollectorTest, SessionObjectExists) {
// in the returned stats.
TEST_F(StatsCollectorTest, OnlyOneSessionObjectExists) {
webrtc::StatsCollector stats; // Implementation under test.
webrtc::StatsReports reports; // returned values.
StatsReports reports; // returned values.
stats.set_session(&session_);
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(ReturnNull());
EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
const webrtc::StatsReport* session_report = FindNthReportByType(
reports, webrtc::StatsReport::kStatsReportTypeSession, 1);
const StatsReport* session_report = FindNthReportByType(
reports, StatsReport::kStatsReportTypeSession, 1);
EXPECT_FALSE(session_report == NULL);
session_report = FindNthReportByType(
reports, webrtc::StatsReport::kStatsReportTypeSession, 2);
reports, StatsReport::kStatsReportTypeSession, 2);
EXPECT_EQ(NULL, session_report);
}
@ -455,18 +576,18 @@ TEST_F(StatsCollectorTest, TrackObjectExistsWithoutUpdateStats) {
stats.set_session(&session_);
webrtc::StatsReports reports;
StatsReports reports;
// Verfies the existence of the track report.
stats.GetStats(NULL, &reports);
EXPECT_EQ((size_t)1, reports.size());
EXPECT_EQ(std::string(webrtc::StatsReport::kStatsReportTypeTrack),
EXPECT_EQ(std::string(StatsReport::kStatsReportTypeTrack),
reports[0].type);
std::string trackValue =
ExtractStatsValue(webrtc::StatsReport::kStatsReportTypeTrack,
ExtractStatsValue(StatsReport::kStatsReportTypeTrack,
reports,
webrtc::StatsReport::kStatsValueNameTrackId);
StatsReport::kStatsValueNameTrackId);
EXPECT_EQ(kTrackId, trackValue);
}
@ -482,7 +603,7 @@ TEST_F(StatsCollectorTest, TrackAndSsrcObjectExistAfterUpdateSsrcStats) {
stats.set_session(&session_);
webrtc::StatsReports reports;
StatsReports reports;
// Constructs an ssrc stats update.
cricket::VideoSenderInfo video_sender_info;
@ -494,8 +615,8 @@ TEST_F(StatsCollectorTest, TrackAndSsrcObjectExistAfterUpdateSsrcStats) {
video_sender_info.bytes_sent = kBytesSent;
stats_read.senders.push_back(video_sender_info);
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(Return(&video_channel));
EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel));
EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
EXPECT_CALL(*media_channel, GetStats(_, _))
.WillOnce(DoAll(SetArgPointee<1>(stats_read),
Return(true)));
@ -505,8 +626,8 @@ TEST_F(StatsCollectorTest, TrackAndSsrcObjectExistAfterUpdateSsrcStats) {
// |reports| should contain at least one session report, one track report,
// and one ssrc report.
EXPECT_LE((size_t)3, reports.size());
const webrtc::StatsReport* track_report = FindNthReportByType(
reports, webrtc::StatsReport::kStatsReportTypeTrack, 1);
const StatsReport* track_report = FindNthReportByType(
reports, StatsReport::kStatsReportTypeTrack, 1);
EXPECT_FALSE(track_report == NULL);
stats.GetStats(track_, &reports);
@ -514,15 +635,15 @@ TEST_F(StatsCollectorTest, TrackAndSsrcObjectExistAfterUpdateSsrcStats) {
// and one ssrc report.
EXPECT_LE((size_t)3, reports.size());
track_report = FindNthReportByType(
reports, webrtc::StatsReport::kStatsReportTypeTrack, 1);
reports, StatsReport::kStatsReportTypeTrack, 1);
EXPECT_FALSE(track_report == NULL);
std::string ssrc_id = ExtractSsrcStatsValue(
reports, webrtc::StatsReport::kStatsValueNameSsrc);
reports, StatsReport::kStatsValueNameSsrc);
EXPECT_EQ(talk_base::ToString<uint32>(kSsrcOfTrack), ssrc_id);
std::string track_id = ExtractSsrcStatsValue(
reports, webrtc::StatsReport::kStatsValueNameTrackId);
reports, StatsReport::kStatsValueNameTrackId);
EXPECT_EQ(kTrackId, track_id);
}
@ -540,7 +661,7 @@ TEST_F(StatsCollectorTest, TransportObjectLinkedFromSsrcObject) {
stats.set_session(&session_);
webrtc::StatsReports reports;
StatsReports reports;
// Constructs an ssrc stats update.
cricket::VideoSenderInfo video_sender_info;
@ -552,26 +673,26 @@ TEST_F(StatsCollectorTest, TransportObjectLinkedFromSsrcObject) {
video_sender_info.bytes_sent = kBytesSent;
stats_read.senders.push_back(video_sender_info);
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(Return(&video_channel));
EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel));
EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
EXPECT_CALL(*media_channel, GetStats(_, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(stats_read),
Return(true)));
InitSessionStats(kVcName);
EXPECT_CALL(session_, GetStats(_))
.WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
Return(true)));
.WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
Return(true)));
stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
std::string transport_id = ExtractStatsValue(
webrtc::StatsReport::kStatsReportTypeSsrc,
StatsReport::kStatsReportTypeSsrc,
reports,
webrtc::StatsReport::kStatsValueNameTransportId);
StatsReport::kStatsValueNameTransportId);
ASSERT_NE(kNotFound, transport_id);
const webrtc::StatsReport* transport_report = FindReportById(reports,
transport_id);
const StatsReport* transport_report = FindReportById(reports,
transport_id);
ASSERT_FALSE(transport_report == NULL);
}
@ -589,14 +710,14 @@ TEST_F(StatsCollectorTest, RemoteSsrcInfoIsAbsent) {
stats.set_session(&session_);
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(ReturnNull());
EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
webrtc::StatsReports reports;
StatsReports reports;
stats.GetStats(NULL, &reports);
const webrtc::StatsReport* remote_report = FindNthReportByType(reports,
webrtc::StatsReport::kStatsReportTypeRemoteSsrc, 1);
const StatsReport* remote_report = FindNthReportByType(reports,
StatsReport::kStatsReportTypeRemoteSsrc, 1);
EXPECT_TRUE(remote_report == NULL);
}
@ -614,13 +735,13 @@ TEST_F(StatsCollectorTest, RemoteSsrcInfoIsPresent) {
stats.set_session(&session_);
webrtc::StatsReports reports;
StatsReports reports;
// Instruct the session to return stats containing the transport channel.
InitSessionStats(kVcName);
EXPECT_CALL(session_, GetStats(_))
.WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
Return(true)));
.WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
Return(true)));
// Constructs an ssrc stats update.
cricket::VideoMediaInfo stats_read;
@ -633,16 +754,16 @@ TEST_F(StatsCollectorTest, RemoteSsrcInfoIsPresent) {
video_sender_info.remote_stats.push_back(remote_ssrc_stats);
stats_read.senders.push_back(video_sender_info);
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(Return(&video_channel));
EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel));
EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
EXPECT_CALL(*media_channel, GetStats(_, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(stats_read),
Return(true)));
stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
const webrtc::StatsReport* remote_report = FindNthReportByType(reports,
webrtc::StatsReport::kStatsReportTypeRemoteSsrc, 1);
const StatsReport* remote_report = FindNthReportByType(reports,
StatsReport::kStatsReportTypeRemoteSsrc, 1);
EXPECT_FALSE(remote_report == NULL);
EXPECT_NE(0, remote_report->timestamp);
}
@ -689,7 +810,7 @@ TEST_F(StatsCollectorTest, ChainlessCertificateReportsCreated) {
// transport is present.
TEST_F(StatsCollectorTest, NoTransport) {
webrtc::StatsCollector stats; // Implementation under test.
webrtc::StatsReports reports; // returned values.
StatsReports reports; // returned values.
stats.set_session(&session_);
// Fake stats to process.
@ -711,24 +832,24 @@ TEST_F(StatsCollectorTest, NoTransport) {
.WillOnce(DoAll(SetArgPointee<0>(session_stats),
Return(true)));
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(ReturnNull());
EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
// Check that the local certificate is absent.
std::string local_certificate_id = ExtractStatsValue(
webrtc::StatsReport::kStatsReportTypeComponent,
StatsReport::kStatsReportTypeComponent,
reports,
webrtc::StatsReport::kStatsValueNameLocalCertificateId);
StatsReport::kStatsValueNameLocalCertificateId);
ASSERT_EQ(kNotFound, local_certificate_id);
// Check that the remote certificate is absent.
std::string remote_certificate_id = ExtractStatsValue(
webrtc::StatsReport::kStatsReportTypeComponent,
StatsReport::kStatsReportTypeComponent,
reports,
webrtc::StatsReport::kStatsValueNameRemoteCertificateId);
StatsReport::kStatsValueNameRemoteCertificateId);
ASSERT_EQ(kNotFound, remote_certificate_id);
}
@ -736,7 +857,7 @@ TEST_F(StatsCollectorTest, NoTransport) {
// does not have any certificates.
TEST_F(StatsCollectorTest, NoCertificates) {
webrtc::StatsCollector stats; // Implementation under test.
webrtc::StatsReports reports; // returned values.
StatsReports reports; // returned values.
stats.set_session(&session_);
// Fake stats to process.
@ -764,24 +885,24 @@ TEST_F(StatsCollectorTest, NoCertificates) {
EXPECT_CALL(session_, GetStats(_))
.WillOnce(DoAll(SetArgPointee<0>(session_stats),
Return(true)));
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(ReturnNull());
EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
// Check that the local certificate is absent.
std::string local_certificate_id = ExtractStatsValue(
webrtc::StatsReport::kStatsReportTypeComponent,
StatsReport::kStatsReportTypeComponent,
reports,
webrtc::StatsReport::kStatsValueNameLocalCertificateId);
StatsReport::kStatsValueNameLocalCertificateId);
ASSERT_EQ(kNotFound, local_certificate_id);
// Check that the remote certificate is absent.
std::string remote_certificate_id = ExtractStatsValue(
webrtc::StatsReport::kStatsReportTypeComponent,
StatsReport::kStatsReportTypeComponent,
reports,
webrtc::StatsReport::kStatsValueNameRemoteCertificateId);
StatsReport::kStatsValueNameRemoteCertificateId);
ASSERT_EQ(kNotFound, remote_certificate_id);
}
@ -810,7 +931,7 @@ TEST_F(StatsCollectorTest, StatsOutputLevelVerbose) {
media_engine_, media_channel, &session_, "", false, NULL);
stats.set_session(&session_);
webrtc::StatsReports reports; // returned values.
StatsReports reports; // returned values.
cricket::VideoMediaInfo stats_read;
cricket::BandwidthEstimationInfo bwe;
bwe.total_received_propagation_delta_ms = 10;
@ -822,6 +943,7 @@ TEST_F(StatsCollectorTest, StatsOutputLevelVerbose) {
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(Return(&video_channel));
EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull());
StatsOptions options;
options.include_received_propagation_stats = true;
@ -844,4 +966,175 @@ TEST_F(StatsCollectorTest, StatsOutputLevelVerbose) {
EXPECT_EQ("[1000, 2000]", result);
}
// This test verifies that a local stats object can get statistics via
// AudioTrackInterface::GetStats() method.
TEST_F(StatsCollectorTest, GetStatsFromLocalAudioTrack) {
webrtc::StatsCollector stats; // Implementation under test.
MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel();
// The content_name known by the voice channel.
const std::string kVcName("vcname");
cricket::VoiceChannel voice_channel(talk_base::Thread::Current(),
media_engine_, media_channel, &session_, kVcName, false);
AddLocalAudioTrackStats();
stats.AddStream(stream_);
stats.AddLocalAudioTrack(audio_track_.get(), kSsrcOfTrack);
stats.set_session(&session_);
// Instruct the session to return stats containing the transport channel.
InitSessionStats(kVcName);
EXPECT_CALL(session_, GetStats(_))
.WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
Return(true)));
cricket::VoiceSenderInfo voice_sender_info;
// Contents won't be modified by the AudioTrackInterface::GetStats().
voice_sender_info.add_ssrc(kSsrcOfTrack);
voice_sender_info.codec_name = "fake_codec";
voice_sender_info.bytes_sent = 100;
voice_sender_info.packets_sent = 101;
voice_sender_info.rtt_ms = 102;
voice_sender_info.fraction_lost = 103;
voice_sender_info.jitter_ms = 104;
voice_sender_info.packets_lost = 105;
voice_sender_info.ext_seqnum = 106;
// Contents will be modified by the AudioTrackInterface::GetStats().
voice_sender_info.audio_level = 107;
voice_sender_info.echo_return_loss = 108;;
voice_sender_info.echo_return_loss_enhancement = 109;
voice_sender_info.echo_delay_median_ms = 110;
voice_sender_info.echo_delay_std_ms = 111;
voice_sender_info.aec_quality_min = 112.0f;
voice_sender_info.typing_noise_detected = false;
// Constructs an ssrc stats update.
cricket::VoiceMediaInfo stats_read;
stats_read.senders.push_back(voice_sender_info);
EXPECT_CALL(session_, voice_channel()).WillRepeatedly(Return(&voice_channel));
EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
EXPECT_CALL(*media_channel, GetStats(_))
.WillRepeatedly(DoAll(SetArgPointee<0>(stats_read),
Return(true)));
StatsReports reports; // returned values.
stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
// Verfy the existence of the track report.
const StatsReport* report = FindNthReportByType(
reports, StatsReport::kStatsReportTypeSsrc, 1);
EXPECT_FALSE(report == NULL);
std::string track_id = ExtractSsrcStatsValue(
reports, StatsReport::kStatsValueNameTrackId);
EXPECT_EQ(kAudioTrackId, track_id);
std::string ssrc_id = ExtractSsrcStatsValue(
reports, StatsReport::kStatsValueNameSsrc);
EXPECT_EQ(talk_base::ToString<uint32>(kSsrcOfTrack), ssrc_id);
// Verifies the values in the track report.
audio_track_->GetSignalLevel(&voice_sender_info.audio_level);
webrtc::AudioProcessorInterface::AudioProcessorStats audio_processor_stats;
audio_track_->GetAudioProcessor()->GetStats(&audio_processor_stats);
voice_sender_info.typing_noise_detected =
audio_processor_stats.typing_noise_detected;
voice_sender_info.echo_return_loss = audio_processor_stats.echo_return_loss;
voice_sender_info.echo_return_loss_enhancement =
audio_processor_stats.echo_return_loss_enhancement;
voice_sender_info.echo_delay_median_ms =
audio_processor_stats.echo_delay_median_ms;
voice_sender_info.aec_quality_min = audio_processor_stats.aec_quality_min;
voice_sender_info.echo_delay_std_ms = audio_processor_stats.echo_delay_std_ms;
VerifyVoiceSenderInfoReport(report, voice_sender_info);
// Verify we get the same result by passing a track to GetStats().
StatsReports track_reports; // returned values.
stats.GetStats(audio_track_.get(), &track_reports);
const StatsReport* track_report = FindNthReportByType(
track_reports, StatsReport::kStatsReportTypeSsrc, 1);
EXPECT_FALSE(track_report == NULL);
track_id = ExtractSsrcStatsValue(track_reports,
StatsReport::kStatsValueNameTrackId);
EXPECT_EQ(kAudioTrackId, track_id);
ssrc_id = ExtractSsrcStatsValue(track_reports,
StatsReport::kStatsValueNameSsrc);
EXPECT_EQ(talk_base::ToString<uint32>(kSsrcOfTrack), ssrc_id);
VerifyVoiceSenderInfoReport(track_report, voice_sender_info);
}
// This test verifies that a local stats object won't update its statistics
// after a RemoveLocalAudioTrack() call.
TEST_F(StatsCollectorTest, GetStatsAfterRemoveAudioStream) {
webrtc::StatsCollector stats; // Implementation under test.
MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel();
// The content_name known by the voice channel.
const std::string kVcName("vcname");
cricket::VoiceChannel voice_channel(talk_base::Thread::Current(),
media_engine_, media_channel, &session_, kVcName, false);
AddLocalAudioTrackStats();
stats.AddStream(stream_);
stats.AddLocalAudioTrack(audio_track_.get(), kSsrcOfTrack);
stats.set_session(&session_);
// Instruct the session to return stats containing the transport channel.
InitSessionStats(kVcName);
EXPECT_CALL(session_, GetStats(_))
.WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
Return(true)));
stats.RemoveLocalAudioTrack(audio_track_.get(), kSsrcOfTrack);
cricket::VoiceSenderInfo voice_sender_info;
// Contents won't be modified by the AudioTrackInterface::GetStats().
voice_sender_info.add_ssrc(kSsrcOfTrack);
voice_sender_info.codec_name = "fake_codec";
voice_sender_info.bytes_sent = 100;
voice_sender_info.packets_sent = 101;
voice_sender_info.rtt_ms = 102;
voice_sender_info.fraction_lost = 103;
voice_sender_info.jitter_ms = 104;
voice_sender_info.packets_lost = 105;
voice_sender_info.ext_seqnum = 106;
// Contents will be modified by the AudioTrackInterface::GetStats().
voice_sender_info.audio_level = 107;
voice_sender_info.echo_return_loss = 108;;
voice_sender_info.echo_return_loss_enhancement = 109;
voice_sender_info.echo_delay_median_ms = 110;
voice_sender_info.echo_delay_std_ms = 111;
voice_sender_info.aec_quality_min = 112;
voice_sender_info.typing_noise_detected = false;
// Constructs an ssrc stats update.
cricket::VoiceMediaInfo stats_read;
stats_read.senders.push_back(voice_sender_info);
EXPECT_CALL(session_, voice_channel()).WillRepeatedly(Return(&voice_channel));
EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
EXPECT_CALL(*media_channel, GetStats(_))
.WillRepeatedly(DoAll(SetArgPointee<0>(stats_read),
Return(true)));
StatsReports reports; // returned values.
stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
// The report will exist since we don't remove them in RemoveStream().
const StatsReport* report = FindNthReportByType(
reports, StatsReport::kStatsReportTypeSsrc, 1);
EXPECT_FALSE(report == NULL);
std::string track_id = ExtractSsrcStatsValue(
reports, StatsReport::kStatsValueNameTrackId);
EXPECT_EQ(kAudioTrackId, track_id);
std::string ssrc_id = ExtractSsrcStatsValue(
reports, StatsReport::kStatsValueNameSsrc);
EXPECT_EQ(talk_base::ToString<uint32>(kSsrcOfTrack), ssrc_id);
// Verifies the values in the track report, no value will be changed by the
// AudioTrackInterface::GetSignalValue() and
// AudioProcessorInterface::AudioProcessorStats::GetStats();
VerifyVoiceSenderInfoReport(report, voice_sender_info);
}
} // namespace

View File

@ -57,6 +57,8 @@ class StatsReport {
void AddValue(const std::string& name, const std::vector<T>& value);
void AddBoolean(const std::string& name, bool value);
void ReplaceValue(const std::string& name, const std::string& value);
double timestamp; // Time since 1970-01-01T00:00:00Z in milliseconds.
typedef std::vector<Value> Values;
Values values;

View File

@ -122,7 +122,8 @@ class FakeMediaStreamSignaling : public webrtc::MediaStreamSignaling,
virtual void OnRemoveLocalAudioTrack(
webrtc::MediaStreamInterface* stream,
webrtc::AudioTrackInterface* audio_track) {
webrtc::AudioTrackInterface* audio_track,
uint32 ssrc) {
}
virtual void OnRemoveLocalVideoTrack(
webrtc::MediaStreamInterface* stream,

View File

@ -45,9 +45,6 @@
#include "talk/examples/call/console.h"
#include "talk/examples/call/mediaenginefactory.h"
#include "talk/p2p/base/constants.h"
#ifdef ANDROID
#include "talk/media/other/androidmediaengine.h"
#endif
#include "talk/session/media/mediasessionclient.h"
#include "talk/session/media/srtpfilter.h"
#include "talk/xmpp/xmppauth.h"
@ -185,7 +182,7 @@ static const int DEFAULT_PORT = 5222;
static std::vector<cricket::AudioCodec> codecs;
static const cricket::AudioCodec ISAC(103, "ISAC", 40000, 16000, 1, 0);
cricket::MediaEngine *AndroidMediaEngineFactory() {
cricket::MediaEngineInterface *CreateAndroidMediaEngine() {
cricket::FakeMediaEngine *engine = new cricket::FakeMediaEngine();
codecs.push_back(ISAC);
@ -438,7 +435,7 @@ int main(int argc, char **argv) {
}
#ifdef ANDROID
InitAndroidMediaEngineFactory(AndroidMediaEngineFactory);
MediaEngineFactory::SetCreateFunction(&CreateAndroidMediaEngine);
#endif
#if WIN32

View File

@ -42,6 +42,13 @@ const int MediaEngineInterface::kDefaultAudioDelayOffset = 0;
#if defined(HAVE_WEBRTC_VIDEO)
#include "talk/media/webrtc/webrtcvideoengine.h"
#endif // HAVE_WEBRTC_VIDEO
#if defined(HAVE_LMI)
#include "talk/media/base/hybridvideoengine.h"
#include "talk/media/lmi/lmimediaengine.h"
#endif // HAVE_LMI
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG
namespace cricket {
#if defined(HAVE_WEBRTC_VOICE)
@ -51,22 +58,59 @@ namespace cricket {
#endif
#if defined(HAVE_WEBRTC_VIDEO)
#if !defined(HAVE_LMI)
template<>
CompositeMediaEngine<WebRtcVoiceEngine, WebRtcVideoEngine>::
CompositeMediaEngine() {
video_.SetVoiceEngine(&voice_);
}
#define VIDEO_ENG_NAME WebRtcVideoEngine
#else
// If we have both WebRtcVideoEngine and LmiVideoEngine, enable dual-stack.
// This small class here allows us to hook the WebRtcVideoChannel up to
// the capturer owned by the LMI engine, without infecting the rest of the
// HybridVideoEngine classes with this abstraction violation.
class WebRtcLmiHybridVideoEngine
: public HybridVideoEngine<WebRtcVideoEngine, LmiVideoEngine> {
public:
void SetVoiceEngine(WebRtcVoiceEngine* engine) {
video1_.SetVoiceEngine(engine);
}
};
template<>
CompositeMediaEngine<WebRtcVoiceEngine, WebRtcLmiHybridVideoEngine>::
CompositeMediaEngine() {
video_.SetVoiceEngine(&voice_);
}
#define VIDEO_ENG_NAME WebRtcLmiHybridVideoEngine
#endif
#elif defined(HAVE_LMI)
#define VIDEO_ENG_NAME LmiVideoEngine
#else
#define VIDEO_ENG_NAME NullVideoEngine
#endif
MediaEngineFactory::MediaEngineCreateFunction
MediaEngineFactory::create_function_ = NULL;
MediaEngineFactory::MediaEngineCreateFunction
MediaEngineFactory::SetCreateFunction(MediaEngineCreateFunction function) {
MediaEngineCreateFunction old_function = create_function_;
create_function_ = function;
return old_function;
};
MediaEngineInterface* MediaEngineFactory::Create() {
if (create_function_) {
return create_function_();
} else {
#if defined(HAVE_LINPHONE)
return new LinphoneMediaEngine("", "");
return new LinphoneMediaEngine("", "");
#elif defined(AUDIO_ENG_NAME) && defined(VIDEO_ENG_NAME)
return new CompositeMediaEngine<AUDIO_ENG_NAME, VIDEO_ENG_NAME>();
return new CompositeMediaEngine<AUDIO_ENG_NAME, VIDEO_ENG_NAME>();
#else
return new NullMediaEngine();
return new NullMediaEngine();
#endif
}
}
}; // namespace cricket

View File

@ -157,7 +157,18 @@ class MediaEngineInterface {
#if !defined(DISABLE_MEDIA_ENGINE_FACTORY)
class MediaEngineFactory {
public:
typedef cricket::MediaEngineInterface* (*MediaEngineCreateFunction)();
// Creates a media engine, using either the compiled system default or the
// creation function specified in SetCreateFunction, if specified.
static MediaEngineInterface* Create();
// Sets the function used when calling Create. If unset, the compiled system
// default will be used. Returns the old create function, or NULL if one
// wasn't set. Likewise, NULL can be used as the |function| parameter to
// reset to the default behavior.
static MediaEngineCreateFunction SetCreateFunction(
MediaEngineCreateFunction function);
private:
static MediaEngineCreateFunction create_function_;
};
#endif

View File

View File