Has anyone been able to add custom commands in the ChromeCast API? I was successful in getting the TicTacToe example working with my developer ID as well as modified Protocol string (changed on both the client and server).
On the Android side, I have the existing "join" command which works, and I am adding a new "image" command:
public final void join(String name) {
try {
Log.d(TAG, "join: " + name);
JSONObject payload = new JSONObject();
payload.put(KEY_COMMAND, KEY_JOIN);
payload.put(KEY_NAME, name);
sendMessage(payload);
} catch (JSONException e) {
Log.e(TAG, "Cannot create object to join a game", e);
} catch (IOException e) {
Log.e(TAG, "Unable to send a join message", e);
} catch (IllegalStateException e) {
Log.e(TAG, "Message Stream is not attached", e);
}
}
public final void sendImage(String sURL) {
try {
Log.d(TAG, "sendImage");
JSONObject payload = new JSONObject();
payload.put(KEY_COMMAND, KEY_IMAGE);
payload.put(KEY_URL, sURL);
sendMessage(payload);
} catch (JSONException e) {
Log.e(TAG, "Cannot create object to send image", e);
} catch (IOException e) {
Log.e(TAG, "Unable to send an image message", e);
} catch (IllegalStateException e) {
Log.e(TAG, "Message Stream is not attached", e);
}
}
If I call the join command, it works fine and I can see the message logged through the console in the browser. But if I call the sendImage function, I get the following error:
"onEnded failed to connect channel: protocol error"
On the ChromeCast side, I can see when a valid command is received. This function is getting called when I send the join command, but not when I send my custom "image" command.
/**
* Message received event; determines event message and command, and
* choose function to call based on them.
* #param {event} event the event to be processed.
*/
onMessage: function(event) {
console.log('***== pre onMessage ==***');
var message = event.message;
var channel = event.target;
console.log('********onMessage********' + JSON.stringify(message));
console.log('mPlayer1: ' + this.mPlayer1);
console.log('mPlayer2: ' + this.mPlayer2);
if (message.command == 'join') {
this.onJoin(channel, message);
} else if (message.command == 'leave') {
this.onLeave(channel);
} else if (message.command == 'move') {
this.onMove(channel, message);
} else if (message.command == 'queue_layout_request') {
this.onQueueLayoutRequest(channel);
} else if (message.command == 'image') {
this.onImage(channel, message);
} else if (message.command == 'video') {
this.onVideo(channel, message);
} else if (message.command == 'song') {
this.onSong(channel, message);
} else {
cast.log.error('Invalid message command: ' + message.command);
}
},
Any ideas? Is there somewhere else where I need to define my custom commands?
EDITED: also showing the onImage prototype:
/**
* Image event: display an image
* #param {cast.receiver.channel} channel the source of the move, which
* determines the player.
* #param {Object|string} message contains the URL of the image
*/
onImage: function(channel, message) {
console.log('****onImage: ' + JSON.stringify(message));
//Hide video and show image
mVideo.style.visibility='hidden';
mImage.style.visibility='visible';
mImage.src = message.url;
},
That usually means there was a JavaScript error in your receiver. Open Chrome on port 9222 at the IP address of your ChromeCast device and use the Chrome developer tools to debug the issue.
Did you declare a new function "onImage" in your receiver prototype for the message handler?
Related
I'm using Sharp.Xmpp to receive upstream messages from Android Device via FCM. It connects fine and 'at times' I can receive the messages sent from Android on my app server but the ratio is 50% whereas Android device gives a successful onMessageSent event.
The server side code is:
try {
using (var cl = new XmppClient("fcm-xmpp.googleapis.com", "Username", "Password", 5236, Sharp.Xmpp.Core.TLSMode.TLSSocket)) {
// Setup any event handlers before connecting.
cl.Message += OnNewMessage;
// Connect and authenticate with the server.
cl.Connect();
SendPushNotification("Connected");
cl.Close(); }
}
catch (InvalidOperationException ex) { SendPushNotification("Error Invalid: " + ex); }
catch (IOException ex) { SendPushNotification("Error IO: " + ex); }
catch (XmppException ex) { SendPushNotification("Error XMPP: " + ex); }
catch (NullReferenceException ex) { SendPushNotification("Error Null: " + ex); }
New Message Received event is
private void OnNewMessage(object sender, Sharp.Xmpp.Im.MessageEventArgs e) {
SendPushNotification("Message from " + e.Jid + " " + e.Message.Body);
div_View_Message.InnerHtml = "Message xyz " + e.Message.Body.ToString();
//throw new NotImplementedException();
}
and the SendPushNotification(String str) is Downstream messages with HTTP protocol. Android Device receives a push notification of 'connected' fine but the 'e.Message.Body' is received at times and not others. What should be added/removed?
Android Sends the messages as
FirebaseMessaging.getInstance().send(new RemoteMessage.Builder("SENDER_ID#gcm.googleapis.com")
.setMessageId(Integer.toString(INT_VALUE)).addData("my_token", str).build());
As mentioned in the accepted answer to this question, XMPP must stay open at all times. Hence, switching for Web based application, that closes the connection after every few requests per second, to a Desktop application, hosted on a local server, solved the issue.
Also, it adding setTtl(86400); for message sending ensures onMessageSent call.
Im trying use use an AMQP message queue in one of my Android applications. I tested the code first in a java application and have no issues but when I put the same code into an Android app no error is thrown but the AMQP channel closes unexpectedly after the first message is received. I tried adding a shutdown listener to the channel but it didnt return anything. Can someone help me figure out why the Rabbitmq channel is closing?
// ------------------------------------------------------------------------
// Function to make AMQP connection and subscribe
// ------------------------------------------------------------------------
int connAmqp()
{
factory = new ConnectionFactory();
factory.setHost(PI_AMQP_BROKER_URL);
factory.setUsername(AMQP_BROKER_USERNAME);
factory.setPassword(AMQP_BROKER_PASSWORD);
factory.setPort(AMQP_BROKER_PORT);
connection=null;
connectionStatus = AMQP_CONNECTING;
try {
connection = factory.newConnection();
Log.i("log_amqp_conn","Successfully connected to AMQP broker");
connectionStatus = AMQP_CONNECTED;
channel = connection.createChannel();
channel.addShutdownListener(new ShutdownListener() {
#Override
public void shutdownCompleted(ShutdownSignalException cause) {
Log.w("log_amqp_shutdown",cause.getCause().toString());
}
});
channel.exchangeDeclare(AMQP_EXCHANGE_NAME, "topic");
Log.i("log_amqp_conn","Successfully connected to Exchange: " + AMQP_EXCHANGE_NAME);
channel.queueDeclare(RX_QUEUE_NAME, false, false, false, null);
String queueBind = RX_BINDING;
Log.i("log_amqp_conn","Successfully declared queue: " + RX_QUEUE_NAME);
channel.queueBind(RX_QUEUE_NAME, AMQP_EXCHANGE_NAME, queueBind);
Log.i("log_amqp_conn","Successfully binding to: " + queueBind);
} catch (TimeoutException e) {
Log.i("log_amqp_conn","Connection timeount - Failed to connect to AMQP broker");
Log.i("log_amqp_conn",e.toString());
connectionStatus = AMQP_NOTCONNECTED_TIMEOUT;
} catch (IOException e) {
Log.i("log_amqp_conn","Failed to connect to AMQP broker");
Log.i("log_amqp_conn",e.toString());
connectionStatus = AMQP_NOTCONNECTED_UNKNOWNREASON;
}catch (Exception e) {
Log.i("log_amqp_conn","Failed to connect to AMQP broker");
Log.i("log_amqp_conn",e.toString());
connectionStatus = AMQP_NOTCONNECTED_UNKNOWNREASON;
}
Log.i("log_amqp_conn"," [*] Waiting for messages.");
consumer = new DefaultConsumer(channel) {
#Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
throws IOException {
Log.i("log_amqp_conn", "handleDelivery() called");
String message = new String(body, "UTF-8");
Log.i("log_amqp_conn"," [Rx] Received: " + message);
//DO SOME WORK HERE
}
};
try {
Log.i("log_amqp_conn", "basicConsume() called");
channel.basicConsume(RX_QUEUE_NAME, true, consumer);
} catch (IOException e) {
Log.e("log_amqp_consume",e.toString());
}
return 0;
}
After spending much time looking in the wrong places I found that the channel was closing due to an unhandled exception in the handleDelivery() function in the "//DO SOME WORK HERE" code. Turns out that if this method errors out that the AMQP channel will close. Thanks.
I have built a chat application using an Openfire (xmpp) server. One-to-one person chats are working fine and the messages are delivered instantly. But when we send a message inside a group, the first message gets delayed and the second message is delivered instantly.
MultiUserChatManager groupChat =
MultiUserChatManager.getInstanceFor(connection).getMultiUserChat("group_name");
groupChat.send("Message object");
Why is the first message getting delayed?
MUC Creation is
MultiUserChatManager mchatManager = MultiUserChatManager.getInstanceFor(xmpptcpConnection);
MultiUserChat mchat = mchatManager.getMultiUserChat(group);
if (!mchat.isJoined()) {
Log.d("CONNECT", "Joining room !! " + group + " and username " + username);
boolean createNow = false;
try {
mchat.createOrJoin(username);
createNow = true;
} catch (Exception e) {
Log.d("CONNECT", "Error while creating the room " + group + e.getMessage());
}
if (createNow) {
Form form = mchat.getConfigurationForm();
Form submitForm = form.createAnswerForm();
List<FormField> formFieldList = submitForm.getFields();
for (FormField formField : formFieldList) {
if(!FormField.Type.hidden.equals(formField.getType()) && formField.getVariable() != null) {
submitForm.setDefaultAnswer(formField.getVariable());
}
}
submitForm.setAnswer("muc#roomconfig_persistentroom", true);
submitForm.setAnswer("muc#roomconfig_publicroom", true);
mchat.sendConfigurationForm(submitForm);
//mchat.sendConfigurationForm(
// new Form(DataForm.Type.submit)); //this is to create the room immediately after join.
}
}
Log.d("CONNECT", "Room created!!");
return true;
} catch (SmackException e) {
e.printStackTrace();
} catch (XMPPException.XMPPErrorException e) {
e.printStackTrace();
}
There's an issue about creation and a kind of side-effect propagated on sending.
I think simply that you need to join the chat the first time since you didn't before and the first message also activate the Groupchat on server, so the first message it's delayed because you didn't finalized the multiuserchat creation.
How to fix.
In creation phase, this part must be improved:
if (!mchat.isJoined()) {
Log.d("CONNECT", "Joining room !! " + group + " and username " + username);
boolean createNow = false;
try {
mchat.createOrJoin(username);
createNow = true;
} catch (Exception e) {
Log.d("CONNECT", "Error while creating the room " + group + e.getMessage());
}
With just:
boolean createNow
try
{
if (!mchat.isJoined())
{
createNow = mchat.createOrJoin(username);
}
}
catch (Exception e)
{
throw new Exception("ERROR!");
}
and after this invokation:
mchat.sendConfigurationForm(submitForm);
add:
if (!mchat.isJoined()) {
mchat.join(username);
}
creationOrJoin method it's about creation OR join (as name says): to activate the chat, you must join it after the creation phase.
However createOrJoin has maybe an unexpected behaviour due a double check about already joined rooms to keep syncro between session in client and session on server, so the mchat.join() must be invoked after.
An explicit name can sounds like: mustCreateBeforeOrCanJoinDirectly()
I am trying to get the details of no.of messages, no.of deleted messages and no.of total messages using javamail api in android. But i am always getting -1 for no.of deleted messages. I couldn't find what is the reason/bug is so please help me with this. Here is my code
class Readmails extends AsyncTask{
Folder inbox;
Folder inbox2;
Properties props = System.getProperties();
#Override
protected String doInBackground(String... params) {
// TODO Auto-generated method stub
props.setProperty("mail.store.protocol", "imaps");
try
{
/* Create the session and get the store for read the mail. */
Session session = Session.getDefaultInstance(props, null);
Store store = session.getStore("imaps");
store.connect("imap.gmail.com","test123#gmail.com", "testmycode12345");
/* Mention the folder name which you want to read. */
inbox = store.getFolder("Inbox");
System.out.println("No of Unread Messages : " + inbox.getUnreadMessageCount());
System.out.println("No of New Messages : " + inbox.getNewMessageCount());
System.out.println("No of Deleted Messages : " +inbox.getDeletedMessageCount());
System.out.println("No of total Messages : " + inbox.getMessageCount());
System.out.println("No of Type Messages : " + inbox.getType());
/*Open the inbox using store.*/
inbox.open(Folder.READ_ONLY);
/* Get the messages which is unread in the Inbox*/
Message messages[] = inbox.search(new FlagTerm(new Flags(Flag.SEEN), false));
/* Use a suitable FetchProfile */
FetchProfile fp = new FetchProfile();
fp.add(FetchProfile.Item.ENVELOPE);
fp.add(FetchProfile.Item.CONTENT_INFO);
inbox.fetch(messages, fp);
try
{
inbox.close(true);
store.close();
}
catch (Exception ex)
{
System.out.println("Exception arise at the time of read mail");
ex.printStackTrace();
}
}
catch (NoSuchProviderException e)
{
e.printStackTrace();
System.exit(1);
}
catch (MessagingException e)
{
e.printStackTrace();
System.exit(2);
}
return null;
}
}
You are calling getDeletedMessageCount() before you open the inbox.
See this comment in the code, it says it returns -1 on closed folders. Move your call to inbox.open() above your println's
I'm trying to add media controls to my app but I can't get the RemoteMediaPlayer to send commands.
The video starts playing but then I can't control it.
This is the code I use:
RemoteMediaPlayer mRemoteMediaPlayer = new RemoteMediaPlayer();
try {
Cast.CastApi.setMessageReceivedCallbacks(apiClient, mRemoteMediaPlayer.getNamespace(), mRemoteMediaPlayer);
MediaMetadata mediaMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE);
JSONObject jsonExtra = new JSONObject();
mediaMetadata.putString(MediaMetadata.KEY_TITLE, "My video");
if (mediaType != null) {
jsonExtra.put("type", mediaType);
}
if ("audio".equals(mediaType)) {
mimeType = "audio/mp3";
}
com.google.android.gms.cast.MediaInfo.Builder builder = new MediaInfo.Builder(getUrl()).setContentType(mimeType).setMetadata(mediaMetadata).setCustomData(jsonExtra);
builder.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED);
MediaInfo mediaInfo = builder.build();
mRemoteMediaPlayer.load(apiClient, mediaInfo, true, inititalTime).setResultCallback(new ResultCallback<RemoteMediaPlayer.MediaChannelResult>() {
#Override
public void onResult(MediaChannelResult result) {
if (result.getStatus().isSuccess()) {
log(context, "Media loaded successfully");
}
}
});
Thread.sleep(5000);
mRemoteMediaPlayer.pause(apiClient);
} catch (IllegalStateException e) {
log(context, "Problem occurred with media during loading " + e);
} catch (IOException e) {
log(context, "Problem occurred with media during loading " + e);
} catch (JSONException e) {
log(context, "Problem occurred with media during loading " + e);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
You may notice that at the end I wait 5 seconds to make sure that the video is playing and then try to pause it.
This always results in an IllegalStateException with the message:
No current media session
Am I missing something?
I also notice that the ResultCallback is never called after the video starts playing. Maybe this is also related to the same issue I'm experiencing.
Thanks in advance.
It is not clear when you are running this piece of code. Do not set a sleep like you did; you have to register callbacks on mRemoteMediaPlayer to be notified when status or metadata changes on the remote player. When the status changed listener is called, get the updated status by calling mRemoteMediaPlayer.getMediaStatus().getPlayerState() and based on the status (whether it is playing, buffering, idle, paused), make the appropriate decision. In asynchronous systems, never use "sleep()", always hook into the callbacks.