How to get real time notification with sound using laravel pusher? - javascript

I want to get real-time notifications with sound when an order is placed into my app. I'm using laravel 8 and pusher to that. I get real-time alerts but the sound does not work perfectly. When an order is placed first time sound does not play, after that sound is played perfectly. Here is my code structure ...
My event class
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class MyEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
public function __construct($message)
{
$this->message = $message;
}
public function broadcastOn()
{
return ['my-channel'];
}
public function broadcastAs()
{
return 'my-event';
}
}
Here is the js code
Pusher.logToConsole = true;
var pusher = new Pusher('***pusher key***', {
cluster: 'ap2'
});
var channel = pusher.subscribe('my-channel');
channel.bind('my-event', function(data) {
alert(data.message)
playAudio();
});
function playAudio() {
var x = new Audio('http://127.0.0.1:8000/backend/assets/notification.mp3');
// Show loading animation.
var playPromise = x.play();
if (playPromise !== undefined) {
playPromise.then(_ => {
x.play();.
})
.catch(error => {
});
}
}
Here is my controller
public function store(){
event(new MyEvent('1 new order has been placed'));
return 'Success';
}
When I hit this route for the first time, real-time alert message is shown but the sound does not play. It shows this error
DOMException: play() failed because the user didn't interact with the document first.
https://some link
And it works perfectly after first time
I would like to give a sound notification to the admin if the order is placed, now how can I do that?

With the latest updates of browsers, it is now impossible to start a sound with the code without the user clicking a button.

Related

Object losing its prototype functions when I pass it to socket io

I am using Agora.io sdk to create a group video chat application. They provide developers with a stream object that is all encompassing of the important methods and properties required to build the app. However, when I pass it to socket io it loses its functions. How can I solve this problem. I saw some questions that ask similar questions but they don't provide an answer that has been able to help me.
Below is my code where I emit :
function UIControls (stream, streamType, streamDiv) {
console.log('inside UIControls :::', stream.streamId, stream.getId(), typeof(stream) === 'function')
// video button
var videoButton = document.createElement('button');
// videoButton.setAttribute('id', 'videoButton');
videoButton.setAttribute('id', 'video_'+String(stream.getId()));
videoButton.innerHTML = '<i class="fas fa-video"></i>';
var clicked = false;
videoButton.addEventListener('click', function(evt) {
toggleVideo(stream);
})
if (streamType === 'me') {
$('#me').append(videoButton);
} else {
$('#' + String(stream.getId())).append(videoButton);
}
function toggleVideo(stream) {
if (clicked) {
videoButton.innerHTML = '<i class="fas fa-video-slash"></i>';
socket.emit("sendPeerInfo_video", {
"type": "mute",
"id": String(stream.getId()),
});
clicked = false;
} else {
// stream.unmuteVideo();
videoButton.innerHTML = '<i class="fas fa-video"></i>';
socket.emit("sendPeerInfo_video", {
"type": "unmute",
"id": String(stream.getId()),
"stream": stream,
});
clicked = true;
}
}
}
Here is the socket.on code:
socket.on("sendPeerInfo_video", function (evt) {
if (evt.type === 'mute') {
evt.stream.muteVideo();
return $('#video_'+evt.id)[0].innerHTML = '<i class="fas fa-video-slash"></i>'
} else if (evt.type === 'unmute') {
evt.stream.unmuteVideo();
return $('#video_'+evt.id)[0].innerHTML = '<i class="fas fa-video"></i>'
}
});
I don't have access to evt.stream.muteVideo() and evt.stream.unmuteVideo() functions anymore inside socket.on
Thank you for your help!
Is there any particular reason why you are using your own sockets?
Check out this sample app which takes care of group video calls and screen sharing along with features like muting and unmuting made using the official Agora.io Documentation.
A snippet showing what you actually need to do for what features you have given an example of:
var client = AgoraRTC.createClient({mode: 'rtc', codec: 'vp8'});
var localStreams = {
uid: '',
camera: {
camId: '',
micId: '',
stream: {}
}
};
// Hide video
client.on("mute-video", function (evt) {
var remoteId = evt.uid;
localStreams.camera.stream.muteVideo();
});
// Show video
client.on("unmute-video", function (evt) {
localStreams.camera.stream.unmuteVideo();
});
// Mute audio
client.on("mute-audio", function (evt) {
var remoteId = evt.uid;
localStreams.camera.stream.muteAudio();
});
// Unmute audio
client.on("unmute-audio", function (evt) {
localStreams.camera.stream.unmuteAudio();
});
Agora automatically mutes and unmutes audio and video for everyone without you having to make your own socket for the same.
If your use case is something different though which needs you to use custom sockets, let me know in the comments.
EDIT:
To implement a hand raise feature as well as to mute or unmute someone else, you can use Agora RTM using this quick start guide or this sample app.
What RTM does is act like your personal web socket and can be used to send messages which are displayed to other users (for chatting) or even do some behind the scenes work like receiving a message of a particular type and performing an action accordingly.
If the admin wants to mute someone else, they can click on a button which triggers a RTM message to a user and automatically parse and use this message to mute him/her.
Hand raise will work in a similar way.

Can Signalr execute client side functions when the browser is minimised or running in the background?

I have got the following code which will create a notification for a user when the browser is open:
Server-side:
[HubName("notificationhub")]
public class ChatHub : Hub
{
private readonly static ConnectionMapping<string> _connections =
new ConnectionMapping<string>();
public void SendNewNotification()
{
string notification_text = "This is a test notification";
Clients.All.triggerNotification(notification_text);
}
}
Client side:
var notification_hub;
$(function () {
notification_hub = $.connection.notificationhub;
$.connection.hub.start();
notification_hub.client.triggerNotification = function (message) {
var notification = new Notification('Test notification', {
body: message,
icon: "~/content/img/favicon/favicon.ico",
vibrate: [200, 100, 200],
});
}
This works as expected when the browser is currently on screen. However, I also want this same piece of client-side code to execute if the user has minimised the browser (or running it in the background if it is a mobile device). The intended effect would be to have the 'push' notification generated for the user. At the moment, however, this is not the case.
Any suggestions on how to achieve this?

SignalR changing hub subscription

I have a simple app, which displays a list of available signalR hubs. A user selects a hub and it connects to it, this subscribes an event to add messages to a table on the page. The user can then send messaged to that hub which will also fire the subscription adding that message to the table. This all works great.
Now if the user selects another hub, the app connects and sets up a new subscription, however the original subscription still fires causing duplicate messages to be added to the table. Each time the hub is changed further subscriptions get added causing one send to result in many messages in the table.
I have tried disconnecting the hub, disposing the hub and trying to remove the subscription with hubProxy.off(eventName), but nothing seems to work, other than a page reload.
Here is the code I have just added the onHub changed function as this is where everything is happening.
Any ideas appreciated. :)
function HubViewModel() {
var self = this;
self.hubConnection = '';
self.hub = '';
$.getScript("../signalR/hubs");
self.hubs = ko.observableArray();
self.selectedHub = ko.observable();
self.messageText = ko.observable();
self.messageCollection = ko.observableArray();
self.hubChanged = function () {
// Setup hub connection.
$.connection.hub.url = "../signalR";
self.hubConnection = $.hubConnection();
// Get the selected hub name.
var selectedHubName;
_.each(self.hubs(), function(item) {
if (item.hubId == self.selectedHub()) {
selectedHubName = item.hubName;
}
});
// Check for a selected connection
if (self.selectedHub()) {
// Create proxy.
self.hub = self.hubConnection.createHubProxy(selectedHubName);
// Remove any existing listener(s).
self.hub.off('addNewMessageToPage');
// Setup listener.
self.hub.On('addNewMessageToPage', function (sender, message) {
self.messageCollection().push({ hubName: selectedHubName, name: selectedHubName, message: message, dateTime: new Date().toLocaleString() });
$('#hubMessageGrid').dxDataGrid('instance').refresh();
});
// start connection.
self.hubConnection.start()
.done(function() {
toastr.success('hub connected');
$('#sendMessageButton').click(function() {
self.hub.invoke('sendAll', 'hub management page', self.messageText());
self.messageText('');
});
})
.fail(function(error) {
toastr.error('hub connection ' + error);
});
}
};
You can to disconnect the hub first by calling the self.hub.stop(); function
You need to pass the exact same handler instance when unsubscribing. Passing a different instance (even if the function body is the same) will not remove the handler.
See https://learn.microsoft.com/en-us/javascript/api/#microsoft/signalr/hubconnection?view=signalr-js-latest#off-string---args--any-------void-

SignalR message from server to client duplicated

I am fighting a problem with SignalR in MVC application. I have created an MVC 4 project based on internet template and instaled SignalR nuget packet. Hub class looks like this:
public class yourAppHub : Hub
{
static Timer t;
public yourAppHub()
{
t = new Timer(5000);
t.Elapsed += Hello;
t.Start();
}
public void Hello(object sender, ElapsedEventArgs e)
{
Clients.All.refreshPage("hello");
}
}
And this is what I have on master page(_Layout.cshtml):
#if (Request.IsAuthenticated)
{
<script>
$(function () {
var con = $.hubConnection();
var hub = con.createHubProxy('yourAppHub');
hub.on('refreshPage', function (message) { alert(message); });
con.start(function () { hub.invoke('Hello'); });
});
</script>
}
When I am logging in I get 2 alerts every 5 seconds. Why 2 alerts? But if I go to home page, then go to contact form, then on some another page, alerts begin to continuously pop up. I can't get what I have done wrong here. I expect alert to pop up once in 5 seconds.
I have followed this wonderful tutorial http://www.dotnetcurry.com/aspnet-mvc/826/server-side-timer-aspnet-mvc-signalr . It implements singleton and starts timer not in hub but in that singleton. Now it works as expected.

Safari issue with HttpContext.User.Identity

I try to play mp3 file, which is returned by MyAudio method from ContentController, through html5 audio tag. Following code:
[Authorize]
public class ContentController : Controller
{
private ContentServices Content { get; set; }
protected override void Initialize(RequestContext requestContext)
{
if (requestContext.HttpContext.User.Identity.isAuthenticated)
{
base.Initialize(requestContext);
}
}
public ActionResult MyAudio(string name)
{
var file = Server.MapPath("~/" + name);
return File(file, "audio/mp3");
}
Common html code
When the user is Authorized all works perfect in Chrome. But when I have tested it in Safari there is a strange mystery. The HttpContext.User.Identity.isAuthenticated returns false and of course code doesn't execute further.
The interesting thing is that when I use for example #Html.Action or #Html.RouteLink, HttpContext.User.Identity.isAuthenticated will return true.
I've tried to use javascript and jquery to solve the problem, but I also had wierd things at Safari.
<script type="text/javascript">
function getAudio() {
if (audio.src == "" || audio.src == null) {
// (1) audio.src = '#Url.Content("~/Content/MyAudio")' + "hello.mp3";
// (2) audio.src = '#Url.Action("MyAudio", "Content", new { name = "hello.mp3" } )';
/* (3) $.get('#Url.Content("~/Content/MyAudio")', {"name": "hello.mp3"},
function(data) {
alert("hello");
});
*/
audio.load();
audio.play();
}
}
</script>
Both (1) and (2) have the same problem. But when I use (3), HttpContext.User.Identity.isAuthenticated returns true at Safary. But I guess u can't give file stream through jquery.
Have anyone have an idea what's is go on nad how I can fix the problem?
PS I use ASP.NET Development Server and Safari 5.1.7 Win32 7.

Categories

Resources