How to create simple okhttp3 websocket connection? - web-services

Can someone please show me an example on how to establish the connection to the wss:// address with specific Authorization header, using okhttp3 okhttp-ws library?
All I have is the url of WS server and Authorization string token.
Later, I must be able to send request to that connection, listen to upcoming data from WS server and than close connection. I have a difficulties with this new to me WS world, always been working only with REST (with okhttp3 too)

So generally this sample is most of what you need
https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/WebSocketEcho.java
But you will have two changes
Use wss instead of ws in your URL
Call request.addHeader to add your token
request.addHeader("Authorization", "Bearer " + token)

I know this is an old question, but when I try to use websocket with okhttp3 there are a lot of options that I want and it was not in the library. So I create a class that handle WS connection with extra functionalities. I hope it will help some body. Gist link
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import java.net.ProtocolException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okhttp3.internal.ws.RealWebSocket;
import okhttp3.logging.HttpLoggingInterceptor;
import okio.ByteString;
/**
* Websocket class based on OkHttp3 with {event->data} message format to make your life easier.
*
* #author Ali Yusuf
* #since 3/13/17
*/
public class Socket {
private final static String TAG = Socket.class.getSimpleName();
private final static String CLOSE_REASON = "End of session";
private final static int MAX_COLLISION = 7;
public final static String EVENT_OPEN = "open";
public final static String EVENT_RECONNECT_ATTEMPT = "reconnecting";
public final static String EVENT_CLOSED = "closed";
/**
* Main socket states
*/
public enum State {
CLOSED, CLOSING, CONNECT_ERROR, RECONNECT_ATTEMPT, RECONNECTING, OPENING, OPEN
}
private static HttpLoggingInterceptor logging =
new HttpLoggingInterceptor()
.setLevel(BuildConfig.DEBUG ? HttpLoggingInterceptor.Level.HEADERS : HttpLoggingInterceptor.Level.NONE);
private static OkHttpClient.Builder httpClient =
new OkHttpClient.Builder()
.addInterceptor(logging);
public static class Builder {
private Request.Builder request;
private Builder(Request.Builder request) {
this.request = request;
}
public static Builder with(#NonNull String url) {
// Silently replace web socket URLs with HTTP URLs.
if (!url.regionMatches(true, 0, "ws:", 0, 3) && !url.regionMatches(true, 0, "wss:", 0, 4))
throw new IllegalArgumentException("web socket url must start with ws or wss, passed url is " + url);
return new Builder(new Request.Builder().url(url));
}
public Builder setPingInterval(long interval, #NonNull TimeUnit unit){
httpClient.pingInterval(interval, unit);
return this;
}
public Builder addHeader(#NonNull String name, #NonNull String value) {
request.addHeader(name, value);
return this;
}
public Socket build() {
return new Socket(request.build());
}
}
/**
* Websocket state
*/
private static State state;
/**
* Websocket main request
*/
private static Request request;
/**
* Websocket connection
*/
private static RealWebSocket realWebSocket;
/**
* Reconnection post delayed handler
*/
private static Handler delayedReconnection;
/**
* Websocket events listeners
*/
private static Map<String,OnEventListener> eventListener;
/**
* Websocket events new message listeners
*/
private static Map<String,OnEventResponseListener> eventResponseListener;
/**
* Message list tobe send onEvent open {#link State#OPEN} connection state
*/
private static Map<String,String> onOpenMessageQueue = new HashMap<>();
/**
* Websocket state change listener
*/
private static OnStateChangeListener onChangeStateListener;
/**
* Websocket new message listener
*/
private static OnMessageListener messageListener;
/**
* Number of reconnection attempts
*/
private static int reconnectionAttempts;
private static boolean skipOnFailure;
private Socket(Request request) {
Socket.request = request;
state = State.CLOSED;
eventListener = new HashMap<>();
eventResponseListener = new HashMap<>();
delayedReconnection = new Handler(Looper.getMainLooper());
skipOnFailure = false;
}
/**
* Start socket connection if i's not already started
*/
public Socket connect() {
if (httpClient == null) {
throw new IllegalStateException("Make sure to use Socket.Builder before using Socket#connect.");
}
if (realWebSocket == null) {
realWebSocket = (RealWebSocket) httpClient.build().newWebSocket(request, webSocketListener);
changeState(State.OPENING);
} else if (state == State.CLOSED) {
realWebSocket.connect(httpClient.build());
changeState(State.OPENING);
}
return this;
}
/**
* Set listener which fired every time message received with contained data.
*
* #param listener message on arrive listener
*/
public Socket onEvent(#NonNull String event, #NonNull OnEventListener listener){
eventListener.put(event,listener);
return this;
}
/**
* Set listener which fired every time message received with contained data.
*
* #param listener message on arrive listener
*/
public Socket onEventResponse(#NonNull String event, #NonNull OnEventResponseListener listener){
eventResponseListener.put(event,listener);
return this;
}
/**
* Send message in {event->data} format
*
* #param event event name that you want sent message to
* #param data message data in JSON format
* #return true if the message send/on socket send quest; false otherwise
*/
public boolean send(#NonNull String event, #NonNull String data){
try {
JSONObject text = new JSONObject();
text.put("event", event);
text.put("data", new JSONObject(data));
Log.v(TAG,"Try to send data "+text.toString());
return realWebSocket.send(text.toString());
} catch (JSONException e) {
Log.e(TAG,"Try to send data with wrong JSON format, data: "+data);
}
return false;
}
/**
* Set state listener which fired every time {#link Socket#state} changed.
*
* #param listener state change listener
*/
public Socket setOnChangeStateListener(#NonNull OnStateChangeListener listener) {
onChangeStateListener = listener;
return this;
}
/**
* Message listener will be called in any message received even if it's not
* in a {event -> data} format.
*
* #param listener message listener
*/
public Socket setMessageListener(#NonNull OnMessageListener listener) {
messageListener = listener;
return this;
}
public void removeEventListener(#NonNull String event) {
eventListener.remove(event);
onOpenMessageQueue.remove(event);
}
/**
* Clear all socket listeners in one line
*/
public void clearListeners() {
eventListener.clear();
messageListener = null;
onChangeStateListener = null;
}
/**
* Send normal close request to the host
*/
public void close() {
if (realWebSocket != null) {
realWebSocket.close(1000, CLOSE_REASON);
}
}
/**
* Send close request to the host
*/
public void close(int code, #NonNull String reason) {
if (realWebSocket != null) {
realWebSocket.close(code, reason);
}
}
/**
* Terminate the socket connection permanently
*/
public void terminate() {
skipOnFailure = true; // skip onFailure callback
if (realWebSocket != null) {
realWebSocket.cancel(); // close connection
realWebSocket = null; // clear socket object
}
}
/**
* Add message in a queue if the socket not open and send them
* if the socket opened
*
* #param event event name that you want sent message to
* #param data message data in JSON format
*/
public void sendOnOpen(#NonNull String event, #NonNull String data) {
if (state != State.OPEN)
onOpenMessageQueue.put(event,data);
else
send(event,data);
}
/**
* Retrieve current socket connection state {#link State}
*/
public State getState() {
return state;
}
/**
* Change current state and call listener method with new state
* {#link OnStateChangeListener#onChange(Socket, State)}
* #param newState new state
*/
private void changeState(State newState) {
state = newState;
if (onChangeStateListener != null) {
onChangeStateListener.onChange(Socket.this, state);
}
}
/**
* Try to reconnect to the websocket after delay time using <i>Exponential backoff</i> method.
* #see
*/
private void reconnect() {
if (state != State.CONNECT_ERROR) // connection not closed !!
return;
changeState(State.RECONNECT_ATTEMPT);
if (realWebSocket != null) {
// Cancel websocket connection
realWebSocket.cancel();
// Clear websocket object
realWebSocket = null;
}
if (eventListener.get(EVENT_RECONNECT_ATTEMPT) != null) {
eventListener.get(EVENT_RECONNECT_ATTEMPT).onMessage(Socket.this, EVENT_RECONNECT_ATTEMPT);
}
// Calculate delay time
int collision = reconnectionAttempts > MAX_COLLISION ? MAX_COLLISION : reconnectionAttempts;
long delayTime = Math.round((Math.pow(2, collision)-1)/2) * 1000;
// Remove any pending posts of callbacks
delayedReconnection.removeCallbacksAndMessages(null);
// Start new post delay
delayedReconnection.postDelayed(new Runnable() {
#Override
public void run() {
changeState(State.RECONNECTING);
reconnectionAttempts++; // Increment connections attempts
connect(); // Establish new connection
}
}, delayTime);
}
private WebSocketListener webSocketListener = new WebSocketListener() {
#Override
public void onOpen(WebSocket webSocket, Response response) {
Log.v(TAG,"Socket has been opened successfully.");
// reset connections attempts counter
reconnectionAttempts = 0;
// fire open event listener
if (eventListener.get(EVENT_OPEN) != null) {
eventListener.get(EVENT_OPEN).onMessage(Socket.this, EVENT_OPEN);
}
// Send data in queue
for (String event : onOpenMessageQueue.keySet()) {
send(event, onOpenMessageQueue.get(event));
}
// clear queue
onOpenMessageQueue.clear();
changeState(State.OPEN);
}
/**
* Accept only Json data with format:
* <b> {"event":"event name","data":{some data ...}} </b>
*/
#Override
public void onMessage(WebSocket webSocket, String text) {
// print received message in log
Log.v(TAG, "New Message received "+text);
// call message listener
if (messageListener != null)
messageListener.onMessage(Socket.this, text);
try {
// Parse message text
JSONObject response = new JSONObject(text);
String event = response.getString("event");
JSONObject data = response.getJSONObject("data");
// call event listener with received data
if (eventResponseListener.get(event) != null) {
eventResponseListener.get(event).onMessage(Socket.this, event, data);
}
// call event listener
if (eventListener.get(event) != null) {
eventListener.get(event).onMessage(Socket.this, event);
}
} catch (JSONException e) {
// Message text not in JSON format or don't have {event}|{data} object
Log.e(TAG, "Unknown message format.");
}
}
#Override
public void onMessage(WebSocket webSocket, ByteString bytes) {
// TODO: some action
}
#Override
public void onClosing(WebSocket webSocket, int code, String reason) {
Log.v(TAG,"Close request from server with reason '"+reason+"'");
changeState(State.CLOSING);
webSocket.close(1000,reason);
}
#Override
public void onClosed(WebSocket webSocket, int code, String reason) {
Log.v(TAG,"Socket connection closed with reason '"+reason+"'");
changeState(State.CLOSED);
if (eventListener.get(EVENT_CLOSED) != null) {
eventListener.get(EVENT_CLOSED).onMessage(Socket.this, EVENT_CLOSED);
}
}
/**
* This method call if:
* - Fail to verify websocket GET request => Throwable {#link ProtocolException}
* - Can't establish websocket connection after upgrade GET request => response null, Throwable {#link Exception}
* - First GET request had been failed => response null, Throwable {#link java.io.IOException}
* - Fail to send Ping => response null, Throwable {#link java.io.IOException}
* - Fail to send data frame => response null, Throwable {#link java.io.IOException}
* - Fail to read data frame => response null, Throwable {#link java.io.IOException}
*/
#Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
if (!skipOnFailure) {
skipOnFailure = false; // reset flag
Log.v(TAG, "Socket connection fail, try to reconnect. (" + reconnectionAttempts + ")");
changeState(State.CONNECT_ERROR);
reconnect();
}
}
};
public abstract static class OnMessageListener {
public abstract void onMessage (String data);
/**
* Method called from socket to execute listener implemented in
* {#link #onMessage(String)} on main thread
*
* #param socket Socket that receive the message
* #param data Data string received
*/
private void onMessage (Socket socket, final String data) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
onMessage(data);
}
});
}
}
public abstract static class OnEventListener {
public abstract void onMessage (String event);
private void onMessage (Socket socket, final String event) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
onMessage(event);
}
});
}
}
public abstract static class OnEventResponseListener extends OnEventListener {
/**
* Method need to override in listener usage
*/
public abstract void onMessage (String event, String data);
/**
* Just override the inherited method
*/
#Override
public void onMessage(String event) {}
/**
* Method called from socket to execute listener implemented in
* {#link #onMessage(String, String)} on main thread
*
* #param socket Socket that receive the message
* #param event Message received event
* #param data Data received in the message
*/
private void onMessage (Socket socket, final String event, final JSONObject data) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
onMessage(event, data.toString());
onMessage(event);
}
});
}
}
public abstract static class OnStateChangeListener {
/**
* Method need to override in listener usage
*/
public abstract void onChange (State status);
/**
* Method called from socket to execute listener implemented in
* {#link #onChange(State)} on main thread
*
* #param socket Socket that receive the message
* #param status new status
*/
private void onChange (Socket socket, final State status){
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
onChange(status);
}
});
}
}
}
Usage example:
Socket socket = Socket.Builder.with(WEBSOCKET_BASE_URL).build().connect();
socket.onEvent(Socket.EVENT_OPEN, socketOpenListener);
socket.onEvent(Socket.EVENT_RECONNECT_ATTEMPT, .....);
socket.onEvent(Socket.EVENT_CLOSED, .....);
socket.onEventResponse("Some event", socketPairListener);
socket.send("Some event", "{"some data":"in JSON format"}");
socket.sendOnOpen("Some event", "{"some data":"in JSON format"}");

Related

Laravel Livewire database notification doesn't exist yet when broadcast notification received

I've worked on getting database and broadcast notifications to play nice for quite a while, and I've finally got it working and identified an issue I don't know how to solve.
The root cause seems to be that the notification from pusher is getting back to the app prior to when the database notification is available to select.
This results in my notification icon showing up on the front end, but the notifications array is empty:
public function getListeners()
{
return [
"echo-private:users.{$this->user->id},StatementCompleted" => 'notifyUser',
];
}
public function notifyUser(mixed $notification)
{
if (!empty($notification)) {
$this->showNotificationsBadge = true;
ray('notification!');
$this->refreshNotifications();
ray($this->notifications); <-- THIS IS EMPTY
}
}
public function refreshNotifications()
{
$this->notifications = $this->user->unreadNotifications()->get();
$this->notificationCount = $this->user->unreadNotifications()->count();
}
HOWEVER, if I add sleep(5) into the notifyUser() method like so:
public function notifyUser(mixed $notification)
{
if (!empty($notification)) {
$this->showNotificationsBadge = true;
ray('notification!');
sleep(5); <-- ADDED THIS
$this->refreshNotifications();
}
}
it results in the notifications array containing the notification and everything works fine. So my theory is that it's a timing issue.
How do I ensure my database notification exists before the pusher notification triggers my livewire front-end refresh?
EVENT/LISTENER/NOTIFICATION CLASSES:
Here's my event:
class StatementCompleted implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $statement;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(Statement $statement)
{
$this->statement = $statement;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('users.' . $this->statement->uploadedBy->id);
}
}
and here's the event listener class:
class HandleStatementCompletedEvent implements ShouldQueue
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param object $event
* #return void
*/
public function handle($event)
{
Notification::send($event->statement->uploadedBy, new SendStatementCompletedNotification($event->statement));
}
}
and here's the notification class:
class SendStatementCompletedNotification extends Notification implements ShouldQueue, ShouldBroadcast
{
use Queueable;
public $statement;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct(Statement $statement)
{
$this->statement = $statement;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['database', 'broadcast'];
}
/**
* Get the broadcastable representation of the notification.
*
* #param mixed $notifiable
* #return BroadcastMessage
*/
public function toBroadcast($notifiable)
{
return new BroadcastMessage([
'title' => 'Statement Processed',
'message' => "Your statement {$this->statement->original_file_name} has been processed.",
'user_id' => $this->statement->uploadedBy->id
]);
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toDatabase($notifiable)
{
return [
'title' => 'Statement Processed',
'message' => "Your statement {$this->statement->original_file_name} has been processed.",
'user_id' => $this->statement->uploadedBy->id
];
}
}

Spring Boot Lambda Startup multiple times at the cold start

I'm writing small Data downloading service function using Spring Boot 2.7. I deployed it in the AWS lambda function. At the cold starting each time it initializes twice as shown in the image below.
Here is the lambderHandler.java
public class LambdaHandler implements RequestHandler<SQSEvent, String> {
private static final ApplicationContext applicationContext = SpringApplication.run(DataDownloaderService.class);
#Override
public String handleRequest(SQSEvent event, Context context) {
context.getLogger().log("Input: " + event);
if (!event.getRecords().isEmpty()) {
SQSEvent.SQSMessage firstRecord = event.getRecords().get(0);
String eventBody = firstRecord.getBody();
if (eventBody != null) {
ProductDownloadService productDownloadService = applicationContext.getBean(ProductDownloadServiceImpl.class);
try {
productDownloadService.downloadProductData(JsonUtil.getUserInfo(eventBody));
return "Successfully processed";
} catch (IOException e) {
return "Error in data downloading: " + e.getMessage();
}
}
}
return "Data download not success";
}
}
Here is the DataDownloaderService.java
#SpringBootApplication
#ComponentScan(basePackages = {"com.test.*"})
#EntityScan(basePackages = {"com.test.*"})
public class DataDownloaderService {
}
Why spring boot lambda function initialize multiple times at the cold start? Did I have some misconfiguration here or is it a bug?
I found a workaround to fix this issue from here.
Here is the workaround for the above code.
public class LambdaHandler implements RequestHandler<SQSEvent, String> {
private ApplicationContext applicationContext;
/**
* Entry point in the lambda function
* #param event
* #param context
* #return
*/
#Override
public String handleRequest(SQSEvent event, Context context) {
return initDataDownloaderService(event, context);
}
/**
* initialize application context and Data downloader service
*
* #param event
* #param context
* #return
*/
private String initDataDownloaderService(SQSEvent event, Context context) {
if (applicationContext == null) {
applicationContext = SpringApplication.run(DataDownloaderService.class);
}
context.getLogger().log("Input: " + event);
if (!event.getRecords().isEmpty()) {
SQSEvent.SQSMessage firstRecord = event.getRecords().get(0);
String eventBody = firstRecord.getBody();
if (eventBody != null) {
ProductDownloadService productDownloadService = applicationContext.getBean(ProductDownloadServiceImpl.class);
try {
productDownloadService.downloadProductData(JsonUtil.getUserInfo(eventBody));
return "Successfully processed";
} catch (IOException e) {
return "Error in data downloading: " + e.getMessage();
}
}
}
return "Data download not success";
}
}

Class inherited from a JAX-WS generated class not getting marshalled

I have used wsimport to generate JAX-WS client code from WSDL.
I am invoking the web service with a parameter inherited from one of the classes generated by wsimport.
The class generated by wsimport is -
package com.mywebservice;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlValue;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "MOR", propOrder = {
"value"
})
public class MOR {
#XmlValue
protected String value;
#XmlAttribute(name = "type")
protected String type;
/**
* Gets the value of the value property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getValue() {
return value;
}
/**
* Sets the value of the value property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setValue(String value) {
this.value = value;
}
/**
* Gets the value of the type property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getType() {
return type;
}
/**
* Sets the value of the type property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setType(String value) {
this.type = value;
}
public synchronized boolean equals(Object paramObject)
{
/*equals implementation*/
}
public synchronized int hashCode()
{
/*hashCode implementation*/*/
}
}
And I am passing instance of following class during web service invocation
public class TaggedMOR extends MOR {
private MOR moRef = null;
private String creatorMethodName = null;
public TaggedMOR(MOR MOR) {
moRef = MOR;
}
public TaggedMOR() {
}
public void setCreatorMethodName(String methodName) {
creatorMethodName = methodName;
}
public String getCreatorMethodName() {
return creatorMethodName;
}
public MOR getMoRef() {
return moRef;
}
}
I enabled http transport dump and saw that TaggedMOR was not marshalled in the SOAP envelope.
I also created an XMLJavaTypeAdapter but that also did not work.
Please advice, I am new to this.

Google glass live stream video using RTSP server of Wowza

I'm trying to build a Google glass app that supports live streaming. Am aware that Livestream app is available to do this but i don't think we can integrate it in our application or am i wrong? is there a way to integrate the livestream in our app?
I came across this https://github.com/andermaco/GlassStream open source project which do the same thing using RTSP server of Wowza. As per the instructions i have given the user name/password and updated the url. But while running there is an issue while running the application., i tried to debug it but am not successful. This is the log am getting repeatedly
java.lang.IllegalStateException at android.media.MediaCodec.dequeueOutputBuffer(Native Method)
at net.majorkernelpanic.streaming.rtp.MediaCodecInputStream.read(MediaCodecInputStream.java :75)
at net.majorkernelpanic.streaming.rtp.AACLATMPacketizer.run(AACLATMPacketizer.java:88)
at java.lang.Thread.run(Thread.java:841)
Some of the users have used and are successful, Please share me the source code or let me know if am missing something in setting up the server. Even if there are any other resource for implementing, it would be great.
Thanks in Advance.
This the code I've used to get it working on Google Glass (XE22) using Wowza media server and libstreaming.
I've two classes AppConfig and MyActivity.
AppConfig:
package com.example.GlassApp;
/**
* User: Colin Shewell
* Date: 21/08/14
* Time: 15:30
*/
public class AppConfig {
public static final String STREAM_URL = "rtsp://193.61.148.73:1935/serg/android_test";
//public static final String STREAM_URL = "rtsp://192.168.2.2:1935/serg/android_test";
public static final String PUBLISHER_USERNAME = "";
public static final String PUBLISHER_PASSWORD = "";
}
MyActivity:
package com.example.GlassApp;
/**
* User: Colin Shewell
* Date: 21/08/14
* Time: 15:30
*/
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.majorkernelpanic.streaming.Session;
import net.majorkernelpanic.streaming.SessionBuilder;
import net.majorkernelpanic.streaming.audio.AudioQuality;
import net.majorkernelpanic.streaming.gl.SurfaceView;
import net.majorkernelpanic.streaming.rtsp.RtspClient;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.Menu;
import android.view.SurfaceHolder;
import android.view.Window;
import android.view.WindowManager;
import net.majorkernelpanic.streaming.video.VideoQuality;
public class MyActivity extends Activity implements RtspClient.Callback, Session.Callback, SurfaceHolder.Callback {
// log tag
public final static String TAG = MyActivity.class.getSimpleName();
// surfaceview
private static SurfaceView mSurfaceView;
// Rtsp session
private Session mSession;
private static RtspClient mClient;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
mSurfaceView = (SurfaceView) findViewById(R.id.surface);
mSurfaceView.getHolder().addCallback(this);
// Initialize RTSP client
initRtspClient();
}
#Override
protected void onResume() {
super.onResume();
toggleStreaming();
}
#Override
protected void onPause(){
super.onPause();
toggleStreaming();
}
private void initRtspClient() {
// Configures the SessionBuilder
mSession = SessionBuilder.getInstance()
.setContext(getApplicationContext())
.setAudioEncoder(SessionBuilder.AUDIO_NONE)
.setVideoEncoder(SessionBuilder.VIDEO_H264)
.setVideoQuality(new VideoQuality(640, 480, 20, 500000)) //only need if you want to change the resolution from default
.setSurfaceView(mSurfaceView).setPreviewOrientation(0)
.setCallback(this).build();
// Configures the RTSP client
mClient = new RtspClient();
mClient.setSession(mSession);
mClient.setCallback(this);
mSurfaceView.setAspectRatioMode(SurfaceView.ASPECT_RATIO_PREVIEW);
String ip, port, path;
// We parse the URI written in the Editext
Pattern uri = Pattern.compile("rtsp://(.+):(\\d+)/(.+)");
Matcher m = uri.matcher(AppConfig.STREAM_URL);
m.find();
ip = m.group(1);
port = m.group(2);
path = m.group(3);
mClient.setCredentials(AppConfig.PUBLISHER_USERNAME,
AppConfig.PUBLISHER_PASSWORD);
mClient.setServerAddress(ip, Integer.parseInt(port));
mClient.setStreamPath("/" + path);
}
private void toggleStreaming() {
if (!mClient.isStreaming()) {
// Start camera preview
mSession.startPreview();
// Start video stream
mClient.startStream();
} else {
// already streaming, stop streaming
// stop camera preview
mSession.stopPreview();
// stop streaming
mClient.stopStream();
}
}
#Override
public void onDestroy() {
super.onDestroy();
mClient.release();
mSession.release();
mSurfaceView.getHolder().removeCallback(this);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public void onSessionError(int reason, int streamType, Exception e) {
switch (reason) {
case Session.ERROR_CAMERA_ALREADY_IN_USE:
break;
case Session.ERROR_CAMERA_HAS_NO_FLASH:
break;
case Session.ERROR_INVALID_SURFACE:
break;
case Session.ERROR_STORAGE_NOT_READY:
break;
case Session.ERROR_CONFIGURATION_NOT_SUPPORTED:
break;
case Session.ERROR_OTHER:
break;
}
if (e != null) {
alertError(e.getMessage());
e.printStackTrace();
}
}
private void alertError(final String msg) {
final String error = (msg == null) ? "Unknown error: " : msg;
AlertDialog.Builder builder = new AlertDialog.Builder(MyActivity.this);
builder.setMessage(error).setPositiveButton("Ok",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
#Override
public void onRtspUpdate(int message, Exception exception) {
switch (message) {
case RtspClient.ERROR_CONNECTION_FAILED:
case RtspClient.ERROR_WRONG_CREDENTIALS:
alertError(exception.getMessage());
exception.printStackTrace();
break;
}
}
#Override
public void onPreviewStarted() {
}
#Override
public void onSessionConfigured() {
}
#Override
public void onSessionStarted() {
}
#Override
public void onSessionStopped() {
}
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
// #Override
public void onBitrateUpdate(long bitrate) {
}
}
EDIT:
I can confirm that the following video quality settings work:
.setVideoQuality(new VideoQuality(640, 480, 20, 500000))
.setVideoQuality(new VideoQuality(960, 720, 20, 500000))
I'd also like to add that an fps value of over 20 seems to result in the app failing to start.

Play framework 1.2.5 Websocket

Instead using the EventStream instead ArchivedEventStream, when I run command alert(notification) message go to all connected socket except the original sender, how I also can send to original sender.
Here is my model and controller, using WebSocket
EventModel
public class EventModel {
// ~~~~~~~~~ Let's chat!
final EventStream<EventModel.Event> events = new EventStream<EventModel.Event>(100);
/**
* Get the event
*/
public EventStream<EventModel.Event> getEventStream() {
return events;
}
/**
* A user say something on the room
*/
public void _alert(Notification notification){
if(notification == null) return;
events.publish(new EventModel.NotificationEvent(notification));
}
// ~~~~~~~~~ Events
public static abstract class Event {
final public String type;
final public Long timestamp;
public boolean sended;
public Event(String type) {
this.sended = false;
this.type = type;
this.timestamp = System.currentTimeMillis();
}
}
public static class NotificationEvent extends EventModel.Event{
public final Notification notification;
public NotificationEvent(Notification notification) {
super("notification");
this.notification = notification;
}
public User getReceiver(){
return notification.receiver;
}
}
// EventModel factory
static EventModel instance = null;
public static EventModel get() {
if(instance == null) {
instance = new EventModel();
}
return instance;
}
//Alert notification
public static void alert(Notification notification){
get()._alert(notification);
}
}
And here is controller
public class MyWebSocket extends RootController {
public static class WebSocket extends WebSocketController {
public static void echo(Long userId) {
//Security
User user = User.findById(userId);
EventModel eventCentre = EventModel.get();
// Socket connected, join the chat room
EventStream<EventModel.Event> eventStrean = eventCentre.getEventStream();
// Loop while the socket is open
while(inbound.isOpen()) {
// Wait for an event (either something coming on the inbound socket channel, or ChatRoom messages)
Either<WebSocketEvent,EventModel.Event> e = await(Promise.waitEither(
inbound.nextEvent(),
eventStrean.nextEvent()
));
//Handle if get any notification
for(EventModel.NotificationEvent event: ClassOf(EventModel.NotificationEvent.class).match(e._2)) {
if(!event.getReceiver().equals(user)) continue;
outbound.send(event.notification.toJson());
}
// Case: The socket has been closed
for(WebSocketClose closed: SocketClosed.match(e._1)) {
disconnect();
}
}
}
}
}
To send to the original sender as well remove or comment out this line:
if(!event.getReceiver().equals(user)) continue;
one small issue to be aware of
https://github.com/playframework/play1/pull/709