Skip to content

Commit

Permalink
Trimmed down version of the changes
Browse files Browse the repository at this point in the history
  • Loading branch information
youennf committed Dec 7, 2018
1 parent 6a51887 commit c115aba
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 54 deletions.
16 changes: 8 additions & 8 deletions webrtc/RTCDataChannel-send.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// createDataChannelPair
// awaitMessage
// blobToArrayBuffer
// assert_equals_array_buffer
// assert_equals_typed_array

/*
6.2. RTCDataChannel
Expand Down Expand Up @@ -140,7 +140,7 @@
assert_true(messageBuffer instanceof ArrayBuffer,
'Expect messageBuffer to be an ArrayBuffer');

assert_equals_array_buffer(messageBuffer, helloBuffer.buffer);
assert_equals_typed_array(messageBuffer, helloBuffer.buffer);
});
}, 'Data channel should be able to send Uint8Array message and receive as ArrayBuffer');

Expand All @@ -162,7 +162,7 @@
assert_true(messageBuffer instanceof ArrayBuffer,
'Expect messageBuffer to be an ArrayBuffer');

assert_equals_array_buffer(messageBuffer, helloBuffer.buffer);
assert_equals_typed_array(messageBuffer, helloBuffer.buffer);
});
}, 'Data channel should be able to send ArrayBuffer message and receive as ArrayBuffer');

Expand All @@ -183,7 +183,7 @@
assert_true(messageBuffer instanceof ArrayBuffer,
'Expect messageBuffer to be an ArrayBuffer');

assert_equals_array_buffer(messageBuffer, helloBuffer.buffer);
assert_equals_typed_array(messageBuffer, helloBuffer.buffer);
});
}, 'Data channel should be able to send Blob message and receive as ArrayBuffer');

Expand All @@ -210,7 +210,7 @@
assert_true(messageBuffer instanceof ArrayBuffer,
'Expect messageBuffer to be an ArrayBuffer');

assert_equals_array_buffer(messageBuffer, helloBuffer.buffer);
assert_equals_typed_array(messageBuffer, helloBuffer.buffer);
});
}, 'Data channel should be able to send ArrayBuffer message and receive as Blob');

Expand Down Expand Up @@ -240,7 +240,7 @@
assert_true(messageBuffer instanceof ArrayBuffer,
'Expect messageBuffer to be an ArrayBuffer');

assert_equals_array_buffer(messageBuffer, helloBuffer.buffer);
assert_equals_typed_array(messageBuffer, helloBuffer.buffer);
});
}, 'Data channel binaryType should receive message as Blob by default');

Expand All @@ -253,9 +253,9 @@
receivedMessages.push(data);

if(receivedMessages.length === 3) {
assert_equals_array_buffer(receivedMessages[0], helloBuffer.buffer);
assert_equals_typed_array(receivedMessages[0], helloBuffer.buffer);
assert_equals(receivedMessages[1], unicodeString);
assert_equals_array_buffer(receivedMessages[2], helloBuffer.buffer);
assert_equals_typed_array(receivedMessages[2], helloBuffer.buffer);

t.done();
}
Expand Down
195 changes: 150 additions & 45 deletions webrtc/RTCPeerConnection-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,39 +159,95 @@ function test_never_resolve(testFunc, testName) {
}, testName);
}

// Helper class to queue ICE candidates of a peer connection
// Can be passed to `exchangeIceCandidates` which will automatically empty the queue.
class IceCandidateQueue {
constructor(pc) {
this.pc = pc;
this._queue = [];
this._listener = (event) => this._handleIceCandidate(event);

// Queue ICE candidates
this.pc.addEventListener('icecandidate', this._listener);
}

// Unbind the event listener and return all queued candidates
disband() {
this.pc.removeEventListener('icecandidate', this._listener);
return this._queue;
}

_handleIceCandidate(event) {
this._queue.push(event.candidate);
}
}

// Helper function to exchange ice candidates between
// two local peer connections
function exchangeIceCandidates(pc1, pc2) {
// private function
function doExchange(localPc, remotePc) {
localPc.addEventListener('icecandidate', event => {
const { candidate } = event;
function exchangeIceCandidates(pc1OrQueue, pc2OrQueue) {
const handleCandidate = (remotePc, candidate) => {
// candidate may be null to indicate end of candidate gathering.
// There is ongoing discussion on w3c/webrtc-pc#1213
// that there should be an empty candidate string event
// for end of candidate for each m= section.
if (candidate && remotePc.signalingState !== 'closed') {
remotePc.addIceCandidate(candidate);
}
};

const exchangeCandidates = (localPcOrQueue, remotePcOrQueue) => {
let localPc = localPcOrQueue;
let remotePc = remotePcOrQueue;
if (remotePcOrQueue instanceof IceCandidateQueue) {
remotePc = remotePcOrQueue.pc;
}

// candidate may be null to indicate end of candidate gathering.
// There is ongoing discussion on w3c/webrtc-pc#1213
// that there should be an empty candidate string event
// for end of candidate for each m= section.
if(candidate && remotePc.signalingState !== 'closed') {
remotePc.addIceCandidate(candidate);
// Queue? Disband it first
if (localPcOrQueue instanceof IceCandidateQueue) {
localPc = localPcOrQueue.pc;
for (const candidate of localPcOrQueue.disband()) {
handleCandidate(remotePc, candidate);
}
}

// Exchange further candidates
localPc.addEventListener('icecandidate', event => {
const { candidate } = event;
handleCandidate(remotePc, candidate);
});
}
};

doExchange(pc1, pc2);
doExchange(pc2, pc1);
exchangeCandidates(pc1OrQueue, pc2OrQueue);
exchangeCandidates(pc2OrQueue, pc1OrQueue);
}

// Helper function for doing one round of offer/answer exchange
// betweeen two local peer connections
function doSignalingHandshake(localPc, remotePc) {
function doSignalingHandshake(localPc, remotePc, options={}) {
return localPc.createOffer()
.then(offer => Promise.all([
localPc.setLocalDescription(offer),
remotePc.setRemoteDescription(offer)]))
.then(offer => {
// Modify offer if callback has been provided
if (options.modifyOffer) {
offer = options.modifyOffer(offer);
}

// Apply offer
return Promise.all([
localPc.setLocalDescription(offer),
remotePc.setRemoteDescription(offer)])
})
.then(() => remotePc.createAnswer())
.then(answer => Promise.all([
remotePc.setLocalDescription(answer),
localPc.setRemoteDescription(answer)]))
.then(answer => {
// Modify answer if callback has been provided
if (options.modifyAnswer) {
answer = options.modifyAnswer(answer);
}

// Apply answer
return Promise.all([
remotePc.setLocalDescription(answer),
localPc.setRemoteDescription(answer)])
});
}

// Helper function to create a pair of connected data channel.
Expand Down Expand Up @@ -295,23 +351,25 @@ function blobToArrayBuffer(blob) {
});
}

// Assert that two ArrayBuffer objects have the same byte values
function assert_equals_array_buffer(buffer1, buffer2) {
assert_true(buffer1 instanceof ArrayBuffer,
'Expect buffer to be instance of ArrayBuffer');

assert_true(buffer2 instanceof ArrayBuffer,
'Expect buffer to be instance of ArrayBuffer');
// Assert that two TypedArray or ArrayBuffer objects have the same byte values
function assert_equals_typed_array(array1, array2) {
const [view1, view2] = [array1, array2].map((array) => {
if (array instanceof ArrayBuffer) {
return new DataView(array);
} else {
assert_true(array.buffer instanceof ArrayBuffer,
'Expect buffer to be instance of ArrayBuffer');
return new DataView(array.buffer, array.byteOffset, array.byteLength);
}
});

assert_equals(buffer1.byteLength, buffer2.byteLength,
'Expect both array buffers to be of the same byte length');
assert_equals(view1.byteLength, view2.byteLength,
'Expect both arrays to be of the same byte length');

const byteLength = buffer1.byteLength;
const byteArray1 = new Uint8Array(buffer1);
const byteArray2 = new Uint8Array(buffer2);
const byteLength = view1.byteLength;

for(let i=0; i<byteLength; i++) {
assert_equals(byteArray1[i], byteArray2[i],
for (let i = 0; i < byteLength; ++i) {
assert_equals(view1.getUint8(i), view2.getUint8(i),
`Expect byte at buffer position ${i} to be equal`);
}
}
Expand Down Expand Up @@ -478,18 +536,45 @@ async function exchangeOfferAndListenToOntrack(t, caller, callee) {
return ontrackPromise;
}

// The resolver has a |promise| that can be resolved or rejected using |resolve|
// The resolver extends a |promise| that can be resolved or rejected using |resolve|
// or |reject|.
class Resolver {
constructor() {
let promiseResolve;
let promiseReject;
this.promise = new Promise(function(resolve, reject) {
promiseResolve = resolve;
promiseReject = reject;
class Resolver extends Promise {
constructor(executor) {
let resolve, reject;
super((resolve_, reject_) => {
resolve = resolve_;
reject = reject_;
if (executor) {
return executor(resolve_, reject_);
}
});
this.resolve = promiseResolve;
this.reject = promiseReject;

this._done = false;
this._resolve = resolve;
this._reject = reject;
}

/**
* Return whether the promise is done (resolved or rejected).
*/
get done() {
return this._done;
}

/**
* Resolve the promise.
*/
resolve(...args) {
this._done = true;
return this._resolve(...args);
}

/**
* Reject the promise.
*/
reject(...args) {
this._done = true;
return this._reject(...args);
}
}

Expand Down Expand Up @@ -526,3 +611,23 @@ function findTransceiverForSender(pc, sender) {
}
return null;
}

// Contains a set of values and will yell at you if you try to add a value twice.
class UniqueSet extends Set {
constructor(items) {
super();
if (items !== undefined) {
for (const item of items) {
this.add(item);
}
}
}

add(value, message) {
if (message === undefined) {
message = `Value '${value}' needs to be unique but it is already in the set`;
}
assert_true(!this.has(value), message);
super.add(value);
}
}
2 changes: 1 addition & 1 deletion webrtc/tools/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ module.exports = {
createDataChannelPair: true,
awaitMessage: true,
blobToArrayBuffer: true,
assert_equals_array_buffer: true,
assert_equals_typed_array: true,
generateMediaStreamTrack: true,
getTrackFromUserMedia: true,
getUserMediaTracksAndStreams: true,
Expand Down

0 comments on commit c115aba

Please sign in to comment.