├── .gitignore ├── Gemfile ├── Gemfile.lock ├── README.md ├── Rakefile ├── app ├── assets │ ├── images │ │ └── .keep │ ├── javascripts │ │ └── application.js │ └── stylesheets │ │ ├── application.css.scss │ │ └── home.css.scss ├── controllers │ ├── application_controller.rb │ ├── concerns │ │ └── .keep │ └── home_controller.rb ├── helpers │ ├── application_helper.rb │ └── home_helper.rb ├── mailers │ └── .keep ├── models │ ├── .keep │ └── concerns │ │ └── .keep ├── rtc │ ├── package.json │ └── server.js └── views │ ├── home │ ├── index.html.haml │ └── room.html.haml │ └── layouts │ ├── application.html.haml │ └── partials │ └── _header.html.haml ├── bin ├── bundle ├── rails └── rake ├── config.ru ├── config ├── application.rb ├── boot.rb ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── initializers │ ├── backtrace_silencers.rb │ ├── filter_parameter_logging.rb │ ├── inflections.rb │ ├── mime_types.rb │ ├── secret_token.rb │ ├── session_store.rb │ └── wrap_parameters.rb ├── locales │ └── en.yml └── routes.rb ├── db └── seeds.rb ├── lib ├── assets │ └── .keep └── tasks │ └── .keep ├── log └── .keep ├── public ├── 404.html ├── 422.html ├── 500.html ├── favicon.ico ├── javascripts │ └── rtc │ │ └── client_signaling.js └── robots.txt └── vendor └── assets ├── javascripts ├── .keep └── adapter.js └── stylesheets └── .keep /.gitignore: -------------------------------------------------------------------------------- 1 | Created by http://gitignore.io 2 | 3 | ### vim ### 4 | .*.s[a-w][a-z] 5 | *.un~ 6 | Session.vim 7 | .netrwhist 8 | *~ 9 | 10 | ### OSX ### 11 | .DS_Store 12 | .AppleDouble 13 | .LSOverride 14 | Icon 15 | 16 | 17 | # Thumbnails 18 | ._* 19 | 20 | # Files that might appear on external disk 21 | .Spotlight-V100 22 | .Trashes 23 | 24 | ### Rails ### 25 | *.rbc 26 | *.sassc 27 | .sass-cache 28 | capybara-*.html 29 | .rspec 30 | .rvmrc 31 | .ruby-gemset 32 | .ruby-version 33 | /.bundle 34 | /vendor/bundle 35 | /log/* 36 | /tmp/* 37 | /db/*.sqlite3 38 | /public/system/* 39 | /coverage/ 40 | /spec/tmp/* 41 | **.orig 42 | rerun.txt 43 | pickle-email-*.html 44 | .project 45 | !.keep 46 | 47 | 48 | ### Ruby ### 49 | *.gem 50 | *.rbc 51 | .bundle 52 | .config 53 | coverage 54 | InstalledFiles 55 | lib/bundler/man 56 | pkg 57 | rdoc 58 | spec/reports 59 | test/tmp 60 | test/version_tmp 61 | tmp 62 | 63 | # YARD artifacts 64 | .yardoc 65 | _yardoc 66 | doc/ 67 | 68 | ### SublimeText ### 69 | # SublimeText project files 70 | *.sublime-workspace 71 | 72 | ### Windows ### 73 | # Windows image file caches 74 | Thumbs.db 75 | ehthumbs.db 76 | 77 | # Folder config file 78 | Desktop.ini 79 | 80 | # Recycle Bin used on file shares 81 | $RECYCLE.BIN/ 82 | 83 | # Created by http://www.gitignore.io 84 | # 85 | # ### Node ### 86 | lib-cov 87 | lcov.info 88 | *.seed 89 | *.log 90 | *.csv 91 | *.dat 92 | *.out 93 | *.pid 94 | *.gz 95 | 96 | pids 97 | logs 98 | results 99 | build 100 | .grunt 101 | 102 | node_modules 103 | 104 | 105 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rails', '4.0.0' 4 | gem 'thin' 5 | gem 'mongoid' 6 | gem 'bootstrap-sass', '~> 3.1.1' 7 | gem 'haml-rails' 8 | gem 'jquery-rails' 9 | gem 'bson_ext' 10 | gem 'jquery-ui-rails' 11 | 12 | gem 'jbuilder', '~> 1.2' 13 | gem 'socket.io-rails' 14 | 15 | gem 'sass-rails', '~> 4.0.0' 16 | gem 'uglifier', '>= 1.3.0' 17 | gem 'therubyracer', :platforms => :ruby 18 | gem 'less-rails' 19 | gem 'coffee-rails', '~> 4.0.0' 20 | 21 | group :development, :test do 22 | gem 'quiet_assets' 23 | gem 'gettext', '>=1.9.3', :require => false 24 | gem 'capistrano' 25 | gem 'rvm-capistrano', require: false 26 | end 27 | 28 | gem 'unicorn' 29 | 30 | group :doc do 31 | gem 'sdoc', require: false 32 | end 33 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actionmailer (4.0.0) 5 | actionpack (= 4.0.0) 6 | mail (~> 2.5.3) 7 | actionpack (4.0.0) 8 | activesupport (= 4.0.0) 9 | builder (~> 3.1.0) 10 | erubis (~> 2.7.0) 11 | rack (~> 1.5.2) 12 | rack-test (~> 0.6.2) 13 | activemodel (4.0.0) 14 | activesupport (= 4.0.0) 15 | builder (~> 3.1.0) 16 | activerecord (4.0.0) 17 | activemodel (= 4.0.0) 18 | activerecord-deprecated_finders (~> 1.0.2) 19 | activesupport (= 4.0.0) 20 | arel (~> 4.0.0) 21 | activerecord-deprecated_finders (1.0.3) 22 | activesupport (4.0.0) 23 | i18n (~> 0.6, >= 0.6.4) 24 | minitest (~> 4.2) 25 | multi_json (~> 1.3) 26 | thread_safe (~> 0.1) 27 | tzinfo (~> 0.3.37) 28 | arel (4.0.1) 29 | atomic (1.1.14) 30 | bootstrap-sass (3.1.1.1) 31 | sass (~> 3.2) 32 | bson (1.10.0) 33 | bson_ext (1.5.1) 34 | builder (3.1.4) 35 | capistrano (2.15.5) 36 | highline 37 | net-scp (>= 1.0.0) 38 | net-sftp (>= 2.0.0) 39 | net-ssh (>= 2.0.14) 40 | net-ssh-gateway (>= 1.1.0) 41 | coffee-rails (4.0.1) 42 | coffee-script (>= 2.2.0) 43 | railties (>= 4.0.0, < 5.0) 44 | coffee-script (2.2.0) 45 | coffee-script-source 46 | execjs 47 | coffee-script-source (1.6.3) 48 | commonjs (0.2.7) 49 | daemons (1.1.9) 50 | durran-validatable (2.0.1) 51 | erubis (2.7.0) 52 | eventmachine (1.0.3) 53 | execjs (2.0.2) 54 | gettext (3.0.2) 55 | locale (>= 2.0.5) 56 | text 57 | haml (4.0.3) 58 | tilt 59 | haml-rails (0.4) 60 | actionpack (>= 3.1, < 4.1) 61 | activesupport (>= 3.1, < 4.1) 62 | haml (>= 3.1, < 4.1) 63 | railties (>= 3.1, < 4.1) 64 | highline (1.6.20) 65 | hike (1.2.3) 66 | i18n (0.6.5) 67 | jbuilder (1.5.2) 68 | activesupport (>= 3.0.0) 69 | multi_json (>= 1.2.0) 70 | jquery-rails (3.0.4) 71 | railties (>= 3.0, < 5.0) 72 | thor (>= 0.14, < 2.0) 73 | jquery-ui-rails (4.1.0) 74 | railties (>= 3.1.0) 75 | json (1.8.1) 76 | kgio (2.8.1) 77 | leshill-will_paginate (2.3.11) 78 | less (2.4.0) 79 | commonjs (~> 0.2.7) 80 | less-rails (2.4.2) 81 | actionpack (>= 3.1) 82 | less (~> 2.4.0) 83 | libv8 (3.16.14.3) 84 | locale (2.0.9) 85 | mail (2.5.4) 86 | mime-types (~> 1.16) 87 | treetop (~> 1.4.8) 88 | mime-types (1.25) 89 | minitest (4.7.5) 90 | mongo (1.10.0) 91 | bson (~> 1.10.0) 92 | mongoid (1.0.6) 93 | activesupport (>= 2.2.2) 94 | durran-validatable (>= 2.0.1) 95 | leshill-will_paginate (>= 2.3.11) 96 | mongo (>= 0.18.2) 97 | multi_json (1.8.2) 98 | net-scp (1.1.2) 99 | net-ssh (>= 2.6.5) 100 | net-sftp (2.1.2) 101 | net-ssh (>= 2.6.5) 102 | net-ssh (2.7.0) 103 | net-ssh-gateway (1.2.0) 104 | net-ssh (>= 2.6.5) 105 | polyglot (0.3.3) 106 | quiet_assets (1.0.2) 107 | railties (>= 3.1, < 5.0) 108 | rack (1.5.2) 109 | rack-test (0.6.2) 110 | rack (>= 1.0) 111 | rails (4.0.0) 112 | actionmailer (= 4.0.0) 113 | actionpack (= 4.0.0) 114 | activerecord (= 4.0.0) 115 | activesupport (= 4.0.0) 116 | bundler (>= 1.3.0, < 2.0) 117 | railties (= 4.0.0) 118 | sprockets-rails (~> 2.0.0) 119 | railties (4.0.0) 120 | actionpack (= 4.0.0) 121 | activesupport (= 4.0.0) 122 | rake (>= 0.8.7) 123 | thor (>= 0.18.1, < 2.0) 124 | raindrops (0.12.0) 125 | rake (10.1.0) 126 | rdoc (3.12.2) 127 | json (~> 1.4) 128 | ref (1.0.5) 129 | rvm-capistrano (1.5.1) 130 | capistrano (~> 2.15.4) 131 | sass (3.2.12) 132 | sass-rails (4.0.1) 133 | railties (>= 4.0.0, < 5.0) 134 | sass (>= 3.1.10) 135 | sprockets-rails (~> 2.0.0) 136 | sdoc (0.3.20) 137 | json (>= 1.1.3) 138 | rdoc (~> 3.10) 139 | socket.io-rails (0.9.16) 140 | railties (>= 3.1) 141 | sprockets (2.10.0) 142 | hike (~> 1.2) 143 | multi_json (~> 1.0) 144 | rack (~> 1.0) 145 | tilt (~> 1.1, != 1.3.0) 146 | sprockets-rails (2.0.1) 147 | actionpack (>= 3.0) 148 | activesupport (>= 3.0) 149 | sprockets (~> 2.8) 150 | text (1.2.3) 151 | therubyracer (0.12.0) 152 | libv8 (~> 3.16.14.0) 153 | ref 154 | thin (1.6.1) 155 | daemons (>= 1.0.9) 156 | eventmachine (>= 1.0.0) 157 | rack (>= 1.0.0) 158 | thor (0.18.1) 159 | thread_safe (0.1.3) 160 | atomic 161 | tilt (1.4.1) 162 | treetop (1.4.15) 163 | polyglot 164 | polyglot (>= 0.3.1) 165 | tzinfo (0.3.38) 166 | uglifier (2.3.0) 167 | execjs (>= 0.3.0) 168 | json (>= 1.8.0) 169 | unicorn (4.6.3) 170 | kgio (~> 2.6) 171 | rack 172 | raindrops (~> 0.7) 173 | 174 | PLATFORMS 175 | ruby 176 | 177 | DEPENDENCIES 178 | bootstrap-sass (~> 3.1.1) 179 | bson_ext 180 | capistrano 181 | coffee-rails (~> 4.0.0) 182 | gettext (>= 1.9.3) 183 | haml-rails 184 | jbuilder (~> 1.2) 185 | jquery-rails 186 | jquery-ui-rails 187 | less-rails 188 | mongoid 189 | quiet_assets 190 | rails (= 4.0.0) 191 | rvm-capistrano 192 | sass-rails (~> 4.0.0) 193 | sdoc 194 | socket.io-rails 195 | therubyracer 196 | thin 197 | uglifier (>= 1.3.0) 198 | unicorn 199 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #WebRTC Rails 2 | 3 | [![Join the chat at https://gitter.im/XescuGC/webrtc-rails](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/XescuGC/webrtc-rails?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 4 | 5 | This is a basic aplication I have build to test WebRTC, my main objective is to practice WebRTC. I will slowly improve the aplication, and add more features each time. 6 | 7 | ##Start Now 8 | 9 | To start the project and test is at your own you have to do the following: 10 | 11 | 1. Clone the repo: ```git clone git@github.com:XescuGC/webrtc-rails.git``` 12 | 2. Install all the gems with ```bundle install``` 13 | 3. Go to ```app/rtc/``` and run ```npm install``` to install ```socket.io``` 14 | 4. Check to see your IP: ```ifconfig```, copy the IP and change the ones in ```public/javascripts/rtc/client_signaling.js``` and at the first line change the ```io.connect('YOUR-IP:2013')``` 15 | 5. Open the server ```rails server``` 16 | 6. Open the NodeJs server ```node app/rtc/server.js``` 17 | 7. Go to the URL: ```localhost:3000``` 18 | 8. ENJOY! 19 | 20 | ##Test it in production 21 | 22 | Here you have the [link](http://webrtc-rails.layeris.com) 23 | 24 | ~~**At the moment it only works between Chrome and Chrome (I'm currently working on the problem)**~~ 25 | 26 | Now it works on Chrome and Firefox. Maybe there was some bug on the API. 27 | 28 | 29 | ##Objectives 30 | 31 | As I said before the main objective is to practice WebRTC but I will list some of the other objectives I have in mind: 32 | 33 | 1. **DONE** WebRTC between 2 peers 34 | 2. **DONE** Clean the webpage of unneeded menus, just the Home page and a page to call 35 | 3. **DONE** Add a chat module (with NodeJs, latter can be improved to be with arbitrary data with RTCDataChannel) 36 | 4. Change the NodeJS server to a native Ruby (EventMachine) 37 | 5. Control of errors in the Call (on of the Peers leave ... etc) 38 | 6. **DONE** Ability to create your own rooms with diferets names, and to setup an user name (for the Chat) 39 | 7. Ability to activate and desactivate Video or Audio, and reactivate them 40 | 8. Room with more than 2 Peers 41 | 9. Change the Chat from NodeJS to WebRTC DataChannel 42 | 43 | ##Slides 44 | 45 | I've made a short Presentation of WebRTC in my Office, here are the [Slides](https://github.com/XescuGC/webrtc-slides) 46 | 47 | ##Collaborate 48 | 49 | You can participate with whatever you want, and use/fork this code (if you find it usefull) for whatever you want ofcourse. If you want to propose more ideas will be welcome jeje 50 | 51 | ##Contact 52 | 53 | email: xescugil@gmail.com 54 | 55 | twitter: [@xescugc](https://twitter.com/xescugc) 56 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | 6 | WebrtcRails::Application.load_tasks 7 | -------------------------------------------------------------------------------- /app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xescugc/webrtc-rails/61fdaaef43bacb699e280aa6782adbcc4ccb550e/app/assets/images/.keep -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // compiled file. 9 | // 10 | // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | //= require jquery 14 | //= require jquery_ujs 15 | //= require bootstrap/tooltip 16 | //= require bootstrap/popover 17 | //= require bootstrap/tab 18 | //= require bootstrap/modal 19 | //= require bootstrap/collapse 20 | //= require bootstrap/dropdown 21 | //= require bootstrap/transition 22 | //= require socket.io 23 | //= require adapter.js 24 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.css.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the top of the 9 | * compiled file, but it's generally better to create a new file per style scope. 10 | * 11 | *= require_self 12 | *= require_tree . 13 | */ 14 | @import "bootstrap" 15 | -------------------------------------------------------------------------------- /app/assets/stylesheets/home.css.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the home controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | 5 | video { 6 | width: 100% !important; 7 | height: auto !important; 8 | } 9 | 10 | #localVideo { 11 | z-index: 99; 12 | position: absolute; 13 | bottom: 0; 14 | right: 0; 15 | border-color: #F0F8FF; 16 | border-radius: 50%; 17 | border-style: solid; 18 | } 19 | 20 | #js-chat-body { 21 | max-height: 255px; 22 | overflow: auto; 23 | } 24 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | # Prevent CSRF attacks by raising an exception. 3 | # For APIs, you may want to use :null_session instead. 4 | protect_from_forgery with: :exception 5 | end 6 | -------------------------------------------------------------------------------- /app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xescugc/webrtc-rails/61fdaaef43bacb699e280aa6782adbcc4ccb550e/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /app/controllers/home_controller.rb: -------------------------------------------------------------------------------- 1 | class HomeController < ApplicationController 2 | 3 | def index 4 | end 5 | 6 | def room 7 | end 8 | 9 | end 10 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/home_helper.rb: -------------------------------------------------------------------------------- 1 | module HomeHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xescugc/webrtc-rails/61fdaaef43bacb699e280aa6782adbcc4ccb550e/app/mailers/.keep -------------------------------------------------------------------------------- /app/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xescugc/webrtc-rails/61fdaaef43bacb699e280aa6782adbcc4ccb550e/app/models/.keep -------------------------------------------------------------------------------- /app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xescugc/webrtc-rails/61fdaaef43bacb699e280aa6782adbcc4ccb550e/app/models/concerns/.keep -------------------------------------------------------------------------------- /app/rtc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webrtc-rails", 3 | "version": "0.0.1", 4 | "description": "a simple RT server with socket.io to suport the WebRTC client comunication of data", 5 | "contributors": [ 6 | { 7 | "name": "Francesc Gil", 8 | "email": "xescugil@gmail.com" 9 | } 10 | ], 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/XescuGC/webrtc-rails" 14 | }, 15 | "dependencies": { 16 | "socket.io": "0.9.16" 17 | }, 18 | "engines": { 19 | "node": ">= 0.4.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/rtc/server.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | var app = http.createServer(function (req, res) { 3 | }).listen(2013); 4 | 5 | var io = require('socket.io').listen(app); 6 | 7 | io.sockets.on('connection', function (socket){ 8 | 9 | socket.on('message', function (data) { 10 | io.sockets.in(data.room).emit('message', data); 11 | }); 12 | 13 | socket.on('create or join', function (room) { 14 | var numClients = io.sockets.clients(room).length; 15 | 16 | console.log('clients', numClients); 17 | 18 | if(numClients == 0){ 19 | socket.join(room); 20 | socket.emit('created'); 21 | } else if (numClients == 1){ 22 | socket.join(room); 23 | io.sockets.in(room).emit('joined'); 24 | } else { 25 | socket.emit('full'); 26 | } 27 | }) 28 | }); 29 | -------------------------------------------------------------------------------- /app/views/home/index.html.haml: -------------------------------------------------------------------------------- 1 | .jumbotron 2 | %h1.text-center 3 | Welcome to WebRTC-Rails 4 | %small 5 | by Francesc Gil 6 | %p.text-center This is a simple app creted to test WebRTC with in a Rails application 7 | %center.form-group 8 | Enter your room name: 9 | = text_field_tag "room[name]", nil, palceholder: "Enter your room name" 10 | = link_to "Create your first Call-Room!", "#", class: 'btn btn-success btn-large', role: 'button', id: "btn-room" 11 | 12 | :javascript 13 | 14 | $roomField = $("#room_name"); 15 | 16 | var redirectToRoom = function(event) { 17 | if (event.type === "click"){ 18 | if ($roomField.val() === ""){ 19 | alert("You have to set the name of the ROOM"); 20 | }else{ 21 | window.location = window.location.pathname + $roomField.val(); 22 | } 23 | } else if (event.type === "keypress"){ 24 | if (event.keyCode === 13){ 25 | if ($roomField.val() === ""){ 26 | alert("You have to set the name of the ROOM"); 27 | } else { 28 | window.location = window.location.pathname + $roomField.val(); 29 | } 30 | } 31 | } 32 | } 33 | 34 | $("#room_name").on("keypress", redirectToRoom); 35 | $("#btn-room").on("click", redirectToRoom); 36 | 37 | -------------------------------------------------------------------------------- /app/views/home/room.html.haml: -------------------------------------------------------------------------------- 1 | %script{src: '/javascripts/rtc/client_signaling.js'} 2 | .container 3 | .row 4 | #video-grid 5 | .col-xs-12.col-md-12 6 | %video#remoteVideo{ "autoplay" => "",} 7 | .col-md-2.col-xs-2 8 | %video#localVideo{ "autoplay" => "", "muted" => "" } 9 | .row 10 | .panel.panel-primary 11 | .panel-heading 12 | Chat 13 | .panel-body#js-chat-body 14 | %br 15 | .input-group 16 | %input.form-control#js-input-im{ type: 'text', placeholder: 'Send a Message'} 17 | %span.input-group-btn 18 | %button.btn.btn-primary#js-send-button-im{ type: "button"} 19 | Send 20 | %button.btn.btn-error#js-hangup{ type: "button"} 21 | Hang Up 22 | :javascript 23 | var user_name = prompt("Your user name?"); 24 | 25 | var $sendButton = $("#js-send-button-im"); 26 | var $inputIM = $("#js-input-im"); 27 | var $chatBody = $("#js-chat-body"); 28 | 29 | $sendButton.on('click', sendIM); 30 | $inputIM.on('keypress', checkEnterKey); 31 | 32 | function sendIM() { 33 | var content = $inputIM.val(); 34 | $inputIM.val(""); 35 | socket.emit('message',{message: {content: content, user: user_name}, type: 'im', room: room}); 36 | } 37 | 38 | function checkEnterKey(event) { 39 | if ( event.keyCode == 13 ) { 40 | $sendButton.click(); 41 | } 42 | } 43 | 44 | function appendNewIM(user, message) { 45 | $chatBody.prepend(mediaObjectIM(user, message)); 46 | } 47 | 48 | function mediaObjectIM(user, message) { 49 | var leftRight = user === user_name ? 'right' : 'left' 50 | return "
"+ 51 | " "+ 52 | " "+ 53 | " "+ 54 | "
"+ 55 | "

"+ user +"

"+ 56 | " "+ message +""+ 57 | "
"+ 58 | "
" 59 | } 60 | /////////////////////////////////////////////////////////////////////////// 61 | 62 | var pc = null; 63 | var localStream; 64 | var isStarted; 65 | var isInitiator; 66 | var isChannelReady; 67 | var pc_config = { 68 | 'iceServers': 69 | [ 70 | { 71 | 'url': 'stun:stun.l.google.com:19302' 72 | }, 73 | { 74 | 'url': 'turn:numb.viagenie.ca:3478', 75 | 'credential': 'webrtcrails', 76 | 'username': 'xescugil@gmail.com' 77 | } 78 | ] 79 | }; 80 | var pc_constraints = {optional: [{DtlsSrtpKeyAgreement: true}]} 81 | // var pc_config = 82 | // { 83 | // 'iceServers': 84 | // [ 85 | // { 86 | // 'url': 'stun:stun.l.google.com:19302' 87 | // }, 88 | // { 89 | // 'url': 'turn:192.158.29.39:3478?transport=udp', 90 | // 'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=', 91 | // 'username': '28224511:1379330808' 92 | // }, 93 | // { 94 | // 'url': 'turn:192.158.29.39:3478?transport=tcp', 95 | // 'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=', 96 | // 'username': '28224511:1379330808' 97 | // } 98 | // ] 99 | // } 100 | var sdpConstraints = 101 | {'mandatory': 102 | { 103 | 'OfferToReceiveAudio':true, 104 | 'OfferToReceiveVideo':true 105 | } 106 | }; 107 | 108 | if (room !== "") { 109 | console.log('Joining room ' + room); 110 | socket.emit('create or join', room); 111 | } 112 | 113 | var localVideo = document.querySelector('#localVideo'); 114 | var remoteVideo = document.querySelector('#remoteVideo'); 115 | 116 | var constraints = 117 | { 118 | video: true, 119 | audio: true 120 | }; 121 | 122 | 123 | // Logs getUserMedia KO 124 | function gotError(error){ 125 | console.alert('Problems with GetUserMedia', error); 126 | } 127 | 128 | // Fetch the user Stream (Video and Audio), getUserMedia OK 129 | function gotStream(stream){ 130 | localStream = stream; 131 | attachMediaStream(localVideo, stream); 132 | socket.emit('message', {message: 'gotStream', type: 'gotStream', room: room}); 133 | if (isInitiator){ 134 | maybeStart(); 135 | } 136 | } 137 | 138 | // Get User Media 139 | getUserMedia(constraints, gotStream, gotError); 140 | 141 | // Stop the PeerConnection when the you leave the window 142 | function stop() { 143 | pc.close(); 144 | pc = null; 145 | attachMediaStream(remoteVideo, null); 146 | } 147 | 148 | $("#js-hangup").on("click", function () { 149 | stop(); 150 | socket.emit('message', {type: 'by', room: room}); 151 | }); 152 | 153 | window.onbeforeunload = function() { 154 | stop(); 155 | socket.emit('message', {type: 'by', room: room}); 156 | } 157 | 158 | requestTurn('https://computeengineondemand.appspot.com/turn?username=41784574&key=4080218913'); 159 | 160 | // Try to start, initiates the RTCPeerConnection 161 | function maybeStart() { 162 | if (isChannelReady && !isStarted && typeof localStream != 'undefined'){ 163 | pc = new RTCPeerConnection(pc_config, pc_constraints); 164 | pc.onicecandidate = handleIceCandidate; 165 | pc.onaddstream = handleOnAddRemoteStream; 166 | pc.onremovestream = handleOnRemoveStream; 167 | pc.addStream(localStream); 168 | isStarted = true; 169 | if (isInitiator) { 170 | startCall(); 171 | } 172 | } 173 | } 174 | 175 | // When recieving a ICE candidate sends it to the app, Trickle ICE. Without checking the gathering status if it's COMPLETE 176 | function handleIceCandidate(event) { 177 | console.log('ice', event); 178 | if (event.candidate) { 179 | socket.emit('message', {room: room, type: 'candidate', message: event.candidate}); 180 | } 181 | } 182 | 183 | function handleOnAddRemoteStream(event){ 184 | console.log("added Remote Stream") 185 | window.remoteVideoEvent = event; 186 | attachMediaStream(remoteVideo, event.stream); 187 | } 188 | 189 | function handleOnRemoveStream(event){ 190 | console.log('Remote stream removed. Event: ', event); 191 | } 192 | 193 | function startCall(){ 194 | console.log("Do Call"); 195 | pc.createOffer(setLocalAndSendMessageOffer, handleCreateOfferError); 196 | } 197 | 198 | function startAnswer(){ 199 | console.log("Do Call"); 200 | pc.createAnswer(setLocalAndSendMessageAnswer, handleCreateAnswerError, sdpConstraints); 201 | } 202 | 203 | function handleCreateOfferError(event) { 204 | console.log("Error when Creating Offer", event); 205 | } 206 | 207 | function handleCreateAnswerError(event) { 208 | console.log("Error when Creating Answer", event); 209 | } 210 | 211 | function setLocalAndSendMessageOffer(offer) { 212 | offer.sdp = preferOpus(offer.sdp); 213 | pc.setLocalDescription(offer); 214 | socket.emit('message', {room: room, type: 'offer', message: offer}) 215 | } 216 | 217 | function setLocalAndSendMessageAnswer(answer) { 218 | answer.sdp = preferOpus(answer.sdp); 219 | pc.setLocalDescription(answer); 220 | socket.emit('message', {room: room, type: 'answer', message: answer}) 221 | } 222 | 223 | function requestTurn(turn_url) { 224 | var turnExists = false; 225 | for (var i in pc_config.iceServers) { 226 | if (pc_config.iceServers[i].url.substr(0, 5) === 'turn:') { 227 | turnExists = true; 228 | turnReady = true; 229 | break; 230 | } 231 | } 232 | if (!turnExists) { 233 | console.log('Getting TURN server from ', turn_url); 234 | // No TURN server. Get one from computeengineondemand.appspot.com: 235 | var xhr = new XMLHttpRequest(); 236 | xhr.onreadystatechange = function(){ 237 | if (xhr.readyState === 4 && xhr.status === 200) { 238 | var turnServer = JSON.parse(xhr.responseText); 239 | console.log('Got TURN server: ', turnServer); 240 | pc_config.iceServers.push({ 241 | 'url': 'turn:' + turnServer.username + '@' + turnServer.turn, 242 | 'credential': turnServer.password 243 | }); 244 | turnReady = true; 245 | } 246 | }; 247 | xhr.open('GET', turn_url, true); 248 | xhr.send(); 249 | } 250 | } 251 | // Set Opus as the default audio codec if it's present. 252 | function preferOpus(sdp) { 253 | var sdpLines = sdp.split('\r\n'); 254 | var mLineIndex; 255 | // Search for m line. 256 | for (var i = 0; i < sdpLines.length; i++) { 257 | if (sdpLines[i].search('m=audio') !== -1) { 258 | mLineIndex = i; 259 | break; 260 | } 261 | } 262 | if (mLineIndex === null) { 263 | return sdp; 264 | } 265 | 266 | // If Opus is available, set it as the default in m line. 267 | for (i = 0; i < sdpLines.length; i++) { 268 | if (sdpLines[i].search('opus/48000') !== -1) { 269 | var opusPayload = extractSdp(sdpLines[i], /:(\d+) opus\/48000/i); 270 | if (opusPayload) { 271 | sdpLines[mLineIndex] = setDefaultCodec(sdpLines[mLineIndex], opusPayload); 272 | } 273 | break; 274 | } 275 | } 276 | 277 | // Remove CN in m line and sdp. 278 | sdpLines = removeCN(sdpLines, mLineIndex); 279 | 280 | sdp = sdpLines.join('\r\n'); 281 | return sdp; 282 | } 283 | 284 | function extractSdp(sdpLine, pattern) { 285 | var result = sdpLine.match(pattern); 286 | return result && result.length === 2 ? result[1] : null; 287 | } 288 | // Set the selected codec to the first in m line. 289 | function setDefaultCodec(mLine, payload) { 290 | var elements = mLine.split(' '); 291 | var newLine = []; 292 | var index = 0; 293 | for (var i = 0; i < elements.length; i++) { 294 | if (index === 3) { // Format of media starts from the fourth. 295 | newLine[index++] = payload; // Put target payload to the first. 296 | } 297 | if (elements[i] !== payload) { 298 | newLine[index++] = elements[i]; 299 | } 300 | } 301 | return newLine.join(' '); 302 | } 303 | 304 | // Strip CN from sdp before CN constraints is ready. 305 | function removeCN(sdpLines, mLineIndex) { 306 | var mLineElements = sdpLines[mLineIndex].split(' '); 307 | // Scan from end for the convenience of removing an item. 308 | for (var i = sdpLines.length-1; i >= 0; i--) { 309 | var payload = extractSdp(sdpLines[i], /a=rtpmap:(\d+) CN\/\d+/i); 310 | if (payload) { 311 | var cnPos = mLineElements.indexOf(payload); 312 | if (cnPos !== -1) { 313 | // Remove CN payload from m line. 314 | mLineElements.splice(cnPos, 1); 315 | } 316 | // Remove CN line in sdp 317 | sdpLines.splice(i, 1); 318 | } 319 | } 320 | 321 | sdpLines[mLineIndex] = mLineElements.join(' '); 322 | return sdpLines; 323 | } 324 | -------------------------------------------------------------------------------- /app/views/layouts/application.html.haml: -------------------------------------------------------------------------------- 1 | !!! 5 2 | %html(lang="en") 3 | %head 4 | %meta(charset="utf-8") 5 | %meta(http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1") 6 | %meta(name="viewport" content="width=device-width, initial-scale=1.0") 7 | %title= content_for?(:title) ? yield(:title) : "WebRTC Rails" 8 | = csrf_meta_tags 9 | %link{:href => "http://fonts.googleapis.com/css?family=Roboto+Condensed:400,700,300", :rel => "stylesheet", :type => "text/css"} 10 | / Le HTML5 shim, for IE6-8 support of HTML elements 11 | /[if lt IE 9] 12 | = javascript_include_tag "//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.6.1/html5shiv.js" 13 | = stylesheet_link_tag "application", :media => "all" 14 | 15 | = javascript_include_tag "application" 16 | 17 | 18 | %body 19 | .container 20 | = render partial: 'layouts/partials/header' 21 | = yield 22 | 23 | -------------------------------------------------------------------------------- /app/views/layouts/partials/_header.html.haml: -------------------------------------------------------------------------------- 1 | %header 2 | %nav.navbar.navbar-default{role: 'navigation'} 3 | .nacbar-header 4 | = link_to "WebRTC Rails", :root, class: 'navbar-brand' 5 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path('../../config/application', __FILE__) 3 | require_relative '../config/boot' 4 | require 'rails/commands' 5 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative '../config/boot' 3 | require 'rake' 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Rails.application 5 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | # Pick the frameworks you want: 4 | # require "active_record/railtie" 5 | require "action_controller/railtie" 6 | require "action_mailer/railtie" 7 | require "sprockets/railtie" 8 | # require "rails/test_unit/railtie" 9 | 10 | # Require the gems listed in Gemfile, including any gems 11 | # you've limited to :test, :development, or :production. 12 | Bundler.require(:default, Rails.env) 13 | 14 | module WebrtcRails 15 | class Application < Rails::Application 16 | # Settings in config/environments/* take precedence over those specified here. 17 | # Application configuration should go into files in config/initializers 18 | # -- all .rb files in that directory are automatically loaded. 19 | 20 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 21 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 22 | # config.time_zone = 'Central Time (US & Canada)' 23 | 24 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 25 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 26 | # config.i18n.default_locale = :de 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | # Set up gems listed in the Gemfile. 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | 4 | require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) 5 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the Rails application. 5 | WebrtcRails::Application.initialize! 6 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | WebrtcRails::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports and disable caching. 13 | config.consider_all_requests_local = true 14 | config.action_controller.perform_caching = false 15 | 16 | # Don't care if the mailer can't send. 17 | config.action_mailer.raise_delivery_errors = false 18 | 19 | # Print deprecation notices to the Rails logger. 20 | config.active_support.deprecation = :log 21 | 22 | 23 | # Debug mode disables concatenation and preprocessing of assets. 24 | # This option may cause significant delays in view rendering with a large 25 | # number of complex assets. 26 | config.assets.debug = true 27 | end 28 | -------------------------------------------------------------------------------- /config/environments/production.rb: -------------------------------------------------------------------------------- 1 | WebrtcRails::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # Code is not reloaded between requests. 5 | config.cache_classes = true 6 | 7 | # Eager load code on boot. This eager loads most of Rails and 8 | # your application in memory, allowing both thread web servers 9 | # and those relying on copy on write to perform better. 10 | # Rake tasks automatically ignore this option for performance. 11 | config.eager_load = true 12 | 13 | # Full error reports are disabled and caching is turned on. 14 | config.consider_all_requests_local = false 15 | config.action_controller.perform_caching = true 16 | 17 | # Enable Rack::Cache to put a simple HTTP cache in front of your application 18 | # Add `rack-cache` to your Gemfile before enabling this. 19 | # For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid. 20 | # config.action_dispatch.rack_cache = true 21 | 22 | # Disable Rails's static asset server (Apache or nginx will already do this). 23 | config.serve_static_assets = false 24 | 25 | # Compress JavaScripts and CSS. 26 | config.assets.js_compressor = :uglifier 27 | # config.assets.css_compressor = :sass 28 | 29 | # Do not fallback to assets pipeline if a precompiled asset is missed. 30 | config.assets.compile = false 31 | 32 | # Generate digests for assets URLs. 33 | config.assets.digest = true 34 | 35 | # Version of your assets, change this if you want to expire all your assets. 36 | config.assets.version = '1.0' 37 | 38 | # Specifies the header that your server uses for sending files. 39 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 40 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 41 | 42 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 43 | # config.force_ssl = true 44 | 45 | # Set to :debug to see everything in the log. 46 | config.log_level = :info 47 | 48 | # Prepend all log lines with the following tags. 49 | # config.log_tags = [ :subdomain, :uuid ] 50 | 51 | # Use a different logger for distributed setups. 52 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 53 | 54 | # Use a different cache store in production. 55 | # config.cache_store = :mem_cache_store 56 | 57 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 58 | # config.action_controller.asset_host = "http://assets.example.com" 59 | 60 | # Precompile additional assets. 61 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 62 | # config.assets.precompile += %w( search.js ) 63 | 64 | # Ignore bad email addresses and do not raise email delivery errors. 65 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 66 | # config.action_mailer.raise_delivery_errors = false 67 | 68 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 69 | # the I18n.default_locale when a translation can not be found). 70 | config.i18n.fallbacks = true 71 | 72 | # Send deprecation notices to registered listeners. 73 | config.active_support.deprecation = :notify 74 | 75 | # Disable automatic flushing of the log to improve performance. 76 | # config.autoflush_log = false 77 | 78 | # Use default logging formatter so that PID and timestamp are not suppressed. 79 | config.log_formatter = ::Logger::Formatter.new 80 | end 81 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | WebrtcRails::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Do not eager load code on boot. This avoids loading your whole application 11 | # just for the purpose of running a single test. If you are using a tool that 12 | # preloads Rails for running tests, you may have to set it to true. 13 | config.eager_load = false 14 | 15 | # Configure static asset server for tests with Cache-Control for performance. 16 | config.serve_static_assets = true 17 | config.static_cache_control = "public, max-age=3600" 18 | 19 | # Show full error reports and disable caching. 20 | config.consider_all_requests_local = true 21 | config.action_controller.perform_caching = false 22 | 23 | # Raise exceptions instead of rendering exception templates. 24 | config.action_dispatch.show_exceptions = false 25 | 26 | # Disable request forgery protection in test environment. 27 | config.action_controller.allow_forgery_protection = false 28 | 29 | # Tell Action Mailer not to deliver emails to the real world. 30 | # The :test delivery method accumulates sent emails in the 31 | # ActionMailer::Base.deliveries array. 32 | config.action_mailer.delivery_method = :test 33 | 34 | # Print deprecation notices to the stderr. 35 | config.active_support.deprecation = :stderr 36 | end 37 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | # Mime::Type.register_alias "text/html", :iphone 6 | -------------------------------------------------------------------------------- /config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rake secret` to generate a secure secret key. 9 | 10 | # Make sure your secret_key_base is kept private 11 | # if you're sharing your code publicly. 12 | WebrtcRails::Application.config.secret_key_base = 'c8cab475ff80c986f75c9cad6b0bf75548a1ea6f0f55079501d7db201c0a2955cf82df70ddcc8ef3a387a3f7e98696f7d01e53b6c90375419e75a5c7454cc64c' 13 | -------------------------------------------------------------------------------- /config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | WebrtcRails::Application.config.session_store :cookie_store, key: '_webrtc-rails_session' 4 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters) 9 | end 10 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # To learn more, please read the Rails Internationalization guide 20 | # available at http://guides.rubyonrails.org/i18n.html. 21 | 22 | en: 23 | hello: "Hello world" 24 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | WebrtcRails::Application.routes.draw do 2 | root to: 'home#index' 3 | 4 | get '/:room' => 'home#room' 5 | 6 | end 7 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) 7 | # Mayor.create(name: 'Emanuel', city: cities.first) 8 | -------------------------------------------------------------------------------- /lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xescugc/webrtc-rails/61fdaaef43bacb699e280aa6782adbcc4ccb550e/lib/assets/.keep -------------------------------------------------------------------------------- /lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xescugc/webrtc-rails/61fdaaef43bacb699e280aa6782adbcc4ccb550e/lib/tasks/.keep -------------------------------------------------------------------------------- /log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xescugc/webrtc-rails/61fdaaef43bacb699e280aa6782adbcc4ccb550e/log/.keep -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 48 | 49 | 50 | 51 | 52 |
53 |

The page you were looking for doesn't exist.

54 |

You may have mistyped the address or the page may have moved.

55 |
56 |

If you are the application owner check the logs for more information.

57 | 58 | 59 | -------------------------------------------------------------------------------- /public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 48 | 49 | 50 | 51 | 52 |
53 |

The change you wanted was rejected.

54 |

Maybe you tried to change something you didn't have access to.

55 |
56 |

If you are the application owner check the logs for more information.

57 | 58 | 59 | -------------------------------------------------------------------------------- /public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 48 | 49 | 50 | 51 | 52 |
53 |

We're sorry, but something went wrong.

54 |
55 |

If you are the application owner check the logs for more information.

56 | 57 | 58 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xescugc/webrtc-rails/61fdaaef43bacb699e280aa6782adbcc4ccb550e/public/favicon.ico -------------------------------------------------------------------------------- /public/javascripts/rtc/client_signaling.js: -------------------------------------------------------------------------------- 1 | var socket = io.connect('192.168.1.37:2013'); 2 | // var socket = io.connect('127.0.0.1:2013'); 3 | 4 | // var room = "room-name" //prompt("Enter room name:"); 5 | var room = window.location.pathname.replace("/", ""); 6 | 7 | socket.on("created", function (){ 8 | console.log("On Created"); 9 | isInitiator = true; 10 | console.log('isInitiator', isInitiator); 11 | }) 12 | 13 | socket.on("joined", function(){ 14 | console.log("Some one Joinded"); 15 | isChannelReady = true; 16 | }) 17 | 18 | socket.on("full", function(){ 19 | console.alert("Room Full, max number of 2"); 20 | }) 21 | 22 | socket.on("message", function(data) { 23 | if (data.type === 'gotStream') { 24 | console.log(data.message); 25 | maybeStart(); 26 | }else if (data.type === 'candidate' && isStarted) { 27 | var candidate = new RTCIceCandidate({ 28 | candidate: data.message.candidate, 29 | sdpMLineIndex: data.message.sdpMLineIndex 30 | }); 31 | pc.addIceCandidate(candidate); 32 | }else if (data.type === 'answer' && isStarted) { 33 | pc.setRemoteDescription(new RTCSessionDescription(data.message)); 34 | }else if (data.type === 'offer') { 35 | if (!isInitiator && !isStarted) { 36 | maybeStart(); 37 | } 38 | pc.setRemoteDescription(new RTCSessionDescription(data.message)); 39 | startAnswer(); 40 | }else if (data.type === 'im') { 41 | appendNewIM(data.message.user, data.message.content); 42 | }else if (data.type === 'by') { 43 | stop(); 44 | } 45 | }) 46 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xescugc/webrtc-rails/61fdaaef43bacb699e280aa6782adbcc4ccb550e/vendor/assets/javascripts/.keep -------------------------------------------------------------------------------- /vendor/assets/javascripts/adapter.js: -------------------------------------------------------------------------------- 1 | var RTCPeerConnection = null; 2 | var getUserMedia = null; 3 | var attachMediaStream = null; 4 | var reattachMediaStream = null; 5 | var webrtcDetectedBrowser = null; 6 | var webrtcDetectedVersion = null; 7 | 8 | function trace(text) { 9 | // This function is used for logging. 10 | if (text[text.length - 1] == '\n') { 11 | text = text.substring(0, text.length - 1); 12 | } 13 | console.log((performance.now() / 1000).toFixed(3) + ": " + text); 14 | } 15 | 16 | if (navigator.mozGetUserMedia) { 17 | console.log("This appears to be Firefox"); 18 | 19 | webrtcDetectedBrowser = "firefox"; 20 | 21 | // The RTCPeerConnection object. 22 | RTCPeerConnection = mozRTCPeerConnection; 23 | 24 | // The RTCSessionDescription object. 25 | RTCSessionDescription = mozRTCSessionDescription; 26 | 27 | // The RTCIceCandidate object. 28 | RTCIceCandidate = mozRTCIceCandidate; 29 | 30 | // Get UserMedia (only difference is the prefix). 31 | // Code from Adam Barth. 32 | getUserMedia = navigator.mozGetUserMedia.bind(navigator); 33 | 34 | // Creates Turn Uri with new turn format. 35 | createIceServer = function(turn_url, username, password) { 36 | var iceServer = { 'url': turn_url, 37 | 'credential': password, 38 | 'username': username }; 39 | return iceServer; 40 | }; 41 | 42 | // Attach a media stream to an element. 43 | attachMediaStream = function(element, stream) { 44 | console.log("Attaching media stream", stream); 45 | window.varRemoteStream = stream; 46 | element.mozSrcObject = stream; 47 | setTimeout(function() { 48 | element.play(); 49 | },500) 50 | }; 51 | 52 | reattachMediaStream = function(to, from) { 53 | console.log("Reattaching media stream"); 54 | to.mozSrcObject = from.mozSrcObject; 55 | setTimeout(function() { 56 | element.play(); 57 | },500) 58 | }; 59 | 60 | // Fake get{Video,Audio}Tracks 61 | MediaStream.prototype.getVideoTracks = function() { 62 | return []; 63 | }; 64 | 65 | MediaStream.prototype.getAudioTracks = function() { 66 | return []; 67 | }; 68 | } else if (navigator.webkitGetUserMedia) { 69 | console.log("This appears to be Chrome"); 70 | 71 | webrtcDetectedBrowser = "chrome"; 72 | webrtcDetectedVersion = 73 | parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2]); 74 | 75 | // For pre-M28 chrome versions use old turn format, else use the new format. 76 | if (webrtcDetectedVersion < 28) { 77 | createIceServer = function(turn_url, username, password) { 78 | var iceServer = { 'url': 'turn:' + username + '@' + turn_url, 79 | 'credential': password }; 80 | return iceServer; 81 | }; 82 | } else { 83 | createIceServer = function(turn_url, username, password) { 84 | var iceServer = { 'url': turn_url, 85 | 'credential': password, 86 | 'username': username }; 87 | return iceServer; 88 | }; 89 | } 90 | 91 | // The RTCPeerConnection object. 92 | RTCPeerConnection = webkitRTCPeerConnection; 93 | 94 | // Get UserMedia (only difference is the prefix). 95 | // Code from Adam Barth. 96 | getUserMedia = navigator.webkitGetUserMedia.bind(navigator); 97 | 98 | // Attach a media stream to an element. 99 | attachMediaStream = function(element, stream) { 100 | if (typeof element.srcObject !== 'undefined') { 101 | element.srcObject = stream; 102 | } else if (typeof element.mozSrcObject !== 'undefined') { 103 | element.mozSrcObject = stream; 104 | } else if (typeof element.src !== 'undefined') { 105 | element.src = URL.createObjectURL(stream); 106 | } else { 107 | console.log('Error attaching stream to element.'); 108 | } 109 | }; 110 | 111 | reattachMediaStream = function(to, from) { 112 | to.src = from.src; 113 | }; 114 | 115 | // The representation of tracks in a stream is changed in M26. 116 | // Unify them for earlier Chrome versions in the coexisting period. 117 | if (!webkitMediaStream.prototype.getVideoTracks) { 118 | webkitMediaStream.prototype.getVideoTracks = function() { 119 | return this.videoTracks; 120 | }; 121 | webkitMediaStream.prototype.getAudioTracks = function() { 122 | return this.audioTracks; 123 | }; 124 | } 125 | 126 | // New syntax of getXXXStreams method in M26. 127 | if (!webkitRTCPeerConnection.prototype.getLocalStreams) { 128 | webkitRTCPeerConnection.prototype.getLocalStreams = function() { 129 | return this.localStreams; 130 | }; 131 | webkitRTCPeerConnection.prototype.getRemoteStreams = function() { 132 | return this.remoteStreams; 133 | }; 134 | } 135 | } else { 136 | console.log("Browser does not appear to be WebRTC-capable"); 137 | } 138 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xescugc/webrtc-rails/61fdaaef43bacb699e280aa6782adbcc4ccb550e/vendor/assets/stylesheets/.keep --------------------------------------------------------------------------------