Update libjingle to 47547184. R=mallinath@webrtc.org Review URL: https://webrtc-codereview.appspot.com/1617004 git-svn-id: http://libjingle.googlecode.com/svn/trunk@338 dd674b97-3498-5ee5-1854-bdd07cd0ff33
diff --git a/talk/app/webrtc/java/jni/peerconnection_jni.cc b/talk/app/webrtc/java/jni/peerconnection_jni.cc index 9db8698..e0d5c09 100644 --- a/talk/app/webrtc/java/jni/peerconnection_jni.cc +++ b/talk/app/webrtc/java/jni/peerconnection_jni.cc
@@ -62,6 +62,7 @@ #include "talk/app/webrtc/peerconnectioninterface.h" #include "talk/app/webrtc/videosourceinterface.h" #include "talk/base/logging.h" +#include "talk/base/ssladapter.h" #include "talk/media/base/videocapturer.h" #include "talk/media/base/videorenderer.h" #include "talk/media/devices/videorendererfactory.h" @@ -891,6 +892,8 @@ g_jvm = jvm; CHECK(g_jvm, "JNI_OnLoad handed NULL?"); + CHECK(talk_base::InitializeSSL(), "Failed to InitializeSSL()"); + JNIEnv* jni; if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK) return -1; @@ -914,6 +917,7 @@ webrtc::Trace::ReturnTrace(); delete g_class_reference_holder; g_class_reference_holder = NULL; + CHECK(talk_base::CleanupSSL(), "Failed to CleanupSSL()"); } JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
diff --git a/talk/base/messagequeue.cc b/talk/base/messagequeue.cc index cbb1ffa..5c40622 100644 --- a/talk/base/messagequeue.cc +++ b/talk/base/messagequeue.cc
@@ -160,17 +160,6 @@ return true; } -struct MessageDeleter { - ~MessageDeleter() { - while (!messages.empty()) { - ASSERT(NULL == messages.front().phandler); - delete messages.front().pdata; - messages.pop_front(); - } - } - MessageList messages; -}; - bool MessageQueue::Get(Message *pmsg, int cmsWait, bool process_io) { // Return and clear peek if present // Always return the peek if it exists so there is Peek/Get symmetry @@ -189,49 +178,55 @@ uint32 msCurrent = msStart; while (true) { // Check for sent messages - ReceiveSends(); - // Check queues - + // Check for posted events int cmsDelayNext = kForever; - { - MessageDeleter deleter; - CritScope cs(&crit_); - - // Check for delayed messages that have been triggered - // Calc the next trigger too - - while (!dmsgq_.empty()) { - if (TimeIsLater(msCurrent, dmsgq_.top().msTrigger_)) { - cmsDelayNext = TimeDiff(dmsgq_.top().msTrigger_, msCurrent); - break; - } - msgq_.push_back(dmsgq_.top().msg_); - dmsgq_.pop(); - } - - // Check for posted events - - while (!msgq_.empty()) { - *pmsg = msgq_.front(); - if (pmsg->ts_sensitive) { - long delay = TimeDiff(msCurrent, pmsg->ts_sensitive); - if (delay > 0) { - LOG_F(LS_WARNING) << "id: " << pmsg->message_id << " delay: " - << (delay + kMaxMsgLatency) << "ms"; + bool first_pass = true; + while (true) { + // All queue operations need to be locked, but nothing else in this loop + // (specifically handling disposed message) can happen inside the crit. + // Otherwise, disposed MessageHandlers will cause deadlocks. + { + CritScope cs(&crit_); + // On the first pass, check for delayed messages that have been + // triggered and calculate the next trigger time. + if (first_pass) { + first_pass = false; + while (!dmsgq_.empty()) { + if (TimeIsLater(msCurrent, dmsgq_.top().msTrigger_)) { + cmsDelayNext = TimeDiff(dmsgq_.top().msTrigger_, msCurrent); + break; + } + msgq_.push_back(dmsgq_.top().msg_); + dmsgq_.pop(); } } - msgq_.pop_front(); - if (MQID_DISPOSE == pmsg->message_id) { - // Delete the object, but *not inside the crit scope!*. - deleter.messages.push_back(*pmsg); - // To be safe, make sure we don't return this message. - *pmsg = Message(); - continue; + // Pull a message off the message queue, if available. + if (msgq_.empty()) { + break; + } else { + *pmsg = msgq_.front(); + msgq_.pop_front(); } - return true; + } // crit_ is released here. + + // Log a warning for time-sensitive messages that we're late to deliver. + if (pmsg->ts_sensitive) { + int32 delay = TimeDiff(msCurrent, pmsg->ts_sensitive); + if (delay > 0) { + LOG_F(LS_WARNING) << "id: " << pmsg->message_id << " delay: " + << (delay + kMaxMsgLatency) << "ms"; + } } + // If this was a dispose message, delete it and skip it. + if (MQID_DISPOSE == pmsg->message_id) { + ASSERT(NULL == pmsg->phandler); + delete pmsg->pdata; + *pmsg = Message(); + continue; + } + return true; } if (fStop_)
diff --git a/talk/base/messagequeue_unittest.cc b/talk/base/messagequeue_unittest.cc index 78f7788..8e55548 100644 --- a/talk/base/messagequeue_unittest.cc +++ b/talk/base/messagequeue_unittest.cc
@@ -106,3 +106,27 @@ EXPECT_TRUE(deleted); EXPECT_FALSE(was_locked); } + +class DeletedMessageHandler : public MessageHandler { + public: + explicit DeletedMessageHandler(bool* deleted) : deleted_(deleted) { } + ~DeletedMessageHandler() { + *deleted_ = true; + } + void OnMessage(Message* msg) { } + private: + bool* deleted_; +}; + +TEST_F(MessageQueueTest, DiposeHandlerWithPostedMessagePending) { + bool deleted = false; + DeletedMessageHandler *handler = new DeletedMessageHandler(&deleted); + // First, post a dispose. + Dispose(handler); + // Now, post a message, which should *not* be returned by Get(). + Post(handler, 1); + Message msg; + EXPECT_FALSE(Get(&msg, 0)); + EXPECT_TRUE(deleted); +} +
diff --git a/talk/examples/android/src/org/appspot/apprtc/AppRTCClient.java b/talk/examples/android/src/org/appspot/apprtc/AppRTCClient.java index 1807359..036e97e 100644 --- a/talk/examples/android/src/org/appspot/apprtc/AppRTCClient.java +++ b/talk/examples/android/src/org/appspot/apprtc/AppRTCClient.java
@@ -34,6 +34,7 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import org.webrtc.MediaConstraints; import org.webrtc.PeerConnection; import java.io.IOException; @@ -122,6 +123,10 @@ return appRTCSignalingParameters.initiator; } + public MediaConstraints pcConstraints() { + return appRTCSignalingParameters.pcConstraints; + } + // Struct holding the signaling parameters of an AppRTC room. private class AppRTCSignalingParameters { public final List<PeerConnection.IceServer> iceServers; @@ -129,15 +134,18 @@ public final String channelToken; public final String postMessageUrl; public final boolean initiator; + public final MediaConstraints pcConstraints; + public AppRTCSignalingParameters( List<PeerConnection.IceServer> iceServers, String gaeBaseHref, String channelToken, String postMessageUrl, - boolean initiator) { + boolean initiator, MediaConstraints pcConstraints) { this.iceServers = iceServers; this.gaeBaseHref = gaeBaseHref; this.channelToken = channelToken; this.postMessageUrl = postMessageUrl; this.initiator = initiator; + this.pcConstraints = pcConstraints; } } @@ -250,8 +258,42 @@ requestTurnServer(getVarValue(roomHtml, "turnUrl", true))); } + MediaConstraints pcConstraints = constraintsFromJSON( + getVarValue(roomHtml, "pcConstraints", false)); + return new AppRTCSignalingParameters( - iceServers, gaeBaseHref, token, postMessageUrl, initiator); + iceServers, gaeBaseHref, token, postMessageUrl, initiator, + pcConstraints); + } + + private MediaConstraints constraintsFromJSON(String jsonString) { + try { + MediaConstraints constraints = new MediaConstraints(); + JSONObject json = new JSONObject(jsonString); + if (json.has("mandatory")) { + JSONObject mandatoryJSON = json.getJSONObject("mandatory"); + JSONArray mandatoryKeys = mandatoryJSON.names(); + for (int i = 0; i < mandatoryKeys.length(); ++i) { + String key = (String) mandatoryKeys.getString(i); + String value = mandatoryJSON.getString(key); + constraints.mandatory.add( + new MediaConstraints.KeyValuePair(key, value)); + } + } + if (json.has("optional")) { + JSONArray optionalJSON = json.getJSONArray("optional"); + for (int i = 0; i < optionalJSON.length(); ++i) { + JSONObject keyValueDict = optionalJSON.getJSONObject(i); + String key = keyValueDict.names().getString(0); + String value = keyValueDict.getString(key); + constraints.optional.add( + new MediaConstraints.KeyValuePair(key, value)); + } + } + return constraints; + } catch (JSONException e) { + throw new RuntimeException(e); + } } // Scan |roomHtml| for declaration & assignment of |varName| and return its
diff --git a/talk/examples/android/src/org/appspot/apprtc/AppRTCDemoActivity.java b/talk/examples/android/src/org/appspot/apprtc/AppRTCDemoActivity.java index 020ab49..70b2594 100644 --- a/talk/examples/android/src/org/appspot/apprtc/AppRTCDemoActivity.java +++ b/talk/examples/android/src/org/appspot/apprtc/AppRTCDemoActivity.java
@@ -167,7 +167,7 @@ PeerConnectionFactory factory = new PeerConnectionFactory(); pc = factory.createPeerConnection( - iceServers, new MediaConstraints(), pcObserver); + iceServers, appRtcClient.pcConstraints(), pcObserver); { final PeerConnection finalPC = pc;
diff --git a/talk/media/devices/devicemanager_unittest.cc b/talk/media/devices/devicemanager_unittest.cc index 02bd273..d8564ea 100644 --- a/talk/media/devices/devicemanager_unittest.cc +++ b/talk/media/devices/devicemanager_unittest.cc
@@ -362,6 +362,8 @@ } #endif // LINUX +// TODO(noahric): These are flaky on windows on headless machines. +#ifndef WIN32 TEST(DeviceManagerTest, GetWindows) { if (!talk_base::WindowPickerFactory::IsSupported()) { LOG(LS_INFO) << "skipping test: window capturing is not supported with " @@ -403,6 +405,7 @@ descriptions.front().id())); EXPECT_FALSE(capturer.get() == NULL); } +#endif // !WIN32 TEST_F(DeviceManagerTestFake, CaptureConstraintsWhitelisted) { const Device device("white", "white_id");
diff --git a/talk/media/webrtc/fakewebrtcvoiceengine.h b/talk/media/webrtc/fakewebrtcvoiceengine.h index a273deb..b2b92d0 100644 --- a/talk/media/webrtc/fakewebrtcvoiceengine.h +++ b/talk/media/webrtc/fakewebrtcvoiceengine.h
@@ -631,16 +631,21 @@ } WEBRTC_STUB(GetRemoteSSRC, (int channel, unsigned int& ssrc)); WEBRTC_FUNC(SetRTPAudioLevelIndicationStatus, (int channel, bool enable, - unsigned char ID)) { + unsigned char id)) { WEBRTC_CHECK_CHANNEL(channel); - channels_[channel]->level_header_ext_ = (enable) ? ID : -1; + if (enable && (id < 1 || id > 14)) { + // [RFC5285] The 4-bit ID is the local identifier of this element in + // the range 1-14 inclusive. + return -1; + } + channels_[channel]->level_header_ext_ = (enable) ? id : -1; return 0; } WEBRTC_FUNC(GetRTPAudioLevelIndicationStatus, (int channel, bool& enabled, - unsigned char& ID)) { + unsigned char& id)) { WEBRTC_CHECK_CHANNEL(channel); enabled = (channels_[channel]->level_header_ext_ != -1); - ID = channels_[channel]->level_header_ext_; + id = channels_[channel]->level_header_ext_; return 0; } WEBRTC_STUB(GetRemoteCSRCs, (int channel, unsigned int arrCSRC[15])); @@ -715,6 +720,9 @@ redPayloadtype = channels_[channel]->fec_type; return 0; } +#ifdef USE_WEBRTC_DEV_BRANCH + WEBRTC_STUB(SetNACKStatus, (int channel, bool enable, int maxNoPackets)); +#endif WEBRTC_STUB(StartRTPDump, (int channel, const char* fileNameUTF8, webrtc::RTPDirections direction)); WEBRTC_STUB(StopRTPDump, (int channel, webrtc::RTPDirections direction));
diff --git a/talk/media/webrtc/webrtcvoiceengine.cc b/talk/media/webrtc/webrtcvoiceengine.cc index e78ffec..70fb1cf 100644 --- a/talk/media/webrtc/webrtcvoiceengine.cc +++ b/talk/media/webrtc/webrtcvoiceengine.cc
@@ -1824,17 +1824,11 @@ } LOG(LS_INFO) << "Enabling audio level header extension with ID " << id; -// This api call is not available in iOS version of VoiceEngine currently. -#if !defined(IOS) && !defined(ANDROID) if (engine()->voe()->rtp()->SetRTPAudioLevelIndicationStatus( voe_channel(), enable, id) == -1) { LOG_RTCERR3(SetRTPAudioLevelIndicationStatus, voe_channel(), enable, id); return false; } -#else - LOG(LS_WARNING) << "Not enabling audio level header extension with ID " << id - << " because it's not supported on iOS or Android."; -#endif return true; }
diff --git a/talk/media/webrtc/webrtcvoiceengine_unittest.cc b/talk/media/webrtc/webrtcvoiceengine_unittest.cc index d13383e..f012930 100644 --- a/talk/media/webrtc/webrtcvoiceengine_unittest.cc +++ b/talk/media/webrtc/webrtcvoiceengine_unittest.cc
@@ -1170,6 +1170,14 @@ channel_num, enable, id)); EXPECT_FALSE(enable); + // Ensure unknown extentions won't cause an error. + extensions.push_back(cricket::RtpHeaderExtension( + "urn:ietf:params:unknowextention", 1)); + EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions)); + EXPECT_EQ(0, voe_.GetRTPAudioLevelIndicationStatus( + channel_num, enable, id)); + EXPECT_FALSE(enable); + // Ensure audio levels stay off with an empty list of headers. EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions)); EXPECT_EQ(0, voe_.GetRTPAudioLevelIndicationStatus(
diff --git a/talk/p2p/base/p2ptransportchannel.cc b/talk/p2p/base/p2ptransportchannel.cc index cdd3cd9..fbf4ae6 100644 --- a/talk/p2p/base/p2ptransportchannel.cc +++ b/talk/p2p/base/p2ptransportchannel.cc
@@ -1069,7 +1069,7 @@ if (remote_ice_mode_ == ICEMODE_FULL && role_ == ROLE_CONTROLLING) { use_candidate = (conn == best_connection_) || (best_connection_ == NULL) || - (best_connection_->writable()) || + (!best_connection_->writable()) || (conn->priority() > best_connection_->priority()); } else if (remote_ice_mode_ == ICEMODE_LITE && conn == best_connection_) { use_candidate = best_connection_->writable();
diff --git a/talk/p2p/base/stun.h b/talk/p2p/base/stun.h index 8051ca0..6416e51 100644 --- a/talk/p2p/base/stun.h +++ b/talk/p2p/base/stun.h
@@ -43,7 +43,7 @@ // These are the types of STUN messages defined in RFC 5389. enum StunMessageType { STUN_BINDING_REQUEST = 0x0001, - STUN_BINDING_INDICATION = 0x0010, + STUN_BINDING_INDICATION = 0x0011, STUN_BINDING_RESPONSE = 0x0101, STUN_BINDING_ERROR_RESPONSE = 0x0111, };
diff --git a/talk/p2p/base/stun_unittest.cc b/talk/p2p/base/stun_unittest.cc index 93db91a..43db959 100644 --- a/talk/p2p/base/stun_unittest.cc +++ b/talk/p2p/base/stun_unittest.cc
@@ -565,6 +565,7 @@ EXPECT_EQ(i == 1, IsStunIndicationType(types[i])); EXPECT_EQ(i == 2, IsStunSuccessResponseType(types[i])); EXPECT_EQ(i == 3, IsStunErrorResponseType(types[i])); + EXPECT_EQ(1, types[i] & 0xFEEF); } }