diff options
author | Torne (Richard Coles) <torne@google.com> | 2014-11-12 00:42:02 +0000 |
---|---|---|
committer | Torne (Richard Coles) <torne@google.com> | 2014-11-12 00:42:02 +0000 |
commit | c8429e63ec07341d0055a8f31f66a995d62f8555 (patch) | |
tree | 3c7d78d81b4c69cae88708e072ba9eee0bec0257 | |
parent | 4a7f10204c64726a266cb4f3e18529f5656e50a8 (diff) | |
parent | f97800413f157c911aefbf5be167dbd4806a2323 (diff) | |
download | talk-c8429e63ec07341d0055a8f31f66a995d62f8555.tar.gz |
Merge third_party/libjingle/source/talk from https://chromium.googlesource.com/external/webrtc/trunk/talk.git at f97800413f157c911aefbf5be167dbd4806a2323
This commit was generated by merge_from_chromium.py.
Change-Id: Ie174f5f2a901346a28e1887ee81dcd22b2fc6dff
22 files changed, 424 insertions, 335 deletions
diff --git a/app/webrtc/peerconnection.cc b/app/webrtc/peerconnection.cc index b64caf7..64ddcad 100644 --- a/app/webrtc/peerconnection.cc +++ b/app/webrtc/peerconnection.cc @@ -420,11 +420,6 @@ bool PeerConnection::AddStream(MediaStreamInterface* local_stream) { return true; } -bool PeerConnection::AddStream(MediaStreamInterface* local_stream, - const MediaConstraintsInterface* constraints) { - return AddStream(local_stream); -} - void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) { mediastream_signaling_->RemoveLocalStream(local_stream); if (IsClosed()) { diff --git a/app/webrtc/peerconnection.h b/app/webrtc/peerconnection.h index 355211c..68aa154 100644 --- a/app/webrtc/peerconnection.h +++ b/app/webrtc/peerconnection.h @@ -66,8 +66,6 @@ class PeerConnection : public PeerConnectionInterface, virtual rtc::scoped_refptr<StreamCollectionInterface> local_streams(); virtual rtc::scoped_refptr<StreamCollectionInterface> remote_streams(); virtual bool AddStream(MediaStreamInterface* local_stream); - virtual bool AddStream(MediaStreamInterface* local_stream, - const MediaConstraintsInterface* constraints); virtual void RemoveStream(MediaStreamInterface* local_stream); virtual rtc::scoped_refptr<DtmfSenderInterface> CreateDtmfSender( diff --git a/app/webrtc/peerconnectioninterface.h b/app/webrtc/peerconnectioninterface.h index 68b7879..73a4812 100644 --- a/app/webrtc/peerconnectioninterface.h +++ b/app/webrtc/peerconnectioninterface.h @@ -255,15 +255,7 @@ class PeerConnectionInterface : public rtc::RefCountInterface { // Add a new MediaStream to be sent on this PeerConnection. // Note that a SessionDescription negotiation is needed before the // remote peer can receive the stream. - // TODO(perkj): Make pure virtual once Chrome mocks have implemented. - virtual bool AddStream(MediaStreamInterface* stream) { return false;} - - // Deprecated: - // TODO(perkj): Remove once its not used by Chrome. - virtual bool AddStream(MediaStreamInterface* stream, - const MediaConstraintsInterface* constraints) { - return false; - } + virtual bool AddStream(MediaStreamInterface* stream) = 0; // Remove a MediaStream from this PeerConnection. // Note that a SessionDescription negotiation is need before the @@ -351,10 +343,6 @@ class PeerConnectionObserver { kIceState, }; - // Deprecated. - // TODO(perkj): Remove once its not used by Chrome. - virtual void OnError() {} - // Triggered when the SignalingState changed. virtual void OnSignalingChange( PeerConnectionInterface::SignalingState new_state) {} diff --git a/app/webrtc/peerconnectionproxy.h b/app/webrtc/peerconnectionproxy.h index 571c676..852d852 100644 --- a/app/webrtc/peerconnectionproxy.h +++ b/app/webrtc/peerconnectionproxy.h @@ -40,8 +40,6 @@ BEGIN_PROXY_MAP(PeerConnection) PROXY_METHOD0(rtc::scoped_refptr<StreamCollectionInterface>, remote_streams) PROXY_METHOD1(bool, AddStream, MediaStreamInterface*) - PROXY_METHOD2(bool, AddStream, MediaStreamInterface*, - const MediaConstraintsInterface*); PROXY_METHOD1(void, RemoveStream, MediaStreamInterface*) PROXY_METHOD1(rtc::scoped_refptr<DtmfSenderInterface>, CreateDtmfSender, AudioTrackInterface*) diff --git a/app/webrtc/webrtcsdp.cc b/app/webrtc/webrtcsdp.cc index 23b8f3d..c7b34c4 100644 --- a/app/webrtc/webrtcsdp.cc +++ b/app/webrtc/webrtcsdp.cc @@ -206,7 +206,9 @@ static const char kMediaPortRejected[] = "0"; // draft-ietf-mmusic-trickle-ice-01 // When no candidates have been gathered, set the connection // address to IP6 ::. -static const char kDummyAddress[] = "::"; +// TODO(perkj): FF can not parse IP6 ::. See http://crbug/430333 +// Use IPV4 per default. +static const char kDummyAddress[] = "0.0.0.0"; static const char kDummyPort[] = "9"; // RFC 3556 static const char kApplicationSpecificMaximum[] = "AS"; @@ -675,7 +677,7 @@ static void GetDefaultDestination( const std::vector<Candidate>& candidates, int component_id, std::string* port, std::string* ip, std::string* addr_type) { - *addr_type = kConnectionIpv6Addrtype; + *addr_type = kConnectionIpv4Addrtype; *port = kDummyPort; *ip = kDummyAddress; int current_preference = kPreferenceUnknown; diff --git a/app/webrtc/webrtcsdp_unittest.cc b/app/webrtc/webrtcsdp_unittest.cc index ea590db..8655487 100644 --- a/app/webrtc/webrtcsdp_unittest.cc +++ b/app/webrtc/webrtcsdp_unittest.cc @@ -213,8 +213,8 @@ static const char kSdpString[] = "t=0 0\r\n" "a=msid-semantic: WMS local_stream_1 local_stream_2\r\n" "m=audio 9 RTP/SAVPF 111 103 104\r\n" - "c=IN IP6 ::\r\n" - "a=rtcp:9 IN IP6 ::\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp:9 IN IP4 0.0.0.0\r\n" "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n" "a=mid:audio_content_name\r\n" "a=sendrecv\r\n" @@ -234,8 +234,8 @@ static const char kSdpString[] = "a=ssrc:4 mslabel:local_stream_2\r\n" "a=ssrc:4 label:audio_track_id_2\r\n" "m=video 9 RTP/SAVPF 120\r\n" - "c=IN IP6 ::\r\n" - "a=rtcp:9 IN IP6 ::\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp:9 IN IP4 0.0.0.0\r\n" "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n" "a=mid:video_content_name\r\n" "a=sendrecv\r\n" @@ -262,8 +262,8 @@ static const char kSdpString[] = static const char kSdpRtpDataChannelString[] = "m=application 9 RTP/SAVPF 101\r\n" - "c=IN IP6 ::\r\n" - "a=rtcp:9 IN IP6 ::\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp:9 IN IP4 0.0.0.0\r\n" "a=ice-ufrag:ufrag_data\r\n" "a=ice-pwd:pwd_data\r\n" "a=mid:data_content_name\r\n" @@ -278,7 +278,7 @@ static const char kSdpRtpDataChannelString[] = static const char kSdpSctpDataChannelString[] = "m=application 9 DTLS/SCTP 5000\r\n" - "c=IN IP6 ::\r\n" + "c=IN IP4 0.0.0.0\r\n" "a=ice-ufrag:ufrag_data\r\n" "a=ice-pwd:pwd_data\r\n" "a=mid:data_content_name\r\n" @@ -289,7 +289,7 @@ static const char kSdpSctpDataChannelStringWithSctpPort[] = "m=application 9 DTLS/SCTP webrtc-datachannel\r\n" "a=fmtp:webrtc-datachannel max-message-size=100000\r\n" "a=sctp-port 5000\r\n" - "c=IN IP6 ::\r\n" + "c=IN IP4 0.0.0.0\r\n" "a=ice-ufrag:ufrag_data\r\n" "a=ice-pwd:pwd_data\r\n" "a=mid:data_content_name\r\n"; @@ -316,10 +316,10 @@ static const char kSdpConferenceString[] = "t=0 0\r\n" "a=msid-semantic: WMS\r\n" "m=audio 9 RTP/SAVPF 111 103 104\r\n" - "c=IN IP6 ::\r\n" + "c=IN IP4 0.0.0.0\r\n" "a=x-google-flag:conference\r\n" "m=video 9 RTP/SAVPF 120\r\n" - "c=IN IP6 ::\r\n" + "c=IN IP4 0.0.0.0\r\n" "a=x-google-flag:conference\r\n"; static const char kSdpSessionString[] = @@ -331,8 +331,8 @@ static const char kSdpSessionString[] = static const char kSdpAudioString[] = "m=audio 9 RTP/SAVPF 111\r\n" - "c=IN IP6 ::\r\n" - "a=rtcp:9 IN IP6 ::\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp:9 IN IP4 0.0.0.0\r\n" "a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n" "a=mid:audio_content_name\r\n" "a=sendrecv\r\n" @@ -344,8 +344,8 @@ static const char kSdpAudioString[] = static const char kSdpVideoString[] = "m=video 9 RTP/SAVPF 120\r\n" - "c=IN IP6 ::\r\n" - "a=rtcp:9 IN IP6 ::\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp:9 IN IP4 0.0.0.0\r\n" "a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n" "a=mid:video_content_name\r\n" "a=sendrecv\r\n" @@ -1596,7 +1596,7 @@ TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithDataChannelAndBandwidth) { // TODO(pthatcher): We need to temporarily allow the SDP to control // this for backwards-compatibility. Once we don't need that any // more, remove this. - InjectAfter("m=application 9 RTP/SAVPF 101\r\nc=IN IP6 ::\r\n", + InjectAfter("m=application 9 RTP/SAVPF 101\r\nc=IN IP4 0.0.0.0\r\n", "b=AS:100\r\n", &expected_sdp); EXPECT_EQ(expected_sdp, message); diff --git a/examples/android/src/org/appspot/apprtc/AppRTCAudioManager.java b/examples/android/src/org/appspot/apprtc/AppRTCAudioManager.java new file mode 100644 index 0000000..b2a1a44 --- /dev/null +++ b/examples/android/src/org/appspot/apprtc/AppRTCAudioManager.java @@ -0,0 +1,108 @@ +/* + * libjingle + * Copyright 2013, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.appspot.apprtc; + +import android.content.Context; +import android.media.AudioManager; +import android.util.Log; + +/** + * AppRTCAudioManager manages all audio related parts of the AppRTC demo. + * TODO(henrika): add support for device enumeration, device selection etc. + */ +public class AppRTCAudioManager { + private static final String TAG = "AppRTCAudioManager"; + + private boolean initialized = false; + private AudioManager audioManager; + private int savedAudioMode = AudioManager.MODE_INVALID; + private boolean savedIsSpeakerPhoneOn = false; + private boolean savedIsMicrophoneMute = false; + + /** Construction */ + static AppRTCAudioManager create(Context context) { + return new AppRTCAudioManager(context); + } + + private AppRTCAudioManager(Context context) { + Log.d(TAG, "AppRTCAudioManager"); + audioManager = ((AudioManager) context.getSystemService( + Context.AUDIO_SERVICE)); + } + + public void init() { + Log.d(TAG, "init"); + if (initialized) { + return; + } + + // Store current audio state so we can restore it when close() is called. + savedAudioMode = audioManager.getMode(); + savedIsSpeakerPhoneOn = audioManager.isSpeakerphoneOn(); + savedIsMicrophoneMute = audioManager.isMicrophoneMute(); + + // The AppRTC demo shall always run in COMMUNICATION mode since it will + // result in best possible "VoIP settings", like audio routing, volume + // control etc. + audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); + + initialized = true; + } + + public void close() { + Log.d(TAG, "close"); + if (!initialized) { + return; + } + + // Restore previously stored audio states. + setSpeakerphoneOn(savedIsSpeakerPhoneOn); + setMicrophoneMute(savedIsMicrophoneMute); + audioManager.setMode(savedAudioMode); + + initialized = false; + } + + /** Sets the speaker phone mode. */ + private void setSpeakerphoneOn(boolean on) { + boolean wasOn = audioManager.isSpeakerphoneOn(); + if (wasOn == on) { + return; + } + audioManager.setSpeakerphoneOn(on); + } + + /** Sets the microphone mute state. */ + private void setMicrophoneMute(boolean on) { + boolean wasMuted = audioManager.isMicrophoneMute(); + if (wasMuted == on) { + return; + } + audioManager.setMicrophoneMute(on); + } +} diff --git a/examples/android/src/org/appspot/apprtc/AppRTCDemoActivity.java b/examples/android/src/org/appspot/apprtc/AppRTCDemoActivity.java index ad0e2d5..3ad26af 100644 --- a/examples/android/src/org/appspot/apprtc/AppRTCDemoActivity.java +++ b/examples/android/src/org/appspot/apprtc/AppRTCDemoActivity.java @@ -34,7 +34,6 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.pm.ActivityInfo; import android.graphics.Color; -import android.media.AudioManager; import android.net.Uri; import android.opengl.GLSurfaceView; import android.os.Bundle; @@ -72,6 +71,7 @@ public class AppRTCDemoActivity extends Activity private PeerConnectionClient pc; private AppRTCClient appRtcClient = new GAERTCClient(this, this); private AppRTCSignalingParameters appRtcParameters; + private AppRTCAudioManager audioManager = null; private View rootView; private View menuBar; private GLSurfaceView videoView; @@ -187,15 +187,9 @@ public class AppRTCDemoActivity extends Activity hudView.setVisibility(View.INVISIBLE); addContentView(hudView, hudLayout); - AudioManager audioManager = - ((AudioManager) getSystemService(AUDIO_SERVICE)); - // TODO(fischman): figure out how to do this Right(tm) and remove the - // suppression. - @SuppressWarnings("deprecation") - boolean isWiredHeadsetOn = audioManager.isWiredHeadsetOn(); - audioManager.setMode(isWiredHeadsetOn ? - AudioManager.MODE_IN_CALL : AudioManager.MODE_IN_COMMUNICATION); - audioManager.setSpeakerphoneOn(!isWiredHeadsetOn); + // Create and audio manager that will take care of audio routing, + // audio modes, audio device enumeration etc. + audioManager = AppRTCAudioManager.create(this); final Intent intent = getIntent(); Uri url = intent.getData(); @@ -253,6 +247,10 @@ public class AppRTCDemoActivity extends Activity @Override protected void onDestroy() { disconnect(); + if (audioManager != null) { + audioManager.close(); + audioManager = null; + } super.onDestroy(); } @@ -360,6 +358,12 @@ public class AppRTCDemoActivity extends Activity // All events are called from UI thread. @Override public void onConnectedToRoom(final AppRTCSignalingParameters params) { + if (audioManager != null) { + // Store existing audio settings and change audio mode to + // MODE_IN_COMMUNICATION for best possible VoIP performance. + logAndToast("Initializing the audio manager..."); + audioManager.init(); + } appRtcParameters = params; abortUnless(PeerConnectionFactory.initializeAndroidGlobals( this, true, true, VideoRendererGui.getEGLContext()), diff --git a/libjingle_examples.gyp b/libjingle_examples.gyp index d0f1747..f7ce53b 100755 --- a/libjingle_examples.gyp +++ b/libjingle_examples.gyp @@ -344,6 +344,7 @@ 'examples/android/res/values/arrays.xml', 'examples/android/res/values/strings.xml', 'examples/android/res/xml/preferences.xml', + 'examples/android/src/org/appspot/apprtc/AppRTCAudioManager.java', 'examples/android/src/org/appspot/apprtc/AppRTCClient.java', 'examples/android/src/org/appspot/apprtc/AppRTCDemoActivity.java', 'examples/android/src/org/appspot/apprtc/ConnectActivity.java', diff --git a/media/base/fakemediaengine.h b/media/base/fakemediaengine.h index db5e2e4..ff6ae16 100644 --- a/media/base/fakemediaengine.h +++ b/media/base/fakemediaengine.h @@ -879,9 +879,6 @@ 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_; } diff --git a/media/base/filemediaengine.h b/media/base/filemediaengine.h index 9cc066d..ba29ab3 100644 --- a/media/base/filemediaengine.h +++ b/media/base/filemediaengine.h @@ -93,9 +93,6 @@ 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; } diff --git a/media/base/mediaengine.h b/media/base/mediaengine.h index e7222f2..b8d661c 100644 --- a/media/base/mediaengine.h +++ b/media/base/mediaengine.h @@ -99,10 +99,6 @@ 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. @@ -219,9 +215,6 @@ 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) { @@ -347,9 +340,6 @@ class NullVideoEngine { return NULL; } bool SetOptions(const VideoOptions& options) { return true; } - VideoEncoderConfig GetDefaultEncoderConfig() const { - return VideoEncoderConfig(); - } bool SetDefaultEncoderConfig(const VideoEncoderConfig& config) { return true; } diff --git a/media/webrtc/constants.h b/media/webrtc/constants.h index 5390c0d..821a41f 100755 --- a/media/webrtc/constants.h +++ b/media/webrtc/constants.h @@ -35,7 +35,9 @@ extern const int kVideoRtpBufferSize; extern const char kVp8CodecName[]; extern const char kH264CodecName[]; -extern const int kDefaultFramerate; +extern const int kDefaultVideoMaxWidth; +extern const int kDefaultVideoMaxHeight; +extern const int kDefaultVideoMaxFramerate; extern const int kMinVideoBitrate; extern const int kStartVideoBitrate; extern const int kMaxVideoBitrate; diff --git a/media/webrtc/webrtcmediaengine.h b/media/webrtc/webrtcmediaengine.h index bfcfb2a..b4436cd 100644 --- a/media/webrtc/webrtcmediaengine.h +++ b/media/webrtc/webrtcmediaengine.h @@ -130,9 +130,6 @@ class DelegatingWebRtcMediaEngine : public cricket::MediaEngineInterface { const VideoEncoderConfig& config) OVERRIDE { return delegate_->SetDefaultVideoEncoderConfig(config); } - virtual VideoEncoderConfig GetDefaultVideoEncoderConfig() const OVERRIDE { - return delegate_->GetDefaultVideoEncoderConfig(); - } virtual bool SetSoundDevices( const Device* in_device, const Device* out_device) OVERRIDE { return delegate_->SetSoundDevices(in_device, out_device); diff --git a/media/webrtc/webrtcvideoengine.cc b/media/webrtc/webrtcvideoengine.cc index a0a8d81..46d316f 100644 --- a/media/webrtc/webrtcvideoengine.cc +++ b/media/webrtc/webrtcvideoengine.cc @@ -55,6 +55,7 @@ #include "webrtc/base/basictypes.h" #include "webrtc/base/buffer.h" #include "webrtc/base/byteorder.h" +#include "webrtc/base/checks.h" #include "webrtc/base/common.h" #include "webrtc/base/cpumonitor.h" #include "webrtc/base/logging.h" @@ -106,7 +107,10 @@ const int kVideoRtpBufferSize = 65536; const char kVp8CodecName[] = "VP8"; -const int kDefaultFramerate = 30; +// TODO(ronghuawu): Change to 640x360. +const int kDefaultVideoMaxWidth = 640; +const int kDefaultVideoMaxHeight = 400; +const int kDefaultVideoMaxFramerate = 30; const int kMinVideoBitrate = 30; const int kStartVideoBitrate = 300; const int kMaxVideoBitrate = 2000; @@ -176,15 +180,57 @@ static const bool kNotSending = false; static const rtc::DiffServCodePoint kVideoDscpValue = rtc::DSCP_AF41; -static bool IsNackEnabled(const VideoCodec& codec) { - return codec.HasFeedbackParam(FeedbackParam(kRtcpFbParamNack, - kParamValueEmpty)); +bool IsNackEnabled(const VideoCodec& codec) { + return codec.HasFeedbackParam( + FeedbackParam(kRtcpFbParamNack, kParamValueEmpty)); +} + +bool IsRembEnabled(const VideoCodec& codec) { + return codec.HasFeedbackParam( + FeedbackParam(kRtcpFbParamRemb, kParamValueEmpty)); +} + +void AddDefaultFeedbackParams(VideoCodec* codec) { + codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamCcm, kRtcpFbCcmParamFir)); + codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamNack, kParamValueEmpty)); + codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamNack, kRtcpFbNackParamPli)); + codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamRemb, kParamValueEmpty)); } -// Returns true if Receiver Estimated Max Bitrate is enabled. -static bool IsRembEnabled(const VideoCodec& codec) { - return codec.HasFeedbackParam(FeedbackParam(kRtcpFbParamRemb, - kParamValueEmpty)); +bool CodecNameMatches(const std::string& name1, const std::string& name2) { + return _stricmp(name1.c_str(), name2.c_str()) == 0; +} + +static VideoCodec MakeVideoCodecWithDefaultFeedbackParams(int payload_type, + const char* name) { + VideoCodec codec(payload_type, name, kDefaultVideoMaxWidth, + kDefaultVideoMaxHeight, kDefaultVideoMaxFramerate, 0); + AddDefaultFeedbackParams(&codec); + return codec; +} + +static VideoCodec MakeVideoCodec(int payload_type, const char* name) { + return VideoCodec(payload_type, name, 0, 0, 0, 0); +} + +static VideoCodec MakeRtxCodec(int payload_type, int associated_payload_type) { + return VideoCodec::CreateRtxCodec(payload_type, associated_payload_type); +} + +bool CodecIsInternallySupported(const std::string& codec_name) { + if (CodecNameMatches(codec_name, kVp8CodecName)) { + return true; + } + return false; +} + +std::vector<VideoCodec> DefaultVideoCodecList() { + std::vector<VideoCodec> codecs; + codecs.push_back(MakeVideoCodecWithDefaultFeedbackParams(100, kVp8CodecName)); + codecs.push_back(MakeRtxCodec(96, 100)); + codecs.push_back(MakeVideoCodec(116, kRedCodecName)); + codecs.push_back(MakeVideoCodec(117, kUlpfecCodecName)); + return codecs; } struct FlushBlackFrameData : public rtc::MessageData { @@ -923,18 +969,6 @@ class WebRtcVideoChannelSendInfo : public sigslot::has_slots<> { AdaptFormatType adapt_format_type_; }; -const WebRtcVideoEngine::VideoCodecPref - WebRtcVideoEngine::kVideoCodecPrefs[] = { - {kVp8CodecName, 100, -1, 0}, - {kRedCodecName, 116, -1, 1}, - {kUlpfecCodecName, 117, -1, 2}, - {kRtxCodecName, 96, 100, 3}, -}; - -const VideoFormatPod WebRtcVideoEngine::kDefaultMaxVideoFormat = - {640, 400, FPS_TO_INTERVAL(30), FOURCC_ANY}; -// TODO(ronghuawu): Change to 640x360. - static bool GetCpuOveruseOptions(const VideoOptions& options, webrtc::CpuOveruseOptions* overuse_options) { int underuse_threshold = 0; @@ -1018,20 +1052,14 @@ void WebRtcVideoEngine::Construct(ViEWrapper* vie_wrapper, LOG_RTCERR1(SetTraceCallback, this); } + default_video_codec_list_ = DefaultVideoCodecList(); + // Set default quality levels for our supported codecs. We override them here // if we know your cpu performance is low, and they can be updated explicitly // by calling SetDefaultCodec. For example by a flute preference setting, or // by the server with a jec in response to our reported system info. - VideoCodec max_codec(kVideoCodecPrefs[0].payload_type, - kVideoCodecPrefs[0].name, - kDefaultMaxVideoFormat.width, - kDefaultMaxVideoFormat.height, - VideoFormat::IntervalToFps( - kDefaultMaxVideoFormat.interval), - 0); - if (!SetDefaultCodec(max_codec)) { - LOG(LS_ERROR) << "Failed to initialize list of supported codec types"; - } + CHECK(SetDefaultCodec(default_video_codec_list_.front())) + << "Failed to initialize list of supported codec types."; // Consider jitter, packet loss, etc when rendering. This will // theoretically make rendering more smooth. @@ -1144,17 +1172,6 @@ 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 @@ -1225,13 +1242,12 @@ bool WebRtcVideoEngine::FindCodec(const VideoCodec& in) { return true; } } - for (size_t j = 0; j < ARRAY_SIZE(kVideoCodecPrefs); ++j) { - VideoCodec codec(kVideoCodecPrefs[j].payload_type, - kVideoCodecPrefs[j].name, 0, 0, 0, 0); - if (codec.Matches(in)) { + for (size_t j = 0; j != default_video_codec_list_.size(); ++j) { + if (default_video_codec_list_[j].Matches(in)) { return true; } } + return false; } @@ -1439,17 +1455,6 @@ void WebRtcVideoEngine::SetTraceOptions(const std::string& options) { } } -static void AddDefaultFeedbackParams(VideoCodec* codec) { - const FeedbackParam kFir(kRtcpFbParamCcm, kRtcpFbCcmParamFir); - codec->AddFeedbackParam(kFir); - const FeedbackParam kNack(kRtcpFbParamNack, kParamValueEmpty); - codec->AddFeedbackParam(kNack); - const FeedbackParam kPli(kRtcpFbParamNack, kRtcpFbNackParamPli); - codec->AddFeedbackParam(kPli); - const FeedbackParam kRemb(kRtcpFbParamRemb, kParamValueEmpty); - codec->AddFeedbackParam(kRemb); -} - // Rebuilds the codec list to be only those that are less intensive // than the specified codec. Prefers internal codec over external with // higher preference field. @@ -1459,27 +1464,17 @@ bool WebRtcVideoEngine::RebuildCodecList(const VideoCodec& in_codec) { video_codecs_.clear(); - bool found = false; std::set<std::string> internal_codec_names; - for (size_t i = 0; i < ARRAY_SIZE(kVideoCodecPrefs); ++i) { - const VideoCodecPref& pref(kVideoCodecPrefs[i]); - if (!found) - found = (in_codec.name == pref.name); - if (found) { - VideoCodec codec(pref.payload_type, pref.name, - in_codec.width, in_codec.height, in_codec.framerate, - static_cast<int>(ARRAY_SIZE(kVideoCodecPrefs) - i)); - if (_stricmp(kVp8CodecName, codec.name.c_str()) == 0) { - AddDefaultFeedbackParams(&codec); - } - if (pref.associated_payload_type != -1) { - codec.SetParam(kCodecParamAssociatedPayloadType, - pref.associated_payload_type); - } - video_codecs_.push_back(codec); - internal_codec_names.insert(codec.name); - } + for (size_t i = 0; i != default_video_codec_list_.size(); ++i) { + VideoCodec codec = default_video_codec_list_[i]; + codec.width = in_codec.width; + codec.height = in_codec.height; + codec.framerate = in_codec.framerate; + video_codecs_.push_back(codec); + + internal_codec_names.insert(codec.name); } + if (encoder_factory_) { const std::vector<WebRtcVideoEncoderFactory::VideoCodec>& codecs = encoder_factory_->codecs(); @@ -1487,8 +1482,6 @@ bool WebRtcVideoEngine::RebuildCodecList(const VideoCodec& in_codec) { bool is_internal_codec = internal_codec_names.find(codecs[i].name) != internal_codec_names.end(); if (!is_internal_codec) { - if (!found) - found = (in_codec.name == codecs[i].name); VideoCodec codec( GetExternalVideoPayloadType(static_cast<int>(i)), codecs[i].name, @@ -1503,7 +1496,6 @@ bool WebRtcVideoEngine::RebuildCodecList(const VideoCodec& in_codec) { } } } - ASSERT(found); return true; } @@ -1609,12 +1601,10 @@ void WebRtcVideoEngine::SetExternalEncoderFactory( encoder_factory_ = encoder_factory; // Rebuild codec list while reapplying the current default codec format. - VideoCodec max_codec(kVideoCodecPrefs[0].payload_type, - kVideoCodecPrefs[0].name, - video_codecs_[0].width, - video_codecs_[0].height, - video_codecs_[0].framerate, - 0); + VideoCodec max_codec = default_video_codec_list_[0]; + max_codec.width = video_codecs_[0].width; + max_codec.height = video_codecs_[0].height; + max_codec.framerate = video_codecs_[0].framerate; if (!RebuildCodecList(max_codec)) { LOG(LS_ERROR) << "Failed to initialize list of supported codec types"; } diff --git a/media/webrtc/webrtcvideoengine.h b/media/webrtc/webrtcvideoengine.h index eee82c8..db091af 100644 --- a/media/webrtc/webrtcvideoengine.h +++ b/media/webrtc/webrtcvideoengine.h @@ -85,6 +85,15 @@ class WebRtcVoiceEngine; struct CapturedFrame; struct Device; +// This set of methods is declared here for the sole purpose of sharing code +// between webrtc video engine v1 and v2. +std::vector<VideoCodec> DefaultVideoCodecList(); +bool CodecNameMatches(const std::string& name1, const std::string& name2); +bool CodecIsInternallySupported(const std::string& codec_name); +bool IsNackEnabled(const VideoCodec& codec); +bool IsRembEnabled(const VideoCodec& codec); +void AddDefaultFeedbackParams(VideoCodec* codec); + class WebRtcVideoEngine : public sigslot::has_slots<>, public webrtc::TraceCallback { public: @@ -108,7 +117,6 @@ class WebRtcVideoEngine : public sigslot::has_slots<>, int GetCapabilities(); bool SetDefaultEncoderConfig(const VideoEncoderConfig& config); - VideoEncoderConfig GetDefaultEncoderConfig() const; // TODO(pbos): Remove when all call sites use VideoOptions. virtual WebRtcVideoMediaChannel* CreateChannel( @@ -188,18 +196,6 @@ class WebRtcVideoEngine : public sigslot::has_slots<>, private: typedef std::vector<WebRtcVideoMediaChannel*> VideoChannels; - struct VideoCodecPref { - const char* name; - int payload_type; - // For RTX, this field is the payload-type that RTX applies to. - // For other codecs, it should be set to -1. - int associated_payload_type; - int pref; - }; - - static const VideoCodecPref kVideoCodecPrefs[]; - static const VideoFormatPod kVideoFormats[]; - static const VideoFormatPod kDefaultMaxVideoFormat; void Construct(ViEWrapper* vie_wrapper, ViETraceWrapper* tracing, @@ -226,6 +222,7 @@ class WebRtcVideoEngine : public sigslot::has_slots<>, WebRtcVideoEncoderFactory* encoder_factory_; WebRtcVideoDecoderFactory* decoder_factory_; std::vector<VideoCodec> video_codecs_; + std::vector<VideoCodec> default_video_codec_list_; std::vector<RtpHeaderExtension> rtp_header_extensions_; VideoFormat default_codec_format_; diff --git a/media/webrtc/webrtcvideoengine2.cc b/media/webrtc/webrtcvideoengine2.cc index 5062fb9..5b5f12e 100644 --- a/media/webrtc/webrtcvideoengine2.cc +++ b/media/webrtc/webrtcvideoengine2.cc @@ -36,6 +36,7 @@ #include "talk/media/base/videorenderer.h" #include "talk/media/webrtc/constants.h" #include "talk/media/webrtc/webrtcvideocapturer.h" +#include "talk/media/webrtc/webrtcvideoengine.h" #include "talk/media/webrtc/webrtcvideoframe.h" #include "talk/media/webrtc/webrtcvoiceengine.h" #include "webrtc/base/buffer.h" @@ -51,26 +52,6 @@ namespace cricket { namespace { - -static bool CodecNameMatches(const std::string& name1, - const std::string& name2) { - return _stricmp(name1.c_str(), name2.c_str()) == 0; -} - -const char* kInternallySupportedCodecs[] = { - kVp8CodecName, -}; - -// True if codec is supported by a software implementation that's always -// available. -static bool CodecIsInternallySupported(const std::string& codec_name) { - for (size_t i = 0; i < ARRAY_SIZE(kInternallySupportedCodecs); ++i) { - if (CodecNameMatches(codec_name, kInternallySupportedCodecs[i])) - return true; - } - return false; -} - static std::string CodecVectorToString(const std::vector<VideoCodec>& codecs) { std::stringstream out; out << '{'; @@ -116,6 +97,29 @@ static std::string RtpExtensionsToString( return out.str(); } +// Merges two fec configs and logs an error if a conflict arises +// such that merging in diferent order would trigger a diferent output. +static void MergeFecConfig(const webrtc::FecConfig& other, + webrtc::FecConfig* output) { + if (other.ulpfec_payload_type != -1) { + if (output->ulpfec_payload_type != -1 && + output->ulpfec_payload_type != other.ulpfec_payload_type) { + LOG(LS_WARNING) << "Conflict merging ulpfec_payload_type configs: " + << output->ulpfec_payload_type << " and " + << other.ulpfec_payload_type; + } + output->ulpfec_payload_type = other.ulpfec_payload_type; + } + if (other.red_payload_type != -1) { + if (output->red_payload_type != -1 && + output->red_payload_type != other.red_payload_type) { + LOG(LS_WARNING) << "Conflict merging red_payload_type configs: " + << output->red_payload_type << " and " + << other.red_payload_type; + } + output->red_payload_type = other.red_payload_type; + } +} } // namespace // This constant is really an on/off, lower-level configurable NACK history @@ -135,19 +139,8 @@ static const int kExternalVideoPayloadTypeBase = 120; static const size_t kMaxExternalVideoCodecs = 8; #endif -struct VideoCodecPref { - int payload_type; - int width; - int height; - const char* name; - int rtx_payload_type; -} kDefaultVideoCodecPref = {100, 640, 400, kVp8CodecName, 96}; - const char kH264CodecName[] = "H264"; -VideoCodecPref kRedPref = {116, -1, -1, kRedCodecName, -1}; -VideoCodecPref kUlpfecPref = {117, -1, -1, kUlpfecCodecName, -1}; - static bool FindFirstMatchingCodec(const std::vector<VideoCodec>& codecs, const VideoCodec& requested_codec, VideoCodec* matching_codec) { @@ -160,59 +153,6 @@ static bool FindFirstMatchingCodec(const std::vector<VideoCodec>& codecs, return false; } -static void AddDefaultFeedbackParams(VideoCodec* codec) { - const FeedbackParam kFir(kRtcpFbParamCcm, kRtcpFbCcmParamFir); - codec->AddFeedbackParam(kFir); - const FeedbackParam kNack(kRtcpFbParamNack, kParamValueEmpty); - codec->AddFeedbackParam(kNack); - const FeedbackParam kPli(kRtcpFbParamNack, kRtcpFbNackParamPli); - codec->AddFeedbackParam(kPli); - const FeedbackParam kRemb(kRtcpFbParamRemb, kParamValueEmpty); - codec->AddFeedbackParam(kRemb); -} - -static bool IsNackEnabled(const VideoCodec& codec) { - return codec.HasFeedbackParam( - FeedbackParam(kRtcpFbParamNack, kParamValueEmpty)); -} - -static bool IsRembEnabled(const VideoCodec& codec) { - return codec.HasFeedbackParam( - FeedbackParam(kRtcpFbParamRemb, kParamValueEmpty)); -} - -static VideoCodec DefaultVideoCodec() { - VideoCodec default_codec(kDefaultVideoCodecPref.payload_type, - kDefaultVideoCodecPref.name, - kDefaultVideoCodecPref.width, - kDefaultVideoCodecPref.height, - kDefaultFramerate, - 0); - AddDefaultFeedbackParams(&default_codec); - return default_codec; -} - -static VideoCodec DefaultRedCodec() { - return VideoCodec(kRedPref.payload_type, kRedPref.name, 0, 0, 0, 0); -} - -static VideoCodec DefaultUlpfecCodec() { - return VideoCodec(kUlpfecPref.payload_type, kUlpfecPref.name, 0, 0, 0, 0); -} - -static std::vector<VideoCodec> DefaultVideoCodecs() { - std::vector<VideoCodec> codecs; - codecs.push_back(DefaultVideoCodec()); - codecs.push_back(DefaultRedCodec()); - codecs.push_back(DefaultUlpfecCodec()); - if (kDefaultVideoCodecPref.rtx_payload_type != -1) { - codecs.push_back( - VideoCodec::CreateRtxCodec(kDefaultVideoCodecPref.rtx_payload_type, - kDefaultVideoCodecPref.payload_type)); - } - return codecs; -} - static bool ValidateRtpHeaderExtensionIds( const std::vector<RtpHeaderExtension>& extensions) { std::set<int> extensions_used; @@ -258,7 +198,7 @@ std::vector<webrtc::VideoStream> WebRtcVideoEncoderFactory2::CreateVideoStreams( stream.width = codec.width; stream.height = codec.height; stream.max_framerate = - codec.framerate != 0 ? codec.framerate : kDefaultFramerate; + codec.framerate != 0 ? codec.framerate : kDefaultVideoMaxFramerate; int min_bitrate = kMinVideoBitrate; codec.GetParam(kCodecParamMinBitrate, &min_bitrate); @@ -350,9 +290,9 @@ void DefaultUnsignalledSsrcHandler::SetDefaultRenderer( WebRtcVideoEngine2::WebRtcVideoEngine2() : worker_thread_(NULL), voice_engine_(NULL), - default_codec_format_(kDefaultVideoCodecPref.width, - kDefaultVideoCodecPref.height, - FPS_TO_INTERVAL(kDefaultFramerate), + default_codec_format_(kDefaultVideoMaxWidth, + kDefaultVideoMaxHeight, + FPS_TO_INTERVAL(kDefaultVideoMaxFramerate), FOURCC_ANY), initialized_(false), cpu_monitor_(new rtc::CpuMonitor(NULL)), @@ -427,10 +367,6 @@ bool WebRtcVideoEngine2::SetDefaultEncoderConfig( return true; } -VideoEncoderConfig WebRtcVideoEngine2::GetDefaultEncoderConfig() const { - return VideoEncoderConfig(DefaultVideoCodec()); -} - WebRtcVideoChannel2* WebRtcVideoEngine2::CreateChannel( const VideoOptions& options, VoiceMediaChannel* voice_channel) { @@ -575,7 +511,7 @@ WebRtcVideoEncoderFactory2* WebRtcVideoEngine2::GetVideoEncoderFactory() { } std::vector<VideoCodec> WebRtcVideoEngine2::GetSupportedCodecs() const { - std::vector<VideoCodec> supported_codecs = DefaultVideoCodecs(); + std::vector<VideoCodec> supported_codecs = DefaultVideoCodecList(); if (external_encoder_factory_ == NULL) { return supported_codecs; @@ -900,9 +836,16 @@ bool WebRtcVideoChannel2::SetSendCodecs(const std::vector<VideoCodec>& codecs) { return false; } - send_codec_.Set(supported_codecs.front()); LOG(LS_INFO) << "Using codec: " << supported_codecs.front().codec.ToString(); + VideoCodecSettings old_codec; + if (send_codec_.Get(&old_codec) && supported_codecs.front() == old_codec) { + // Using same codec, avoid reconfiguring. + return true; + } + + send_codec_.Set(supported_codecs.front()); + rtc::CritScope stream_lock(&stream_crit_); for (std::map<uint32, WebRtcVideoSendStream*>::iterator it = send_streams_.begin(); @@ -1101,19 +1044,19 @@ void WebRtcVideoChannel2::ConfigureReceiverRtp( } for (size_t i = 0; i < recv_codecs_.size(); ++i) { - if (recv_codecs_[i].codec.id == kDefaultVideoCodecPref.payload_type) { - config->rtp.fec = recv_codecs_[i].fec; - uint32 rtx_ssrc; - if (recv_codecs_[i].rtx_payload_type != -1 && - sp.GetFidSsrc(ssrc, &rtx_ssrc)) { - config->rtp.rtx[kDefaultVideoCodecPref.payload_type].ssrc = rtx_ssrc; - config->rtp.rtx[kDefaultVideoCodecPref.payload_type].payload_type = - recv_codecs_[i].rtx_payload_type; - } - break; - } + MergeFecConfig(recv_codecs_[i].fec, &config->rtp.fec); } + for (size_t i = 0; i < recv_codecs_.size(); ++i) { + uint32 rtx_ssrc; + if (recv_codecs_[i].rtx_payload_type != -1 && + sp.GetFidSsrc(ssrc, &rtx_ssrc)) { + webrtc::VideoReceiveStream::Config::Rtp::Rtx& rtx = + config->rtp.rtx[recv_codecs_[i].codec.id]; + rtx.ssrc = rtx_ssrc; + rtx.payload_type = recv_codecs_[i].rtx_payload_type; + } + } } bool WebRtcVideoChannel2::RemoveRecvStream(uint32 ssrc) { @@ -1336,6 +1279,7 @@ bool WebRtcVideoChannel2::SetSendRtpHeaderExtensions( return false; send_rtp_extensions_ = FilterRtpExtensions(extensions); + rtc::CritScope stream_lock(&stream_crit_); for (std::map<uint32, WebRtcVideoSendStream*>::iterator it = send_streams_.begin(); @@ -1353,8 +1297,13 @@ bool WebRtcVideoChannel2::SetMaxSendBandwidth(int bps) { } bool WebRtcVideoChannel2::SetOptions(const VideoOptions& options) { - LOG(LS_VERBOSE) << "SetOptions: " << options.ToString(); + LOG(LS_INFO) << "SetOptions: " << options.ToString(); + VideoOptions old_options = options_; options_.SetAll(options); + if (options_ == old_options) { + // No new options to set. + return true; + } rtc::CritScope stream_lock(&stream_crit_); for (std::map<uint32, WebRtcVideoSendStream*>::iterator it = send_streams_.begin(); @@ -1566,13 +1515,16 @@ bool WebRtcVideoChannel2::WebRtcVideoSendStream::SetCapturer( LOG(LS_VERBOSE) << "Disabling capturer, sending black frame."; webrtc::I420VideoFrame black_frame; + // TODO(pbos): Base width/height on last_dimensions_. This will however + // fail the test AddRemoveCapturer which needs to be fixed to permit + // sending black frames in the same size that was previously sent. int width = format_.width; int height = format_.height; int half_width = (width + 1) / 2; black_frame.CreateEmptyFrame( width, height, width, half_width, half_width); SetWebRtcFrameToBlack(&black_frame); - SetDimensions(width, height, false); + SetDimensions(width, height, last_dimensions_.is_screencast); stream_->Input()->SwapFrame(&black_frame); } @@ -1699,13 +1651,17 @@ void WebRtcVideoChannel2::WebRtcVideoSendStream::DestroyVideoEncoder( void WebRtcVideoChannel2::WebRtcVideoSendStream::SetCodecAndOptions( const VideoCodecSettings& codec_settings, const VideoOptions& options) { - std::vector<webrtc::VideoStream> video_streams = - encoder_factory_->CreateVideoStreams( - codec_settings.codec, options, parameters_.config.rtp.ssrcs.size()); - if (video_streams.empty()) { + if (last_dimensions_.width == -1) { + last_dimensions_.width = codec_settings.codec.width; + last_dimensions_.height = codec_settings.codec.height; + last_dimensions_.is_screencast = false; + } + parameters_.encoder_config = + CreateVideoEncoderConfig(last_dimensions_, codec_settings.codec); + if (parameters_.encoder_config.streams.empty()) { return; } - parameters_.encoder_config.streams = video_streams; + format_ = VideoFormat(codec_settings.codec.width, codec_settings.codec.height, VideoFormat::FpsToInterval(30), @@ -1749,6 +1705,50 @@ void WebRtcVideoChannel2::WebRtcVideoSendStream::SetRtpExtensions( RecreateWebRtcStream(); } +webrtc::VideoEncoderConfig +WebRtcVideoChannel2::WebRtcVideoSendStream::CreateVideoEncoderConfig( + const Dimensions& dimensions, + const VideoCodec& codec) const { + webrtc::VideoEncoderConfig encoder_config; + if (dimensions.is_screencast) { + int screencast_min_bitrate_kbps; + parameters_.options.screencast_min_bitrate.Get( + &screencast_min_bitrate_kbps); + encoder_config.min_transmit_bitrate_bps = + screencast_min_bitrate_kbps * 1000; + encoder_config.content_type = webrtc::VideoEncoderConfig::kScreenshare; + } else { + encoder_config.min_transmit_bitrate_bps = 0; + encoder_config.content_type = webrtc::VideoEncoderConfig::kRealtimeVideo; + } + + // Restrict dimensions according to codec max. + int width = dimensions.width; + int height = dimensions.height; + if (!dimensions.is_screencast) { + if (codec.width < width) + width = codec.width; + if (codec.height < height) + height = codec.height; + } + + VideoCodec clamped_codec = codec; + clamped_codec.width = width; + clamped_codec.height = height; + + encoder_config.streams = encoder_factory_->CreateVideoStreams( + clamped_codec, parameters_.options, parameters_.config.rtp.ssrcs.size()); + + // Conference mode screencast uses 2 temporal layers split at 100kbit. + if (parameters_.options.conference_mode.GetWithDefaultIfUnset(false) && + dimensions.is_screencast && encoder_config.streams.size() == 1) { + encoder_config.streams[0].temporal_layer_thresholds_bps.clear(); + encoder_config.streams[0].temporal_layer_thresholds_bps.push_back( + kConferenceModeTemporalLayerBitrateBps); + } + return encoder_config; +} + void WebRtcVideoChannel2::WebRtcVideoSendStream::SetDimensions( int width, int height, @@ -1758,56 +1758,25 @@ void WebRtcVideoChannel2::WebRtcVideoSendStream::SetDimensions( // Configured using the same parameters, do not reconfigure. return; } + LOG(LS_INFO) << "SetDimensions: " << width << "x" << height + << (is_screencast ? " (screencast)" : " (not screencast)"); last_dimensions_.width = width; last_dimensions_.height = height; last_dimensions_.is_screencast = is_screencast; assert(!parameters_.encoder_config.streams.empty()); - LOG(LS_VERBOSE) << "SetDimensions: " << width << "x" << height; VideoCodecSettings codec_settings; parameters_.codec_settings.Get(&codec_settings); - // Restrict dimensions according to codec max. - if (!is_screencast) { - if (codec_settings.codec.width < width) - width = codec_settings.codec.width; - if (codec_settings.codec.height < height) - height = codec_settings.codec.height; - } - webrtc::VideoEncoderConfig encoder_config = parameters_.encoder_config; + webrtc::VideoEncoderConfig encoder_config = + CreateVideoEncoderConfig(last_dimensions_, codec_settings.codec); + encoder_config.encoder_specific_settings = encoder_factory_->CreateVideoEncoderSettings(codec_settings.codec, parameters_.options); - if (is_screencast) { - int screencast_min_bitrate_kbps; - parameters_.options.screencast_min_bitrate.Get( - &screencast_min_bitrate_kbps); - encoder_config.min_transmit_bitrate_bps = - screencast_min_bitrate_kbps * 1000; - encoder_config.content_type = webrtc::VideoEncoderConfig::kScreenshare; - } else { - encoder_config.min_transmit_bitrate_bps = 0; - encoder_config.content_type = webrtc::VideoEncoderConfig::kRealtimeVideo; - } - - VideoCodec codec = codec_settings.codec; - codec.width = width; - codec.height = height; - - encoder_config.streams = encoder_factory_->CreateVideoStreams( - codec, parameters_.options, parameters_.config.rtp.ssrcs.size()); - - // Conference mode screencast uses 2 temporal layers split at 100kbit. - if (parameters_.options.conference_mode.GetWithDefaultIfUnset(false) && - is_screencast && encoder_config.streams.size() == 1) { - encoder_config.streams[0].temporal_layer_thresholds_bps.clear(); - encoder_config.streams[0].temporal_layer_thresholds_bps.push_back( - kConferenceModeTemporalLayerBitrateBps); - } - bool stream_reconfigured = stream_->ReconfigureVideoEncoder(encoder_config); encoder_factory_->DestroyVideoEncoderSettings( @@ -2137,6 +2106,14 @@ WebRtcVideoChannel2::WebRtcVideoReceiveStream::GetVideoReceiverInfo() { WebRtcVideoChannel2::VideoCodecSettings::VideoCodecSettings() : rtx_payload_type(-1) {} +bool WebRtcVideoChannel2::VideoCodecSettings::operator==( + const WebRtcVideoChannel2::VideoCodecSettings& other) const { + return codec == other.codec && + fec.ulpfec_payload_type == other.fec.ulpfec_payload_type && + fec.red_payload_type == other.fec.red_payload_type && + rtx_payload_type == other.rtx_payload_type; +} + std::vector<WebRtcVideoChannel2::VideoCodecSettings> WebRtcVideoChannel2::MapCodecs(const std::vector<VideoCodec>& codecs) { assert(!codecs.empty()); diff --git a/media/webrtc/webrtcvideoengine2.h b/media/webrtc/webrtcvideoengine2.h index 299ac35..9a5fe65 100644 --- a/media/webrtc/webrtcvideoengine2.h +++ b/media/webrtc/webrtcvideoengine2.h @@ -145,7 +145,6 @@ class WebRtcVideoEngine2 : public sigslot::has_slots<> { int GetCapabilities(); bool SetDefaultEncoderConfig(const VideoEncoderConfig& config); - VideoEncoderConfig GetDefaultEncoderConfig() const; WebRtcVideoChannel2* CreateChannel(const VideoOptions& options, VoiceMediaChannel* voice_channel); @@ -281,6 +280,8 @@ class WebRtcVideoChannel2 : public rtc::MessageHandler, struct VideoCodecSettings { VideoCodecSettings(); + bool operator ==(const VideoCodecSettings& other) const; + VideoCodec codec; webrtc::FecConfig fec; int rtx_payload_type; @@ -349,8 +350,8 @@ class WebRtcVideoChannel2 : public rtc::MessageHandler, bool external; }; - struct LastDimensions { - LastDimensions() : width(-1), height(-1), is_screencast(false) {} + struct Dimensions { + Dimensions() : width(-1), height(-1), is_screencast(false) {} int width; int height; bool is_screencast; @@ -358,23 +359,28 @@ class WebRtcVideoChannel2 : public rtc::MessageHandler, AllocatedEncoder CreateVideoEncoder(const VideoCodec& codec) EXCLUSIVE_LOCKS_REQUIRED(lock_); - void DestroyVideoEncoder(AllocatedEncoder* encoder); + void DestroyVideoEncoder(AllocatedEncoder* encoder) + EXCLUSIVE_LOCKS_REQUIRED(lock_); void SetCodecAndOptions(const VideoCodecSettings& codec, const VideoOptions& options) EXCLUSIVE_LOCKS_REQUIRED(lock_); void RecreateWebRtcStream() EXCLUSIVE_LOCKS_REQUIRED(lock_); + webrtc::VideoEncoderConfig CreateVideoEncoderConfig( + const Dimensions& dimensions, + const VideoCodec& codec) const EXCLUSIVE_LOCKS_REQUIRED(lock_); void SetDimensions(int width, int height, bool is_screencast) EXCLUSIVE_LOCKS_REQUIRED(lock_); webrtc::Call* const call_; - WebRtcVideoEncoderFactory* const external_encoder_factory_; - WebRtcVideoEncoderFactory2* const encoder_factory_; + WebRtcVideoEncoderFactory* const external_encoder_factory_ + GUARDED_BY(lock_); + WebRtcVideoEncoderFactory2* const encoder_factory_ GUARDED_BY(lock_); rtc::CriticalSection lock_; webrtc::VideoSendStream* stream_ GUARDED_BY(lock_); VideoSendStreamParameters parameters_ GUARDED_BY(lock_); AllocatedEncoder allocated_encoder_ GUARDED_BY(lock_); - LastDimensions last_dimensions_ GUARDED_BY(lock_); + Dimensions last_dimensions_ GUARDED_BY(lock_); VideoCapturer* capturer_ GUARDED_BY(lock_); bool sending_ GUARDED_BY(lock_); diff --git a/media/webrtc/webrtcvoiceengine.cc b/media/webrtc/webrtcvoiceengine.cc index 95e16e4..74b3163 100644 --- a/media/webrtc/webrtcvoiceengine.cc +++ b/media/webrtc/webrtcvoiceengine.cc @@ -74,7 +74,7 @@ static const CodecPref kCodecPrefs[] = { { "ISAC", 32000, 1, 104, true }, { "CELT", 32000, 1, 109, true }, { "CELT", 32000, 2, 110, true }, - { "G722", 16000, 1, 9, false }, + { "G722", 8000, 1, 9, false }, { "ILBC", 8000, 1, 102, false }, { "PCMU", 8000, 1, 0, false }, { "PCMA", 8000, 1, 8, false }, @@ -110,6 +110,7 @@ static const int kDefaultAudioDeviceId = 0; static const char kIsacCodecName[] = "ISAC"; static const char kL16CodecName[] = "L16"; +static const char kG722CodecName[] = "G722"; // Parameter used for NACK. // This value is equivalent to 5 seconds of audio data at 20 ms per packet. @@ -485,12 +486,24 @@ static void GetOpusConfig(const AudioCodec& codec, webrtc::CodecInst* voe_codec, voe_codec->rate = GetOpusBitrate(codec, *max_playback_rate); } +// Changes RTP timestamp rate of G722. This is due to the "bug" in the RFC +// which says that G722 should be advertised as 8 kHz although it is a 16 kHz +// codec. +static void MaybeFixupG722(webrtc::CodecInst* voe_codec, int new_plfreq) { + if (_stricmp(voe_codec->plname, kG722CodecName) == 0) { + // If the ASSERT triggers, the codec definition in WebRTC VoiceEngine + // has changed, and this special case is no longer needed. + ASSERT(voe_codec->plfreq != new_plfreq); + voe_codec->plfreq = new_plfreq; + } +} + void WebRtcVoiceEngine::ConstructCodecs() { LOG(LS_INFO) << "WebRtc VoiceEngine codecs:"; int ncodecs = voe_wrapper_->codec()->NumOfCodecs(); for (int i = 0; i < ncodecs; ++i) { webrtc::CodecInst voe_codec; - if (voe_wrapper_->codec()->GetCodec(i, voe_codec) != -1) { + if (GetVoeCodec(i, voe_codec)) { // Skip uncompressed formats. if (_stricmp(voe_codec.plname, kL16CodecName) == 0) { continue; @@ -540,6 +553,15 @@ void WebRtcVoiceEngine::ConstructCodecs() { std::sort(codecs_.begin(), codecs_.end(), &AudioCodec::Preferable); } +bool WebRtcVoiceEngine::GetVoeCodec(int index, webrtc::CodecInst& codec) { + if (voe_wrapper_->codec()->GetCodec(index, codec) != -1) { + // Change the sample rate of G722 to 8000 to match SDP. + MaybeFixupG722(&codec, 8000); + return true; + } + return false; +} + WebRtcVoiceEngine::~WebRtcVoiceEngine() { LOG(LS_VERBOSE) << "WebRtcVoiceEngine::~WebRtcVoiceEngine"; if (voe_wrapper_->base()->DeRegisterVoiceEngineObserver() == -1) { @@ -1224,7 +1246,7 @@ bool WebRtcVoiceEngine::FindWebRtcCodec(const AudioCodec& in, int ncodecs = voe_wrapper_->codec()->NumOfCodecs(); for (int i = 0; i < ncodecs; ++i) { webrtc::CodecInst voe_codec; - if (voe_wrapper_->codec()->GetCodec(i, voe_codec) != -1) { + if (GetVoeCodec(i, voe_codec)) { AudioCodec codec(voe_codec.pltype, voe_codec.plname, voe_codec.plfreq, voe_codec.rate, voe_codec.channels, 0); bool multi_rate = IsCodecMultiRate(voe_codec); @@ -1243,6 +1265,9 @@ bool WebRtcVoiceEngine::FindWebRtcCodec(const AudioCodec& in, voe_codec.rate = in.bitrate; } + // Reset G722 sample rate to 16000 to match WebRTC. + MaybeFixupG722(&voe_codec, 16000); + // Apply codec-specific settings. if (IsIsac(codec)) { // If ISAC and an explicit bitrate is not specified, diff --git a/media/webrtc/webrtcvoiceengine.h b/media/webrtc/webrtcvoiceengine.h index f19059b..34b9f3c 100644 --- a/media/webrtc/webrtcvoiceengine.h +++ b/media/webrtc/webrtcvoiceengine.h @@ -199,6 +199,7 @@ class WebRtcVoiceEngine void Construct(); void ConstructCodecs(); + bool GetVoeCodec(int index, webrtc::CodecInst& codec); bool InitInternal(); bool EnsureSoundclipEngineInit(); void SetTraceFilter(int filter); diff --git a/media/webrtc/webrtcvoiceengine_unittest.cc b/media/webrtc/webrtcvoiceengine_unittest.cc index 5deabd2..5eb6e24 100644 --- a/media/webrtc/webrtcvoiceengine_unittest.cc +++ b/media/webrtc/webrtcvoiceengine_unittest.cc @@ -52,14 +52,16 @@ static const cricket::AudioCodec kPcmuCodec(0, "PCMU", 8000, 64000, 1, 0); static const cricket::AudioCodec kIsacCodec(103, "ISAC", 16000, 32000, 1, 0); static const cricket::AudioCodec kCeltCodec(110, "CELT", 32000, 64000, 2, 0); static const cricket::AudioCodec kOpusCodec(111, "opus", 48000, 64000, 2, 0); +static const cricket::AudioCodec kG722CodecVoE(9, "G722", 16000, 64000, 1, 0); +static const cricket::AudioCodec kG722CodecSdp(9, "G722", 8000, 64000, 1, 0); static const cricket::AudioCodec kRedCodec(117, "red", 8000, 0, 1, 0); static const cricket::AudioCodec kCn8000Codec(13, "CN", 8000, 0, 1, 0); static const cricket::AudioCodec kCn16000Codec(105, "CN", 16000, 0, 1, 0); static const cricket::AudioCodec kTelephoneEventCodec(106, "telephone-event", 8000, 0, 1, 0); static const cricket::AudioCodec* const kAudioCodecs[] = { - &kPcmuCodec, &kIsacCodec, &kCeltCodec, &kOpusCodec, &kRedCodec, - &kCn8000Codec, &kCn16000Codec, &kTelephoneEventCodec, + &kPcmuCodec, &kIsacCodec, &kCeltCodec, &kOpusCodec, &kG722CodecVoE, + &kRedCodec, &kCn8000Codec, &kCn16000Codec, &kTelephoneEventCodec, }; const char kRingbackTone[] = "RIFF____WAVE____ABCD1234"; static uint32 kSsrc1 = 0x99; @@ -770,6 +772,20 @@ TEST_F(WebRtcVoiceEngineTestFake, DontResetSetSendCodec) { EXPECT_EQ(1, voe_.GetNumSetSendCodecs()); } +// Verify that G722 is set with 16000 samples per second to WebRTC. +TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecG722) { + EXPECT_TRUE(SetupEngine()); + int channel_num = voe_.GetLastChannel(); + std::vector<cricket::AudioCodec> codecs; + codecs.push_back(kG722CodecSdp); + EXPECT_TRUE(channel_->SetSendCodecs(codecs)); + webrtc::CodecInst gcodec; + EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec)); + EXPECT_STREQ("G722", gcodec.plname); + EXPECT_EQ(1, gcodec.channels); + EXPECT_EQ(16000, gcodec.plfreq); +} + // Test that if clockrate is not 48000 for opus, we fail. TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecOpusBadClockrate) { EXPECT_TRUE(SetupEngine()); @@ -3208,7 +3224,7 @@ TEST(WebRtcVoiceEngineTest, HasCorrectCodecs) { EXPECT_TRUE(engine.FindCodec( cricket::AudioCodec(96, "PCMA", 8000, 0, 1, 0))); EXPECT_TRUE(engine.FindCodec( - cricket::AudioCodec(96, "G722", 16000, 0, 1, 0))); + cricket::AudioCodec(96, "G722", 8000, 0, 1, 0))); EXPECT_TRUE(engine.FindCodec( cricket::AudioCodec(96, "red", 8000, 0, 1, 0))); EXPECT_TRUE(engine.FindCodec( @@ -3225,7 +3241,7 @@ TEST(WebRtcVoiceEngineTest, HasCorrectCodecs) { EXPECT_TRUE(engine.FindCodec( cricket::AudioCodec(8, "", 8000, 0, 1, 0))); // PCMA EXPECT_TRUE(engine.FindCodec( - cricket::AudioCodec(9, "", 16000, 0, 1, 0))); // G722 + cricket::AudioCodec(9, "", 8000, 0, 1, 0))); // G722 EXPECT_TRUE(engine.FindCodec( cricket::AudioCodec(13, "", 8000, 0, 1, 0))); // CN // Check sample/bitrate matching. @@ -3248,7 +3264,7 @@ TEST(WebRtcVoiceEngineTest, HasCorrectCodecs) { EXPECT_EQ(103, it->id); } else if (it->name == "ISAC" && it->clockrate == 32000) { EXPECT_EQ(104, it->id); - } else if (it->name == "G722" && it->clockrate == 16000) { + } else if (it->name == "G722" && it->clockrate == 8000) { EXPECT_EQ(9, it->id); } else if (it->name == "telephone-event") { EXPECT_EQ(126, it->id); diff --git a/session/media/mediasessionclient_unittest.cc b/session/media/mediasessionclient_unittest.cc index 3e8a90f..eb052ef 100644 --- a/session/media/mediasessionclient_unittest.cc +++ b/session/media/mediasessionclient_unittest.cc @@ -61,7 +61,7 @@ static const cricket::AudioCodec kAudioCodecs[] = { cricket::AudioCodec(119, "ISACLC", 16000, 40000, 1, 16), cricket::AudioCodec(99, "speex", 16000, 22000, 1, 15), cricket::AudioCodec(97, "IPCMWB", 16000, 80000, 1, 14), - cricket::AudioCodec(9, "G722", 16000, 64000, 1, 13), + cricket::AudioCodec(9, "G722", 8000, 64000, 1, 13), cricket::AudioCodec(102, "iLBC", 8000, 13300, 1, 12), cricket::AudioCodec(98, "speex", 8000, 11000, 1, 11), cricket::AudioCodec(3, "GSM", 8000, 13000, 1, 10), @@ -81,7 +81,7 @@ static const cricket::AudioCodec kAudioCodecs[] = { static const cricket::AudioCodec kAudioCodecsDifferentPreference[] = { cricket::AudioCodec(104, "ISAC", 32000, -1, 1, 17), cricket::AudioCodec(97, "IPCMWB", 16000, 80000, 1, 14), - cricket::AudioCodec(9, "G722", 16000, 64000, 1, 13), + cricket::AudioCodec(9, "G722", 8000, 64000, 1, 13), cricket::AudioCodec(119, "ISACLC", 16000, 40000, 1, 16), cricket::AudioCodec(103, "ISAC", 16000, -1, 1, 18), cricket::AudioCodec(99, "speex", 16000, 22000, 1, 15), @@ -197,7 +197,7 @@ const std::string kGingleInitiate( " <payload-type xmlns='http://www.google.com/session/phone' " \ " id='97' name='IPCMWB' clockrate='16000' bitrate='80000' /> " \ " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='9' name='G722' clockrate='16000' bitrate='64000' /> " \ + " id='9' name='G722' clockrate='8000' bitrate='64000' /> " \ " <payload-type xmlns='http://www.google.com/session/phone' " \ " id='102' name='iLBC' clockrate='8000' bitrate='13300' />" \ " <payload-type xmlns='http://www.google.com/session/phone' " \ @@ -248,7 +248,7 @@ const std::string kJingleInitiate( " <parameter name='bitrate' value='80000'/> " \ " </payload-type> " \ " <payload-type " \ - " id='9' name='G722' clockrate='16000'> " \ + " id='9' name='G722' clockrate='8000'> " \ " <parameter name='bitrate' value='64000'/> " \ " </payload-type> " \ " <payload-type " \ @@ -1918,7 +1918,7 @@ class MediaSessionClientTest : public sigslot::has_slots<> { e = NextFromPayloadType(e); ASSERT_TRUE(e != NULL); codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 9, "G722", 16000, 64000, 1); + VerifyAudioCodec(codec, 9, "G722", 8000, 64000, 1); e = NextFromPayloadType(e); ASSERT_TRUE(e != NULL); @@ -2112,7 +2112,7 @@ class MediaSessionClientTest : public sigslot::has_slots<> { codec = AudioCodecFromPayloadType(e); ASSERT_EQ(9, codec.id); ASSERT_EQ("G722", codec.name); - ASSERT_EQ(16000, codec.clockrate); + ASSERT_EQ(8000, codec.clockrate); ASSERT_EQ(64000, codec.bitrate); ASSERT_EQ(1, codec.channels); |