Twilio: I get "Participant is unavailable at the moment" in rejected call - java

I'm currently working on the implementation of Twilio Video in my Android app, where the normal behavior (and the one I need) should be:
If client A calls a client B, and client B rejects the call, client A receives (onConversation) an error (object TwilioConversationsException) containing code:107, message:Participant rejects the call..
Or if client A calls client B, and client B isn't connected to Twilio, Client A receives an error immediately with code:106, message:Participant is unavailable at the moment.. At this point I retry several times until the user connects and responds (accepting or rejecting), or 30 seconds pass after the call was initiated.
I'm working based on this, but I've encountered an issue after client B loses internet connection or the app closes unexpectedly. After reconnecting to Twilio, when client B rejects a call, client A receives an error code:106, message:Participant is unavailable at the moment. instead of code:107, message:Participant rejects the call., deceiving client A into thinking that cliente B is disconnected from Twilio (when he actually is connected), which triggers a new call try. For what I've been observing, this problem is associated to the client B identity, where somehow it remained registered as unavailable and is not letting it work properly. If I change client B identity, the behavior goes back to regular, but it's not the idea. My intention is for the identity to be my users id: unique and fixed.
In iOS is happening the same, according to this thread:
Twilio iOS Video Call: Getting "User is unavailable" error message when user rejects the call
I would appreciated some help! Best regards!

A co-worker asked Twilio support and was told this:
Hey Deneb,
These workflows have some challenges with the current Conversations
API in Programmable Video, and we're working on solving them in an
upcoming addition to the product: A new Rooms API. Rooms will allow
your users to connect to named Room (a multi-party conference call) by
a name that you define, or by its unique ID (RoomSid). Using this API,
you won't have to worry about if/when your endpoints are online--you
can just have your users connect to the proper Room and they'll be
able to share voice and video with one another.
The Rooms API will be rolling out in just a few weeks, and I think
it'll be a much better fit for your use case. If you're in need of a
solution more urgently, I'd recommend using a third-party
notifications product, like Firebase or PubNub, to make sure that both
participants are "awake" and connected, then initiating the invite
flow.
Let me know if you have any questions on this. Thanks for trying
Programmable Video,
Regards, Rob Brazier

Related

How check my device is connected (IOTCore - GCP) [duplicate]

Does anybody know of an easy way to trigger an event when a device on Google Core IoT goes offline? Before I switched to Google's IoT implementation, this was very easily handled by triggering an event when MQTT disconnects, but it seems Google has no easy way of doing this.
Does anybody know if there is something planned for this?
Who's back do I need to scratch to get them to see that something like this is a basic requirement for IoT device management!
Other platforms like AWS and Microsoft already have this implemented (or some way to handle it easily):
https://docs.aws.amazon.com/iot/latest/developerguide/life-cycle-events.html
Device connectivity(online/offline)status with the Auzure iot hub
I wish I had known this before writing all my code and implementing my setup using Google's IoT platform, I guess that's my fault for assuming something so simple and that should be standard for IoT devices would be available.
How are you going to compete with other IoT providers if you can't even provide basic offline/online events?!
My reply in this SO question shows how I had to write 100+ lines of code just to create a firebase function to check if a device is online (but that still doesn't handle offline events, and is just a hack for something that should be native to ANY IoT service provider!):
https://stackoverflow.com/a/54609628/378506
I'm hoping someone else has figured out a way to do this, as i've spent numerous days searching SO, Google, Google Core IoT Documentation, and still have not found anything.
Even if MQTT Last Will was supported we could make that work, but even that IS NOT SUPPORTED by Google (https://cloud.google.com/iot/docs/requirements) ... come on guys!
Your cloud project does have access to the individual MQTT connect/disconnect events, but currently they only show up in the Stackdriver logs. Within the cloud console, you can create an exporter that will publish these events to a Pub/Sub topic:
Visit the Stackdriver Logs in the
Cloud Console.
Enter the following advanced filter:
resource.type="cloudiot_device"
jsonPayload.eventType="DISCONNECT" OR "CONNECT"
Click CREATE EXPORT
Enter a value for Sink Name
Select Cloud Pub/Sub for Sink Service
Create a new Cloud Pub/Sub topic as the Sink Destination
The exporter publishes the full LogEntry, which you can then consume from a cloud function subscribed to the same Pub/Sub topic:
export const checkDeviceOnline = functions.pubsub.topic('online-state').onPublish(async (message) => {
const logEntry = JSON.parse(Buffer.from(message.data, 'base64').toString());
const deviceId = logEntry.labels.device_id;
let online;
switch (logEntry.jsonPayload.eventType) {
case 'CONNECT':
online = true;
break;
case 'DISCONNECT':
online = false;
break;
default:
throw new Error('Invalid message type');
}
// ...write updated state to Firebase...
});
Note that in cases of connectivity loss, the time lag between the device being unreachable and an actual DISCONNECT event could be as long the MQTT keep-alive interval. If you need an immediate check on whether a device is reachable, you can send a command to that device.
The best solution i think is that
We need 3 things
cloud sheduler ,
and 2 cloud functions
The first function will be the #devunwired answer but instant of
// ...write updated state to Firebase... schedule a second function to trigger in 2-3 min (let device to recconect)
the seccond function will send a command to device
if the device resposne to command
if stored status is connected dont do nothing
else if the stored status is disconnected then update the status to connected and do what ever you want maybe email
else
if stored status is disconnected dont do nothing
if stored status is connected change the status alert by email or something

How to handle SSL encrypted alert in Netty

I've created server (10.32.240.50) with SslHandler. Client (10.32.240.5) connects to server and everything works fine. After some time client disconects with no reason. I've took tcp dump and saw there ncrypted alert right before disconect:
I have no idea what client send me in this alert - it's encrypted. What could be the cause of this alert and why it leads to disconect? Is there any way to trace this events with netty?
At this stage it is difficult to see if your question is really related to programming, and hence ontopic here or not.
A TLS 1.2 alert can be many things, see https://www.rfc-editor.org/rfc/rfc5246#section-7.2 which gives you the whole list:
enum { warning(1), fatal(2), (255) } AlertLevel;
enum {
close_notify(0),
unexpected_message(10),
bad_record_mac(20),
decryption_failed_RESERVED(21),
record_overflow(22),
decompression_failure(30),
handshake_failure(40),
no_certificate_RESERVED(41),
bad_certificate(42),
unsupported_certificate(43),
certificate_revoked(44),
certificate_expired(45),
certificate_unknown(46),
illegal_parameter(47),
unknown_ca(48),
access_denied(49),
decode_error(50),
decrypt_error(51),
export_restriction_RESERVED(60),
protocol_version(70),
insufficient_security(71),
internal_error(80),
user_canceled(90),
no_renegotiation(100),
unsupported_extension(110),
(255)
} AlertDescription;
struct {
AlertLevel level;
AlertDescription description;
} Alert;
Of course it is encrypted so if you really wanted to see it, you need to:
change the client so that it outputs the master secret and client random when doing the connection that triggers this error
record the relevant connection with wireshark
and then you will be able, inside wireshark, with the items in first point, to decrypt it (you can find numerous tutorials on how to do that)
From experience, if the alert happens after some application data the most probable case is "close_notify". It is a "normal" case it just means that the server decides to shutdown the TLS socket (but not necessarily the TCP one) and hence warns (alerts) the other party about it.
If it is this case, then it is expected for the other party to send the same alert, and then the connection is shut down at the TCP level with FIN. So the chain of observations you have is expected. The only reason remaining is about the initial alert.
After clarification, since the first alert comes from .5 which is the client, and not the server, it means the client that you do not control has decided to shutdown the TLS stream, for reasons only known by it
(if we still guess correctly that the alert is "close_notify" which is still only a guess that can be tested only if you decrypt the exchange per the instructions above, or maybe increase server verbosity, like this idea given by #dave_thompson_085 in comment: "If you set sysprop javax.net.debug=ssl it will trace all JSSE (SSL/TLS) operations, which includes the received alert. ")
Other than that, except asking the client operator/developer I see no way to understand why the client decided not to talk to you anymore. It also depends on the underlying application data exchanged, maybe it was indeed the end of the transmission and the client does not need the TLS stream anymore?

Android/Firebase - Check to see if you are subscribed to topic

I am wondering if there is a way to test to see if you are subscribed to a topic on the android side of things.
Basically, I am HOPING that all devices will subscribe to a topic during their installation, when the token is first obtained by the device. However, there is always a chance that the device fails to subscribe. The FCM registration token should be installed on the device for a long time, and thus, the onTokenRefresh() method shouldn't be called again without clearing data, uninstall/reinstall, etc.
My idea was to test to see if the device is subscribed to a topic in my MainActivity, and if not, then try to subscribe again. If it fails to subscribe, then get a new token and try again, etc.
#Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.e(TAG, "Refreshed token: " + refreshedToken);
// Subscribe to a topic
Log.e(TAG, "Subscribing to topic");
FirebaseMessaging.getInstance().subscribeToTopic("test");
So, I can subscribe and unsubscribe, but how do I check if the device is subscribed to a topic? I did my fair share of googling, and couldn't find anything, unfortunately.
I would greatly appreciate any/all assistance. Thanks!
There is currently no way to check on the client side if they are subscribed to a topic.
The behavior for subscribeToTopic is it would immediately subscribe to the specified topic, if it fails, it would retry on it's own (unless your app was killed). See my answer here.
I think that forcing the onTokenRefresh call just to make sure that subscribeToTopic is too much. You could simply just call it in your initial activity if you want, that way, everytime the app starts, it sends the subscription request.
Actually this can be done by using this api: https://developers.google.com/instance-id/reference/server#get_information_about_app_instances
As IID_TOKEN you need the FCM token and in the header you have to pass Authentication: key=YOUR_SERVER_KEY. You can find the server key as described here: Firebase messaging, where to get Server Key?.
Don't forget to include details=true as query parameter in the url, otherwise the topics won't be included in the response.
I would recommend writing a Cloud Function to encapsulate it, so you don't deploy your server key to the client.

Basic authenticator with Netty

Actually for my server game I'm not using Netty. I've created a socket multithreaded system for send packet object who is serialized into and deserialized from (Int and Out)StreamBuffer.
I've discovered Netty and I think it's better to use it for my network system.
I've actually created a Client and Server handler (both extends ChannelInboundHandlerAdapter) to serialized and deserialized my packet from the ByteBuf, it's work FINE :) !
Now I want migrate my authentication system.
Actually, I've two Handler, the LoginHandler which can receive and process only the Login Packet (defined by an id when I send a buffer packet), and the ServerHandler which can receive and process all others packets.
Actual algorithme
Client side :
User launch a client a new window ask him to enter his username and password When he click on "Login", the client connect to the server, and after send a LoginPacket.
If a AuthServerPacket is sent by the server with the auth flag to true, he continue and open all others features.
If a AuthServerPacket is sent by the server with the auth flag to false, it display a popup with the reason, and re-open the window login.
Server side :
When a user is connecting to the server it's the LoginHandler which is attached to the client.
In this LoginHandler, only LoginPacket is processed, so, when it receive a LoginPacket it check the informations in a database, if these are correct, the client are added to the ServerHandler and deleted from the LoginHandler, and now he can receive and send all others packets.
ServerHandler send a AuthServerPacket with auth flag to true.
My question is, what is the best way to re-create this system with Netty ?
I don't know if I can add the login handler in the pipeline which it will be not check it if a channel is authentified. I don't know how or if the process is stopped if one of the handler reject the channel.
Someone can help me to understand what is the best way to do what I want with Netty ?
Thanks you in advance for your answers.
Programmatically, beaucoralk.
we talked on IRC #netty today :)
My suggestion is:
In your Pipeline Initializer, always add the LoginHandler
Once Login is successful, then the LoginHandler should:
ctx.pipeline.addAfter(this, "gameHandler", new GameLogicHandler());
ctx.pipeline.remove(this);
So basically your LoginHandler removes itself, after a successful authentication. Important: add the new Handler before removing the old Handler. :)
best regards
I've solved my problem with this :
In my Pipeline Initialize always add the LoginHandler (don't add my ServerHandler)
Once Login is successful, then the LoginHandler do :
ctx.pipeline.addLast(new GameLogicServerHandler());
ctx.pipeline.remove(this);
In fact I have not succeeded to use the addAfter like said Franz Bettag, no method was appropriate.
But thanks you to Bettag who help me to understand many things on #netty IRC.

Spring Java WebSockets Messaging between users

This is question about websockets and architecture of messaging between users. What i've done:
Client side:
Send message to server with parameter - conversation uuid. And also i subscribed to topic where new messages must be appeared.
Server side:
When i receive message with conversation uuid, i launch scheduler which sends new messages for conversation to topic.
But there alot of conversation could be, so i my controller class i got field of class "conversationSchedulers" - it is HashMap where key is a username and value is current scheduler which sends new messages for conversation. When user wants to recieve new messages for other conversation, he click on conversation in web application and next code works:
Cliend side:
Send messages with new conversation uuid.
Server side:
Gain previous running scheduler - if it is - cancel it, and run new scheduler with new conversation uuid.
And everything is works... when there are ONE tab with messages. When user open two or more tabs - all architecture gone to the hell. Because i accept only one scheduler for messaging... only one conversation could be opened.
In that moment i got an idea - accept many schedulers to messaging with more than one user at the same time, but i did not do this implementation because on messaging page i have got a button to write a NEW message, when user want to write new message all new messages from other users must stop to sends to client, but i can not stop them because user got a two tabs. Stop all schedulers that means stop messaging on all tabs. And this is a problem. May be i choose wrong architecture? Or websockets it is a bad idea for such task?

Categories