Posts: 169
Threads: 58
Joined: Oct 2017
Reputation:
0
Hi all,
for users' interface, I use some PC and an Android Tablet.
I have to alert users with sound (wav/mp3) or simple beep through Lua (and JS developpements if necessary) : It's works fine on Windows, but my Android 5.1.1 machine refuse to issue any sound (I obtain a simple "crack").
Is there an "universal" method for this ?
I know it should be very complex...
Have a good end of monday !
Dominique
Posts: 1764
Threads: 6
Joined: Jul 2015
Reputation:
117
27.03.2018, 18:01
(This post was last modified: 27.03.2018, 18:07 by Erwin van der Zwart.)
Hi,
You could use this custom JS for that: (note that iOS devices needs to be touch once before audio works, Apple crazy policy)
Note that the audio files are uploaded in the Apps FTP user folder, otherwise you have to adjust the path.
Code: // Closing current script section to add elements
</script>
<audio id="SE_Audio" style="display: none;"></audio>
<script type="text/javascript"> // Starting new script section after adding elements
$(function(){
// Table with parameters
var AudioTable = [
{ address:"32/2/0", url:"/user/audio1.mp3"},
{ address:"32/2/1", url:"/user/audio2.mp3" },
{ address:"32/2/2", url:"/user/audio3.mp3" },
];
var ctx = new(window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.oAudioContext || window.msAudioContext), request = new XMLHttpRequest();
var snd = document.getElementById("SE_Audio");
function getMobileOperatingSystem() {
var userAgent = navigator.userAgent || navigator.vendor || window.opera;
//console.log(userAgent)
if (userAgent.match(/iPad/i) || userAgent.match(/iPhone/i) || userAgent.match(/iPod/i)) {
return 'iOS';
} else if ( userAgent.match(/Android/i)) {
return 'Android';
} else if ( userAgent.match(/iKonWebTouch/i)) {
return 'U.Motion';
} else {
return 'PC';
}
}
var OS_Version = getMobileOperatingSystem();
// Fix iOS Audio Context
(function() {
var fixAudioContext = function (e) {
if (ctx) {
// Create empty buffer
var buffer = ctx.createBuffer(1, 1, 22050);
var source = ctx.createBufferSource();
source.buffer = buffer;
// Connect to output
source.connect(ctx.destination);
// Play sound
if (source.start) {
source.start(0);
} else if (source.play) {
source.play(0);
} else if (source.noteOn) {
source.noteOn(0);
}
}
// Check if document is loaded in iframe
if (window.frameElement){
// Remove event listeners from parent
var thisparent = window.parent;
thisparent.document.removeEventListener('touchstart', fixAudioContext);
thisparent.document.removeEventListener('touchend', fixAudioContext);
}
// Remove events
document.removeEventListener('touchstart', fixAudioContext);
document.removeEventListener('touchend', fixAudioContext);
};
// Check if document is loaded in iframe
if (window.frameElement){
// Add event listeners to parent
var thisparent = window.parent;
// Event listener for iOS 6-8 (was previous touchstart event)
thisparent.document.addEventListener('touchstart', fixAudioContext);
// Event listener for iOS 9+ (is now touchend event)
thisparent.document.addEventListener('touchend', fixAudioContext);
}
// Event listener for iOS 6-8 (was previous touchstart event)
document.addEventListener('touchstart', fixAudioContext);
// Event listener for iOS 9+ (is now touchend event)
document.addEventListener('touchend', fixAudioContext);
})();
// Function to play audio by URL
function Play_Audio(url){
//console.log(OS_Version)
if (OS_Version === 'Android' || OS_Version === 'U.Motion' ){
//alert(OS_Version);
snd.src = url;
snd.pause();
sndcurrentTime = 0;
//snd.load();
snd.play();
} else {
request.open("GET", url, true);
request.responseType = "arraybuffer";
request.onload = function(){
ctx.decodeAudioData(request.response, onDecoded);
}
function onDecoded(buffer){
var bufferSource = ctx.createBufferSource();
bufferSource.buffer = buffer;
bufferSource.connect(ctx.destination);
bufferSource.start();
}
request.send();
}
};
// Function to create event listeners
function CreateListeners(groupaddr,url){
// Make event listener to object
if (typeof grp != 'undefined') {
grp.listen(groupaddr, function(object, state) {
var value = object.value;
if (state == 'value') {
if (value == 1) {
Play_Audio(url);
}
}
}, true);
}
}
// Start creating listeners
for (var i in AudioTable) {
CreateListeners(AudioTable[i].address,AudioTable[i].url);
}
});
BR,
Erwin
PS: Not complex at all (:
Posts: 169
Threads: 58
Joined: Oct 2017
Reputation:
0
Erwin...
...you are a genius
Many thank's again for all.
Dominique, a fan of LM
Posts: 136
Threads: 20
Joined: Jul 2015
Reputation:
0
(27.03.2018, 18:01)Erwin van der Zwart Wrote: Hi,
You could use this custom JS for that: (note that iOS devices needs to be touch once before audio works, Apple crazy policy)
Hi,
Same for Android Chrome !!
JMM
Jean-Marc
Posts: 23
Threads: 7
Joined: Aug 2017
Reputation:
0
Hi,
I was try this script add file in ftp but for me is not working sound. I was try from windows PC on the button need to add function in Additional class?
Posts: 1764
Threads: 6
Joined: Jul 2015
Reputation:
117
Hi,
No there are no additional classes needed, the events are attached to grp addr.
Are you sure the ftp files are correct located? In Apps ‘user’ folder?
Can you try in your browser http://192.168.0.10/user/audio1.mp3 and see if the file get played?
BR,
Erwin
Posts: 940
Threads: 161
Joined: Jul 2015
Reputation:
33
Check console.log() in Browser console, maybe there are some errors.
Done is better than perfect
Posts: 8
Threads: 4
Joined: Apr 2019
Reputation:
0
Is there a decent way to create a "mute" button for this script?
Posts: 7758
Threads: 42
Joined: Jun 2015
Reputation:
447
You can use an additional object to control whether to play the sound or not. In this example the sound will play only when 1/1/1 value is true.
Code: function CreateListeners(groupaddr,url){
// Make event listener to object
if (typeof grp != 'undefined') {
grp.listen(groupaddr, function(object, state) {
var value = object.value;
var enabled = grp.getvalue('1/1/1');
if (state == 'value' && value == 1 && enabled) {
Play_Audio(url);
}
}, true);
}
}
Posts: 2
Threads: 0
Joined: Dec 2020
Reputation:
0
Hello Erwin,
I am working on an android based system and am having some trouble with where the audio files go.
If I place them in e.g. /user/audio1.mp3 (where /user/ is the absolute path, ie. a subfolder of the filesystem root folder) per your code below, then that is the wrong location.
Therefor it looks like /user/ should be a interpreted as being a relative path, ie. a sub-folder of some other folder.
But which one? What do you mean by the "Apps FTP user folder"? How do I modify the path to point to an absolute path within the filesystem's root folder?
Many thanks!
Quote:Hi,
You could use this custom JS for that: (note that iOS devices needs to be touch once before audio works, Apple crazy policy)
Note that the audio files are uploaded in the Apps FTP user folder, otherwise you have to adjust the path.
Code: (....)
$(function(){
// Table with parameters
var AudioTable = [
{ address:"32/2/0", url:"/user/audio1.mp3"},
{ address:"32/2/1", url:"/user/audio2.mp3" },
{ address:"32/2/2", url:"/user/audio3.mp3" },
];
(....)
Posts: 7758
Threads: 42
Joined: Jun 2015
Reputation:
447
Enable FTP and use apps login. There you will see user directory where files that can be accessed from HTTP /user/ path should be placed.
Posts: 2
Threads: 0
Joined: Dec 2020
Reputation:
0
(07.12.2020, 13:08)admin Wrote: Enable FTP and use apps login. There you will see user directory where files that can be accessed from HTTP /user/ path should be placed.
Thanks, admin! This clarified sufficiently to solve the problem. For the benefit of any future visitors to this post:
The file /user/audio1.mp3 should be under the home ftp folder of user 'apps' (on the visualisation server). In my case, the first FTP client I used did not show the contents of my home ftp folder. But the second client which I tried (due to a hunch) did.
Posts: 270
Threads: 72
Joined: May 2017
Reputation:
0
17.12.2020, 11:41
(This post was last modified: 17.12.2020, 11:42 by gdimaria.)
(27.03.2018, 18:01)Erwin van der Zwart Wrote: Hi,
You could use this custom JS for that: (note that iOS devices needs to be touch once before audio works, Apple crazy policy)
Note that the audio files are uploaded in the Apps FTP user folder, otherwise you have to adjust the path.
Code: // Closing current script section to add elements
</script>
<audio id="SE_Audio" style="display: none;"></audio>
<script type="text/javascript"> // Starting new script section after adding elements
$(function(){
// Table with parameters
var AudioTable = [
{ address:"32/2/0", url:"/user/audio1.mp3"},
{ address:"32/2/1", url:"/user/audio2.mp3" },
{ address:"32/2/2", url:"/user/audio3.mp3" },
];
var ctx = new(window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.oAudioContext || window.msAudioContext), request = new XMLHttpRequest();
var snd = document.getElementById("SE_Audio");
function getMobileOperatingSystem() {
var userAgent = navigator.userAgent || navigator.vendor || window.opera;
//console.log(userAgent)
if (userAgent.match(/iPad/i) || userAgent.match(/iPhone/i) || userAgent.match(/iPod/i)) {
return 'iOS';
} else if ( userAgent.match(/Android/i)) {
return 'Android';
} else if ( userAgent.match(/iKonWebTouch/i)) {
return 'U.Motion';
} else {
return 'PC';
}
}
var OS_Version = getMobileOperatingSystem();
// Fix iOS Audio Context
(function() {
var fixAudioContext = function (e) {
if (ctx) {
// Create empty buffer
var buffer = ctx.createBuffer(1, 1, 22050);
var source = ctx.createBufferSource();
source.buffer = buffer;
// Connect to output
source.connect(ctx.destination);
// Play sound
if (source.start) {
source.start(0);
} else if (source.play) {
source.play(0);
} else if (source.noteOn) {
source.noteOn(0);
}
}
// Check if document is loaded in iframe
if (window.frameElement){
// Remove event listeners from parent
var thisparent = window.parent;
thisparent.document.removeEventListener('touchstart', fixAudioContext);
thisparent.document.removeEventListener('touchend', fixAudioContext);
}
// Remove events
document.removeEventListener('touchstart', fixAudioContext);
document.removeEventListener('touchend', fixAudioContext);
};
// Check if document is loaded in iframe
if (window.frameElement){
// Add event listeners to parent
var thisparent = window.parent;
// Event listener for iOS 6-8 (was previous touchstart event)
thisparent.document.addEventListener('touchstart', fixAudioContext);
// Event listener for iOS 9+ (is now touchend event)
thisparent.document.addEventListener('touchend', fixAudioContext);
}
// Event listener for iOS 6-8 (was previous touchstart event)
document.addEventListener('touchstart', fixAudioContext);
// Event listener for iOS 9+ (is now touchend event)
document.addEventListener('touchend', fixAudioContext);
})();
// Function to play audio by URL
function Play_Audio(url){
//console.log(OS_Version)
if (OS_Version === 'Android' || OS_Version === 'U.Motion' ){
//alert(OS_Version);
snd.src = url;
snd.pause();
sndcurrentTime = 0;
//snd.load();
snd.play();
} else {
request.open("GET", url, true);
request.responseType = "arraybuffer";
request.onload = function(){
ctx.decodeAudioData(request.response, onDecoded);
}
function onDecoded(buffer){
var bufferSource = ctx.createBufferSource();
bufferSource.buffer = buffer;
bufferSource.connect(ctx.destination);
bufferSource.start();
}
request.send();
}
};
// Function to create event listeners
function CreateListeners(groupaddr,url){
// Make event listener to object
if (typeof grp != 'undefined') {
grp.listen(groupaddr, function(object, state) {
var value = object.value;
if (state == 'value') {
if (value == 1) {
Play_Audio(url);
}
}
}, true);
}
}
// Start creating listeners
for (var i in AudioTable) {
CreateListeners(AudioTable[i].address,AudioTable[i].url);
}
});
BR,
Erwin
PS: Not complex at all (:
is there a simple way to adapt it to make a sound for every alert, regardless the object address?
Posts: 7758
Threads: 42
Joined: Jun 2015
Reputation:
447
You can override the built-in alert function:
Code: // Start creating listeners
for (var i in AudioTable) {
CreateListeners(AudioTable[i].address,AudioTable[i].url);
}
var alertfn = alert;
alert = function(text) {
Play_Audio("/user/audio1.mp3");
alertfn(text);
};
});
Posts: 270
Threads: 72
Joined: May 2017
Reputation:
0
(17.12.2020, 11:46)admin Wrote: You can override the built-in alert function:
Code: // Start creating listeners
for (var i in AudioTable) {
CreateListeners(AudioTable[i].address,AudioTable[i].url);
}
var alertfn = alert;
alert = function(text) {
Play_Audio("/user/audio1.mp3");
alertfn(text);
};
});
I can get no sound when an alert occours.... anyway I think would be more useful to use with tagged objects... is it possible?
Posts: 7758
Threads: 42
Joined: Jun 2015
Reputation:
447
You can use grp.taglisten(tag_name, callback_function, all_events) instead of grp.listen(group_address, callback_function, all_events) for this
Posts: 270
Threads: 72
Joined: May 2017
Reputation:
0
Code: // alert sound
// Closing current script section to add elements
</script>
<audio id="SE_Audio" style="display: none;"></audio>
<script type="text/javascript"> // Starting new script section after adding elements
$(function(){
// Table with parameters
var AudioTable = [
{ address:"32/2/12", url:"/scada/resources/img/beep.mp3"},
// { address:"32/2/1", url:"/user/audio2.mp3" },
//{ address:"32/2/2", url:"/user/audio3.mp3" },
];
var ctx = new(window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.oAudioContext || window.msAudioContext), request = new XMLHttpRequest();
var snd = document.getElementById("SE_Audio");
function getMobileOperatingSystem() {
var userAgent = navigator.userAgent || navigator.vendor || window.opera;
//console.log(userAgent)
if (userAgent.match(/iPad/i) || userAgent.match(/iPhone/i) || userAgent.match(/iPod/i)) {
return 'iOS';
} else if ( userAgent.match(/Android/i)) {
return 'Android';
} else if ( userAgent.match(/iKonWebTouch/i)) {
return 'U.Motion';
} else {
return 'PC';
}
}
var OS_Version = getMobileOperatingSystem();
// Fix iOS Audio Context
(function() {
var fixAudioContext = function (e) {
if (ctx) {
// Create empty buffer
var buffer = ctx.createBuffer(1, 1, 22050);
var source = ctx.createBufferSource();
source.buffer = buffer;
// Connect to output
source.connect(ctx.destination);
// Play sound
if (source.start) {
source.start(0);
} else if (source.play) {
source.play(0);
} else if (source.noteOn) {
source.noteOn(0);
}
}
// Check if document is loaded in iframe
if (window.frameElement){
// Remove event listeners from parent
var thisparent = window.parent;
thisparent.document.removeEventListener('touchstart', fixAudioContext);
thisparent.document.removeEventListener('touchend', fixAudioContext);
}
// Remove events
document.removeEventListener('touchstart', fixAudioContext);
document.removeEventListener('touchend', fixAudioContext);
};
// Check if document is loaded in iframe
if (window.frameElement){
// Add event listeners to parent
var thisparent = window.parent;
// Event listener for iOS 6-8 (was previous touchstart event)
thisparent.document.addEventListener('touchstart', fixAudioContext);
// Event listener for iOS 9+ (is now touchend event)
thisparent.document.addEventListener('touchend', fixAudioContext);
}
// Event listener for iOS 6-8 (was previous touchstart event)
document.addEventListener('touchstart', fixAudioContext);
// Event listener for iOS 9+ (is now touchend event)
document.addEventListener('touchend', fixAudioContext);
})();
// Function to play audio by URL
function Play_Audio(url){
//console.log(OS_Version)
if (OS_Version === 'Android' || OS_Version === 'U.Motion' ){
//alert(OS_Version);
snd.src = url;
snd.pause();
sndcurrentTime = 0;
//snd.load();
snd.play();
} else {
request.open("GET", url, true);
request.responseType = "arraybuffer";
request.onload = function(){
ctx.decodeAudioData(request.response, onDecoded);
}
function onDecoded(buffer){
var bufferSource = ctx.createBufferSource();
bufferSource.buffer = buffer;
bufferSource.connect(ctx.destination);
bufferSource.start();
}
request.send();
}
};
// Function to create event listeners
function CreateListeners(groupaddr,url){
// Make event listener to object
if (typeof grp != 'undefined') {
grp.listen(groupaddr, function(object, state) {
var value = object.value;
var enabled = grp.getvalue('32/2/1');
if (state == 'value' && value == 1 && enabled) {
Play_Audio(url);
}
}, true);
}
// Start creating listeners
for (var i in AudioTable) {
CreateListeners(AudioTable[i].address,AudioTable[i].url);
}
});
That's my Custom JS.... I loaded beep.mp3 file in /scada/resources/img/ (I guess it's ok?) and set '32/2/1' as enable/disable alarm sound. Then I try to put on and off the object '32/2/12' from visualization on my Windows 10 PC, but I can get no sound.
what's wrong? Thanks
Peppe
Posts: 7758
Threads: 42
Joined: Jun 2015
Reputation:
447
You are missing a closing } for the CreateListeners function. It should be like this:
Code: // Function to create event listeners
function CreateListeners(groupaddr,url){
// Make event listener to object
if (typeof grp != 'undefined') {
grp.listen(groupaddr, function(object, state) {
var value = object.value;
var enabled = grp.getvalue('32/2/1');
if (state == 'value' && value == 1 && enabled) {
Play_Audio(url);
}
}, true);
}
} // missing closing "}"
// Start creating listeners
for (var i in AudioTable) {
CreateListeners(AudioTable[i].address,AudioTable[i].url);
}
Next time if Custom JS is not working check browser console (F12) for any error messages.
Posts: 270
Threads: 72
Joined: May 2017
Reputation:
0
(23.12.2020, 06:54)admin Wrote: You are missing a closing } for the CreateListeners function. It should be like this:
Code: // Function to create event listeners
function CreateListeners(groupaddr,url){
// Make event listener to object
if (typeof grp != 'undefined') {
grp.listen(groupaddr, function(object, state) {
var value = object.value;
var enabled = grp.getvalue('32/2/1');
if (state == 'value' && value == 1 && enabled) {
Play_Audio(url);
}
}, true);
}
} // missing closing "}"
// Start creating listeners
for (var i in AudioTable) {
CreateListeners(AudioTable[i].address,AudioTable[i].url);
}
Next time if Custom JS is not working check browser console (F12) for any error messages.
ok, thank you. Now it's working!
Another request, be patient : I would repeat the play of the beep until the condition change. I tried with a while - do loop, but it seems I make something wrong....
Posts: 7758
Threads: 42
Joined: Jun 2015
Reputation:
447
This should do what you want. You can change the interval (it is 2000 milliseconds now) if needed.
Code: var interval;
// Function to play audio by URL
function Play_Audio(url){
//console.log(OS_Version)
if (OS_Version === 'Android' || OS_Version === 'U.Motion' ){
//alert(OS_Version);
snd.src = url;
snd.pause();
sndcurrentTime = 0;
//snd.load();
snd.play();
} else {
request.open("GET", url, true);
request.responseType = "arraybuffer";
request.onload = function(){
ctx.decodeAudioData(request.response, onDecoded);
}
function onDecoded(buffer){
var bufferSource = ctx.createBufferSource();
bufferSource.buffer = buffer;
bufferSource.connect(ctx.destination);
bufferSource.start();
}
request.send();
}
};
// Function to create event listeners
function CreateListeners(groupaddr,url){
// Make event listener to object
if (typeof grp != 'undefined') {
grp.listen(groupaddr, function(object, state) {
var value = object.value;
var enabled = grp.getvalue('32/2/1');
clearInterval(interval);
if (state == 'value' && value == 1 && enabled) {
Play_Audio(url);
interval = setInterval(function() {
Play_Audio(url);
}, 2000);
}
}, true);
}
}
// Start creating listeners
for (var i in AudioTable) {
CreateListeners(AudioTable[i].address,AudioTable[i].url);
}
});
|