Update talk folder to revision=49260075. Same as 369 in libjingle's google code repository.

TBR=wu@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/1797004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@4338 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
henrike@webrtc.org 2013-07-12 16:04:50 +00:00
parent a9b74ad716
commit 723d683ecb
29 changed files with 934 additions and 211 deletions

12
talk/app/webrtc/OWNERS Normal file
View File

@ -0,0 +1,12 @@
hellner
juberti
mallinath
perkj
ronghuawu
tommi
hellner
juberti
mallinath
perkj
ronghuawu
tommi

View File

@ -95,7 +95,7 @@ class DataChannelObserver {
class DataChannelInterface : public talk_base::RefCountInterface {
public:
enum DataState {
enum DataState { // Keep in sync with DataChannel.java:State.
kConnecting,
kOpen, // The DataChannel is ready to send data.
kClosing,

View File

@ -56,6 +56,7 @@
#undef JNIEXPORT
#define JNIEXPORT __attribute__((visibility("default")))
#include <limits>
#include <map>
#include "talk/app/webrtc/mediaconstraintsinterface.h"
@ -77,6 +78,10 @@ using webrtc::AudioSourceInterface;
using webrtc::AudioTrackInterface;
using webrtc::AudioTrackVector;
using webrtc::CreateSessionDescriptionObserver;
using webrtc::DataBuffer;
using webrtc::DataChannelInit;
using webrtc::DataChannelInterface;
using webrtc::DataChannelObserver;
using webrtc::IceCandidateInterface;
using webrtc::MediaConstraintsInterface;
using webrtc::MediaSourceInterface;
@ -156,6 +161,10 @@ class ClassReferenceHolder {
explicit ClassReferenceHolder(JNIEnv* jni) {
LoadClass(jni, "java/nio/ByteBuffer");
LoadClass(jni, "org/webrtc/AudioTrack");
LoadClass(jni, "org/webrtc/DataChannel");
LoadClass(jni, "org/webrtc/DataChannel$Buffer");
LoadClass(jni, "org/webrtc/DataChannel$Init");
LoadClass(jni, "org/webrtc/DataChannel$State");
LoadClass(jni, "org/webrtc/IceCandidate");
LoadClass(jni, "org/webrtc/MediaSource$State");
LoadClass(jni, "org/webrtc/MediaStream");
@ -254,13 +263,28 @@ jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
return o;
}
jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
return static_cast<jstring>(GetObjectField(jni, object, id));
}
jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
jlong l = jni->GetLongField(object, id);
CHECK_EXCEPTION(jni, "error during GetLongField");
CHECK(l, "");
return l;
}
jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
jint i = jni->GetIntField(object, id);
CHECK_EXCEPTION(jni, "error during GetIntField");
return i;
}
bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
jboolean b = jni->GetBooleanField(object, id);
CHECK_EXCEPTION(jni, "error during GetBooleanField");
return b;
}
jobject NewGlobalRef(JNIEnv* jni, jobject o) {
jobject ret = jni->NewGlobalRef(o);
CHECK_EXCEPTION(jni, "error during NewGlobalRef");
@ -314,18 +338,19 @@ class ScopedLocalRef {
};
// Scoped holder for global Java refs.
template<class T> // T is jclass, jobject, jintArray, etc.
class ScopedGlobalRef {
public:
explicit ScopedGlobalRef(JNIEnv* jni, jobject obj)
: obj_(jni->NewGlobalRef(obj)) {}
explicit ScopedGlobalRef(JNIEnv* jni, T obj)
: obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
~ScopedGlobalRef() {
DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
}
jobject operator*() const {
T operator*() const {
return obj_;
}
private:
jobject obj_;
T obj_;
};
// Return the (singleton) Java Enum object corresponding to |index|;
@ -365,6 +390,32 @@ static std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) {
return ustr.toUTF8String(ret);
}
static DataChannelInit JavaDataChannelInitToNative(
JNIEnv* jni, jobject j_init) {
DataChannelInit init;
jclass j_init_class = FindClass(jni, "org/webrtc/DataChannel$Init");
jfieldID ordered_id = GetFieldID(jni, j_init_class, "ordered", "Z");
jfieldID max_retransmit_time_id =
GetFieldID(jni, j_init_class, "maxRetransmitTimeMs", "I");
jfieldID max_retransmits_id =
GetFieldID(jni, j_init_class, "maxRetransmits", "I");
jfieldID protocol_id =
GetFieldID(jni, j_init_class, "protocol", "Ljava/lang/String;");
jfieldID negotiated_id = GetFieldID(jni, j_init_class, "negotiated", "Z");
jfieldID id_id = GetFieldID(jni, j_init_class, "id", "I");
init.ordered = GetBooleanField(jni, j_init, ordered_id);
init.maxRetransmitTime = GetIntField(jni, j_init, max_retransmit_time_id);
init.maxRetransmits = GetIntField(jni, j_init, max_retransmits_id);
init.protocol = JavaToStdString(
jni, GetStringField(jni, j_init, protocol_id));
init.negotiated = GetBooleanField(jni, j_init, negotiated_id);
init.id = GetIntField(jni, j_init, id_id);
return init;
}
class ConstraintsWrapper;
// Adapter between the C++ PeerConnectionObserver interface and the Java
@ -374,25 +425,24 @@ class PCOJava : public PeerConnectionObserver {
public:
PCOJava(JNIEnv* jni, jobject j_observer)
: j_observer_global_(jni, j_observer),
j_observer_class_((jclass)NewGlobalRef(
jni, GetObjectClass(jni, *j_observer_global_))),
j_media_stream_class_((jclass)NewGlobalRef(
jni, FindClass(jni, "org/webrtc/MediaStream"))),
j_media_stream_ctor_(GetMethodID(jni,
j_media_stream_class_, "<init>", "(J)V")),
j_audio_track_class_((jclass)NewGlobalRef(
jni, FindClass(jni, "org/webrtc/AudioTrack"))),
j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)),
j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")),
j_media_stream_ctor_(GetMethodID(
jni, *j_media_stream_class_, "<init>", "(J)V")),
j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")),
j_audio_track_ctor_(GetMethodID(
jni, j_audio_track_class_, "<init>", "(J)V")),
j_video_track_class_((jclass)NewGlobalRef(
jni, FindClass(jni, "org/webrtc/VideoTrack"))),
j_video_track_ctor_(GetMethodID(jni,
j_video_track_class_, "<init>", "(J)V")) {
jni, *j_audio_track_class_, "<init>", "(J)V")),
j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")),
j_video_track_ctor_(GetMethodID(
jni, *j_video_track_class_, "<init>", "(J)V")),
j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")),
j_data_channel_ctor_(GetMethodID(
jni, *j_data_channel_class_, "<init>", "(J)V")) {
}
virtual ~PCOJava() {}
virtual void OnIceCandidate(const IceCandidateInterface* candidate) {
virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
std::string sdp;
CHECK(candidate->ToString(&sdp), "got so far: " << sdp);
jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
@ -404,22 +454,22 @@ class PCOJava : public PeerConnectionObserver {
ScopedLocalRef<jobject> j_candidate(jni(), jni()->NewObject(
candidate_class, ctor, *j_mid, candidate->sdp_mline_index(), *j_sdp));
CHECK_EXCEPTION(jni(), "error during NewObject");
jmethodID m = GetMethodID(jni(), j_observer_class_,
jmethodID m = GetMethodID(jni(), *j_observer_class_,
"onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
jni()->CallVoidMethod(*j_observer_global_, m, *j_candidate);
CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
}
virtual void OnError() {
jmethodID m = GetMethodID(jni(), j_observer_class_, "onError", "(V)V");
virtual void OnError() OVERRIDE {
jmethodID m = GetMethodID(jni(), *j_observer_class_, "onError", "(V)V");
jni()->CallVoidMethod(*j_observer_global_, m);
CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
}
virtual void OnSignalingChange(
PeerConnectionInterface::SignalingState new_state) {
PeerConnectionInterface::SignalingState new_state) OVERRIDE {
jmethodID m = GetMethodID(
jni(), j_observer_class_, "onSignalingChange",
jni(), *j_observer_class_, "onSignalingChange",
"(Lorg/webrtc/PeerConnection$SignalingState;)V");
ScopedLocalRef<jobject> new_state_enum(jni(), JavaEnumFromIndex(
jni(), "PeerConnection$SignalingState", new_state));
@ -428,9 +478,9 @@ class PCOJava : public PeerConnectionObserver {
}
virtual void OnIceConnectionChange(
PeerConnectionInterface::IceConnectionState new_state) {
PeerConnectionInterface::IceConnectionState new_state) OVERRIDE {
jmethodID m = GetMethodID(
jni(), j_observer_class_, "onIceConnectionChange",
jni(), *j_observer_class_, "onIceConnectionChange",
"(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
ScopedLocalRef<jobject> new_state_enum(jni(), JavaEnumFromIndex(
jni(), "PeerConnection$IceConnectionState", new_state));
@ -439,9 +489,9 @@ class PCOJava : public PeerConnectionObserver {
}
virtual void OnIceGatheringChange(
PeerConnectionInterface::IceGatheringState new_state) {
PeerConnectionInterface::IceGatheringState new_state) OVERRIDE {
jmethodID m = GetMethodID(
jni(), j_observer_class_, "onIceGatheringChange",
jni(), *j_observer_class_, "onIceGatheringChange",
"(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
ScopedLocalRef<jobject> new_state_enum(jni(), JavaEnumFromIndex(
jni(), "PeerConnection$IceGatheringState", new_state));
@ -449,9 +499,9 @@ class PCOJava : public PeerConnectionObserver {
CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
}
virtual void OnAddStream(MediaStreamInterface* stream) {
virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE {
ScopedLocalRef<jobject> j_stream(jni(), jni()->NewObject(
j_media_stream_class_, j_media_stream_ctor_, (jlong)stream));
*j_media_stream_class_, j_media_stream_ctor_, (jlong)stream));
CHECK_EXCEPTION(jni(), "error during NewObject");
AudioTrackVector audio_tracks = stream->GetAudioTracks();
@ -460,10 +510,10 @@ class PCOJava : public PeerConnectionObserver {
ScopedLocalRef<jstring> id(
jni(), JavaStringFromStdString(jni(), track->id()));
ScopedLocalRef<jobject> j_track(jni(), jni()->NewObject(
j_audio_track_class_, j_audio_track_ctor_, (jlong)track, *id));
*j_audio_track_class_, j_audio_track_ctor_, (jlong)track, *id));
CHECK_EXCEPTION(jni(), "error during NewObject");
jfieldID audio_tracks_id = GetFieldID(jni(),
j_media_stream_class_, "audioTracks", "Ljava/util/List;");
jfieldID audio_tracks_id = GetFieldID(
jni(), *j_media_stream_class_, "audioTracks", "Ljava/util/List;");
ScopedLocalRef<jobject> audio_tracks(jni(), GetObjectField(
jni(), *j_stream, audio_tracks_id));
jmethodID add = GetMethodID(jni(),
@ -479,10 +529,10 @@ class PCOJava : public PeerConnectionObserver {
ScopedLocalRef<jstring> id(
jni(), JavaStringFromStdString(jni(), track->id()));
ScopedLocalRef<jobject> j_track(jni(), jni()->NewObject(
j_video_track_class_, j_video_track_ctor_, (jlong)track, *id));
*j_video_track_class_, j_video_track_ctor_, (jlong)track, *id));
CHECK_EXCEPTION(jni(), "error during NewObject");
jfieldID video_tracks_id = GetFieldID(jni(),
j_media_stream_class_, "videoTracks", "Ljava/util/List;");
jfieldID video_tracks_id = GetFieldID(
jni(), *j_media_stream_class_, "videoTracks", "Ljava/util/List;");
ScopedLocalRef<jobject> video_tracks(jni(), GetObjectField(
jni(), *j_stream, video_tracks_id));
jmethodID add = GetMethodID(jni(),
@ -494,13 +544,13 @@ class PCOJava : public PeerConnectionObserver {
streams_[stream] = jni()->NewWeakGlobalRef(*j_stream);
CHECK_EXCEPTION(jni(), "error during NewWeakGlobalRef");
jmethodID m = GetMethodID(jni(),
j_observer_class_, "onAddStream", "(Lorg/webrtc/MediaStream;)V");
jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
"(Lorg/webrtc/MediaStream;)V");
jni()->CallVoidMethod(*j_observer_global_, m, *j_stream);
CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
}
virtual void OnRemoveStream(MediaStreamInterface* stream) {
virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
NativeToJavaStreamsMap::iterator it = streams_.find(stream);
CHECK(it != streams_.end(), "unexpected stream: " << std::hex << stream);
@ -509,12 +559,26 @@ class PCOJava : public PeerConnectionObserver {
if (!s.obj())
return;
jmethodID m = GetMethodID(jni(),
j_observer_class_, "onRemoveStream", "(Lorg/webrtc/MediaStream;)V");
jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
"(Lorg/webrtc/MediaStream;)V");
jni()->CallVoidMethod(*j_observer_global_, m, s.obj());
CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
}
virtual void OnDataChannel(DataChannelInterface* channel) OVERRIDE {
ScopedLocalRef<jobject> j_channel(jni(), jni()->NewObject(
*j_data_channel_class_, j_data_channel_ctor_, (jlong)channel));
CHECK_EXCEPTION(jni(), "error during NewObject");
// Channel is now owned by Java object, and will be freed from
// DataChannel.dispose().
channel->AddRef();
jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
"(Lorg/webrtc/DataChannel;)V");
jni()->CallVoidMethod(*j_observer_global_, m, *j_channel);
CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
}
void SetConstraints(ConstraintsWrapper* constraints) {
CHECK(!constraints_.get(), "constraints already set!");
constraints_.reset(constraints);
@ -527,14 +591,16 @@ class PCOJava : public PeerConnectionObserver {
return AttachCurrentThreadIfNeeded();
}
const ScopedGlobalRef j_observer_global_;
const jclass j_observer_class_;
const jclass j_media_stream_class_;
const ScopedGlobalRef<jobject> j_observer_global_;
const ScopedGlobalRef<jclass> j_observer_class_;
const ScopedGlobalRef<jclass> j_media_stream_class_;
const jmethodID j_media_stream_ctor_;
const jclass j_audio_track_class_;
const ScopedGlobalRef<jclass> j_audio_track_class_;
const jmethodID j_audio_track_ctor_;
const jclass j_video_track_class_;
const ScopedGlobalRef<jclass> j_video_track_class_;
const jmethodID j_video_track_ctor_;
const ScopedGlobalRef<jclass> j_data_channel_class_;
const jmethodID j_data_channel_ctor_;
typedef std::map<void*, jweak> NativeToJavaStreamsMap;
NativeToJavaStreamsMap streams_; // C++ -> Java streams.
talk_base::scoped_ptr<ConstraintsWrapper> constraints_;
@ -554,8 +620,13 @@ class ConstraintsWrapper : public MediaConstraintsInterface {
virtual ~ConstraintsWrapper() {}
// MediaConstraintsInterface.
virtual const Constraints& GetMandatory() const { return mandatory_; }
virtual const Constraints& GetOptional() const { return optional_; }
virtual const Constraints& GetMandatory() const OVERRIDE {
return mandatory_;
}
virtual const Constraints& GetOptional() const OVERRIDE {
return optional_;
}
private:
// Helper for translating a List<Pair<String, String>> to a Constraints.
@ -630,28 +701,26 @@ class SdpObserverWrapper : public T {
SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
ConstraintsWrapper* constraints)
: constraints_(constraints),
j_observer_global_(NewGlobalRef(jni, j_observer)),
j_observer_class_((jclass)NewGlobalRef(
jni, GetObjectClass(jni, j_observer))) {
j_observer_global_(jni, j_observer),
j_observer_class_(jni, GetObjectClass(jni, j_observer)) {
}
virtual ~SdpObserverWrapper() {
DeleteGlobalRef(jni(), j_observer_global_);
DeleteGlobalRef(jni(), j_observer_class_);
}
virtual ~SdpObserverWrapper() {}
// Can't mark OVERRIDE because of templating.
virtual void OnSuccess() {
jmethodID m = GetMethodID(jni(), j_observer_class_, "onSetSuccess", "()V");
jni()->CallVoidMethod(j_observer_global_, m);
jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
jni()->CallVoidMethod(*j_observer_global_, m);
CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
}
// Can't mark OVERRIDE because of templating.
virtual void OnSuccess(SessionDescriptionInterface* desc) {
jmethodID m = GetMethodID(
jni(), j_observer_class_, "onCreateSuccess",
jni(), *j_observer_class_, "onCreateSuccess",
"(Lorg/webrtc/SessionDescription;)V");
ScopedLocalRef<jobject> j_sdp(jni(), JavaSdpFromNativeSdp(jni(), desc));
jni()->CallVoidMethod(j_observer_global_, m, *j_sdp);
jni()->CallVoidMethod(*j_observer_global_, m, *j_sdp);
CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
}
@ -659,11 +728,11 @@ class SdpObserverWrapper : public T {
// Common implementation for failure of Set & Create types, distinguished by
// |op| being "Set" or "Create".
void OnFailure(const std::string& op, const std::string& error) {
jmethodID m = GetMethodID(jni(),
j_observer_class_, "on" + op + "Failure", "(Ljava/lang/String;)V");
jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure",
"(Ljava/lang/String;)V");
ScopedLocalRef<jstring> j_error_string(
jni(), JavaStringFromStdString(jni(), error));
jni()->CallVoidMethod(j_observer_global_, m, *j_error_string);
jni()->CallVoidMethod(*j_observer_global_, m, *j_error_string);
CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
}
@ -673,8 +742,8 @@ class SdpObserverWrapper : public T {
}
talk_base::scoped_ptr<ConstraintsWrapper> constraints_;
const jobject j_observer_global_;
const jclass j_observer_class_;
const ScopedGlobalRef<jobject> j_observer_global_;
const ScopedGlobalRef<jclass> j_observer_class_;
};
class CreateSdpObserverWrapper
@ -684,7 +753,7 @@ class CreateSdpObserverWrapper
ConstraintsWrapper* constraints)
: SdpObserverWrapper(jni, j_observer, constraints) {}
virtual void OnFailure(const std::string& error) {
virtual void OnFailure(const std::string& error) OVERRIDE {
SdpObserverWrapper::OnFailure(std::string("Create"), error);
}
};
@ -696,42 +765,84 @@ class SetSdpObserverWrapper
ConstraintsWrapper* constraints)
: SdpObserverWrapper(jni, j_observer, constraints) {}
virtual void OnFailure(const std::string& error) {
virtual void OnFailure(const std::string& error) OVERRIDE {
SdpObserverWrapper::OnFailure(std::string("Set"), error);
}
};
// Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
// and dispatching the callback from C++ back to Java.
class DataChannelObserverWrapper : public DataChannelObserver {
public:
DataChannelObserverWrapper(JNIEnv* jni, jobject j_observer)
: j_observer_global_(jni, j_observer),
j_observer_class_(jni, GetObjectClass(jni, j_observer)),
j_on_state_change_mid_(GetMethodID(jni, *j_observer_class_,
"onStateChange", "()V")),
j_on_message_mid_(GetMethodID(jni, *j_observer_class_, "onMessage",
"(Lorg/webrtc/DataChannel$Buffer;)V")),
j_buffer_class_(jni, FindClass(jni, "org/webrtc/DataChannel$Buffer")),
j_buffer_ctor_(GetMethodID(jni, *j_buffer_class_,
"<init>", "(Ljava/nio/ByteBuffer;Z)V")) {
}
virtual ~DataChannelObserverWrapper() {}
virtual void OnStateChange() OVERRIDE {
jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
}
virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
jobject byte_buffer =
jni()->NewDirectByteBuffer(const_cast<char*>(buffer.data.data()),
buffer.data.length());
jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_,
byte_buffer, buffer.binary);
jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer);
CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
}
private:
JNIEnv* jni() {
return AttachCurrentThreadIfNeeded();
}
const ScopedGlobalRef<jobject> j_observer_global_;
const ScopedGlobalRef<jclass> j_observer_class_;
const ScopedGlobalRef<jclass> j_buffer_class_;
const jmethodID j_on_state_change_mid_;
const jmethodID j_on_message_mid_;
const jmethodID j_buffer_ctor_;
};
// Adapter for a Java StatsObserver presenting a C++ StatsObserver and
// dispatching the callback from C++ back to Java.
class StatsObserverWrapper : public StatsObserver {
public:
StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
: j_observer_global_(NewGlobalRef(jni, j_observer)),
j_observer_class_((jclass)NewGlobalRef(
jni, GetObjectClass(jni, j_observer))),
j_stats_report_class_(FindClass(jni, "org/webrtc/StatsReport")),
: j_observer_global_(jni, j_observer),
j_observer_class_(jni, GetObjectClass(jni, j_observer)),
j_stats_report_class_(jni, FindClass(jni, "org/webrtc/StatsReport")),
j_stats_report_ctor_(GetMethodID(
jni, j_stats_report_class_, "<init>",
jni, *j_stats_report_class_, "<init>",
"(Ljava/lang/String;Ljava/lang/String;D"
"[Lorg/webrtc/StatsReport$Value;)V")),
j_value_class_(FindClass(
j_value_class_(jni, FindClass(
jni, "org/webrtc/StatsReport$Value")),
j_value_ctor_(GetMethodID(
jni, j_value_class_, "<init>",
jni, *j_value_class_, "<init>",
"(Ljava/lang/String;Ljava/lang/String;)V")) {
}
virtual ~StatsObserverWrapper() {
DeleteGlobalRef(jni(), j_observer_global_);
DeleteGlobalRef(jni(), j_observer_class_);
}
virtual ~StatsObserverWrapper() {}
virtual void OnComplete(const std::vector<StatsReport>& reports) {
virtual void OnComplete(const std::vector<StatsReport>& reports) OVERRIDE {
ScopedLocalRef<jobjectArray> j_reports(jni(),
ReportsToJava(jni(), reports));
jmethodID m = GetMethodID(
jni(), j_observer_class_, "onComplete", "([Lorg/webrtc/StatsReport;)V");
jni()->CallVoidMethod(j_observer_global_, m, *j_reports);
jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
"([Lorg/webrtc/StatsReport;)V");
jni()->CallVoidMethod(*j_observer_global_, m, *j_reports);
CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
}
@ -739,7 +850,7 @@ class StatsObserverWrapper : public StatsObserver {
jobjectArray ReportsToJava(
JNIEnv* jni, const std::vector<StatsReport>& reports) {
jobjectArray reports_array = jni->NewObjectArray(
reports.size(), j_stats_report_class_, NULL);
reports.size(), *j_stats_report_class_, NULL);
for (int i = 0; i < reports.size(); ++i) {
const StatsReport& report = reports[i];
ScopedLocalRef<jstring> j_id(
@ -749,7 +860,7 @@ class StatsObserverWrapper : public StatsObserver {
ScopedLocalRef<jobjectArray> j_values(
jni, ValuesToJava(jni, report.values));
ScopedLocalRef<jobject> j_report(jni, jni->NewObject(
j_stats_report_class_, j_stats_report_ctor_, *j_id, *j_type,
*j_stats_report_class_, j_stats_report_ctor_, *j_id, *j_type,
report.timestamp, *j_values));
jni->SetObjectArrayElement(reports_array, i, *j_report);
}
@ -758,7 +869,7 @@ class StatsObserverWrapper : public StatsObserver {
jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
jobjectArray j_values = jni->NewObjectArray(
values.size(), j_value_class_, NULL);
values.size(), *j_value_class_, NULL);
for (int i = 0; i < values.size(); ++i) {
const StatsReport::Value& value = values[i];
ScopedLocalRef<jstring> j_name(
@ -766,7 +877,7 @@ class StatsObserverWrapper : public StatsObserver {
ScopedLocalRef<jstring> j_value(
jni, JavaStringFromStdString(jni, value.value));
ScopedLocalRef<jobject> j_element_value(jni, jni->NewObject(
j_value_class_, j_value_ctor_, *j_name, *j_value));
*j_value_class_, j_value_ctor_, *j_name, *j_value));
jni->SetObjectArrayElement(j_values, i, *j_element_value);
}
return j_values;
@ -776,11 +887,11 @@ class StatsObserverWrapper : public StatsObserver {
return AttachCurrentThreadIfNeeded();
}
const jobject j_observer_global_;
const jclass j_observer_class_;
const jclass j_stats_report_class_;
const ScopedGlobalRef<jobject> j_observer_global_;
const ScopedGlobalRef<jclass> j_observer_class_;
const ScopedGlobalRef<jclass> j_stats_report_class_;
const jmethodID j_stats_report_ctor_;
const jclass j_value_class_;
const ScopedGlobalRef<jclass> j_value_class_;
const jmethodID j_value_ctor_;
};
@ -796,12 +907,12 @@ class VideoRendererWrapper : public VideoRendererInterface {
virtual ~VideoRendererWrapper() {}
virtual void SetSize(int width, int height) {
virtual void SetSize(int width, int height) OVERRIDE {
const bool kNotReserved = false; // What does this param mean??
renderer_->SetSize(width, height, kNotReserved);
}
virtual void RenderFrame(const cricket::VideoFrame* frame) {
virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
renderer_->RenderFrame(frame);
}
@ -817,25 +928,28 @@ class VideoRendererWrapper : public VideoRendererInterface {
class JavaVideoRendererWrapper : public VideoRendererInterface {
public:
JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
: j_callbacks_(jni, j_callbacks) {
j_set_size_id_ = GetMethodID(
jni, GetObjectClass(jni, j_callbacks), "setSize", "(II)V");
j_render_frame_id_ = GetMethodID(
jni, GetObjectClass(jni, j_callbacks), "renderFrame",
"(Lorg/webrtc/VideoRenderer$I420Frame;)V");
j_frame_class_ = FindClass(jni, "org/webrtc/VideoRenderer$I420Frame");
j_frame_ctor_id_ = GetMethodID(
jni, j_frame_class_, "<init>", "(II[I[Ljava/nio/ByteBuffer;)V");
j_byte_buffer_class_ = FindClass(jni, "java/nio/ByteBuffer");
: j_callbacks_(jni, j_callbacks),
j_set_size_id_(GetMethodID(
jni, GetObjectClass(jni, j_callbacks), "setSize", "(II)V")),
j_render_frame_id_(GetMethodID(
jni, GetObjectClass(jni, j_callbacks), "renderFrame",
"(Lorg/webrtc/VideoRenderer$I420Frame;)V")),
j_frame_class_(jni,
FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")),
j_frame_ctor_id_(GetMethodID(
jni, *j_frame_class_, "<init>", "(II[I[Ljava/nio/ByteBuffer;)V")),
j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) {
CHECK_EXCEPTION(jni, "");
}
virtual void SetSize(int width, int height) {
virtual ~JavaVideoRendererWrapper() {}
virtual void SetSize(int width, int height) OVERRIDE {
jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
CHECK_EXCEPTION(jni(), "");
}
virtual void RenderFrame(const cricket::VideoFrame* frame) {
virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
ScopedLocalRef<jobject> j_frame(jni(), CricketToJavaFrame(frame));
jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, *j_frame);
CHECK_EXCEPTION(jni(), "");
@ -851,7 +965,7 @@ class JavaVideoRendererWrapper : public VideoRendererInterface {
strides_array[2] = frame->GetVPitch();
jni()->ReleaseIntArrayElements(*strides, strides_array, 0);
ScopedLocalRef<jobjectArray> planes(
jni(), jni()->NewObjectArray(3, j_byte_buffer_class_, NULL));
jni(), jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL));
ScopedLocalRef<jobject> y_buffer(jni(), jni()->NewDirectByteBuffer(
const_cast<uint8*>(frame->GetYPlane()),
frame->GetYPitch() * frame->GetHeight()));
@ -863,7 +977,7 @@ class JavaVideoRendererWrapper : public VideoRendererInterface {
jni()->SetObjectArrayElement(*planes, 1, *u_buffer);
jni()->SetObjectArrayElement(*planes, 2, *v_buffer);
return jni()->NewObject(
j_frame_class_, j_frame_ctor_id_,
*j_frame_class_, j_frame_ctor_id_,
frame->GetWidth(), frame->GetHeight(), *strides, *planes);
}
@ -871,12 +985,12 @@ class JavaVideoRendererWrapper : public VideoRendererInterface {
return AttachCurrentThreadIfNeeded();
}
ScopedGlobalRef j_callbacks_;
ScopedGlobalRef<jobject> j_callbacks_;
jmethodID j_set_size_id_;
jmethodID j_render_frame_id_;
jclass j_frame_class_;
ScopedGlobalRef<jclass> j_frame_class_;
jmethodID j_frame_ctor_id_;
jclass j_byte_buffer_class_;
ScopedGlobalRef<jclass> j_byte_buffer_class_;
};
} // anonymous namespace
@ -920,6 +1034,63 @@ extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
CHECK(talk_base::CleanupSSL(), "Failed to CleanupSSL()");
}
static talk_base::scoped_refptr<DataChannelInterface> ExtractNativeDC(
JNIEnv* jni, jobject j_dc) {
jfieldID native_dc_id = GetFieldID(jni,
GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
jlong j_d = GetLongField(jni, j_dc, native_dc_id);
return talk_base::scoped_refptr<DataChannelInterface>(
reinterpret_cast<DataChannelInterface*>(j_d));
}
JOW(jlong, DataChannel_registerObserverNative)(
JNIEnv* jni, jobject j_dc, jobject j_observer) {
talk_base::scoped_ptr<DataChannelObserverWrapper> observer(
new DataChannelObserverWrapper(jni, j_observer));
ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
return reinterpret_cast<jlong>(observer.release());
}
JOW(void, DataChannel_unregisterObserverNative)(
JNIEnv* jni, jobject j_dc, jlong native_observer) {
ExtractNativeDC(jni, j_dc)->UnregisterObserver();
delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
}
JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
}
JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
return JavaEnumFromIndex(
jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
}
JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
uint64 buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
CHECK(buffered_amount <= std::numeric_limits<int64>::max(),
"buffered_amount overflowed jlong!");
return static_cast<jlong>(buffered_amount);
}
JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
ExtractNativeDC(jni, j_dc)->Close();
}
JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
jbyteArray data, jboolean binary) {
jbyte* bytes = jni->GetByteArrayElements(data, NULL);
bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
talk_base::Buffer(bytes, jni->GetArrayLength(data)),
binary));
jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
return ret;
}
JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
ExtractNativeDC(jni, j_dc)->Release();
}
JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
reinterpret_cast<PeerConnectionInterface*>(j_p)->Release();
}
@ -1134,6 +1305,23 @@ JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
}
JOW(jobject, PeerConnection_createDataChannel)(
JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
talk_base::scoped_refptr<DataChannelInterface> channel(
ExtractNativePC(jni, j_pc)->CreateDataChannel(
JavaToStdString(jni, j_label), &init));
jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
jmethodID j_data_channel_ctor = GetMethodID(
jni, j_data_channel_class, "<init>", "(J)V");
jobject j_channel = jni->NewObject(
j_data_channel_class, j_data_channel_ctor, channel.get());
CHECK_EXCEPTION(jni, "error during NewObject");
// Channel is now owned by Java object, and will be freed from there.
channel->AddRef();
return j_channel;
}
JOW(void, PeerConnection_createOffer)(
JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
ConstraintsWrapper* constraints =

View File

@ -0,0 +1,282 @@
/*
* 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.webrtc;
import java.nio.ByteBuffer;
/** Java wrapper for a C++ DataChannelInterface. */
public class DataChannel {
/** Java wrapper for WebIDL RTCDataChannel. */
public static class Init {
public boolean ordered = true;
// Optional unsigned short in WebIDL, -1 means unspecified.
public int maxRetransmitTimeMs = -1;
// Optional unsigned short in WebIDL, -1 means unspecified.
public int maxRetransmits = -1;
public String protocol = "";
public boolean negotiated = true;
// Optional unsigned short in WebIDL, -1 means unspecified.
public int id = -1;
public Init() {}
// Called only by native code.
private Init(
boolean ordered, int maxRetransmitTimeMs, int maxRetransmits,
String protocol, boolean negotiated, int id) {
this.ordered = ordered;
this.maxRetransmitTimeMs = maxRetransmitTimeMs;
this.maxRetransmits = maxRetransmits;
this.protocol = protocol;
this.negotiated = negotiated;
this.id = id;
}
}
/** Java version of C++ DataBuffer. The atom of data in a DataChannel. */
public static class Buffer {
/** The underlying data. */
public final ByteBuffer data;
/**
* Indicates whether |data| contains UTF-8 text or "binary data"
* (i.e. anything else).
*/
public final boolean binary;
public Buffer(ByteBuffer data, boolean binary) {
this.data = data;
this.binary = binary;
}
}
/** Java version of C++ DataChannelObserver. */
public interface Observer {
/** The data channel state has changed. */
public void onStateChange();
/**
* A data buffer was successfully received. NOTE: |buffer.data| will be
* freed once this function returns so callers who want to use the data
* asynchronously must make sure to copy it first.
*/
public void onMessage(Buffer buffer);
}
/** Keep in sync with DataChannelInterface::DataState. */
public enum State { CONNECTING, OPEN, CLOSING, CLOSED };
private final long nativeDataChannel;
private long nativeObserver;
public DataChannel(long nativeDataChannel) {
this.nativeDataChannel = nativeDataChannel;
}
/** Register |observer|, replacing any previously-registered observer. */
public void registerObserver(Observer observer) {
if (nativeObserver != 0) {
unregisterObserverNative(nativeObserver);
}
nativeObserver = registerObserverNative(observer);
}
private native long registerObserverNative(Observer observer);
/** Unregister the (only) observer. */
public void unregisterObserver() {
unregisterObserverNative(nativeObserver);
}
private native void unregisterObserverNative(long nativeObserver);
public native String label();
public native State state();
/**
* Return the number of bytes of application data (UTF-8 text and binary data)
* that have been queued using SendBuffer but have not yet been transmitted
* to the network.
*/
public native long bufferedAmount();
/** Close the channel. */
public native void close();
/** Send |data| to the remote peer; return success. */
public boolean send(Buffer buffer) {
// TODO(fischman): this could be cleverer about avoiding copies if the
// ByteBuffer is direct and/or is backed by an array.
byte[] data = new byte[buffer.data.remaining()];
buffer.data.get(data);
return sendNative(data, buffer.binary);
}
private native boolean sendNative(byte[] data, boolean binary);
/** Dispose of native resources attached to this channel. */
public native void dispose();
};
/*
* 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.webrtc;
import java.nio.ByteBuffer;
/** Java wrapper for a C++ DataChannelInterface. */
public class DataChannel {
/** Java wrapper for WebIDL RTCDataChannel. */
public static class Init {
public boolean ordered = true;
// Optional unsigned short in WebIDL, -1 means unspecified.
public int maxRetransmitTimeMs = -1;
// Optional unsigned short in WebIDL, -1 means unspecified.
public int maxRetransmits = -1;
public String protocol = "";
public boolean negotiated = true;
// Optional unsigned short in WebIDL, -1 means unspecified.
public int id = -1;
public Init() {}
// Called only by native code.
private Init(
boolean ordered, int maxRetransmitTimeMs, int maxRetransmits,
String protocol, boolean negotiated, int id) {
this.ordered = ordered;
this.maxRetransmitTimeMs = maxRetransmitTimeMs;
this.maxRetransmits = maxRetransmits;
this.protocol = protocol;
this.negotiated = negotiated;
this.id = id;
}
}
/** Java version of C++ DataBuffer. The atom of data in a DataChannel. */
public static class Buffer {
/** The underlying data. */
public final ByteBuffer data;
/**
* Indicates whether |data| contains UTF-8 text or "binary data"
* (i.e. anything else).
*/
public final boolean binary;
public Buffer(ByteBuffer data, boolean binary) {
this.data = data;
this.binary = binary;
}
}
/** Java version of C++ DataChannelObserver. */
public interface Observer {
/** The data channel state has changed. */
public void onStateChange();
/**
* A data buffer was successfully received. NOTE: |buffer.data| will be
* freed once this function returns so callers who want to use the data
* asynchronously must make sure to copy it first.
*/
public void onMessage(Buffer buffer);
}
/** Keep in sync with DataChannelInterface::DataState. */
public enum State { CONNECTING, OPEN, CLOSING, CLOSED };
private final long nativeDataChannel;
private long nativeObserver;
public DataChannel(long nativeDataChannel) {
this.nativeDataChannel = nativeDataChannel;
}
/** Register |observer|, replacing any previously-registered observer. */
public void registerObserver(Observer observer) {
if (nativeObserver != 0) {
unregisterObserverNative(nativeObserver);
}
nativeObserver = registerObserverNative(observer);
}
private native long registerObserverNative(Observer observer);
/** Unregister the (only) observer. */
public void unregisterObserver() {
unregisterObserverNative(nativeObserver);
}
private native void unregisterObserverNative(long nativeObserver);
public native String label();
public native State state();
/**
* Return the number of bytes of application data (UTF-8 text and binary data)
* that have been queued using SendBuffer but have not yet been transmitted
* to the network.
*/
public native long bufferedAmount();
/** Close the channel. */
public native void close();
/** Send |data| to the remote peer; return success. */
public boolean send(Buffer buffer) {
// TODO(fischman): this could be cleverer about avoiding copies if the
// ByteBuffer is direct and/or is backed by an array.
byte[] data = new byte[buffer.data.remaining()];
buffer.data.get(data);
return sendNative(data, buffer.binary);
}
private native boolean sendNative(byte[] data, boolean binary);
/** Dispose of native resources attached to this channel. */
public native void dispose();
};

View File

@ -79,6 +79,9 @@ public class PeerConnection {
/** Triggered when a remote peer close a stream. */
public void onRemoveStream(MediaStream stream);
/** Triggered when a remote peer opens a DataChannel. */
public void onDataChannel(DataChannel dataChannel);
}
/** Java version of PeerConnectionInterface.IceServer. */
@ -118,6 +121,9 @@ public class PeerConnection {
public native SessionDescription getRemoteDescription();
public native DataChannel createDataChannel(
String label, DataChannel.Init init);
public native void createOffer(
SdpObserver observer, MediaConstraints constraints);

View File

@ -35,9 +35,13 @@ import org.webrtc.PeerConnection.IceGatheringState;
import org.webrtc.PeerConnection.SignalingState;
import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.IdentityHashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.TreeSet;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@ -48,7 +52,9 @@ public class PeerConnectionTest extends TestCase {
private static class ObserverExpectations implements PeerConnection.Observer,
VideoRenderer.Callbacks,
DataChannel.Observer,
StatsObserver {
private final String name;
private int expectedIceCandidates = 0;
private int expectedErrors = 0;
private LinkedList<Integer> expectedSetSizeDimensions =
@ -68,10 +74,28 @@ public class PeerConnectionTest extends TestCase {
new LinkedList<IceCandidate>();
private Map<MediaStream, WeakReference<VideoRenderer>> renderers =
new IdentityHashMap<MediaStream, WeakReference<VideoRenderer>>();
private DataChannel dataChannel;
private LinkedList<DataChannel.Buffer> expectedBuffers =
new LinkedList<DataChannel.Buffer>();
private LinkedList<DataChannel.State> expectedStateChanges =
new LinkedList<DataChannel.State>();
private LinkedList<String> expectedRemoteDataChannelLabels =
new LinkedList<String>();
private int expectedStatsCallbacks = 0;
private LinkedList<StatsReport[]> gotStatsReports =
new LinkedList<StatsReport[]>();
public ObserverExpectations(String name) {
this.name = name;
}
public synchronized void setDataChannel(DataChannel dataChannel) {
assertNull(this.dataChannel);
this.dataChannel = dataChannel;
this.dataChannel.registerObserver(this);
assertNotNull(this.dataChannel);
}
public synchronized void expectIceCandidates(int count) {
expectedIceCandidates += count;
}
@ -93,17 +117,24 @@ public class PeerConnectionTest extends TestCase {
}
public synchronized void expectSetSize(int width, int height) {
if (RENDER_TO_GUI) {
// When new frames are delivered to the GUI renderer we don't get
// notified of frame size info.
return;
}
expectedSetSizeDimensions.add(width);
expectedSetSizeDimensions.add(height);
}
@Override
public synchronized void setSize(int width, int height) {
assertFalse(RENDER_TO_GUI);
assertEquals(width, expectedSetSizeDimensions.removeFirst().intValue());
assertEquals(height, expectedSetSizeDimensions.removeFirst().intValue());
}
public synchronized void expectFramesDelivered(int count) {
assertFalse(RENDER_TO_GUI);
expectedFramesDelivered += count;
}
@ -127,7 +158,8 @@ public class PeerConnectionTest extends TestCase {
}
@Override
public void onIceConnectionChange(IceConnectionState newState) {
public synchronized void onIceConnectionChange(
IceConnectionState newState) {
assertEquals(expectedIceConnectionChanges.removeFirst(), newState);
}
@ -137,7 +169,7 @@ public class PeerConnectionTest extends TestCase {
}
@Override
public void onIceGatheringChange(IceGatheringState newState) {
public synchronized void onIceGatheringChange(IceGatheringState newState) {
// It's fine to get a variable number of GATHERING messages before
// COMPLETE fires (depending on how long the test runs) so we don't assert
// any particular count.
@ -178,6 +210,40 @@ public class PeerConnectionTest extends TestCase {
stream.videoTracks.get(0).removeRenderer(renderer.get());
}
public synchronized void expectDataChannel(String label) {
expectedRemoteDataChannelLabels.add(label);
}
@Override
public synchronized void onDataChannel(DataChannel remoteDataChannel) {
assertEquals(expectedRemoteDataChannelLabels.removeFirst(),
remoteDataChannel.label());
setDataChannel(remoteDataChannel);
assertEquals(DataChannel.State.CONNECTING, dataChannel.state());
}
public synchronized void expectMessage(ByteBuffer expectedBuffer,
boolean expectedBinary) {
expectedBuffers.add(
new DataChannel.Buffer(expectedBuffer, expectedBinary));
}
@Override
public synchronized void onMessage(DataChannel.Buffer buffer) {
DataChannel.Buffer expected = expectedBuffers.removeFirst();
assertEquals(expected.binary, buffer.binary);
assertTrue(expected.data.equals(buffer.data));
}
@Override
public synchronized void onStateChange() {
assertEquals(expectedStateChanges.removeFirst(), dataChannel.state());
}
public synchronized void expectStateChange(DataChannel.State state) {
expectedStateChanges.add(state);
}
@Override
public synchronized void onComplete(StatsReport[] reports) {
if (--expectedStatsCallbacks < 0) {
@ -196,17 +262,61 @@ public class PeerConnectionTest extends TestCase {
return got;
}
public synchronized boolean areAllExpectationsSatisfied() {
return expectedIceCandidates <= 0 && // See comment in onIceCandidate.
expectedErrors == 0 &&
expectedSignalingChanges.size() == 0 &&
expectedIceConnectionChanges.size() == 0 &&
expectedIceGatheringChanges.size() == 0 &&
expectedAddStreamLabels.size() == 0 &&
expectedRemoveStreamLabels.size() == 0 &&
expectedSetSizeDimensions.isEmpty() &&
expectedFramesDelivered <= 0 &&
expectedStatsCallbacks == 0;
// Return a set of expectations that haven't been satisfied yet, possibly
// empty if no such expectations exist.
public synchronized TreeSet<String> unsatisfiedExpectations() {
TreeSet<String> stillWaitingForExpectations = new TreeSet<String>();
if (expectedIceCandidates > 0) { // See comment in onIceCandidate.
stillWaitingForExpectations.add("expectedIceCandidates");
}
if (expectedErrors != 0) {
stillWaitingForExpectations.add("expectedErrors: " + expectedErrors);
}
if (expectedSignalingChanges.size() != 0) {
stillWaitingForExpectations.add(
"expectedSignalingChanges: " + expectedSignalingChanges.size());
}
if (expectedIceConnectionChanges.size() != 0) {
stillWaitingForExpectations.add("expectedIceConnectionChanges: " +
expectedIceConnectionChanges.size());
}
if (expectedIceGatheringChanges.size() != 0) {
stillWaitingForExpectations.add("expectedIceGatheringChanges: " +
expectedIceGatheringChanges.size());
}
if (expectedAddStreamLabels.size() != 0) {
stillWaitingForExpectations.add(
"expectedAddStreamLabels: " + expectedAddStreamLabels.size());
}
if (expectedRemoveStreamLabels.size() != 0) {
stillWaitingForExpectations.add(
"expectedRemoveStreamLabels: " + expectedRemoveStreamLabels.size());
}
if (!expectedSetSizeDimensions.isEmpty()) {
stillWaitingForExpectations.add(
"expectedSetSizeDimensions: " + expectedSetSizeDimensions.size());
}
if (expectedFramesDelivered > 0) {
stillWaitingForExpectations.add(
"expectedFramesDelivered: " + expectedFramesDelivered);
}
if (!expectedBuffers.isEmpty()) {
stillWaitingForExpectations.add(
"expectedBuffers: " + expectedBuffers.size());
}
if (!expectedStateChanges.isEmpty()) {
stillWaitingForExpectations.add(
"expectedStateChanges: " + expectedStateChanges.size());
}
if (!expectedRemoteDataChannelLabels.isEmpty()) {
stillWaitingForExpectations.add("expectedRemoteDataChannelLabels: " +
expectedRemoteDataChannelLabels.size());
}
if (expectedStatsCallbacks != 0) {
stillWaitingForExpectations.add(
"expectedStatsCallbacks: " + expectedStatsCallbacks);
}
return stillWaitingForExpectations;
}
public void waitForAllExpectationsToBeSatisfied() {
@ -219,12 +329,27 @@ public class PeerConnectionTest extends TestCase {
// stall a wait). Use callbacks to fire off dependent steps instead of
// explicitly waiting, so there can be just a single wait at the end of
// the test.
while (!areAllExpectationsSatisfied()) {
TreeSet<String> prev = null;
TreeSet<String> stillWaitingForExpectations = unsatisfiedExpectations();
while (!stillWaitingForExpectations.isEmpty()) {
if (!stillWaitingForExpectations.equals(prev)) {
System.out.println(
name + " still waiting at\n " +
(new Throwable()).getStackTrace()[1] +
"\n for: " +
Arrays.toString(stillWaitingForExpectations.toArray()));
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
prev = stillWaitingForExpectations;
stillWaitingForExpectations = unsatisfiedExpectations();
}
if (prev == null) {
System.out.println(name + " didn't need to wait at\n " +
(new Throwable()).getStackTrace()[1]);
}
}
}
@ -298,9 +423,9 @@ public class PeerConnectionTest extends TestCase {
}
private static VideoRenderer createVideoRenderer(
ObserverExpectations observer) {
VideoRenderer.Callbacks videoCallbacks) {
if (!RENDER_TO_GUI) {
return new VideoRenderer(observer);
return new VideoRenderer(videoCallbacks);
}
++videoWindowsMapped;
assertTrue(videoWindowsMapped < 4);
@ -315,12 +440,12 @@ public class PeerConnectionTest extends TestCase {
PeerConnectionFactory factory, PeerConnection pc,
VideoSource videoSource,
String streamLabel, String videoTrackId, String audioTrackId,
ObserverExpectations observer) {
VideoRenderer.Callbacks videoCallbacks) {
MediaStream lMS = factory.createLocalMediaStream(streamLabel);
VideoTrack videoTrack =
factory.createVideoTrack(videoTrackId, videoSource);
assertNotNull(videoTrack);
VideoRenderer videoRenderer = createVideoRenderer(observer);
VideoRenderer videoRenderer = createVideoRenderer(videoCallbacks);
assertNotNull(videoRenderer);
videoTrack.addRenderer(videoRenderer);
lMS.addTrack(videoTrack);
@ -343,7 +468,15 @@ public class PeerConnectionTest extends TestCase {
CountDownLatch testDone = new CountDownLatch(1);
PeerConnectionFactory factory = new PeerConnectionFactory();
MediaConstraints constraints = new MediaConstraints();
MediaConstraints pcConstraints = new MediaConstraints();
pcConstraints.mandatory.add(
new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));
pcConstraints.optional.add(
new MediaConstraints.KeyValuePair("RtpDataChannels", "true"));
// TODO(fischman): replace above with below to test SCTP channels when
// supported (https://code.google.com/p/webrtc/issues/detail?id=1408).
// pcConstraints.optional.add(new MediaConstraints.KeyValuePair(
// "internalSctpDataChannels", "true"));
LinkedList<PeerConnection.IceServer> iceServers =
new LinkedList<PeerConnection.IceServer>();
@ -351,14 +484,16 @@ public class PeerConnectionTest extends TestCase {
"stun:stun.l.google.com:19302"));
iceServers.add(new PeerConnection.IceServer(
"turn:fake.example.com", "fakeUsername", "fakePassword"));
ObserverExpectations offeringExpectations = new ObserverExpectations();
ObserverExpectations offeringExpectations =
new ObserverExpectations("PCTest:offerer");
PeerConnection offeringPC = factory.createPeerConnection(
iceServers, constraints, offeringExpectations);
iceServers, pcConstraints, offeringExpectations);
assertNotNull(offeringPC);
ObserverExpectations answeringExpectations = new ObserverExpectations();
ObserverExpectations answeringExpectations =
new ObserverExpectations("PCTest:answerer");
PeerConnection answeringPC = factory.createPeerConnection(
iceServers, constraints, answeringExpectations);
iceServers, pcConstraints, answeringExpectations);
assertNotNull(answeringPC);
// We want to use the same camera for offerer & answerer, so create it here
@ -371,12 +506,16 @@ public class PeerConnectionTest extends TestCase {
// serialized SDP, because the C++ API doesn't auto-translate.
// Drop |label| params from {Audio,Video}Track-related APIs once
// https://code.google.com/p/webrtc/issues/detail?id=1253 is fixed.
offeringExpectations.expectSetSize(640, 480);
WeakReference<MediaStream> oLMS = addTracksToPC(
factory, offeringPC, videoSource, "oLMS", "oLMSv0", "oLMSa0",
offeringExpectations);
offeringExpectations.setDataChannel(offeringPC.createDataChannel(
"offeringDC", new DataChannel.Init()));
SdpObserverLatch sdpLatch = new SdpObserverLatch();
offeringPC.createOffer(sdpLatch, constraints);
offeringPC.createOffer(sdpLatch, new MediaConstraints());
assertTrue(sdpLatch.await());
SessionDescription offerSdp = sdpLatch.getSdp();
assertEquals(offerSdp.type, SessionDescription.Type.OFFER);
@ -386,19 +525,20 @@ public class PeerConnectionTest extends TestCase {
answeringExpectations.expectSignalingChange(
SignalingState.HAVE_REMOTE_OFFER);
answeringExpectations.expectAddStream("oLMS");
answeringExpectations.expectDataChannel("offeringDC");
answeringPC.setRemoteDescription(sdpLatch, offerSdp);
answeringExpectations.waitForAllExpectationsToBeSatisfied();
assertEquals(
PeerConnection.SignalingState.STABLE, offeringPC.signalingState());
assertTrue(sdpLatch.await());
assertNull(sdpLatch.getSdp());
answeringExpectations.expectSetSize(640, 480);
WeakReference<MediaStream> aLMS = addTracksToPC(
factory, answeringPC, videoSource, "aLMS", "aLMSv0", "aLMSa0",
answeringExpectations);
sdpLatch = new SdpObserverLatch();
answeringPC.createAnswer(sdpLatch, constraints);
answeringPC.createAnswer(sdpLatch, new MediaConstraints());
assertTrue(sdpLatch.await());
SessionDescription answerSdp = sdpLatch.getSdp();
assertEquals(answerSdp.type, SessionDescription.Type.ANSWER);
@ -407,6 +547,9 @@ public class PeerConnectionTest extends TestCase {
offeringExpectations.expectIceCandidates(2);
answeringExpectations.expectIceCandidates(2);
offeringExpectations.expectIceGatheringChange(IceGatheringState.COMPLETE);
answeringExpectations.expectIceGatheringChange(IceGatheringState.COMPLETE);
sdpLatch = new SdpObserverLatch();
answeringExpectations.expectSignalingChange(SignalingState.STABLE);
answeringPC.setLocalDescription(sdpLatch, answerSdp);
@ -434,14 +577,12 @@ public class PeerConnectionTest extends TestCase {
assertEquals(answeringPC.getRemoteDescription().type, offerSdp.type);
if (!RENDER_TO_GUI) {
offeringExpectations.expectSetSize(640, 480);
offeringExpectations.expectSetSize(640, 480);
answeringExpectations.expectSetSize(640, 480);
answeringExpectations.expectSetSize(640, 480);
// Wait for at least some frames to be delivered at each end (number
// chosen arbitrarily).
offeringExpectations.expectFramesDelivered(10);
answeringExpectations.expectFramesDelivered(10);
offeringExpectations.expectSetSize(640, 480);
answeringExpectations.expectSetSize(640, 480);
}
offeringExpectations.expectIceConnectionChange(
@ -453,8 +594,8 @@ public class PeerConnectionTest extends TestCase {
answeringExpectations.expectIceConnectionChange(
IceConnectionState.CONNECTED);
offeringExpectations.expectIceGatheringChange(IceGatheringState.COMPLETE);
answeringExpectations.expectIceGatheringChange(IceGatheringState.COMPLETE);
offeringExpectations.expectStateChange(DataChannel.State.OPEN);
answeringExpectations.expectStateChange(DataChannel.State.OPEN);
for (IceCandidate candidate : offeringExpectations.gotIceCandidates) {
answeringPC.addIceCandidate(candidate);
@ -473,6 +614,38 @@ public class PeerConnectionTest extends TestCase {
assertEquals(
PeerConnection.SignalingState.STABLE, answeringPC.signalingState());
// Test send & receive UTF-8 text.
answeringExpectations.expectMessage(
ByteBuffer.wrap("hello!".getBytes(Charset.forName("UTF-8"))), false);
DataChannel.Buffer buffer = new DataChannel.Buffer(
ByteBuffer.wrap("hello!".getBytes(Charset.forName("UTF-8"))), false);
assertTrue(offeringExpectations.dataChannel.send(buffer));
answeringExpectations.waitForAllExpectationsToBeSatisfied();
// TODO(fischman): add testing of binary messages when SCTP channels are
// supported (https://code.google.com/p/webrtc/issues/detail?id=1408).
// // Construct this binary message two different ways to ensure no
// // shortcuts are taken.
// ByteBuffer expectedBinaryMessage = ByteBuffer.allocateDirect(5);
// for (byte i = 1; i < 6; ++i) {
// expectedBinaryMessage.put(i);
// }
// expectedBinaryMessage.flip();
// offeringExpectations.expectMessage(expectedBinaryMessage, true);
// assertTrue(answeringExpectations.dataChannel.send(
// new DataChannel.Buffer(
// ByteBuffer.wrap(new byte[] { 1, 2, 3, 4, 5 } ), true)));
// offeringExpectations.waitForAllExpectationsToBeSatisfied();
offeringExpectations.expectStateChange(DataChannel.State.CLOSING);
answeringExpectations.expectStateChange(DataChannel.State.CLOSING);
answeringExpectations.dataChannel.close();
offeringExpectations.dataChannel.close();
// TODO(fischman): implement a new offer/answer exchange to finalize the
// closing of the channel in order to see the CLOSED state reached.
// offeringExpectations.expectStateChange(DataChannel.State.CLOSED);
// answeringExpectations.expectStateChange(DataChannel.State.CLOSED);
if (RENDER_TO_GUI) {
try {
Thread.sleep(3000);
@ -505,6 +678,8 @@ public class PeerConnectionTest extends TestCase {
private static void shutdownPC(
PeerConnection pc, ObserverExpectations expectations) {
expectations.dataChannel.unregisterObserver();
expectations.dataChannel.dispose();
expectations.expectStatsCallback();
assertTrue(pc.getStats(expectations, null));
expectations.waitForAllExpectationsToBeSatisfied();

View File

@ -732,8 +732,9 @@ TEST_F(MediaStreamSignalingTest, AddRemoveTrackFromExistingRemoteMediaStream) {
reference_collection_));
// Remove the extra audio and video tracks again.
CreateSessionDescriptionAndReference(1, 1, desc_ms1.use());
signaling_->OnRemoteDescriptionChanged(desc_ms1.get());
talk_base::scoped_ptr<SessionDescriptionInterface> desc_ms2;
CreateSessionDescriptionAndReference(1, 1, desc_ms2.use());
signaling_->OnRemoteDescriptionChanged(desc_ms2.get());
EXPECT_TRUE(CompareStreamCollections(signaling_->remote_streams(),
reference_collection_));
EXPECT_TRUE(CompareStreamCollections(observer_->remote_streams(),

View File

@ -83,9 +83,11 @@
}
webrtc::RTCPeerConnectionObserver *observer =
new webrtc::RTCPeerConnectionObserver(delegate);
webrtc::DTLSIdentityServiceInterface* dummy_dtls_identity_service = NULL;
talk_base::scoped_refptr<webrtc::PeerConnectionInterface> peerConnection =
self.nativeFactory->CreatePeerConnection(
iceServers, constraints.constraints, observer);
iceServers, constraints.constraints, dummy_dtls_identity_service,
observer);
RTCPeerConnection *pc =
[[RTCPeerConnection alloc] initWithPeerConnection:peerConnection
observer:observer];

View File

@ -884,6 +884,7 @@ class P2PTestConductor : public testing::Test {
if (receiving_client_) {
receiving_client_->set_signaling_message_receiver(NULL);
}
talk_base::CleanupSSL();
}
bool CreateTestClients() {

View File

@ -31,7 +31,7 @@
#include "talk/base/network.h"
#include "talk/base/thread.h"
#include "talk/p2p/base/basicpacketsocketfactory.h"
#include "talk/p2p/client/httpportallocator.h"
#include "talk/p2p/client/basicportallocator.h"
static const char kUserAgent[] = "PeerConnection User Agent";

View File

@ -470,8 +470,8 @@ class WebRtcSessionTest : public testing::Test {
desc_factory_->set_secure(cricket::SEC_ENABLED);
std::string identity_name = "WebRTC" +
talk_base::ToString(talk_base::CreateRandomId());
tdesc_factory_->set_identity(talk_base::SSLIdentity::Generate(
identity_name));
identity_.reset(talk_base::SSLIdentity::Generate(identity_name));
tdesc_factory_->set_identity(identity_.get());
tdesc_factory_->set_digest_algorithm(talk_base::DIGEST_SHA_256);
tdesc_factory_->set_secure(cricket::SEC_REQUIRED);
}
@ -701,8 +701,8 @@ class WebRtcSessionTest : public testing::Test {
// and answer.
SetLocalDescriptionWithoutError(offer);
SessionDescriptionInterface* answer = CreateRemoteAnswer(
session_->local_description());
talk_base::scoped_ptr<SessionDescriptionInterface> answer(
CreateRemoteAnswer(session_->local_description()));
std::string sdp;
EXPECT_TRUE(answer->ToString(&sdp));
@ -722,11 +722,9 @@ class WebRtcSessionTest : public testing::Test {
SessionDescriptionInterface* new_answer = CreateSessionDescription(
JsepSessionDescription::kAnswer, sdp, NULL);
delete answer;
answer = new_answer;
// SetRemoteDescription to enable rtcp mux.
SetRemoteDescriptionWithoutError(answer);
SetRemoteDescriptionWithoutError(new_answer);
EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout);
EXPECT_EQ(expected_candidate_num, observer_.mline_0_candidates_.size());
EXPECT_EQ(expected_candidate_num, observer_.mline_1_candidates_.size());
@ -858,6 +856,7 @@ class WebRtcSessionTest : public testing::Test {
cricket::FakeDeviceManager* device_manager_;
talk_base::scoped_ptr<cricket::ChannelManager> channel_manager_;
talk_base::scoped_ptr<cricket::TransportDescriptionFactory> tdesc_factory_;
talk_base::scoped_ptr<talk_base::SSLIdentity> identity_;
talk_base::scoped_ptr<cricket::MediaSessionDescriptionFactory> desc_factory_;
talk_base::scoped_ptr<talk_base::PhysicalSocketServer> pss_;
talk_base::scoped_ptr<talk_base::VirtualSocketServer> vss_;
@ -1877,8 +1876,8 @@ TEST_F(WebRtcSessionTest, VerifyCryptoParamsInSDP) {
session_->CreateOffer(NULL));
VerifyCryptoParams(offer->description());
SetRemoteDescriptionWithoutError(offer.release());
const webrtc::SessionDescriptionInterface* answer =
session_->CreateAnswer(NULL);
scoped_ptr<SessionDescriptionInterface> answer(
session_->CreateAnswer(NULL));
VerifyCryptoParams(answer->description());
}
@ -2101,7 +2100,8 @@ TEST_F(WebRtcSessionTest, TestInitiatorGIceInAnswer) {
Init();
mediastream_signaling_.SendAudioVideoStream1();
SessionDescriptionInterface* offer = session_->CreateOffer(NULL);
SessionDescriptionInterface* answer = CreateRemoteAnswer(offer);
talk_base::scoped_ptr<SessionDescriptionInterface> answer(
CreateRemoteAnswer(offer));
SetLocalDescriptionWithoutError(offer);
std::string sdp;
EXPECT_TRUE(answer->ToString(&sdp));
@ -2137,7 +2137,8 @@ TEST_F(WebRtcSessionTest, TestReceiverGIceInOffer) {
mediastream_signaling_.SendAudioVideoStream1();
SessionDescriptionInterface* offer = session_->CreateOffer(NULL);
SetRemoteDescriptionWithoutError(offer);
SessionDescriptionInterface* answer = session_->CreateAnswer(NULL);
talk_base::scoped_ptr<SessionDescriptionInterface> answer(
session_->CreateAnswer(NULL));
std::string sdp;
EXPECT_TRUE(answer->ToString(&sdp));
// Adding ice-options to the session level.
@ -2185,15 +2186,16 @@ TEST_F(WebRtcSessionTest, TestIceOfferGIceOnlyAnswer) {
SetLocalDescriptionWithoutError(ice_only_offer);
std::string original_offer_sdp;
EXPECT_TRUE(offer->ToString(&original_offer_sdp));
SessionDescriptionInterface* pranswer_with_gice =
talk_base::scoped_ptr<SessionDescriptionInterface> pranswer_with_gice(
CreateSessionDescription(JsepSessionDescription::kPrAnswer,
original_offer_sdp, NULL);
original_offer_sdp, NULL));
SetRemoteDescriptionExpectError(kPushDownPranswerTDFailed,
pranswer_with_gice);
SessionDescriptionInterface* answer_with_gice =
pranswer_with_gice.get());
talk_base::scoped_ptr<SessionDescriptionInterface> answer_with_gice(
CreateSessionDescription(JsepSessionDescription::kAnswer,
original_offer_sdp, NULL);
SetRemoteDescriptionExpectError(kPushDownAnswerTDFailed, answer_with_gice);
original_offer_sdp, NULL));
SetRemoteDescriptionExpectError(kPushDownAnswerTDFailed,
answer_with_gice.get());
}
// Verifing local offer and remote answer have matching m-lines as per RFC 3264.
@ -2207,13 +2209,13 @@ TEST_F(WebRtcSessionTest, TestIncorrectMLinesInRemoteAnswer) {
cricket::SessionDescription* answer_copy = answer->description()->Copy();
answer_copy->RemoveContentByName("video");
JsepSessionDescription* modified_answer =
new JsepSessionDescription(JsepSessionDescription::kAnswer);
talk_base::scoped_ptr<JsepSessionDescription> modified_answer(
new JsepSessionDescription(JsepSessionDescription::kAnswer));
EXPECT_TRUE(modified_answer->Initialize(answer_copy,
answer->session_id(),
answer->session_version()));
SetRemoteDescriptionExpectError(kMlineMismatch, modified_answer);
SetRemoteDescriptionExpectError(kMlineMismatch, modified_answer.get());
// Modifying content names.
std::string sdp;
@ -2227,9 +2229,9 @@ TEST_F(WebRtcSessionTest, TestIncorrectMLinesInRemoteAnswer) {
kAudioMidReplaceStr.length(),
&sdp);
SessionDescriptionInterface* modified_answer1 =
CreateSessionDescription(JsepSessionDescription::kAnswer, sdp, NULL);
SetRemoteDescriptionExpectError(kMlineMismatch, modified_answer1);
talk_base::scoped_ptr<SessionDescriptionInterface> modified_answer1(
CreateSessionDescription(JsepSessionDescription::kAnswer, sdp, NULL));
SetRemoteDescriptionExpectError(kMlineMismatch, modified_answer1.get());
SetRemoteDescriptionWithoutError(answer.release());
}
@ -2388,9 +2390,9 @@ TEST_F(WebRtcSessionTest, TestSessionContentError) {
video_channel_->set_fail_set_send_codecs(true);
mediastream_signaling_.SendAudioVideoStream2();
SessionDescriptionInterface* answer =
CreateRemoteAnswer(session_->local_description());
SetRemoteDescriptionExpectError("ERROR_CONTENT", answer);
talk_base::scoped_ptr<SessionDescriptionInterface> answer(
CreateRemoteAnswer(session_->local_description()));
SetRemoteDescriptionExpectError("ERROR_CONTENT", answer.get());
}
// Runs the loopback call test with BUNDLE and STUN disabled.

View File

@ -73,6 +73,7 @@ public:
virtual void SetUp() { }
virtual void TearDown() {
delete http_stream;
// Avoid an ASSERT, in case a test doesn't clean up properly
base.abort(HE_NONE);
}

View File

@ -78,8 +78,8 @@ TEST(MultipartTest, TestAddAndRead) {
EXPECT_TRUE(multipart.GetSize(&size));
EXPECT_EQ(part_size, size);
talk_base::MemoryStream* stream =
new talk_base::MemoryStream(kTestStreamContent);
talk_base::scoped_ptr<talk_base::MemoryStream> stream(
new talk_base::MemoryStream(kTestStreamContent));
size_t stream_size = 0;
EXPECT_TRUE(stream->GetSize(&stream_size));
part_size +=

View File

@ -247,11 +247,11 @@ void TestPhysicalInternal(const SocketAddress& int_addr) {
SocketAddress(ext_addr2)
};
PhysicalSocketServer* int_pss = new PhysicalSocketServer();
PhysicalSocketServer* ext_pss = new PhysicalSocketServer();
scoped_ptr<PhysicalSocketServer> int_pss(new PhysicalSocketServer());
scoped_ptr<PhysicalSocketServer> ext_pss(new PhysicalSocketServer());
TestBindings(int_pss, int_addr, ext_pss, ext_addrs);
TestFilters(int_pss, int_addr, ext_pss, ext_addrs);
TestBindings(int_pss.get(), int_addr, ext_pss.get(), ext_addrs);
TestFilters(int_pss.get(), int_addr, ext_pss.get(), ext_addrs);
}
TEST(NatTest, TestPhysicalIPv4) {
@ -269,16 +269,20 @@ TEST(NatTest, TestPhysicalIPv6) {
class TestVirtualSocketServer : public VirtualSocketServer {
public:
explicit TestVirtualSocketServer(SocketServer* ss)
: VirtualSocketServer(ss) {}
: VirtualSocketServer(ss),
ss_(ss) {}
// Expose this publicly
IPAddress GetNextIP(int af) { return VirtualSocketServer::GetNextIP(af); }
private:
scoped_ptr<SocketServer> ss_;
};
void TestVirtualInternal(int family) {
TestVirtualSocketServer* int_vss = new TestVirtualSocketServer(
new PhysicalSocketServer());
TestVirtualSocketServer* ext_vss = new TestVirtualSocketServer(
new PhysicalSocketServer());
scoped_ptr<TestVirtualSocketServer> int_vss(new TestVirtualSocketServer(
new PhysicalSocketServer()));
scoped_ptr<TestVirtualSocketServer> ext_vss(new TestVirtualSocketServer(
new PhysicalSocketServer()));
SocketAddress int_addr;
SocketAddress ext_addrs[4];
@ -288,8 +292,8 @@ void TestVirtualInternal(int family) {
ext_addrs[2].SetIP(ext_addrs[0].ipaddr());
ext_addrs[3].SetIP(ext_addrs[1].ipaddr());
TestBindings(int_vss, int_addr, ext_vss, ext_addrs);
TestFilters(int_vss, int_addr, ext_vss, ext_addrs);
TestBindings(int_vss.get(), int_addr, ext_vss.get(), ext_addrs);
TestFilters(int_vss.get(), int_addr, ext_vss.get(), ext_addrs);
}
TEST(NatTest, TestVirtualIPv4) {

View File

@ -498,6 +498,11 @@ void BasicNetworkManager::DumpNetworks(bool include_ignored) {
<< ((network->ignored()) ? ", Ignored" : "");
}
}
// Release the network list created previously.
// Do this in a seperated for loop for better readability.
for (size_t i = 0; i < list.size(); ++i) {
delete list[i];
}
}
Network::Network(const std::string& name, const std::string& desc,

View File

@ -128,6 +128,7 @@ TEST_F(NetworkTest, TestCreateNetworks) {
close(fd);
#endif
}
delete (*it);
}
}
@ -480,6 +481,10 @@ TEST_F(NetworkTest, TestIPv6Toggle) {
}
}
EXPECT_TRUE(ipv6_found);
for (NetworkManager::NetworkList::iterator it = list.begin();
it != list.end(); ++it) {
delete (*it);
}
#endif
ipv6_found = false;
manager.set_ipv6_enabled(false);
@ -492,6 +497,10 @@ TEST_F(NetworkTest, TestIPv6Toggle) {
}
}
EXPECT_FALSE(ipv6_found);
for (NetworkManager::NetworkList::iterator it = list.begin();
it != list.end(); ++it) {
delete (*it);
}
}
#if defined(POSIX)

View File

@ -287,7 +287,8 @@ TEST_F(PosixSignalDeliveryTest, SignalOnDifferentThread) {
// thread. Our implementation should safely handle it and dispatch
// RecordSignal() on this thread.
scoped_ptr<Thread> thread(new Thread());
thread->Start(new RaiseSigTermRunnable());
scoped_ptr<RaiseSigTermRunnable> runnable(new RaiseSigTermRunnable());
thread->Start(runnable.get());
EXPECT_TRUE(ss_->Wait(1500, true));
EXPECT_TRUE(ExpectSignal(SIGTERM));
EXPECT_EQ(Thread::Current(), signaled_thread_);

View File

@ -445,7 +445,7 @@ bool GetDefaultFirefoxProfile(Pathname* profile_path) {
// Note: we are looking for the first entry with "Default=1", or the last
// entry in the file
path.SetFilename("profiles.ini");
FileStream* fs = Filesystem::OpenFile(path, "r");
scoped_ptr<FileStream> fs(Filesystem::OpenFile(path, "r"));
if (!fs) {
return false;
}
@ -510,7 +510,7 @@ bool GetDefaultFirefoxProfile(Pathname* profile_path) {
bool ReadFirefoxPrefs(const Pathname& filename,
const char * prefix,
StringMap* settings) {
FileStream* fs = Filesystem::OpenFile(filename, "r");
scoped_ptr<FileStream> fs(Filesystem::OpenFile(filename, "r"));
if (!fs) {
LOG(LS_ERROR) << "Failed to open file: " << filename.pathname();
return false;

View File

@ -127,6 +127,8 @@ class OwnerThread : public Thread, public sigslot::has_slots<> {
signal_thread->Start();
Thread::Current()->socketserver()->Wait(100, false);
signal_thread->Release();
// Delete |signal_thread|.
signal_thread->Destroy(true);
has_run_ = true;
}

View File

@ -926,6 +926,8 @@ void SocketTest::UdpReadyToSend(const IPAddress& loopback) {
new TestClient(AsyncUDPSocket::Create(ss_, empty)));
int test_packet_size = 1200;
talk_base::scoped_array<char> test_packet(new char[test_packet_size]);
// Init the test packet just to avoid memcheck warning.
memset(test_packet.get(), 0, test_packet_size);
// Set the send buffer size to the same size as the test packet to have a
// better chance to get EWOULDBLOCK.
int send_buffer_size = test_packet_size;

View File

@ -102,6 +102,11 @@
'use_nss%': 1,
},
}],
['libjingle_objc==1', {
'defines': [
'CARBON_DEPRECATED=YES',
],
}],
['os_posix==1', {
'defines': [
'HASH_NAMESPACE=__gnu_cxx',

View File

@ -42,6 +42,7 @@ import android.widget.Toast;
import org.json.JSONException;
import org.json.JSONObject;
import org.webrtc.DataChannel;
import org.webrtc.IceCandidate;
import org.webrtc.MediaConstraints;
import org.webrtc.MediaStream;
@ -333,6 +334,16 @@ public class AppRTCDemoActivity extends Activity
}
});
}
@Override public void onDataChannel(final DataChannel dc) {
runOnUiThread(new Runnable() {
public void run() {
throw new RuntimeException(
"AppRTC doesn't use data channels, but got: " + dc.label() +
" anyway!");
}
});
}
}
// Implementation detail: handle offer creation/signaling and answer setting,

View File

@ -84,6 +84,7 @@
'peerconnection_java_files': [
'app/webrtc/java/src/org/webrtc/AudioSource.java',
'app/webrtc/java/src/org/webrtc/AudioTrack.java',
'app/webrtc/java/src/org/webrtc/DataChannel.java',
'app/webrtc/java/src/org/webrtc/IceCandidate.java',
'app/webrtc/java/src/org/webrtc/MediaConstraints.java',
'app/webrtc/java/src/org/webrtc/MediaSource.java',
@ -590,15 +591,7 @@
}],
['OS=="mac"', {
'conditions': [
[ 'libjingle_objc != 1', {
'sources': [
'base/macasyncsocket.cc',
'base/macasyncsocket.h',
'base/maccocoasocketserver.h',
'base/maccocoasocketserver.mm',
'base/macsocketserver.cc',
'base/macsocketserver.h',
],
['libjingle_objc != 1', {
'link_settings' :{
'xcode_settings': {
'OTHER_LDFLAGS': [
@ -606,15 +599,17 @@
],
},
},
}, {
'defines': [
'CARBON_DEPRECATED=YES',
],
}],
],
'sources': [
'base/macasyncsocket.cc',
'base/macasyncsocket.h',
'base/maccocoasocketserver.h',
'base/maccocoasocketserver.mm',
'base/macconversion.cc',
'base/macconversion.h',
'base/macsocketserver.cc',
'base/macsocketserver.h',
'base/macutils.cc',
'base/macutils.h',
'base/macwindowpicker.cc',
@ -967,11 +962,11 @@
'libjingle_media',
],
'include_dirs': [
'<(DEPTH)/third_party/gtest/include',
'<(DEPTH)/testing/gtest/include',
],
'direct_dependent_settings': {
'include_dirs': [
'<(DEPTH)/third_party/gtest/include',
'<(DEPTH)/testing/gtest/include',
],
},
'defines': [

View File

@ -233,6 +233,7 @@
# (http://crbug.com/225101)
'action_name': 'build_apprtcdemo_apk',
'inputs' : [
'<(PRODUCT_DIR)/libjingle_peerconnection.jar',
'<(PRODUCT_DIR)/libjingle_peerconnection_so.so',
'examples/android/AndroidManifest.xml',
'examples/android/README',
@ -256,7 +257,7 @@
],
'action': [
'bash', '-ec',
'rm -f <(_outputs) && '
'rm -fr <(_outputs) examples/android/{bin,libs} && '
'mkdir -p examples/android/libs/<(android_app_abi) && '
'cp <(PRODUCT_DIR)/libjingle_peerconnection.jar examples/android/libs/ &&'
'<(android_strip) -o examples/android/libs/<(android_app_abi)/libjingle_peerconnection_so.so <(PRODUCT_DIR)/libjingle_peerconnection_so.so &&'

View File

@ -33,15 +33,15 @@
'target_name': 'gunit',
'type': 'static_library',
'sources': [
'<(DEPTH)/third_party/gtest/src/gtest-all.cc',
'<(DEPTH)/testing/gtest/src/gtest-all.cc',
],
'include_dirs': [
'<(DEPTH)/third_party/gtest/include',
'<(DEPTH)/third_party/gtest',
'<(DEPTH)/testing/gtest/include',
'<(DEPTH)/testing/gtest',
],
'direct_dependent_settings': {
'include_dirs': [
'<(DEPTH)/third_party/gtest/include',
'<(DEPTH)/testing/gtest/include',
],
},
'conditions': [

View File

@ -708,10 +708,6 @@ class FakeWebRtcVideoEngine
WEBRTC_STUB(DeregisterDecoderObserver, (const int));
WEBRTC_STUB(SendKeyFrame, (const int));
WEBRTC_STUB(WaitForFirstKeyFrame, (const int, const bool));
#ifdef USE_WEBRTC_DEV_BRANCH
WEBRTC_STUB(StartDebugRecording, (int, const char*));
WEBRTC_STUB(StopDebugRecording, (int));
#endif
// webrtc::ViECapture
WEBRTC_STUB(NumberOfCaptureDevices, ());
@ -783,10 +779,12 @@ class FakeWebRtcVideoEngine
// Not using WEBRTC_STUB due to bool return value
virtual bool IsIPv6Enabled(int channel) { return true; }
WEBRTC_STUB(SetMTU, (int, unsigned int));
#ifndef USE_WEBRTC_DEV_BRANCH
WEBRTC_STUB(SetPacketTimeoutNotification, (const int, bool, int));
WEBRTC_STUB(RegisterObserver, (const int, webrtc::ViENetworkObserver&));
WEBRTC_STUB(SetPeriodicDeadOrAliveStatus, (const int, const bool,
const unsigned int));
#endif
// webrtc::ViERender
WEBRTC_STUB(RegisterVideoRenderModule, (webrtc::VideoRender&));

View File

@ -609,6 +609,7 @@ class FakeWebRtcVoiceEngine
}
WEBRTC_STUB(ReceivedRTCPPacket, (int channel, const void* data,
unsigned int length));
#ifndef USE_WEBRTC_DEV_BRANCH
// Not using WEBRTC_STUB due to bool return value
WEBRTC_STUB(SetPacketTimeoutNotification, (int channel, bool enable,
int timeoutSeconds));
@ -621,6 +622,7 @@ class FakeWebRtcVoiceEngine
int& sampleTimeSeconds));
WEBRTC_STUB(SetPeriodicDeadOrAliveStatus, (int channel, bool enable,
int sampleTimeSeconds));
#endif
// webrtc::VoERTP_RTCP
WEBRTC_STUB(RegisterRTPObserver, (int channel,
@ -741,7 +743,11 @@ class FakeWebRtcVoiceEngine
// webrtc::VoEVideoSync
WEBRTC_STUB(GetPlayoutBufferSize, (int& bufferMs));
WEBRTC_STUB(GetPlayoutTimestamp, (int channel, unsigned int& timestamp));
#ifdef USE_WEBRTC_DEV_BRANCH
WEBRTC_STUB(GetRtpRtcp, (int, webrtc::RtpRtcp**, webrtc::RtpReceiver**));
#else
WEBRTC_STUB(GetRtpRtcp, (int, webrtc::RtpRtcp*&));
#endif
WEBRTC_STUB(SetInitTimestamp, (int channel, unsigned int timestamp));
WEBRTC_STUB(SetInitSequenceNumber, (int channel, short sequenceNumber));
WEBRTC_STUB(SetMinimumPlayoutDelay, (int channel, int delayMs));

View File

@ -43,6 +43,7 @@
#include "talk/media/base/hybriddataengine.h"
#include "talk/media/base/rtpdataengine.h"
#include "talk/media/base/videocapturer.h"
#include "talk/media/devices/devicemanager.h"
#ifdef HAVE_SCTP
#include "talk/media/sctp/sctpdataengine.h"
#endif
@ -595,6 +596,14 @@ bool ChannelManager::IsSameCapturer(const std::string& capturer_name,
return capturer->GetId() == device.id;
}
bool ChannelManager::GetVideoCaptureDevice(Device* device) {
std::string device_name;
if (!GetCaptureDevice(&device_name)) {
return false;
}
return device_manager_->GetVideoCaptureDevice(device_name, device);
}
bool ChannelManager::GetCaptureDevice(std::string* cam_name) {
if (camera_device_.empty()) {
// Initialize camera_device_ with default.

View File

@ -144,7 +144,12 @@ class ChannelManager : public talk_base::MessageHandler,
bool SetOutputVolume(int level);
bool IsSameCapturer(const std::string& capturer_name,
VideoCapturer* capturer);
// TODO(noahric): Nearly everything called "device" in this API is actually a
// device name, so this should really be GetCaptureDeviceName, and the
// next method should be GetCaptureDevice.
bool GetCaptureDevice(std::string* cam_device);
// Gets the current capture Device.
bool GetVideoCaptureDevice(Device* device);
// Create capturer based on what has been set in SetCaptureDevice().
VideoCapturer* CreateVideoCapturer();
bool SetCaptureDevice(const std::string& cam_device);