Update libjingle to 53856368.
R=mallinath@webrtc.org Review URL: https://webrtc-codereview.appspot.com/2366004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@4941 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
@@ -85,6 +85,7 @@ const char* kRtcpFbCcmParamFir = "fir";
|
||||
const char* kCodecParamMaxBitrate = "x-google-max-bitrate";
|
||||
const char* kCodecParamMinBitrate = "x-google-min-bitrate";
|
||||
const char* kCodecParamMaxQuantization = "x-google-max-quantization";
|
||||
const char* kCodecParamPort = "x-google-port";
|
||||
|
||||
const int kGoogleRtpDataCodecId = 101;
|
||||
const char kGoogleRtpDataCodecName[] = "google-data";
|
||||
|
||||
@@ -99,6 +99,7 @@ extern const char* kRtcpFbCcmParamFir;
|
||||
extern const char* kCodecParamMaxBitrate;
|
||||
extern const char* kCodecParamMinBitrate;
|
||||
extern const char* kCodecParamMaxQuantization;
|
||||
extern const char* kCodecParamPort;
|
||||
|
||||
// We put the data codec names here so callers of
|
||||
// DataEngine::CreateChannel don't have to import rtpdataengine.h or
|
||||
|
||||
@@ -837,6 +837,9 @@ class FakeVideoEngine : public FakeBaseEngine {
|
||||
default_encoder_config_ = config;
|
||||
return true;
|
||||
}
|
||||
VideoEncoderConfig GetDefaultEncoderConfig() const {
|
||||
return default_encoder_config_;
|
||||
}
|
||||
const VideoEncoderConfig& default_encoder_config() const {
|
||||
return default_encoder_config_;
|
||||
}
|
||||
|
||||
@@ -93,6 +93,9 @@ class FileMediaEngine : public MediaEngineInterface {
|
||||
virtual bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config) {
|
||||
return true;
|
||||
}
|
||||
virtual VideoEncoderConfig GetDefaultVideoEncoderConfig() const {
|
||||
return VideoEncoderConfig();
|
||||
}
|
||||
virtual bool SetSoundDevices(const Device* in_dev, const Device* out_dev) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -204,6 +204,20 @@ class HybridVideoEngine : public HybridVideoEngineInterface {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
VideoEncoderConfig GetDefaultEncoderConfig() const {
|
||||
// This looks pretty strange, but, in practice, it'll do sane things if
|
||||
// GetDefaultEncoderConfig is only called after SetDefaultEncoderConfig,
|
||||
// since both engines should be essentially equivalent at that point. If it
|
||||
// hasn't been called, though, we'll use the first meaningful encoder
|
||||
// config, or the config from the second video engine if neither are
|
||||
// meaningful.
|
||||
VideoEncoderConfig config = video1_.GetDefaultEncoderConfig();
|
||||
if (config.max_codec.width != 0) {
|
||||
return config;
|
||||
} else {
|
||||
return video2_.GetDefaultEncoderConfig();
|
||||
}
|
||||
}
|
||||
const std::vector<VideoCodec>& codecs() const {
|
||||
return codecs_;
|
||||
}
|
||||
|
||||
@@ -98,6 +98,10 @@ class MediaEngineInterface {
|
||||
// and encode video.
|
||||
virtual bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config)
|
||||
= 0;
|
||||
// Gets the default (maximum) codec/resolution and encoder option used to
|
||||
// capture and encode video, as set by SetDefaultVideoEncoderConfig or the
|
||||
// default from the video engine if not previously set.
|
||||
virtual VideoEncoderConfig GetDefaultVideoEncoderConfig() const = 0;
|
||||
|
||||
// Device selection
|
||||
// TODO(tschmelcher): Add method for selecting the soundclip device.
|
||||
@@ -203,6 +207,9 @@ class CompositeMediaEngine : public MediaEngineInterface {
|
||||
virtual bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config) {
|
||||
return video_.SetDefaultEncoderConfig(config);
|
||||
}
|
||||
virtual VideoEncoderConfig GetDefaultVideoEncoderConfig() const {
|
||||
return video_.GetDefaultEncoderConfig();
|
||||
}
|
||||
|
||||
virtual bool SetSoundDevices(const Device* in_device,
|
||||
const Device* out_device) {
|
||||
@@ -327,6 +334,9 @@ class NullVideoEngine {
|
||||
return NULL;
|
||||
}
|
||||
bool SetOptions(const VideoOptions& options) { return true; }
|
||||
VideoEncoderConfig GetDefaultEncoderConfig() const {
|
||||
return VideoEncoderConfig();
|
||||
}
|
||||
bool SetDefaultEncoderConfig(const VideoEncoderConfig& config) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,10 @@
|
||||
|
||||
#include "talk/media/devices/libudevsymboltable.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "talk/base/logging.h"
|
||||
|
||||
namespace cricket {
|
||||
|
||||
#define LATE_BINDING_SYMBOL_TABLE_CLASS_NAME LIBUDEV_SYMBOLS_CLASS_NAME
|
||||
@@ -37,4 +41,30 @@ namespace cricket {
|
||||
#undef LATE_BINDING_SYMBOL_TABLE_SYMBOLS_LIST
|
||||
#undef LATE_BINDING_SYMBOL_TABLE_DLL_NAME
|
||||
|
||||
bool IsWrongLibUDevAbiVersion(talk_base::DllHandle libudev_0) {
|
||||
talk_base::DllHandle libudev_1 = dlopen("libudev.so.1", RTLD_NOW|RTLD_NOLOAD);
|
||||
bool unsafe_symlink = (libudev_0 == libudev_1);
|
||||
if (unsafe_symlink) {
|
||||
// .0 and .1 are distinct ABIs, so if they point to the same thing then one
|
||||
// of them must be wrong. Probably the old has been symlinked to the new in
|
||||
// a misguided attempt at backwards compatibility.
|
||||
LOG(LS_ERROR) << "libudev.so.0 and libudev.so.1 unsafely point to the"
|
||||
" same thing; not using libudev";
|
||||
} else if (libudev_1) {
|
||||
// If libudev.so.1 is resident but distinct from libudev.so.0, then some
|
||||
// system library loaded the new ABI separately. This is not a problem for
|
||||
// LateBindingSymbolTable because its symbol look-ups are restricted to its
|
||||
// DllHandle, but having libudev.so.0 resident may cause problems for that
|
||||
// system library because symbol names are not namespaced by DLL.
|
||||
LOG(LS_WARNING)
|
||||
<< "libudev.so.1 is resident but distinct from libudev.so.0";
|
||||
}
|
||||
if (libudev_1) {
|
||||
// Release the refcount that we acquired above. (Does not unload the DLL;
|
||||
// whoever loaded it still needs it.)
|
||||
dlclose(libudev_1);
|
||||
}
|
||||
return unsafe_symlink;
|
||||
}
|
||||
|
||||
} // namespace cricket
|
||||
|
||||
@@ -66,6 +66,14 @@ namespace cricket {
|
||||
#undef LATE_BINDING_SYMBOL_TABLE_CLASS_NAME
|
||||
#undef LATE_BINDING_SYMBOL_TABLE_SYMBOLS_LIST
|
||||
|
||||
// libudev has changed ABIs to libudev.so.1 in recent distros and lots of users
|
||||
// and/or software (including Google Chrome) are symlinking the old to the new.
|
||||
// The entire point of ABI versions is that you can't safely do that, and
|
||||
// it has caused crashes in the wild. This function checks if the DllHandle that
|
||||
// we got back for libudev.so.0 is actually for libudev.so.1. If so, the library
|
||||
// cannot safely be used.
|
||||
bool IsWrongLibUDevAbiVersion(talk_base::DllHandle libudev_0);
|
||||
|
||||
} // namespace cricket
|
||||
|
||||
#endif // TALK_MEDIA_DEVICES_LIBUDEVSYMBOLTABLE_H_
|
||||
|
||||
@@ -52,7 +52,8 @@ class ScopedLibUdev {
|
||||
ScopedLibUdev() {}
|
||||
|
||||
bool Init() {
|
||||
return libudev_.Load();
|
||||
return libudev_.Load() &&
|
||||
!IsWrongLibUDevAbiVersion(libudev_.GetDllHandle());
|
||||
}
|
||||
|
||||
LibUDevSymbolTable libudev_;
|
||||
|
||||
@@ -306,8 +306,9 @@ bool LinuxDeviceWatcher::Start() {
|
||||
// We deliberately return true in the failure paths here because libudev is
|
||||
// not a critical component of a Linux system so it may not be present/usable,
|
||||
// and we don't want to halt LinuxDeviceManager initialization in such a case.
|
||||
if (!libudev_.Load()) {
|
||||
LOG(LS_WARNING) << "libudev not present/usable; LinuxDeviceWatcher disabled";
|
||||
if (!libudev_.Load() || IsWrongLibUDevAbiVersion(libudev_.GetDllHandle())) {
|
||||
LOG(LS_WARNING)
|
||||
<< "libudev not present/usable; LinuxDeviceWatcher disabled";
|
||||
return true;
|
||||
}
|
||||
udev_ = libudev_.udev_new()();
|
||||
|
||||
@@ -242,8 +242,8 @@ DataMediaChannel* SctpDataEngine::CreateChannel(
|
||||
|
||||
SctpDataMediaChannel::SctpDataMediaChannel(talk_base::Thread* thread)
|
||||
: worker_thread_(thread),
|
||||
local_port_(kSctpDefaultPort),
|
||||
remote_port_(kSctpDefaultPort),
|
||||
local_port_(-1),
|
||||
remote_port_(-1),
|
||||
sock_(NULL),
|
||||
sending_(false),
|
||||
receiving_(false),
|
||||
@@ -344,6 +344,12 @@ void SctpDataMediaChannel::CloseSctpSocket() {
|
||||
|
||||
bool SctpDataMediaChannel::Connect() {
|
||||
LOG(LS_VERBOSE) << debug_name_ << "->Connect().";
|
||||
if (remote_port_ < 0) {
|
||||
remote_port_ = kSctpDefaultPort;
|
||||
}
|
||||
if (local_port_ < 0) {
|
||||
local_port_ = kSctpDefaultPort;
|
||||
}
|
||||
|
||||
// If we already have a socket connection, just return.
|
||||
if (sock_) {
|
||||
@@ -677,6 +683,38 @@ void SctpDataMediaChannel::OnNotificationAssocChange(
|
||||
}
|
||||
}
|
||||
|
||||
// Puts the specified |param| from the codec identified by |id| into |dest|
|
||||
// and returns true. Or returns false if it wasn't there, leaving |dest|
|
||||
// untouched.
|
||||
static bool GetCodecIntParameter(const std::vector<DataCodec>& codecs,
|
||||
int id, const std::string& name,
|
||||
const std::string& param, int* dest) {
|
||||
std::string value;
|
||||
Codec match_pattern;
|
||||
match_pattern.id = id;
|
||||
match_pattern.name = name;
|
||||
for (size_t i = 0; i < codecs.size(); ++i) {
|
||||
if (codecs[i].Matches(match_pattern)) {
|
||||
if (codecs[i].GetParam(param, &value)) {
|
||||
*dest = talk_base::FromString<int>(value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SctpDataMediaChannel::SetSendCodecs(const std::vector<DataCodec>& codecs) {
|
||||
return GetCodecIntParameter(
|
||||
codecs, kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, kCodecParamPort,
|
||||
&remote_port_);
|
||||
}
|
||||
|
||||
bool SctpDataMediaChannel::SetRecvCodecs(const std::vector<DataCodec>& codecs) {
|
||||
return GetCodecIntParameter(
|
||||
codecs, kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, kCodecParamPort,
|
||||
&local_port_);
|
||||
}
|
||||
|
||||
void SctpDataMediaChannel::OnPacketFromSctpToNetwork(
|
||||
talk_base::Buffer* buffer) {
|
||||
|
||||
@@ -168,12 +168,8 @@ class SctpDataMediaChannel : public DataMediaChannel,
|
||||
const std::vector<RtpHeaderExtension>& extensions) { return true; }
|
||||
virtual bool SetSendRtpHeaderExtensions(
|
||||
const std::vector<RtpHeaderExtension>& extensions) { return true; }
|
||||
virtual bool SetSendCodecs(const std::vector<DataCodec>& codecs) {
|
||||
return true;
|
||||
}
|
||||
virtual bool SetRecvCodecs(const std::vector<DataCodec>& codecs) {
|
||||
return true;
|
||||
}
|
||||
virtual bool SetSendCodecs(const std::vector<DataCodec>& codecs);
|
||||
virtual bool SetRecvCodecs(const std::vector<DataCodec>& codecs);
|
||||
virtual void OnRtcpReceived(talk_base::Buffer* packet) {}
|
||||
virtual void OnReadyToSend(bool ready) {}
|
||||
|
||||
@@ -211,7 +207,8 @@ class SctpDataMediaChannel : public DataMediaChannel,
|
||||
talk_base::Thread* worker_thread_;
|
||||
// The local and remote SCTP port to use. These are passed along the wire
|
||||
// and the listener and connector must be using the same port. It is not
|
||||
// related to the ports at the IP level.
|
||||
// related to the ports at the IP level. If set to -1, we default to
|
||||
// kSctpDefaultPort.
|
||||
int local_port_;
|
||||
int remote_port_;
|
||||
struct socket* sock_; // The socket created by usrsctp_socket(...).
|
||||
|
||||
@@ -318,20 +318,32 @@ class WebRtcDecoderObserver : public webrtc::ViEDecoderObserver {
|
||||
virtual void IncomingRate(const int videoChannel,
|
||||
const unsigned int framerate,
|
||||
const unsigned int bitrate) {
|
||||
talk_base::CritScope cs(&crit_);
|
||||
ASSERT(video_channel_ == videoChannel);
|
||||
framerate_ = framerate;
|
||||
bitrate_ = bitrate;
|
||||
}
|
||||
virtual void RequestNewKeyFrame(const int videoChannel) {
|
||||
talk_base::CritScope cs(&crit_);
|
||||
ASSERT(video_channel_ == videoChannel);
|
||||
++firs_requested_;
|
||||
}
|
||||
|
||||
int framerate() const { return framerate_; }
|
||||
int bitrate() const { return bitrate_; }
|
||||
int firs_requested() const { return firs_requested_; }
|
||||
int framerate() const {
|
||||
talk_base::CritScope cs(&crit_);
|
||||
return framerate_;
|
||||
}
|
||||
int bitrate() const {
|
||||
talk_base::CritScope cs(&crit_);
|
||||
return bitrate_;
|
||||
}
|
||||
int firs_requested() const {
|
||||
talk_base::CritScope cs(&crit_);
|
||||
return firs_requested_;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable talk_base::CriticalSection crit_;
|
||||
int video_channel_;
|
||||
int framerate_;
|
||||
int bitrate_;
|
||||
@@ -350,15 +362,23 @@ class WebRtcEncoderObserver : public webrtc::ViEEncoderObserver {
|
||||
virtual void OutgoingRate(const int videoChannel,
|
||||
const unsigned int framerate,
|
||||
const unsigned int bitrate) {
|
||||
talk_base::CritScope cs(&crit_);
|
||||
ASSERT(video_channel_ == videoChannel);
|
||||
framerate_ = framerate;
|
||||
bitrate_ = bitrate;
|
||||
}
|
||||
|
||||
int framerate() const { return framerate_; }
|
||||
int bitrate() const { return bitrate_; }
|
||||
int framerate() const {
|
||||
talk_base::CritScope cs(&crit_);
|
||||
return framerate_;
|
||||
}
|
||||
int bitrate() const {
|
||||
talk_base::CritScope cs(&crit_);
|
||||
return bitrate_;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable talk_base::CriticalSection crit_;
|
||||
int video_channel_;
|
||||
int framerate_;
|
||||
int bitrate_;
|
||||
@@ -914,6 +934,17 @@ bool WebRtcVideoEngine::SetDefaultEncoderConfig(
|
||||
return SetDefaultCodec(config.max_codec);
|
||||
}
|
||||
|
||||
VideoEncoderConfig WebRtcVideoEngine::GetDefaultEncoderConfig() const {
|
||||
ASSERT(!video_codecs_.empty());
|
||||
VideoCodec max_codec(kVideoCodecPrefs[0].payload_type,
|
||||
kVideoCodecPrefs[0].name,
|
||||
video_codecs_[0].width,
|
||||
video_codecs_[0].height,
|
||||
video_codecs_[0].framerate,
|
||||
0);
|
||||
return VideoEncoderConfig(max_codec);
|
||||
}
|
||||
|
||||
// SetDefaultCodec may be called while the capturer is running. For example, a
|
||||
// test call is started in a page with QVGA default codec, and then a real call
|
||||
// is started in another page with VGA default codec. This is the corner case
|
||||
@@ -924,6 +955,7 @@ bool WebRtcVideoEngine::SetDefaultCodec(const VideoCodec& codec) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ASSERT(!video_codecs_.empty());
|
||||
default_codec_format_ = VideoFormat(
|
||||
video_codecs_[0].width,
|
||||
video_codecs_[0].height,
|
||||
|
||||
@@ -106,6 +106,7 @@ class WebRtcVideoEngine : public sigslot::has_slots<>,
|
||||
int GetCapabilities();
|
||||
bool SetOptions(const VideoOptions &options);
|
||||
bool SetDefaultEncoderConfig(const VideoEncoderConfig& config);
|
||||
VideoEncoderConfig GetDefaultEncoderConfig() const;
|
||||
|
||||
WebRtcVideoMediaChannel* CreateChannel(VoiceMediaChannel* voice_channel);
|
||||
|
||||
|
||||
@@ -2158,6 +2158,11 @@ bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) {
|
||||
return false;
|
||||
uint32 ssrc = sp.first_ssrc();
|
||||
|
||||
if (ssrc == 0) {
|
||||
LOG(LS_WARNING) << "AddRecvStream with 0 ssrc is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (receive_channels_.find(ssrc) != receive_channels_.end()) {
|
||||
LOG(LS_ERROR) << "Stream already exists with ssrc " << ssrc;
|
||||
return false;
|
||||
@@ -2181,6 +2186,21 @@ bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ConfigureRecvChannel(channel)) {
|
||||
DeleteChannel(channel);
|
||||
return false;
|
||||
}
|
||||
|
||||
receive_channels_.insert(
|
||||
std::make_pair(ssrc, WebRtcVoiceChannelInfo(channel, NULL)));
|
||||
|
||||
LOG(LS_INFO) << "New audio stream " << ssrc
|
||||
<< " registered to VoiceEngine channel #"
|
||||
<< channel << ".";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebRtcVoiceMediaChannel::ConfigureRecvChannel(int channel) {
|
||||
// Configure to use external transport, like our default channel.
|
||||
if (engine()->voe()->network()->RegisterExternalTransport(
|
||||
channel, *this) == -1) {
|
||||
@@ -2237,13 +2257,6 @@ bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) {
|
||||
}
|
||||
SetNack(channel, nack_enabled_);
|
||||
|
||||
receive_channels_.insert(
|
||||
std::make_pair(ssrc, WebRtcVoiceChannelInfo(channel, NULL)));
|
||||
|
||||
// TODO(juberti): We should rollback the add if SetPlayout fails.
|
||||
LOG(LS_INFO) << "New audio stream " << ssrc
|
||||
<< " registered to VoiceEngine channel #"
|
||||
<< channel << ".";
|
||||
return SetPlayout(channel, playout_);
|
||||
}
|
||||
|
||||
|
||||
@@ -381,6 +381,7 @@ class WebRtcVoiceMediaChannel
|
||||
bool ChangeSend(SendFlags send);
|
||||
bool ChangeSend(int channel, SendFlags send);
|
||||
void ConfigureSendChannel(int channel);
|
||||
bool ConfigureRecvChannel(int channel);
|
||||
bool DeleteChannel(int channel);
|
||||
bool InConferenceMode() const {
|
||||
return options_.conference_mode.GetWithDefaultIfUnset(false);
|
||||
|
||||
@@ -2044,6 +2044,26 @@ TEST_F(WebRtcVoiceEngineTestFake, StreamCleanup) {
|
||||
EXPECT_EQ(0, voe_.GetNumChannels());
|
||||
}
|
||||
|
||||
TEST_F(WebRtcVoiceEngineTestFake, TestAddRecvStreamFailWithZeroSsrc) {
|
||||
EXPECT_TRUE(SetupEngine());
|
||||
EXPECT_FALSE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(0)));
|
||||
}
|
||||
|
||||
TEST_F(WebRtcVoiceEngineTestFake, TestNoLeakingWhenAddRecvStreamFail) {
|
||||
EXPECT_TRUE(SetupEngine());
|
||||
// Stream 1 reuses default channel.
|
||||
EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(1)));
|
||||
// Manually delete default channel to simulate a failure.
|
||||
int default_channel = voe_.GetLastChannel();
|
||||
EXPECT_EQ(0, voe_.DeleteChannel(default_channel));
|
||||
// Add recv stream 2 should fail because default channel is gone.
|
||||
EXPECT_FALSE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2)));
|
||||
int new_channel = voe_.GetLastChannel();
|
||||
EXPECT_NE(default_channel, new_channel);
|
||||
// The last created channel should have already been deleted.
|
||||
EXPECT_EQ(-1, voe_.DeleteChannel(new_channel));
|
||||
}
|
||||
|
||||
// Test the InsertDtmf on default send stream as caller.
|
||||
TEST_F(WebRtcVoiceEngineTestFake, InsertDtmfOnDefaultSendStreamAsCaller) {
|
||||
TestInsertDtmf(0, true);
|
||||
|
||||
Reference in New Issue
Block a user