Files
2025-11-20 15:27:34 -06:00

141 lines
5.4 KiB
HTML

<!DOCTYPE html>
<!--
Copyright 2015 Lorentz Lasson
Copyright 2015-2019 Lorentz Lasson, Dave Conway-Jones
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/javascript">
(function() {
var voices;
var sources = [];
RED.nodes.registerType('play audio',{
category: 'output',
color: '#DAAFF7',
defaults: {
name: {value:""},
voice: {value:""}
},
inputs:1,
outputs:0,
icon: "feed.png",
align: "right",
label: function() {
return this.name||"play audio";
},
onpaletteadd: function() {
this.handleAudio = function(t,o) {
var context = new AudioContext();
var byteArray = (o.hasOwnProperty("data")) ? o.data : o;
( function () {
return new Promise(function resolver(resolve, reject) {
if (context.state && 'running' !== context.state && context.resume) {
context.resume().then(() => {
resolve();
})
} else {
resolve();
}
});
}()).then(() => {
try {
var source = context.createBufferSource();
var buffer = new Uint8Array(byteArray.length);
buffer.set(new Uint8Array(byteArray), 0);
source.addEventListener('ended', () => { context.close(); context = undefined; }, {capture:false, once:true});
context.decodeAudioData(buffer.buffer, function(buffer) {
source.buffer = buffer;
source.onended = function() {
$.getJSON('playaudio',function() { });
sources = sources.filter(function(s) {
if (source === s) { return false; }
else { return true; }
});
}
source.connect(context.destination);
source.start(0);
sources.push(source);
});
}
catch(e) {
alert("Error playing audio: "+e);
}
}).catch((e)=> {
alert("Audio context error: "+e);
});
};
this.handleTTS = function(t,o) {
var v = o.split('#',2);
if ('speechSynthesis' in window) {
voices = window.speechSynthesis.getVoices();
var words = new SpeechSynthesisUtterance(v[1]);
words.voice = voices[parseInt(v[0])];
window.speechSynthesis.speak(words);
words.onend = function(event) {
$.getJSON('playaudio',function() { });
}
}
else {
alert("Your Browser does not support Text-to-Speech");
}
};
RED.comms.subscribe("playaudio", this.handleAudio);
RED.comms.subscribe("playtts", this.handleTTS);
},
oneditprepare: function() {
if ('speechSynthesis' in window) {
voices = window.speechSynthesis.getVoices();
for (i = 0; i < voices.length ; i++) {
//console.log(i,voices[i].name,voices[i].lang,voices[i].voiceURI,voices[i].default);
var option = document.createElement('option');
option.textContent = voices[i].name + ' (' + voices[i].lang + ')';
if (voices[i].default) { option.textContent += ' -- DEFAULT'; }
option.setAttribute('value', i);
document.getElementById("node-input-voice").appendChild(option);
}
$('#node-input-voice').val(this.voice || 0);
}
else {
$('#voice-input-row').hide();
}
},
button : {
enabled : true,
onclick : function() {
sources = sources.filter(function(source) {
source.stop(0);
return false;
});
}
}
});
})();
</script>
<script type="text/html" data-template-name="play audio">
<div class="form-row" id="voice-input-row">
<label for="node-input-voice"><i class="fa fa-language"></i> <span data-i18n="playAudio.label.ttsVoice"></label>
<select id="node-input-voice"></select>
</div>
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> <span data-i18n="node-red:common.label.name"></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div>
</script>