commit
6ed650410c
@ -0,0 +1,59 @@ |
||||
@fileUpload = (files) -> |
||||
files = [].concat files |
||||
|
||||
consume = -> |
||||
file = files.pop() |
||||
if not file? |
||||
swal.close() |
||||
return |
||||
|
||||
reader = new FileReader() |
||||
reader.onload = (event) -> |
||||
fileContent = event.target.result |
||||
|
||||
text = '' |
||||
|
||||
if file.type is 'audio' |
||||
text = """ |
||||
<div class='upload-preview'> |
||||
<audio style="width: 100%;" controls="controls"> |
||||
<source src="#{fileContent}" type="audio/wav"> |
||||
Your browser does not support the audio element. |
||||
</audio> |
||||
</div> |
||||
<div class='upload-preview-title'>#{file.name}</div> |
||||
""" |
||||
else |
||||
text = """ |
||||
<div class='upload-preview'> |
||||
<div class='upload-preview-file' style='background-image: url(#{fileContent})'></div> |
||||
</div> |
||||
<div class='upload-preview-title'>#{file.name}</div> |
||||
""" |
||||
|
||||
swal |
||||
title: t('Upload_file_question') |
||||
text: text |
||||
showCancelButton: true |
||||
closeOnConfirm: false |
||||
closeOnCancel: false |
||||
html: true |
||||
, (isConfirm) -> |
||||
consume() |
||||
|
||||
if isConfirm isnt true |
||||
return |
||||
|
||||
newFile = new (FS.File)(file.file) |
||||
if file.name? |
||||
newFile.name(file.name) |
||||
newFile.rid = Session.get('openedRoom') |
||||
newFile.recId = Random.id() |
||||
newFile.userId = Meteor.userId() |
||||
Files.insert newFile, (error, fileObj) -> |
||||
unless error |
||||
toastr.success 'Upload succeeded!' |
||||
|
||||
reader.readAsDataURL(file.file) |
||||
|
||||
consume() |
||||
@ -0,0 +1,40 @@ |
||||
@AudioRecorder = new class |
||||
start: (cb) -> |
||||
window.AudioContext = window.AudioContext or window.webkitAudioContext |
||||
navigator.getUserMedia = navigator.getUserMedia or navigator.webkitGetUserMedia |
||||
window.URL = window.URL or window.webkitURL |
||||
|
||||
@audio_context = new AudioContext |
||||
|
||||
ok = (stream) => |
||||
@startUserMedia(stream) |
||||
cb?.call(@) |
||||
|
||||
if not navigator.getUserMedia? |
||||
return cb false |
||||
|
||||
navigator.getUserMedia {audio: true}, ok, (e) -> |
||||
console.log('No live audio input: ' + e) |
||||
|
||||
startUserMedia: (stream) -> |
||||
@stream = stream |
||||
input = @audio_context.createMediaStreamSource(stream) |
||||
@recorder = new Recorder(input, {workerPath: '/recorderWorker.js'}) |
||||
@recorder.record() |
||||
|
||||
stop: (cb) -> |
||||
@recorder.stop() |
||||
|
||||
if cb? |
||||
@getBlob cb |
||||
|
||||
@stream.stop() |
||||
|
||||
@recorder.clear() |
||||
|
||||
delete @audio_context |
||||
delete @recorder |
||||
delete @stream |
||||
|
||||
getBlob: (cb) -> |
||||
@recorder.exportWAV cb |
||||
@ -0,0 +1,92 @@ |
||||
(function(window){ |
||||
|
||||
var WORKER_PATH = 'recorderWorker.js'; |
||||
|
||||
var Recorder = function(source, cfg){ |
||||
var config = cfg || {}; |
||||
var bufferLen = config.bufferLen || 4096; |
||||
var numChannels = config.numChannels || 2; |
||||
this.context = source.context; |
||||
this.node = (this.context.createScriptProcessor || |
||||
this.context.createJavaScriptNode).call(this.context, |
||||
bufferLen, numChannels, numChannels); |
||||
var worker = new Worker(config.workerPath || WORKER_PATH); |
||||
worker.postMessage({ |
||||
command: 'init', |
||||
config: { |
||||
sampleRate: this.context.sampleRate, |
||||
numChannels: numChannels |
||||
} |
||||
}); |
||||
var recording = false, |
||||
currCallback; |
||||
|
||||
this.node.onaudioprocess = function(e){ |
||||
if (!recording) return; |
||||
var buffer = []; |
||||
for (var channel = 0; channel < numChannels; channel++){ |
||||
buffer.push(e.inputBuffer.getChannelData(channel)); |
||||
} |
||||
worker.postMessage({ |
||||
command: 'record', |
||||
buffer: buffer |
||||
}); |
||||
} |
||||
|
||||
this.configure = function(cfg){ |
||||
for (var prop in cfg){ |
||||
if (cfg.hasOwnProperty(prop)){ |
||||
config[prop] = cfg[prop]; |
||||
} |
||||
} |
||||
} |
||||
|
||||
this.record = function(){ |
||||
recording = true; |
||||
} |
||||
|
||||
this.stop = function(){ |
||||
recording = false; |
||||
} |
||||
|
||||
this.clear = function(){ |
||||
worker.postMessage({ command: 'clear' }); |
||||
} |
||||
|
||||
this.getBuffer = function(cb) { |
||||
currCallback = cb || config.callback; |
||||
worker.postMessage({ command: 'getBuffer' }) |
||||
} |
||||
|
||||
this.exportWAV = function(cb, type){ |
||||
currCallback = cb || config.callback; |
||||
type = type || config.type || 'audio/wav'; |
||||
if (!currCallback) throw new Error('Callback not set'); |
||||
worker.postMessage({ |
||||
command: 'exportWAV', |
||||
type: type |
||||
}); |
||||
} |
||||
|
||||
worker.onmessage = function(e){ |
||||
var blob = e.data; |
||||
currCallback(blob); |
||||
} |
||||
|
||||
source.connect(this.node); |
||||
this.node.connect(this.context.destination); //this should not be necessary
|
||||
}; |
||||
|
||||
Recorder.forceDownload = function(blob, filename){ |
||||
var url = (window.URL || window.webkitURL).createObjectURL(blob); |
||||
var link = window.document.createElement('a'); |
||||
link.href = url; |
||||
link.download = filename || 'output.wav'; |
||||
var click = document.createEvent("Event"); |
||||
click.initEvent("click", true, true); |
||||
link.dispatchEvent(click); |
||||
} |
||||
|
||||
window.Recorder = Recorder; |
||||
|
||||
})(window); |
||||
@ -1,14 +1,5 @@ |
||||
Template.home.helpers |
||||
arrowPosition: -> |
||||
return 'left' unless Session.equals('flexOpened', true) |
||||
flexOpened: -> |
||||
return 'opened' if Session.equals('flexOpened', true) |
||||
withParagraph: -> |
||||
return { |
||||
withParagraph: true |
||||
} |
||||
|
||||
Template.home.events |
||||
"click .flex-tab .more": (event) -> |
||||
Session.set('flexOpened', !Session.get('flexOpened')) |
||||
|
||||
title: -> |
||||
return RocketChat.settings.get 'Layout_Home_Title' |
||||
body: -> |
||||
return RocketChat.settings.get 'Layout_Home_Body' |
||||
|
||||
@ -1 +1,5 @@ |
||||
{ } |
||||
{ |
||||
"LDAP_Url" : "LDAP URL", |
||||
"LDAP_Port" : "LDAP portti", |
||||
"LDAP_Dn" : "LDAP DN" |
||||
} |
||||
@ -0,0 +1,12 @@ |
||||
<template name="oembedAudioWidget"> |
||||
<a href="{{url}}" target="_blank"> |
||||
{{#if parsedUrl}} |
||||
<blockquote> |
||||
<audio controls> |
||||
<source src="{{url}}" type="{{headers.contentType}}"> |
||||
Your browser does not support the audio element. |
||||
</audio> |
||||
</blockquote> |
||||
{{/if}} |
||||
</a> |
||||
</template> |
||||
@ -1 +1,6 @@ |
||||
{ } |
||||
{ |
||||
"Video_Chat" : "Video-Chat", |
||||
"Remote" : "Entfernt", |
||||
"Setup" : "Einrichten", |
||||
"Stop_Video" : "Video stoppen" |
||||
} |
||||
@ -1 +1,6 @@ |
||||
{ } |
||||
{ |
||||
"Video_Chat" : "Videokeskustelu", |
||||
"Remote" : "Etä", |
||||
"Setup" : "Asennus", |
||||
"Stop_Video" : "Pysäytä video" |
||||
} |
||||
@ -1 +1,6 @@ |
||||
{ } |
||||
{ |
||||
"Video_Chat" : "Chat wideo", |
||||
"Remote" : "Zdalny", |
||||
"Setup" : "Opcje", |
||||
"Stop_Video" : "Zatrzymaj wideo" |
||||
} |
||||
@ -0,0 +1,147 @@ |
||||
var recLength = 0, |
||||
recBuffers = [], |
||||
sampleRate, |
||||
numChannels; |
||||
|
||||
this.onmessage = function(e){ |
||||
switch(e.data.command){ |
||||
case 'init': |
||||
init(e.data.config); |
||||
break; |
||||
case 'record': |
||||
record(e.data.buffer); |
||||
break; |
||||
case 'exportWAV': |
||||
exportWAV(e.data.type); |
||||
break; |
||||
case 'getBuffer': |
||||
getBuffer(); |
||||
break; |
||||
case 'clear': |
||||
clear(); |
||||
break; |
||||
} |
||||
}; |
||||
|
||||
function init(config){ |
||||
sampleRate = config.sampleRate; |
||||
numChannels = config.numChannels; |
||||
initBuffers(); |
||||
} |
||||
|
||||
function record(inputBuffer){ |
||||
for (var channel = 0; channel < numChannels; channel++){ |
||||
recBuffers[channel].push(inputBuffer[channel]); |
||||
} |
||||
recLength += inputBuffer[0].length; |
||||
} |
||||
|
||||
function exportWAV(type){ |
||||
var buffers = []; |
||||
for (var channel = 0; channel < numChannels; channel++){ |
||||
buffers.push(mergeBuffers(recBuffers[channel], recLength)); |
||||
} |
||||
if (numChannels === 2){ |
||||
var interleaved = interleave(buffers[0], buffers[1]); |
||||
} else { |
||||
var interleaved = buffers[0]; |
||||
} |
||||
var dataview = encodeWAV(interleaved); |
||||
var audioBlob = new Blob([dataview], { type: type }); |
||||
|
||||
this.postMessage(audioBlob); |
||||
} |
||||
|
||||
function getBuffer(){ |
||||
var buffers = []; |
||||
for (var channel = 0; channel < numChannels; channel++){ |
||||
buffers.push(mergeBuffers(recBuffers[channel], recLength)); |
||||
} |
||||
this.postMessage(buffers); |
||||
} |
||||
|
||||
function clear(){ |
||||
recLength = 0; |
||||
recBuffers = []; |
||||
initBuffers(); |
||||
} |
||||
|
||||
function initBuffers(){ |
||||
for (var channel = 0; channel < numChannels; channel++){ |
||||
recBuffers[channel] = []; |
||||
} |
||||
} |
||||
|
||||
function mergeBuffers(recBuffers, recLength){ |
||||
var result = new Float32Array(recLength); |
||||
var offset = 0; |
||||
for (var i = 0; i < recBuffers.length; i++){ |
||||
result.set(recBuffers[i], offset); |
||||
offset += recBuffers[i].length; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
function interleave(inputL, inputR){ |
||||
var length = inputL.length + inputR.length; |
||||
var result = new Float32Array(length); |
||||
|
||||
var index = 0, |
||||
inputIndex = 0; |
||||
|
||||
while (index < length){ |
||||
result[index++] = inputL[inputIndex]; |
||||
result[index++] = inputR[inputIndex]; |
||||
inputIndex++; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
function floatTo16BitPCM(output, offset, input){ |
||||
for (var i = 0; i < input.length; i++, offset+=2){ |
||||
var s = Math.max(-1, Math.min(1, input[i])); |
||||
output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true); |
||||
} |
||||
} |
||||
|
||||
function writeString(view, offset, string){ |
||||
for (var i = 0; i < string.length; i++){ |
||||
view.setUint8(offset + i, string.charCodeAt(i)); |
||||
} |
||||
} |
||||
|
||||
function encodeWAV(samples){ |
||||
var buffer = new ArrayBuffer(44 + samples.length * 2); |
||||
var view = new DataView(buffer); |
||||
|
||||
/* RIFF identifier */ |
||||
writeString(view, 0, 'RIFF'); |
||||
/* RIFF chunk length */ |
||||
view.setUint32(4, 36 + samples.length * 2, true); |
||||
/* RIFF type */ |
||||
writeString(view, 8, 'WAVE'); |
||||
/* format chunk identifier */ |
||||
writeString(view, 12, 'fmt '); |
||||
/* format chunk length */ |
||||
view.setUint32(16, 16, true); |
||||
/* sample format (raw) */ |
||||
view.setUint16(20, 1, true); |
||||
/* channel count */ |
||||
view.setUint16(22, numChannels, true); |
||||
/* sample rate */ |
||||
view.setUint32(24, sampleRate, true); |
||||
/* byte rate (sample rate * block align) */ |
||||
view.setUint32(28, sampleRate * 4, true); |
||||
/* block align (channel count * bytes per sample) */ |
||||
view.setUint16(32, numChannels * 2, true); |
||||
/* bits per sample */ |
||||
view.setUint16(34, 16, true); |
||||
/* data chunk identifier */ |
||||
writeString(view, 36, 'data'); |
||||
/* data chunk length */ |
||||
view.setUint32(40, samples.length * 2, true); |
||||
|
||||
floatTo16BitPCM(view, 44, samples); |
||||
|
||||
return view; |
||||
} |
||||
Loading…
Reference in new issue