Seth Ladd talks about Dart and Web components.
Worth watching.
http://blog.sethladd.com/2013/02/slides-from-jfokus-talk-on-dart-and-web.html
Seth Ladd talks about Dart and Web components.
Worth watching.
http://blog.sethladd.com/2013/02/slides-from-jfokus-talk-on-dart-and-web.html
Milestone 3 has been released
http://news.dartlang.org/2013/02/new-streams-api-with-dart-milestone-3.html
This build should include a fix for my arch enemy
Now, I’m eagerly waiting for a fix to my new arch enemy and that Chrome finally implements reliable binary data channels.
Updated example for a simple video “conference”.
Things are going slow, but going.
Here’s an updated sample for the library which demonstrates the key parts of “getting chatting”.
Later on, when i have enough time, i’ll post an sample on howto tie all together with Nginx,
Flask and Upstart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | import 'dart:html'; import 'package:dart_rtc_common/rtc_common.dart'; import 'package:dart_rtc_client/rtc_client.dart'; const int RECONNECT_MS = 10000; const String MYCHANNEL = "abc"; const String CONNECTION_STRING = "ws://127.0.0.1:8234/ws"; /** * WebRTC video "conference" sample */ void main() { /** * DataSource connects to the signaling server */ DataSource src = new WebSocketDataSource(CONNECTION_STRING); /** * ChannelClient accepts on parameter, which is the data source. */ ChannelClient client = new ChannelClient(src) //.setChannel(MYCHANNEL) // Setting channel here sets the client to join the channel on connect .setRequireAudio(true) // Microphone required .setRequireVideo(true) // Webcam or some other video source required .setRequireDataChannel(false) // Set true if you want to send data over data channels .setAutoCreatePeer(true); // If true, creates peerconnection automicly when joining a channel /** * Client sets states, in this callback you can track the state changes * and do actions when required */ client.onInitializationStateChangeEvent.listen((InitializationStateEvent e) { if (e.state == InitializationState.LOCAL_READY) { // Client has initialized local, not connected to the signaling server yet. } if (e.state == InitializationState.MEDIA_READY) { // Your local video stream is ready } if (e.state == InitializationState.REMOTE_READY) { // If you did not use .setChannel above, this is where you can join channel (Or later on if you so wish) client.joinChannel(MYCHANNEL); } if (e.state == InitializationState.CHANNEL_READY) { // Channel has been joined. // Setting channel limit to 2, which means that only 2 persons are able to join the channel. client.setChannelLimit(2); } }); /** * Client has connected to the server */ client.onSignalingOpenEvent.listen((SignalingOpenEvent e) { }); /** * MediaStream available events * Event name subject to change to onMediaStreamAvailableEvent * since this carries also local media stream event */ client.onRemoteMediaStreamAvailableEvent.listen((MediaStreamAvailableEvent e) { // Event contains a reference to PeerWrapper (e.peerWrapper) which has an id property // Usefull for tracking created video elements for example. // set the video element id to peerwrapper id. if (e.isLocal) { LocalMediaStream localStream = e.stream; // Do what is needed with your local media stream // someVideoElement.src = Url.createObjectUrl(localStream); // someVideoElement.play(); } else { MediaStream remoteStream = e.stream; // Do what is needed with your local media stream // someOtherVideoElement.src = Url.createObjectUrl(remoteStream); // someOtherVideoElement.play(); } }); /** * MediaStream removed events */ client.onRemoteMediaStreamRemovedEvent.listen((MediaStreamRemovedEvent e) { // Remove the video element created earlier // If you used the e.peerWrapper.id as an id to the video element // you can use that again to find the element and remove it. }); /** * Callback for when you loose connection to the server */ client.onSignalingCloseEvent.listen((SignalingCloseEvent e) { window.setTimeout(() { client.initialize(); }, RECONNECT_MS); }); client.initialize(); } |
… Did not go so well =)
At the moment, the javascript generated by dart2js, does not compute when viewed with Firefox.
this Gist is enough to throw the error.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | import 'dart:html'; void main() { RtcPeerConnection pc1 = new RtcPeerConnection(null); RtcPeerConnection pc2 = new RtcPeerConnection(null); pc1.onAddStream.listen((MediaStreamEvent e) { print("pc1 got stream"); }); pc2.onAddStream.listen((MediaStreamEvent e) { print("pc2 got stream"); }); pc1.onIceCandidate.listen((RtcIceCandidateEvent e) { if (e.candidate != null) pc2.addIceCandidate(e.candidate); }); pc2.onIceCandidate.listen((RtcIceCandidateEvent e) { if (e.candidate != null) pc1.addIceCandidate(e.candidate); }); pc1.onNegotiationNeeded.listen((Event e) { pc1.createOffer((RtcSessionDescription sdp) { pc1.setLocalDescription(sdp, _onLocalDescriptionSuccess, _onRTCError); pc2.setRemoteDescription(sdp, _onRemoteDescriptionSuccess, _onRTCError); pc2.createAnswer((RtcSessionDescription sdp2) { pc2.setLocalDescription(sdp2, _onLocalDescriptionSuccess, _onRTCError); pc1.setRemoteDescription(sdp2, _onRemoteDescriptionSuccess, _onRTCError); },(String s) { }, null); },(String s) { }, null); }); if (MediaStream.supported) { window.navigator.getUserMedia(audio: true, video: true).then((LocalMediaStream stream) { pc1.addStream(stream); pc2.addStream(stream); }); } } void _onLocalDescriptionSuccess() { print("local desc success"); } void _onRemoteDescriptionSuccess() { print("remote desc success"); } void _onRTCError(String error) { print("error $error"); } |
Has something to do with Object.defineProperty.
Update!
New Sample here
Here’s a quick example howto use the dart_rtc_* libs.
Assuming that you have cloned the dart_rtc_server repo, do:
dart bin/start_channel.dart
This will start the channel server at your localhost at port 8234
then run the sample below (with modifications where required).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | import 'dart:html'; import 'package:dart_rtc_common/rtc_common.dart'; import 'package:dart_rtc_client/rtc_client.dart'; void main() { ChannelClient channelClient = new ChannelClient(new WebSocketDataSource("ws://YOURIP:YOURPORT/ws")) .setChannel("YOURCHANNEL") .setRequireAudio(true) // Microphone required .setRequireVideo(true) // Webcam required for this .setRequireDataChannel(false); // Datachannels required chrome v >= 25 with special flags channelClient.onSignalingOpenEvent.listen((SignalingOpenEvent e) { // If you need to initialize somethign after connection done, do it here. }); channelClient.onRemoteMediaStreamAvailableEvent.listen((MediaStreamAvailableEvent e) { // e.stream exposes the mediastream // currently, if you want to check if the stream is LocalMediaStream (your own) // you can check e.isLocal // Add the stream into a video element // (query("#video") as VideoElement).src = Url.createObjectUrl(e.stream); // Remember to press play =) }); channelClient.onRemoteMediaStreamRemovedEvent.listen((MediaStreamRemovedEvent e) { // Mediastream removed, remove the video element from dom traa etc.. }); channelClient.onSignalingCloseEvent.listen((SignalingCloseEvent e) { // Close, reconnect. window.setTimeout(() { channelClient.initialize(); }, 10000); }); channelClient.initialize(); } |
Due to the structure change in dart_rtc_* libs, i can now import the required files from github directly:
name: sample_pubspec description: A sample application dependencies: unittest: 0.3.4 browser: any dart_rtc_common: git: git://github.com/samiy-xx/dart_rtc_common.git dart_rtc_client: git: git://github.com/samiy-xx/dart_rtc_client.git
And then just…
import 'package:dart_rtc_common/rtc_common.dart'; import 'package:dart_rtc_client/rtc_client.dart';
Ended up restructuring my dart-rtc project due to not being able to “pub require” it, and in the end, it appears to be now 4 separate projects. 5th coming soon.
https://github.com/samiy-xx/dart_rtc_common
https://github.com/samiy-xx/dart_rtc_server
Frustrating bugs =)
https://code.google.com/p/dart/issues/detail?id=7030
https://code.google.com/p/dart/issues/detail?id=8361
https://code.google.com/p/dart/issues/detail?id=8370
Hopefully fixed some day
Prepared 2 samples.
1st one demonstrates the datachannel in chat application.
This demo requires chrome version >= 25 with datachannels enabled.
http://loosebyte.com/demo/data-channel-chat
2nd one demonstrates the video streaming part.
The demo requires chrome version >= 24 and webcam. You can fake it with manycam.com
http://loosebyte.com/demo/channel-video
These are programmed in Dart language and then compiled to javascript.
Create an entry to /etc/init
In my case this would be /etc/init/channelserver.conf
# Channel server script</code> description "Channel server" start on startup stop on shutdown respawn env DART=/home/sami/dart-sdk/bin/dart env SCRIPTPATH=/sites/src/trunk/dart-rtc/rtc_server/bin env SCRIPT=start_channel.dart env LOGTO=/sites/uwsgi/log/channel.log env USER=sami env OPTIONS="--port 8555" exec start-stop-daemon --start --make-pidfile --pidfile /var/run/channelserver.pid --chuid $USER --exec $DART $SCRIPTPATH/$SCRIPT -- $OPTIONS
After configuration is saved, reload upstart configuration.
initctl reload-configuration
And then start your process
start channelserver