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:
parent
a9b74ad716
commit
723d683ecb
12
talk/app/webrtc/OWNERS
Normal file
12
talk/app/webrtc/OWNERS
Normal file
@ -0,0 +1,12 @@
|
||||
hellner
|
||||
juberti
|
||||
mallinath
|
||||
perkj
|
||||
ronghuawu
|
||||
tommi
|
||||
hellner
|
||||
juberti
|
||||
mallinath
|
||||
perkj
|
||||
ronghuawu
|
||||
tommi
|
@ -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,
|
||||
|
@ -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 =
|
||||
|
282
talk/app/webrtc/java/src/org/webrtc/DataChannel.java
Normal file
282
talk/app/webrtc/java/src/org/webrtc/DataChannel.java
Normal 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();
|
||||
};
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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(),
|
||||
|
@ -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];
|
||||
|
@ -884,6 +884,7 @@ class P2PTestConductor : public testing::Test {
|
||||
if (receiving_client_) {
|
||||
receiving_client_->set_signaling_message_receiver(NULL);
|
||||
}
|
||||
talk_base::CleanupSSL();
|
||||
}
|
||||
|
||||
bool CreateTestClients() {
|
||||
|
@ -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";
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 +=
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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_);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -102,6 +102,11 @@
|
||||
'use_nss%': 1,
|
||||
},
|
||||
}],
|
||||
['libjingle_objc==1', {
|
||||
'defines': [
|
||||
'CARBON_DEPRECATED=YES',
|
||||
],
|
||||
}],
|
||||
['os_posix==1', {
|
||||
'defines': [
|
||||
'HASH_NAMESPACE=__gnu_cxx',
|
||||
|
@ -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,
|
||||
|
@ -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': [
|
||||
|
@ -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 &&'
|
||||
|
@ -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': [
|
||||
|
@ -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&));
|
||||
|
@ -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));
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user