v2
This commit is contained in:
@@ -0,0 +1,401 @@
|
||||
/* eslint-disable key-spacing */
|
||||
|
||||
exports.ROOM_OPTIONS =
|
||||
{
|
||||
requestTimeout: 10000,
|
||||
transportOptions:
|
||||
{
|
||||
tcp: false
|
||||
},
|
||||
__turnServers:
|
||||
[
|
||||
{
|
||||
urls: [ 'turn:worker2.versatica.com:3478?transport=udp' ],
|
||||
username: 'testuser1',
|
||||
credential: 'testpasswd1'
|
||||
}
|
||||
],
|
||||
hidden: false
|
||||
};
|
||||
|
||||
exports.ROOM_RTP_CAPABILITIES =
|
||||
{
|
||||
codecs:
|
||||
[
|
||||
{
|
||||
name: 'PCMA',
|
||||
mimeType: 'audio/PCMA',
|
||||
kind: 'audio',
|
||||
clockRate: 8000,
|
||||
preferredPayloadType: 8,
|
||||
rtcpFeedback: [],
|
||||
parameters: {}
|
||||
},
|
||||
{
|
||||
name: 'opus',
|
||||
mimeType: 'audio/opus',
|
||||
kind: 'audio',
|
||||
clockRate: 48000,
|
||||
channels: 2,
|
||||
preferredPayloadType: 96,
|
||||
rtcpFeedback: [],
|
||||
parameters: {}
|
||||
},
|
||||
{
|
||||
name: 'SILK',
|
||||
mimeType: 'audio/SILK',
|
||||
kind: 'audio',
|
||||
clockRate: 16000,
|
||||
preferredPayloadType: 97,
|
||||
rtcpFeedback: [],
|
||||
parameters: {}
|
||||
},
|
||||
{
|
||||
name: 'VP9',
|
||||
mimeType: 'video/VP9',
|
||||
kind: 'video',
|
||||
clockRate: 90000,
|
||||
preferredPayloadType: 102,
|
||||
rtcpFeedback:
|
||||
[
|
||||
{
|
||||
parameter: '',
|
||||
type: 'nack'
|
||||
},
|
||||
{
|
||||
parameter: 'pli',
|
||||
type: 'nack'
|
||||
},
|
||||
{
|
||||
parameter: '',
|
||||
type: 'goog-remb'
|
||||
},
|
||||
{
|
||||
parameter: 'bar',
|
||||
type: 'foo'
|
||||
}
|
||||
],
|
||||
parameters: {}
|
||||
},
|
||||
{
|
||||
name: 'rtx',
|
||||
mimeType: 'video/rtx',
|
||||
kind: 'video',
|
||||
clockRate: 90000,
|
||||
preferredPayloadType: 103,
|
||||
rtcpFeedback: [],
|
||||
parameters: {
|
||||
apt: 102
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'VP8',
|
||||
mimeType: 'video/VP8',
|
||||
kind: 'video',
|
||||
clockRate: 90000,
|
||||
preferredPayloadType: 100,
|
||||
rtcpFeedback:
|
||||
[
|
||||
{
|
||||
parameter: '',
|
||||
type: 'nack'
|
||||
},
|
||||
{
|
||||
parameter: 'pli',
|
||||
type: 'nack'
|
||||
},
|
||||
{
|
||||
parameter: '',
|
||||
type: 'goog-remb'
|
||||
},
|
||||
{
|
||||
parameter: 'bar',
|
||||
type: 'foo'
|
||||
}
|
||||
],
|
||||
parameters: {}
|
||||
},
|
||||
{
|
||||
name: 'rtx',
|
||||
mimeType: 'video/rtx',
|
||||
kind: 'video',
|
||||
clockRate: 90000,
|
||||
preferredPayloadType: 101,
|
||||
rtcpFeedback: [],
|
||||
parameters: {
|
||||
apt: 100
|
||||
}
|
||||
}
|
||||
],
|
||||
headerExtensions: [
|
||||
{
|
||||
kind: 'audio',
|
||||
uri: 'urn:ietf:params:rtp-hdrext:ssrc-audio-level',
|
||||
preferredId: 10
|
||||
},
|
||||
{
|
||||
kind: 'video',
|
||||
uri: 'http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time',
|
||||
preferredId: 11
|
||||
},
|
||||
{
|
||||
kind: 'video',
|
||||
uri: 'http://foo.bar',
|
||||
preferredId: 12
|
||||
}
|
||||
],
|
||||
fecMechanisms: []
|
||||
};
|
||||
|
||||
exports.QUERY_ROOM_RESPONSE =
|
||||
{
|
||||
rtpCapabilities: exports.ROOM_RTP_CAPABILITIES
|
||||
};
|
||||
|
||||
exports.JOIN_ROOM_RESPONSE =
|
||||
{
|
||||
peers:
|
||||
[
|
||||
{
|
||||
name: 'alice',
|
||||
appData: 'Alice iPad Pro',
|
||||
consumers:
|
||||
[
|
||||
{
|
||||
id: 3333,
|
||||
kind: 'audio',
|
||||
paused: false,
|
||||
appData: 'ALICE_MIC',
|
||||
rtpParameters:
|
||||
{
|
||||
muxId: null,
|
||||
codecs:
|
||||
[
|
||||
{
|
||||
name: 'PCMA',
|
||||
mimeType: 'audio/PCMA',
|
||||
clockRate: 8000,
|
||||
payloadType: 8,
|
||||
rtcpFeedback: [],
|
||||
parameters: {}
|
||||
}
|
||||
],
|
||||
headerExtensions:
|
||||
[
|
||||
{
|
||||
uri: 'urn:ietf:params:rtp-hdrext:ssrc-audio-level',
|
||||
id: 1
|
||||
}
|
||||
],
|
||||
encodings:
|
||||
[
|
||||
{
|
||||
ssrc: 33333333
|
||||
}
|
||||
],
|
||||
rtcp:
|
||||
{
|
||||
cname: 'ALICECNAME',
|
||||
reducedSize: true,
|
||||
mux: true
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'bob',
|
||||
appData: 'Bob HP Laptop',
|
||||
consumers:
|
||||
[
|
||||
{
|
||||
id: 6666,
|
||||
kind: 'audio',
|
||||
paused: false,
|
||||
appData: 'BOB_MIC',
|
||||
rtpParameters:
|
||||
{
|
||||
muxId: null,
|
||||
codecs:
|
||||
[
|
||||
{
|
||||
name: 'opus',
|
||||
mimeType: 'audio/opus',
|
||||
clockRate: 48000,
|
||||
channels: 2,
|
||||
payloadType: 96,
|
||||
rtcpFeedback: [],
|
||||
parameters: {}
|
||||
}
|
||||
],
|
||||
headerExtensions:
|
||||
[
|
||||
{
|
||||
uri: 'urn:ietf:params:rtp-hdrext:ssrc-audio-level',
|
||||
id: 1
|
||||
}
|
||||
],
|
||||
encodings:
|
||||
[
|
||||
{
|
||||
ssrc: 66666666
|
||||
}
|
||||
],
|
||||
rtcp:
|
||||
{
|
||||
cname: 'BOBCNAME',
|
||||
reducedSize: true,
|
||||
mux: true
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
exports.CREATE_TRANSPORT_1_RESPONSE =
|
||||
{
|
||||
iceParameters:
|
||||
{
|
||||
usernameFragment: 'server-usernamefragment-12345678',
|
||||
password: 'server-password-xxxxxxxx',
|
||||
iceLite: true
|
||||
},
|
||||
iceCandidates:
|
||||
[
|
||||
{
|
||||
foundation: 'F1',
|
||||
priority: 1234,
|
||||
ip: '1.2.3.4',
|
||||
protocol: 'udp',
|
||||
port: 9999,
|
||||
type: 'host'
|
||||
}
|
||||
],
|
||||
dtlsParameters:
|
||||
{
|
||||
fingerprints:
|
||||
[
|
||||
{
|
||||
algorithm: 'sha-256',
|
||||
value: 'FF:FF:39:66:A4:E2:66:60:30:18:A7:59:B3:AF:A5:33:58:5E:7F:69:A4:62:A6:D4:EB:9F:B7:42:05:35:FF:FF'
|
||||
}
|
||||
],
|
||||
role: 'client'
|
||||
}
|
||||
};
|
||||
|
||||
exports.CREATE_TRANSPORT_2_RESPONSE =
|
||||
{
|
||||
iceParameters:
|
||||
{
|
||||
usernameFragment: 'server-usernamefragment-12345678',
|
||||
password: 'server-password-xxxxxxxx',
|
||||
iceLite: true
|
||||
},
|
||||
iceCandidates:
|
||||
[
|
||||
{
|
||||
foundation: 'F1',
|
||||
priority: 1234,
|
||||
ip: '1.2.3.4',
|
||||
protocol: 'udp',
|
||||
port: 9999,
|
||||
type: 'host'
|
||||
}
|
||||
],
|
||||
dtlsParameters:
|
||||
{
|
||||
fingerprints:
|
||||
[
|
||||
{
|
||||
algorithm: 'sha-256',
|
||||
value: 'FF:FF:39:66:A4:E2:66:60:30:18:A7:59:B3:AF:A5:33:58:5E:7F:69:A4:62:A6:D4:EB:9F:B7:42:05:35:FF:FF'
|
||||
}
|
||||
],
|
||||
role: 'auto'
|
||||
}
|
||||
};
|
||||
|
||||
exports.ALICE_WEBCAM_NEW_CONSUMER_NOTIFICATION =
|
||||
{
|
||||
method: 'newConsumer',
|
||||
notification: true,
|
||||
id: 4444,
|
||||
peerName: 'alice',
|
||||
kind: 'video',
|
||||
paused: true,
|
||||
appData: 'ALICE_WEBCAM',
|
||||
rtpParameters:
|
||||
{
|
||||
muxId: null,
|
||||
codecs:
|
||||
[
|
||||
{
|
||||
name: 'VP8',
|
||||
mimeType: 'video/VP8',
|
||||
clockRate: 90000,
|
||||
payloadType: 100,
|
||||
rtcpFeedback:
|
||||
[
|
||||
{
|
||||
parameter: '',
|
||||
type: 'nack'
|
||||
},
|
||||
{
|
||||
parameter: 'pli',
|
||||
type: 'nack'
|
||||
},
|
||||
{
|
||||
parameter: '',
|
||||
type: 'goog-remb'
|
||||
},
|
||||
{
|
||||
parameter: 'bar',
|
||||
type: 'foo'
|
||||
}
|
||||
],
|
||||
parameters: {}
|
||||
},
|
||||
{
|
||||
name: 'rtx',
|
||||
mimeType: 'video/rtx',
|
||||
clockRate: 90000,
|
||||
payloadType: 101,
|
||||
rtcpFeedback: [],
|
||||
parameters: {
|
||||
apt: 100
|
||||
}
|
||||
}
|
||||
],
|
||||
headerExtensions:
|
||||
[
|
||||
{
|
||||
kind: 'video',
|
||||
uri: 'http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time',
|
||||
id: 11
|
||||
},
|
||||
{
|
||||
kind: 'video',
|
||||
uri: 'http://foo.bar',
|
||||
id: 12
|
||||
}
|
||||
],
|
||||
encodings:
|
||||
[
|
||||
{
|
||||
ssrc: 444444441,
|
||||
rtx: {
|
||||
ssrc: 444444442
|
||||
}
|
||||
}
|
||||
],
|
||||
rtcp:
|
||||
{
|
||||
cname: 'ALICECNAME',
|
||||
reducedSize: true,
|
||||
mux: true
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,145 @@
|
||||
const path = require('path');
|
||||
const gulp = require('gulp');
|
||||
const gutil = require('gulp-util');
|
||||
const plumber = require('gulp-plumber');
|
||||
const rename = require('gulp-rename');
|
||||
const browserify = require('browserify');
|
||||
const watchify = require('watchify');
|
||||
const envify = require('envify/custom');
|
||||
const source = require('vinyl-source-stream');
|
||||
const buffer = require('vinyl-buffer');
|
||||
const eslint = require('gulp-eslint');
|
||||
const browserSync = require('browser-sync');
|
||||
|
||||
const OUTPUT_DIR = 'output';
|
||||
const APP_NAME = 'mediasoup-client-test';
|
||||
|
||||
// Node environment.
|
||||
process.env.NODE_ENV = 'development';
|
||||
|
||||
function logError(error)
|
||||
{
|
||||
gutil.log(gutil.colors.red(error.stack));
|
||||
}
|
||||
|
||||
gulp.task('lint', () =>
|
||||
{
|
||||
const src =
|
||||
[
|
||||
'gulpfile.js',
|
||||
'**/*.js',
|
||||
'**/*.jsx'
|
||||
];
|
||||
|
||||
return gulp.src(src)
|
||||
.pipe(plumber())
|
||||
.pipe(eslint())
|
||||
.pipe(eslint.format());
|
||||
});
|
||||
|
||||
gulp.task('html', () =>
|
||||
{
|
||||
return gulp.src('index.html')
|
||||
.pipe(gulp.dest(OUTPUT_DIR));
|
||||
});
|
||||
|
||||
gulp.task('bundle', () =>
|
||||
{
|
||||
const watch = true;
|
||||
|
||||
let bundler = browserify(
|
||||
{
|
||||
entries : 'index.jsx',
|
||||
extensions : [ '.js', '.jsx' ],
|
||||
// required for sourcemaps (must be false otherwise).
|
||||
debug : process.env.NODE_ENV === 'development',
|
||||
// required for watchify.
|
||||
cache : {},
|
||||
// required for watchify.
|
||||
packageCache : {},
|
||||
// required to be true only for watchify.
|
||||
fullPaths : watch
|
||||
})
|
||||
.transform('babelify',
|
||||
{
|
||||
presets : [ 'es2015', 'es2017', 'react' ],
|
||||
plugins :
|
||||
[
|
||||
'transform-runtime',
|
||||
'transform-object-assign',
|
||||
'transform-object-rest-spread'
|
||||
]
|
||||
})
|
||||
.transform(envify(
|
||||
{
|
||||
NODE_ENV : process.env.NODE_ENV,
|
||||
_ : 'purge'
|
||||
}));
|
||||
|
||||
if (watch)
|
||||
{
|
||||
bundler = watchify(bundler);
|
||||
|
||||
bundler.on('update', () =>
|
||||
{
|
||||
const start = Date.now();
|
||||
|
||||
gutil.log('bundling...');
|
||||
rebundle();
|
||||
gutil.log('bundle took %sms', (Date.now() - start));
|
||||
});
|
||||
}
|
||||
|
||||
function rebundle()
|
||||
{
|
||||
return bundler.bundle()
|
||||
.on('error', logError)
|
||||
.pipe(plumber())
|
||||
.pipe(source(`${APP_NAME}.js`))
|
||||
.pipe(buffer())
|
||||
.pipe(rename(`${APP_NAME}.js`))
|
||||
.pipe(gulp.dest(OUTPUT_DIR));
|
||||
}
|
||||
|
||||
return rebundle();
|
||||
});
|
||||
|
||||
gulp.task('livebrowser', (done) =>
|
||||
{
|
||||
browserSync(
|
||||
{
|
||||
server :
|
||||
{
|
||||
baseDir : OUTPUT_DIR
|
||||
},
|
||||
ghostMode : false,
|
||||
files : path.join(OUTPUT_DIR, '**', '*')
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task('watch', (done) =>
|
||||
{
|
||||
// Watch changes in HTML.
|
||||
gulp.watch([ 'index.html' ], gulp.series(
|
||||
'html'
|
||||
));
|
||||
|
||||
// Watch changes in JS files.
|
||||
gulp.watch([ 'gulpfile.js', '**/*.js', '**/*.jsx' ], gulp.series(
|
||||
'lint'
|
||||
));
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task('live', gulp.series(
|
||||
'lint',
|
||||
'html',
|
||||
'bundle',
|
||||
'watch',
|
||||
'livebrowser'
|
||||
));
|
||||
|
||||
gulp.task('default', gulp.series('live'));
|
||||
@@ -0,0 +1,16 @@
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>mediasoup-client test</title>
|
||||
<meta charset='UTF-8'>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no'>
|
||||
<meta name='description' content='mediasoup-client test'>
|
||||
|
||||
<script async src='/mediasoup-client-test.js'></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>mediasoup-client test</h1>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,692 @@
|
||||
import * as mediasoupClient from 'mediasoup-client';
|
||||
import domready from 'domready';
|
||||
import Logger from '../lib/Logger';
|
||||
const DATA = require('./DATA');
|
||||
|
||||
window.mediasoupClient = mediasoupClient;
|
||||
|
||||
const logger = new Logger();
|
||||
|
||||
|
||||
const SEND = true;
|
||||
const SEND_AUDIO = true;
|
||||
const SEND_VIDEO = false;
|
||||
const RECV = true;
|
||||
|
||||
|
||||
domready(() =>
|
||||
{
|
||||
logger.debug('DOM ready');
|
||||
|
||||
run();
|
||||
});
|
||||
|
||||
function run()
|
||||
{
|
||||
logger.debug('run() [environment:%s]', process.env.NODE_ENV);
|
||||
|
||||
let transport1;
|
||||
let transport2;
|
||||
let audioTrack;
|
||||
let videoTrack;
|
||||
let audioProducer1;
|
||||
let audioProducer2;
|
||||
let videoProducer;
|
||||
|
||||
logger.debug('calling room = new mediasoupClient.Room()');
|
||||
|
||||
// const room = new mediasoupClient.Room();
|
||||
const room = new mediasoupClient.Room(DATA.ROOM_OPTIONS);
|
||||
|
||||
window.room = room;
|
||||
|
||||
room.on('closed', (originator, appData) =>
|
||||
{
|
||||
logger.warn(
|
||||
'room "closed" event [originator:%s, appData:%o]', originator, appData);
|
||||
});
|
||||
|
||||
room.on('request', (request, callback, errback) =>
|
||||
{
|
||||
logger.warn('sending request [method:%s]:%o', request.method, request);
|
||||
|
||||
switch (request.method)
|
||||
{
|
||||
case 'queryRoom':
|
||||
{
|
||||
setTimeout(() =>
|
||||
{
|
||||
callback(DATA.QUERY_ROOM_RESPONSE);
|
||||
errback('upppps');
|
||||
}, 200);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'joinRoom':
|
||||
{
|
||||
setTimeout(() =>
|
||||
{
|
||||
callback(DATA.JOIN_ROOM_RESPONSE);
|
||||
// errback('upppps');
|
||||
}, 200);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'createTransport':
|
||||
{
|
||||
setTimeout(() =>
|
||||
{
|
||||
switch (request.appData)
|
||||
{
|
||||
case 'TRANSPORT_1':
|
||||
callback(DATA.CREATE_TRANSPORT_1_RESPONSE);
|
||||
break;
|
||||
case 'TRANSPORT_2':
|
||||
callback(DATA.CREATE_TRANSPORT_2_RESPONSE);
|
||||
break;
|
||||
default:
|
||||
errback('upppps');
|
||||
}
|
||||
}, 250);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'createProducer':
|
||||
{
|
||||
setTimeout(() =>
|
||||
{
|
||||
callback();
|
||||
}, 250);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'enableConsumer':
|
||||
{
|
||||
setTimeout(() =>
|
||||
{
|
||||
callback();
|
||||
}, 500);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
errback(`NO IDEA ABOUT REQUEST METHOD "${request.method}"`);
|
||||
}
|
||||
});
|
||||
|
||||
room.on('notify', (notification) =>
|
||||
{
|
||||
logger.warn(
|
||||
'sending notification [method:%s]:%o', notification.method, notification);
|
||||
|
||||
switch (notification.method)
|
||||
{
|
||||
case 'leaveRoom':
|
||||
case 'updateTransport':
|
||||
case 'closeTransport':
|
||||
case 'closeProducer':
|
||||
case 'pauseProducer':
|
||||
case 'resumeProducer':
|
||||
case 'pauseConsumer':
|
||||
case 'resumeConsumer':
|
||||
break;
|
||||
|
||||
default:
|
||||
logger.error(`NO IDEA ABOUT NOTIFICATION METHOD "${notification.method}"`);
|
||||
}
|
||||
});
|
||||
|
||||
room.on('newpeer', (peer) =>
|
||||
{
|
||||
logger.warn('room "newpeer" event [name:"%s", peer:%o]', peer.name, peer);
|
||||
|
||||
handlePeer(peer);
|
||||
});
|
||||
|
||||
Promise.resolve()
|
||||
.then(() =>
|
||||
{
|
||||
logger.debug('calling room.join()');
|
||||
|
||||
const deviceInfo = mediasoupClient.getDeviceInfo();
|
||||
const appData =
|
||||
{
|
||||
device : `${deviceInfo.name} ${deviceInfo.version}`
|
||||
};
|
||||
|
||||
return room.join(null, appData);
|
||||
// return room.join(DATA.ROOM_RTP_CAPABILITIES, appData);
|
||||
})
|
||||
.then((peers) =>
|
||||
{
|
||||
if (!RECV)
|
||||
return;
|
||||
|
||||
logger.debug('room.join() succeeded');
|
||||
|
||||
logger.debug('calling transport2 = room.createTransport("recv")');
|
||||
|
||||
transport2 = room.createTransport('recv', 'TRANSPORT_2');
|
||||
window.transport2 = transport2;
|
||||
window.pc2 = transport2._handler._pc;
|
||||
|
||||
handleTransport(transport2);
|
||||
|
||||
for (const peer of peers)
|
||||
{
|
||||
handlePeer(peer);
|
||||
}
|
||||
})
|
||||
.then(() =>
|
||||
{
|
||||
if (!SEND)
|
||||
return;
|
||||
|
||||
if (room.canSend('audio'))
|
||||
logger.debug('can send audio');
|
||||
else
|
||||
logger.warn('cannot send audio');
|
||||
|
||||
if (room.canSend('video'))
|
||||
logger.debug('can send video');
|
||||
else
|
||||
logger.warn('cannot send video');
|
||||
|
||||
logger.debug('calling transport1 = room.createTransport("send")');
|
||||
|
||||
transport1 = room.createTransport('send', 'TRANSPORT_1');
|
||||
window.transport1 = transport1;
|
||||
window.pc1 = transport1._handler._pc;
|
||||
|
||||
handleTransport(transport1);
|
||||
|
||||
logger.debug('calling getUserMedia()');
|
||||
|
||||
return navigator.mediaDevices
|
||||
.getUserMedia({ audio: SEND_AUDIO, video: SEND_VIDEO });
|
||||
})
|
||||
.then((stream) =>
|
||||
{
|
||||
if (!SEND)
|
||||
return;
|
||||
|
||||
audioTrack = stream.getAudioTracks()[0];
|
||||
videoTrack = stream.getVideoTracks()[0];
|
||||
window.audioTrack = audioTrack;
|
||||
window.videoTrack = videoTrack;
|
||||
})
|
||||
// Add Producers.
|
||||
.then(() =>
|
||||
{
|
||||
if (audioTrack)
|
||||
{
|
||||
const deviceId = audioTrack.getSettings().deviceId;
|
||||
|
||||
logger.debug('calling audioProducer1 = room.createProducer(audioTrack)');
|
||||
|
||||
try
|
||||
{
|
||||
audioProducer1 = room.createProducer(audioTrack, `${deviceId}-1`);
|
||||
window.audioProducer1 = audioProducer1;
|
||||
|
||||
handleProducer(audioProducer1);
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
logger.error(error);
|
||||
}
|
||||
|
||||
logger.debug('calling audioProducer2 = room.createProducer(audioTrack)');
|
||||
|
||||
try
|
||||
{
|
||||
audioProducer2 = room.createProducer(audioTrack, `${deviceId}-2`);
|
||||
window.audioProducer2 = audioProducer2;
|
||||
|
||||
handleProducer(audioProducer2);
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
logger.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
if (videoTrack)
|
||||
{
|
||||
const deviceId = videoTrack.getSettings().deviceId;
|
||||
|
||||
logger.debug('calling videoProducer = room.createProducer(videoTrack)');
|
||||
|
||||
try
|
||||
{
|
||||
videoProducer = room.createProducer(videoTrack, `${deviceId}-1`);
|
||||
window.videoProducer = videoProducer;
|
||||
|
||||
handleProducer(videoProducer);
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
logger.error(error);
|
||||
}
|
||||
}
|
||||
})
|
||||
// Receive notifications.
|
||||
.then(() =>
|
||||
{
|
||||
if (!RECV)
|
||||
return;
|
||||
|
||||
setTimeout(() =>
|
||||
{
|
||||
room.receiveNotification(DATA.ALICE_WEBCAM_NEW_CONSUMER_NOTIFICATION);
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
function handleTransport(transport)
|
||||
{
|
||||
logger.warn(
|
||||
'handleTransport() [direction:%s, appData:"%s", transport:%o]',
|
||||
transport.direction, transport.appData, transport);
|
||||
|
||||
transport.on('closed', (originator, appData) =>
|
||||
{
|
||||
logger.warn(
|
||||
'transport "closed" event [originator:%s, appData:%o, transport:%o]',
|
||||
originator, appData, transport);
|
||||
});
|
||||
|
||||
transport.on('connectionstatechange', (state) =>
|
||||
{
|
||||
logger.warn(
|
||||
'transport "connectionstatechange" event [direction:%s, state:%s, transport:%o]',
|
||||
transport.direction, state, transport);
|
||||
});
|
||||
|
||||
setInterval(() =>
|
||||
{
|
||||
const queue = transport._commandQueue._queue;
|
||||
|
||||
if (queue.length !== 0)
|
||||
logger.error('queue not empty [transport:%o, queue:%o]', transport, queue);
|
||||
}, 15000);
|
||||
}
|
||||
|
||||
function handlePeer(peer)
|
||||
{
|
||||
logger.warn('handlePeer() [name:"%s", peer:%o]', peer.name, peer);
|
||||
|
||||
switch (peer.name)
|
||||
{
|
||||
case 'alice':
|
||||
window.alice = peer;
|
||||
break;
|
||||
case 'bob':
|
||||
window.bob = peer;
|
||||
break;
|
||||
}
|
||||
|
||||
for (const consumer of peer.consumers)
|
||||
{
|
||||
handleConsumer(consumer);
|
||||
}
|
||||
|
||||
peer.on('closed', (originator, appData) =>
|
||||
{
|
||||
logger.warn(
|
||||
'peer "closed" event [name:"%s", originator:%s, appData:%o]',
|
||||
peer.name, originator, appData);
|
||||
});
|
||||
|
||||
peer.on('newconsumer', (consumer) =>
|
||||
{
|
||||
logger.warn(
|
||||
'peer "newconsumer" event [name:"%s", id:%s, consumer:%o]',
|
||||
peer.name, consumer.id, consumer);
|
||||
|
||||
handleConsumer(consumer);
|
||||
});
|
||||
}
|
||||
|
||||
function handleProducer(producer)
|
||||
{
|
||||
const transport1 = window.transport1;
|
||||
|
||||
logger.debug(
|
||||
'handleProducer() [id:"%s", appData:%o, producer:%o]',
|
||||
producer.id, producer.appData, producer);
|
||||
|
||||
logger.debug('handleProducer() | calling transport1.send(producer)');
|
||||
|
||||
transport1.send(producer)
|
||||
.then(() =>
|
||||
{
|
||||
logger.debug('transport1.send(producer) succeeded');
|
||||
})
|
||||
.catch((error) =>
|
||||
{
|
||||
logger.error('transport1.send(producer) failed: %o', error);
|
||||
});
|
||||
|
||||
producer.on('closed', (originator, appData) =>
|
||||
{
|
||||
logger.warn(
|
||||
'producer "closed" event [id:%s, originator:%s, appData:%o, producer:%o]',
|
||||
producer.id, originator, appData, producer);
|
||||
});
|
||||
|
||||
producer.on('paused', (originator, appData) =>
|
||||
{
|
||||
logger.warn(
|
||||
'producer "paused" event [id:%s, originator:%s, appData:%o, producer:%o]',
|
||||
producer.id, originator, appData, producer);
|
||||
});
|
||||
|
||||
producer.on('resumed', (originator, appData) =>
|
||||
{
|
||||
logger.warn(
|
||||
'producer "resumed" event [id:%s, originator:%s, appData:%o, producer:%o]',
|
||||
producer.id, originator, appData, producer);
|
||||
});
|
||||
|
||||
producer.on('unhandled', () =>
|
||||
{
|
||||
logger.warn(
|
||||
'producer "unhandled" event [id:%s, producer:%o]', producer.id, producer);
|
||||
});
|
||||
}
|
||||
|
||||
function handleConsumer(consumer)
|
||||
{
|
||||
const transport2 = window.transport2;
|
||||
|
||||
logger.debug(
|
||||
'handleConsumer() [id:"%s", appData:%o, consumer:%o]',
|
||||
consumer.id, consumer.appData, consumer);
|
||||
|
||||
switch (consumer.appData)
|
||||
{
|
||||
case 'ALICE_MIC':
|
||||
window.aliceAudioConsumer = consumer;
|
||||
break;
|
||||
case 'ALICE_WEBCAM':
|
||||
window.aliceVideoConsumer = consumer;
|
||||
break;
|
||||
case 'BOB_MIC':
|
||||
window.bobAudioConsumer = consumer;
|
||||
break;
|
||||
}
|
||||
|
||||
logger.debug('handleConsumer() calling transport2.receive(consumer)');
|
||||
|
||||
transport2.receive(consumer)
|
||||
.then((track) =>
|
||||
{
|
||||
logger.warn(
|
||||
'transport2.receive(consumer) succeeded [track:%o]', track);
|
||||
})
|
||||
.catch((error) =>
|
||||
{
|
||||
logger.error('transport2.receive() failed:%o', error);
|
||||
});
|
||||
|
||||
consumer.on('closed', (originator, appData) =>
|
||||
{
|
||||
logger.warn(
|
||||
'consumer "closed" event [id:%s, originator:%s, appData:%o, consumer:%o]',
|
||||
consumer.id, originator, appData, consumer);
|
||||
});
|
||||
|
||||
consumer.on('paused', (originator, appData) =>
|
||||
{
|
||||
logger.warn(
|
||||
'consumer "paused" event [id:%s, originator:%s, appData:%o, consumer:%o]',
|
||||
consumer.id, originator, appData, consumer);
|
||||
});
|
||||
|
||||
consumer.on('resumed', (originator, appData) =>
|
||||
{
|
||||
logger.warn(
|
||||
'consumer "resumed" event [id:%s, originator:%s, appData:%o, consumer:%o]',
|
||||
consumer.id, originator, appData, consumer);
|
||||
});
|
||||
|
||||
consumer.on('unhandled', () =>
|
||||
{
|
||||
logger.warn(
|
||||
'consumer "unhandled" event [id:%s, consumer:%o]', consumer.id, consumer);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// NOTE: Trigger server notifications.
|
||||
|
||||
window.notifyRoomClosed = function()
|
||||
{
|
||||
const room = window.room;
|
||||
const notification =
|
||||
{
|
||||
method : 'roomClosed',
|
||||
notification : true,
|
||||
appData : 'ha cascao la room remota!!!'
|
||||
};
|
||||
|
||||
room.receiveNotification(notification);
|
||||
};
|
||||
|
||||
window.notifyTransportClosed = function()
|
||||
{
|
||||
const room = window.room;
|
||||
const notification =
|
||||
{
|
||||
method : 'transportClosed',
|
||||
notification : true,
|
||||
id : room.transports[0].id,
|
||||
appData : 'admin closed your transport'
|
||||
};
|
||||
|
||||
room.receiveNotification(notification);
|
||||
};
|
||||
|
||||
window.notifyAudioProducer1Closed = function()
|
||||
{
|
||||
const room = window.room;
|
||||
const notification =
|
||||
{
|
||||
method : 'producerClosed',
|
||||
notification : true,
|
||||
id : window.audioProducer1.id,
|
||||
appData : 'te paro el micro por la fuerza'
|
||||
};
|
||||
|
||||
room.receiveNotification(notification);
|
||||
};
|
||||
|
||||
window.notifyAudioProducer1Paused = function()
|
||||
{
|
||||
const room = window.room;
|
||||
const notification =
|
||||
{
|
||||
method : 'producerPaused',
|
||||
notification : true,
|
||||
id : window.audioProducer1.id,
|
||||
appData : 'te pause el micro por la fuerza'
|
||||
};
|
||||
|
||||
room.receiveNotification(notification);
|
||||
};
|
||||
|
||||
window.notifyAudioProducer1Resumed = function()
|
||||
{
|
||||
const room = window.room;
|
||||
const notification =
|
||||
{
|
||||
method : 'producerResumed',
|
||||
notification : true,
|
||||
id : window.audioProducer1.id,
|
||||
appData : 'te resumo el micro'
|
||||
};
|
||||
|
||||
room.receiveNotification(notification);
|
||||
};
|
||||
|
||||
window.notifyAlicePeerClosed = function()
|
||||
{
|
||||
const room = window.room;
|
||||
const notification =
|
||||
{
|
||||
method : 'peerClosed',
|
||||
notification : true,
|
||||
name : 'alice',
|
||||
appData : 'peer left'
|
||||
};
|
||||
|
||||
room.receiveNotification(notification);
|
||||
};
|
||||
|
||||
window.notifyAliceAudioConsumerClosed = function()
|
||||
{
|
||||
const room = window.room;
|
||||
const notification =
|
||||
{
|
||||
method : 'consumerClosed',
|
||||
notification : true,
|
||||
peerName : 'alice',
|
||||
id : 3333,
|
||||
appData : 'mic broken'
|
||||
};
|
||||
|
||||
room.receiveNotification(notification);
|
||||
};
|
||||
|
||||
window.notifyAliceVideoConsumerClosed = function()
|
||||
{
|
||||
const room = window.room;
|
||||
const notification =
|
||||
{
|
||||
method : 'consumerClosed',
|
||||
notification : true,
|
||||
peerName : 'alice',
|
||||
id : 4444,
|
||||
appData : 'webcam broken'
|
||||
};
|
||||
|
||||
room.receiveNotification(notification);
|
||||
};
|
||||
|
||||
window.notifyAliceVideoConsumerPaused = function()
|
||||
{
|
||||
const room = window.room;
|
||||
const notification =
|
||||
{
|
||||
method : 'consumerPaused',
|
||||
notification : true,
|
||||
peerName : 'alice',
|
||||
id : 4444,
|
||||
appData : 'webcam paused'
|
||||
};
|
||||
|
||||
room.receiveNotification(notification);
|
||||
};
|
||||
|
||||
window.notifyAliceVideoConsumerResumed = function()
|
||||
{
|
||||
const room = window.room;
|
||||
const notification =
|
||||
{
|
||||
method : 'consumerResumed',
|
||||
notification : true,
|
||||
peerName : 'alice',
|
||||
id : 4444,
|
||||
appData : 'webcam resumed'
|
||||
};
|
||||
|
||||
room.receiveNotification(notification);
|
||||
};
|
||||
|
||||
|
||||
// NOTE: Test pause/resume.
|
||||
|
||||
window.testPauseResume = function()
|
||||
{
|
||||
logger.debug('testPauseResume() with audioProducer1');
|
||||
|
||||
const producer = window.audioProducer1;
|
||||
|
||||
// producer.once('paused', () =>
|
||||
// {
|
||||
// producer.resume('I RESUME TO FUACK!!!');
|
||||
// });
|
||||
|
||||
logger.debug('testPauseResume() | (1) calling producer.pause()');
|
||||
|
||||
if (producer.pause('I PAUSE (1)'))
|
||||
{
|
||||
logger.warn(
|
||||
'testPauseResume() | (1) producer.pause() succeeded [locallyPaused:%s]',
|
||||
producer.locallyPaused);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.error(
|
||||
'testPauseResume() | (1) producer.pause() failed [locallyPaused:%s]',
|
||||
producer.locallyPaused);
|
||||
}
|
||||
|
||||
logger.debug('testPauseResume() | (2) calling producer.pause()');
|
||||
|
||||
if (producer.pause('I PAUSE (2)'))
|
||||
{
|
||||
logger.warn(
|
||||
'testPauseResume() | (2) producer.pause() succeeded [locallyPaused:%s]',
|
||||
producer.locallyPaused);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.error(
|
||||
'testPauseResume() | (2) producer.pause() failed [locallyPaused:%s]',
|
||||
producer.locallyPaused);
|
||||
}
|
||||
|
||||
logger.debug('testPauseResume() | (3) calling producer.resume()');
|
||||
|
||||
if (producer.resume('I RESUME (3)'))
|
||||
{
|
||||
logger.warn(
|
||||
'testPauseResume() | (3) producer.resume() succeeded [locallyPaused:%s]',
|
||||
producer.locallyPaused);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.error(
|
||||
'testPauseResume() | (3) producer.resume() failed [locallyPaused:%s]',
|
||||
producer.locallyPaused);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// NOTE: For debugging.
|
||||
|
||||
window.dump1 = function()
|
||||
{
|
||||
const transport1 = window.transport1;
|
||||
const pc1 = transport1._handler._pc;
|
||||
|
||||
if (pc1 && pc1.localDescription)
|
||||
logger.warn('PC1 SEND LOCAL OFFER:\n%s', pc1.localDescription.sdp);
|
||||
|
||||
if (pc1 && pc1.remoteDescription)
|
||||
logger.warn('PC1 SEND REMOTE ANSWER:\n%s', pc1.remoteDescription.sdp);
|
||||
};
|
||||
|
||||
window.dump2 = function()
|
||||
{
|
||||
const transport2 = window.transport2;
|
||||
const pc2 = transport2._handler._pc;
|
||||
|
||||
if (pc2 && pc2.remoteDescription)
|
||||
logger.warn('PC2 RECV REMOTE OFFER:\n%s', pc2.remoteDescription.sdp);
|
||||
|
||||
if (pc2 && pc2.localDescription)
|
||||
logger.warn('PC2 RECV LOCAL ANSWER:\n%s', pc2.localDescription.sdp);
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>mediasoup-client test</title>
|
||||
<meta charset='UTF-8'>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no'>
|
||||
<meta name='description' content='mediasoup-client test'>
|
||||
|
||||
<script async src='/mediasoup-client-test.js'></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>mediasoup-client test</h1>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user