webrtc_rails 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +3 -0
  4. data/Rakefile +34 -0
  5. data/app/assets/javascripts/webrtc_rails/application.js +16 -0
  6. data/app/assets/javascripts/webrtc_rails/rooms.js +141 -0
  7. data/app/assets/stylesheets/webrtc_rails/application.css +13 -0
  8. data/app/assets/stylesheets/webrtc_rails/rooms.css +4 -0
  9. data/app/controllers/webrtc_rails/application_controller.rb +2 -0
  10. data/app/controllers/webrtc_rails/rooms_controller.rb +31 -0
  11. data/app/helpers/webrtc_rails/application_helper.rb +4 -0
  12. data/app/helpers/webrtc_rails/videoconfs_helper.rb +4 -0
  13. data/app/models/uri_string.rb +0 -0
  14. data/app/views/layouts/webrtc_rails/application.html.erb +17 -0
  15. data/app/views/webrtc_rails/rooms/new.html.erb +15 -0
  16. data/app/views/webrtc_rails/rooms/show.html.erb +19 -0
  17. data/config/locales/en.yml +4 -0
  18. data/config/locales/es.yml +4 -0
  19. data/config/routes.rb +3 -0
  20. data/lib/tasks/webrtc_rails_tasks.rake +4 -0
  21. data/lib/webrtc_rails.rb +8 -0
  22. data/lib/webrtc_rails/engine.rb +5 -0
  23. data/lib/webrtc_rails/parameterizable_validator.rb +7 -0
  24. data/lib/webrtc_rails/room.rb +20 -0
  25. data/lib/webrtc_rails/version.rb +3 -0
  26. data/test/controllers/webrtc_rails/videoconfs_controller_test.rb +9 -0
  27. data/test/dummy/README.rdoc +28 -0
  28. data/test/dummy/Rakefile +6 -0
  29. data/test/dummy/app/assets/javascripts/application.js +13 -0
  30. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  31. data/test/dummy/app/controllers/application_controller.rb +5 -0
  32. data/test/dummy/app/helpers/application_helper.rb +2 -0
  33. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  34. data/test/dummy/bin/bundle +3 -0
  35. data/test/dummy/bin/rails +4 -0
  36. data/test/dummy/bin/rake +4 -0
  37. data/test/dummy/config.ru +4 -0
  38. data/test/dummy/config/application.rb +23 -0
  39. data/test/dummy/config/boot.rb +5 -0
  40. data/test/dummy/config/database.yml +25 -0
  41. data/test/dummy/config/environment.rb +5 -0
  42. data/test/dummy/config/environments/development.rb +29 -0
  43. data/test/dummy/config/environments/production.rb +80 -0
  44. data/test/dummy/config/environments/test.rb +36 -0
  45. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  46. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  47. data/test/dummy/config/initializers/inflections.rb +16 -0
  48. data/test/dummy/config/initializers/mime_types.rb +5 -0
  49. data/test/dummy/config/initializers/secret_token.rb +12 -0
  50. data/test/dummy/config/initializers/session_store.rb +3 -0
  51. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  52. data/test/dummy/config/locales/en.yml +23 -0
  53. data/test/dummy/config/routes.rb +6 -0
  54. data/test/dummy/public/404.html +58 -0
  55. data/test/dummy/public/422.html +58 -0
  56. data/test/dummy/public/500.html +57 -0
  57. data/test/dummy/public/favicon.ico +0 -0
  58. data/test/helpers/webrtc_rails/videoconfs_helper_test.rb +6 -0
  59. data/test/integration/navigation_test.rb +10 -0
  60. data/test/test_helper.rb +15 -0
  61. data/test/webrtc_rails_test.rb +7 -0
  62. data/vendor/assets/javascripts/webrtc_rails/getusermedia.js +68 -0
  63. data/vendor/assets/javascripts/webrtc_rails/hark.js +256 -0
  64. data/vendor/assets/javascripts/webrtc_rails/simplewebrtc.js +5 -0
  65. metadata +212 -0
@@ -0,0 +1,58 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/404.html -->
52
+ <div class="dialog">
53
+ <h1>The page you were looking for doesn't exist.</h1>
54
+ <p>You may have mistyped the address or the page may have moved.</p>
55
+ </div>
56
+ <p>If you are the application owner check the logs for more information.</p>
57
+ </body>
58
+ </html>
@@ -0,0 +1,58 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/422.html -->
52
+ <div class="dialog">
53
+ <h1>The change you wanted was rejected.</h1>
54
+ <p>Maybe you tried to change something you didn't have access to.</p>
55
+ </div>
56
+ <p>If you are the application owner check the logs for more information.</p>
57
+ </body>
58
+ </html>
@@ -0,0 +1,57 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/500.html -->
52
+ <div class="dialog">
53
+ <h1>We're sorry, but something went wrong.</h1>
54
+ </div>
55
+ <p>If you are the application owner check the logs for more information.</p>
56
+ </body>
57
+ </html>
File without changes
@@ -0,0 +1,6 @@
1
+ require 'test_helper'
2
+
3
+ module WebrtcRails
4
+ class VideoconfsHelperTest < ActionView::TestCase
5
+ end
6
+ end
@@ -0,0 +1,10 @@
1
+ require 'test_helper'
2
+
3
+ class NavigationTest < ActionDispatch::IntegrationTest
4
+ fixtures :all
5
+
6
+ # test "the truth" do
7
+ # assert true
8
+ # end
9
+ end
10
+
@@ -0,0 +1,15 @@
1
+ # Configure Rails Environment
2
+ ENV["RAILS_ENV"] = "test"
3
+
4
+ require File.expand_path("../dummy/config/environment.rb", __FILE__)
5
+ require "rails/test_help"
6
+
7
+ Rails.backtrace_cleaner.remove_silencers!
8
+
9
+ # Load support files
10
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
11
+
12
+ # Load fixtures from the engine
13
+ if ActiveSupport::TestCase.method_defined?(:fixture_path=)
14
+ ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__)
15
+ end
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class WebrtcRailsTest < ActiveSupport::TestCase
4
+ test "truth" do
5
+ assert_kind_of Module, WebrtcRails
6
+ end
7
+ end
@@ -0,0 +1,68 @@
1
+ !function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.getUserMedia=e():"undefined"!=typeof global?global.getUserMedia=e():"undefined"!=typeof self&&(self.getUserMedia=e())}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
2
+ // getUserMedia helper by @HenrikJoreteg
3
+ var func = (window.navigator.getUserMedia ||
4
+ window.navigator.webkitGetUserMedia ||
5
+ window.navigator.mozGetUserMedia ||
6
+ window.navigator.msGetUserMedia);
7
+
8
+
9
+ module.exports = function (constraints, cb) {
10
+ var options;
11
+ var haveOpts = arguments.length === 2;
12
+ var defaultOpts = {video: true, audio: true};
13
+ var error;
14
+ var denied = 'PERMISSION_DENIED';
15
+ var notSatified = 'CONSTRAINT_NOT_SATISFIED';
16
+
17
+ // make constraints optional
18
+ if (!haveOpts) {
19
+ cb = constraints;
20
+ constraints = defaultOpts;
21
+ }
22
+
23
+ // treat lack of browser support like an error
24
+ if (!func) {
25
+ // throw proper error per spec
26
+ error = new Error('NavigatorUserMediaError');
27
+ error.name = 'NOT_SUPPORTED_ERROR';
28
+ return cb(error);
29
+ }
30
+
31
+ func.call(window.navigator, constraints, function (stream) {
32
+ cb(null, stream);
33
+ }, function (err) {
34
+ var error;
35
+ // coerce into an error object since FF gives us a string
36
+ // there are only two valid names according to the spec
37
+ // we coerce all non-denied to "constraint not satisfied".
38
+ if (typeof err === 'string') {
39
+ error = new Error('NavigatorUserMediaError');
40
+ if (err === denied) {
41
+ error.name = denied;
42
+ } else {
43
+ error.name = notSatified;
44
+ }
45
+ } else {
46
+ // if we get an error object make sure '.name' property is set
47
+ // according to spec: http://dev.w3.org/2011/webrtc/editor/getusermedia.html#navigatorusermediaerror-and-navigatorusermediaerrorcallback
48
+ error = err;
49
+ if (!error.name) {
50
+ // this is likely chrome which
51
+ // sets a property called "ERROR_DENIED" on the error object
52
+ // if so we make sure to set a name
53
+ if (error[denied]) {
54
+ err.name = denied;
55
+ } else {
56
+ err.name = notSatified;
57
+ }
58
+ }
59
+ }
60
+
61
+ cb(error);
62
+ });
63
+ };
64
+
65
+ },{}]},{},[1])
66
+ (1)
67
+ });
68
+ ;
@@ -0,0 +1,256 @@
1
+ (function(e){if("function"==typeof bootstrap)bootstrap("hark",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeHark=e}else"undefined"!=typeof window?window.hark=e():global.hark=e()})(function(){var define,ses,bootstrap,module,exports;
2
+ return (function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s<n.length;s++)i(n[s]);return i})({1:[function(require,module,exports){
3
+ var WildEmitter = require('wildemitter');
4
+
5
+ function getMaxVolume (analyser, fftBins) {
6
+ var maxVolume = -Infinity;
7
+ analyser.getFloatFrequencyData(fftBins);
8
+
9
+ for(var i=0, ii=fftBins.length; i < ii; i++) {
10
+ if (fftBins[i] > maxVolume && fftBins[i] < 0) {
11
+ maxVolume = fftBins[i];
12
+ }
13
+ };
14
+
15
+ return maxVolume;
16
+ }
17
+
18
+
19
+ var audioContextType = window.webkitAudioContext || window.AudioContext;
20
+ // use a single audio context due to hardware limits
21
+ var audioContext = null;
22
+ module.exports = function(stream, options) {
23
+ var harker = new WildEmitter();
24
+
25
+
26
+ // make it not break in non-supported browsers
27
+ if (!audioContextType) return harker;
28
+
29
+ //Config
30
+ var options = options || {},
31
+ smoothing = (options.smoothing || 0.5),
32
+ interval = (options.interval || 100),
33
+ threshold = options.threshold,
34
+ play = options.play,
35
+ running = true;
36
+
37
+ //Setup Audio Context
38
+ if (!audioContext) {
39
+ audioContext = new audioContextType();
40
+ }
41
+ var sourceNode, fftBins, analyser;
42
+
43
+ analyser = audioContext.createAnalyser();
44
+ analyser.fftSize = 512;
45
+ analyser.smoothingTimeConstant = smoothing;
46
+ fftBins = new Float32Array(analyser.fftSize);
47
+
48
+ if (stream.jquery) stream = stream[0];
49
+ if (stream instanceof HTMLAudioElement) {
50
+ //Audio Tag
51
+ sourceNode = audioContext.createMediaElementSource(stream);
52
+ if (typeof play === 'undefined') play = true;
53
+ threshold = threshold || -65;
54
+ } else {
55
+ //WebRTC Stream
56
+ sourceNode = audioContext.createMediaStreamSource(stream);
57
+ threshold = threshold || -45;
58
+ }
59
+
60
+ sourceNode.connect(analyser);
61
+ if (play) analyser.connect(audioContext.destination);
62
+
63
+ harker.speaking = false;
64
+
65
+ harker.setThreshold = function(t) {
66
+ threshold = t;
67
+ };
68
+
69
+ harker.setInterval = function(i) {
70
+ interval = i;
71
+ };
72
+
73
+ harker.stop = function() {
74
+ running = false;
75
+ harker.emit('volume_change', -100, threshold);
76
+ if (harker.speaking) {
77
+ harker.speaking = false;
78
+ harker.emit('stopped_speaking');
79
+ }
80
+ };
81
+
82
+ // Poll the analyser node to determine if speaking
83
+ // and emit events if changed
84
+ var looper = function() {
85
+ setTimeout(function() {
86
+
87
+ //check if stop has been called
88
+ if(!running) {
89
+ return;
90
+ }
91
+
92
+ var currentVolume = getMaxVolume(analyser, fftBins);
93
+
94
+ harker.emit('volume_change', currentVolume, threshold);
95
+
96
+ if (currentVolume > threshold) {
97
+ if (!harker.speaking) {
98
+ harker.speaking = true;
99
+ harker.emit('speaking');
100
+ }
101
+ } else {
102
+ if (harker.speaking) {
103
+ harker.speaking = false;
104
+ harker.emit('stopped_speaking');
105
+ }
106
+ }
107
+
108
+ looper();
109
+ }, interval);
110
+ };
111
+ looper();
112
+
113
+
114
+ return harker;
115
+ }
116
+
117
+ },{"wildemitter":2}],2:[function(require,module,exports){
118
+ /*
119
+ WildEmitter.js is a slim little event emitter by @henrikjoreteg largely based
120
+ on @visionmedia's Emitter from UI Kit.
121
+
122
+ Why? I wanted it standalone.
123
+
124
+ I also wanted support for wildcard emitters like this:
125
+
126
+ emitter.on('*', function (eventName, other, event, payloads) {
127
+
128
+ });
129
+
130
+ emitter.on('somenamespace*', function (eventName, payloads) {
131
+
132
+ });
133
+
134
+ Please note that callbacks triggered by wildcard registered events also get
135
+ the event name as the first argument.
136
+ */
137
+ module.exports = WildEmitter;
138
+
139
+ function WildEmitter() {
140
+ this.callbacks = {};
141
+ }
142
+
143
+ // Listen on the given `event` with `fn`. Store a group name if present.
144
+ WildEmitter.prototype.on = function (event, groupName, fn) {
145
+ var hasGroup = (arguments.length === 3),
146
+ group = hasGroup ? arguments[1] : undefined,
147
+ func = hasGroup ? arguments[2] : arguments[1];
148
+ func._groupName = group;
149
+ (this.callbacks[event] = this.callbacks[event] || []).push(func);
150
+ return this;
151
+ };
152
+
153
+ // Adds an `event` listener that will be invoked a single
154
+ // time then automatically removed.
155
+ WildEmitter.prototype.once = function (event, groupName, fn) {
156
+ var self = this,
157
+ hasGroup = (arguments.length === 3),
158
+ group = hasGroup ? arguments[1] : undefined,
159
+ func = hasGroup ? arguments[2] : arguments[1];
160
+ function on() {
161
+ self.off(event, on);
162
+ func.apply(this, arguments);
163
+ }
164
+ this.on(event, group, on);
165
+ return this;
166
+ };
167
+
168
+ // Unbinds an entire group
169
+ WildEmitter.prototype.releaseGroup = function (groupName) {
170
+ var item, i, len, handlers;
171
+ for (item in this.callbacks) {
172
+ handlers = this.callbacks[item];
173
+ for (i = 0, len = handlers.length; i < len; i++) {
174
+ if (handlers[i]._groupName === groupName) {
175
+ //console.log('removing');
176
+ // remove it and shorten the array we're looping through
177
+ handlers.splice(i, 1);
178
+ i--;
179
+ len--;
180
+ }
181
+ }
182
+ }
183
+ return this;
184
+ };
185
+
186
+ // Remove the given callback for `event` or all
187
+ // registered callbacks.
188
+ WildEmitter.prototype.off = function (event, fn) {
189
+ var callbacks = this.callbacks[event],
190
+ i;
191
+
192
+ if (!callbacks) return this;
193
+
194
+ // remove all handlers
195
+ if (arguments.length === 1) {
196
+ delete this.callbacks[event];
197
+ return this;
198
+ }
199
+
200
+ // remove specific handler
201
+ i = callbacks.indexOf(fn);
202
+ callbacks.splice(i, 1);
203
+ return this;
204
+ };
205
+
206
+ // Emit `event` with the given args.
207
+ // also calls any `*` handlers
208
+ WildEmitter.prototype.emit = function (event) {
209
+ var args = [].slice.call(arguments, 1),
210
+ callbacks = this.callbacks[event],
211
+ specialCallbacks = this.getWildcardCallbacks(event),
212
+ i,
213
+ len,
214
+ item;
215
+
216
+ if (callbacks) {
217
+ for (i = 0, len = callbacks.length; i < len; ++i) {
218
+ if (callbacks[i]) {
219
+ callbacks[i].apply(this, args);
220
+ } else {
221
+ break;
222
+ }
223
+ }
224
+ }
225
+
226
+ if (specialCallbacks) {
227
+ for (i = 0, len = specialCallbacks.length; i < len; ++i) {
228
+ if (specialCallbacks[i]) {
229
+ specialCallbacks[i].apply(this, [event].concat(args));
230
+ } else {
231
+ break;
232
+ }
233
+ }
234
+ }
235
+
236
+ return this;
237
+ };
238
+
239
+ // Helper for for finding special wildcard event handlers that match the event
240
+ WildEmitter.prototype.getWildcardCallbacks = function (eventName) {
241
+ var item,
242
+ split,
243
+ result = [];
244
+
245
+ for (item in this.callbacks) {
246
+ split = item.split('*');
247
+ if (item === '*' || (split.length === 2 && eventName.slice(0, split[1].length) === split[1])) {
248
+ result = result.concat(this.callbacks[item]);
249
+ }
250
+ }
251
+ return result;
252
+ };
253
+
254
+ },{}]},{},[1])(1)
255
+ });
256
+ ;