How to register hooks into Jetty Startup Lifecycle? - jetty

I am trying to run a piece of code just before a Jetty server starts and stops.
The configuration that starts my server looks similar to this:
public class ExampleServer {
public static void main(String[] args) throws Exception {
Server server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(8080);
server.setConnectors(new Connector[] { connector });
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/hello");
context.addServlet(HelloServlet.class, "/");
HandlerCollection handlers = new HandlerCollection();
handlers.setHandlers(new Handler[] { context, new DefaultHandler() });
server.setHandler(handlers);
server.start();
server.join();
}
}
I am not sure what piece of Jetty component I need to configure to be able to insert into the lifecycle.
How do I go about doing this?

The most basic is LifeCycle.Listener which when added to a LifeCycle capable component in the LifeCycle will report the state changes to your own listener.
This will only report for that one component that you have used LifeCycle.addListener(LifeCycle.Listener) on.
Example:
package jetty;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.component.LifeCycle;
public class LifeCycleListenerDemo
{
public static void main(String[] args) throws Exception
{
Server server = new Server();
server.addLifeCycleListener(new CustomLifeCycleListener());
ServerConnector connector = new ServerConnector(server);
connector.setPort(8080);
server.setConnectors(new Connector[] {connector });
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/hello");
context.addServlet(HelloServlet.class, "/");
HandlerCollection handlers = new HandlerCollection();
handlers.setHandlers(new Handler[] {context, new DefaultHandler() });
server.setHandler(handlers);
server.start();
server.join();
}
public static class CustomLifeCycleListener implements LifeCycle.Listener
{
#Override
public void lifeCycleStarting(LifeCycle event)
{
System.out.println("Starting: " + event);
}
#Override
public void lifeCycleStarted(LifeCycle event)
{
System.out.println("Started: " + event);
}
#Override
public void lifeCycleFailure(LifeCycle event, Throwable cause)
{
System.out.println("Failure: " + event);
cause.printStackTrace(System.out);
}
#Override
public void lifeCycleStopping(LifeCycle event)
{
System.out.println("Stopping: " + event);
}
#Override
public void lifeCycleStopped(LifeCycle event)
{
System.out.println("Stopped: " + event);
}
}
}
There is also a Container.Listener which will tell you about the beans added to a specific container component via ContainerLifeCycle.addEventListener(Container.Listener).
And then there's the specialized Container.InheritedListener which will propagate your Container.InheritedListener to all child beans of the container as well (nested).
You can use this to add your custom LifeCycle.Listener too all registered beans.
Example:
package jetty;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.component.Container;
import org.eclipse.jetty.util.component.LifeCycle;
public class LifeCycleNestedListenerDemo
{
public static void main(String[] args) throws Exception
{
Server server = new Server();
CustomLifeCycleListener lifeCycleListener = new CustomLifeCycleListener();
server.addEventListener(lifeCycleListener);
lifeCycleListener.addListener(server); // so we can see server/starting event
ServerConnector connector = new ServerConnector(server);
connector.setPort(8080);
server.setConnectors(new Connector[]{connector});
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/hello");
context.addServlet(HelloServlet.class, "/");
HandlerCollection handlers = new HandlerCollection();
handlers.setHandlers(new Handler[]{context, new DefaultHandler()});
server.setHandler(handlers);
server.start();
server.join();
}
public static class CustomLifeCycleListener implements Container.InheritedListener, LifeCycle.Listener
{
private Set<Integer> addedObjects = new HashSet<>();
public void addListener(LifeCycle lifeCycle)
{
// identify what we've added the listener too already, so we don't add it multiple times
int identityHashCode = System.identityHashCode(lifeCycle);
if (!addedObjects.contains(identityHashCode))
{
lifeCycle.addLifeCycleListener(this);
addedObjects.add(identityHashCode);
}
}
#Override
public void beanAdded(Container parent, Object child)
{
System.out.printf("beanAdded(%s, %s)%n", parent.getClass().getName(), child.getClass().getName());
if (child instanceof LifeCycle)
{
LifeCycle lifeCycle = (LifeCycle)child;
addListener(lifeCycle);
}
}
#Override
public void beanRemoved(Container parent, Object child)
{
}
#Override
public void lifeCycleStarting(LifeCycle event)
{
System.out.println("Starting: " + event);
}
#Override
public void lifeCycleStarted(LifeCycle event)
{
System.out.println("Started: " + event);
}
#Override
public void lifeCycleFailure(LifeCycle event, Throwable cause)
{
System.out.println("Failure: " + event);
cause.printStackTrace(System.out);
}
#Override
public void lifeCycleStopping(LifeCycle event)
{
System.out.println("Stopping: " + event);
}
#Override
public void lifeCycleStopped(LifeCycle event)
{
System.out.println("Stopped: " + event);
}
}
}

Related

Testing an API endpoint with Lambda + API Gateway

I'm trying to create and test an API endpoint using AWS Lambda and API Gateway. I can test my function successfully using Lambda Test, but when I try to test my endpoint it gives:
{
"message": "Internal server error"
}
This is my handler class:
package com.amazonaws.lambda.gandhi.conversion.api;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.RandomStringUtils;
import com.amazonaws.lambda.gandhi.conversion.api.Response.AuthClientCredentialResponse;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.lambda.gandhi.conversion.api.utils.ClientAuthPOJO;
public class AuthClientCredentialServiceHandler implements RequestHandler<ClientAuthPOJO, Object> {
private AuthClientCredentialResponse authClientCredentialResponse;
private static final SecureRandom RANDOM = new SecureRandom();
public static int MAX_CLIENT_KEY = 10;
public static int CLIENT_SECRET_LENGTH = 69;
#Override
public AuthClientCredentialResponse handleRequest(ClientAuthPOJO clientIdSecret, Context context) {
String clientSecret;
try {
context.getLogger().log("Input: "
+ clientIdSecret);
String clientId = clientIdSecret.getClientId();
clientSecret = generateClientSecretKey();
Map<String, String> clientCredsMap = getClientCredentials();
if (clientCredsMap.size() > MAX_CLIENT_KEY) {
throw new RuntimeException(String.format("Max limit is %d, Please delete some keys", MAX_CLIENT_KEY));
}
clientCredsMap.forEach((k, v) -> {
if (clientId.equals(k)) {
throw new RuntimeException("Client Already exists");
}
});
storeClientCredentials(clientId, clientSecret);
AuthClientCredentialResponse authClientCredentialResponse = AuthClientCredentialResponse.builder().success(
true).clientId(clientId).clientSecret(clientSecret).build();
this.authClientCredentialResponse = authClientCredentialResponse;
} catch (Exception e) {
throw new RuntimeException(
"Failed to generate client secret: "
+ e.getMessage());
}
return authClientCredentialResponse;
}
private String generateClientSecretKey() throws NoSuchAlgorithmException, InvalidKeySpecException {
String clientSecret = RandomStringUtils.randomAlphanumeric(CLIENT_SECRET_LENGTH);
System.out.printf("clientSecret: %s%n", clientSecret);
return clientSecret;
}
private void storeClientCredentials(String clientId, String clientSecret) throws IOException {
/*
* TODO:
* Some logic to store clientCredentials to a file or DB. Decide later.
*/
System.out.println("temp ClientCredentials stored");
}
public Map<String, String> getClientCredentials() throws IOException {
/*
* TODO:
* Some logic to fetch clientCredentials from file or DB. Decide later.
*/
Map<String, String> clientCredMap = new HashMap<String, String>();
clientCredMap.put("1", "secretKey1");
clientCredMap.put("2", "secretKey2");
clientCredMap.put("3", "secretKey3");
clientCredMap.put("4", "secretKey4");
return clientCredMap;
}
}
My input class:
package com.amazonaws.lambda.gandhi.conversion.api.utils;
public class ClientAuthPOJO {
String clientId;
String clientSecret;
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getClientSecret() {
return clientSecret;
}
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
public ClientAuthPOJO(String clientId, String clientSecret) {
super();
this.clientId = clientId;
this.clientSecret = clientSecret;
}
public ClientAuthPOJO() {
}
}
My test object in lambda:
My test for endpoint in API Gateway:
Can someone please help me figure out the problem in creating the function or API Gateway?
Edit:
When I check the logs, I found that the parameters to the functions (clientId and clientSecret) are null. So there seems to be some problem in the way I'm sending my request body.

Jetty priority treatment of health checks?

My Jetty is servicing requests on /myservice/*
My problem is that when the server's queue gets full, the health check requests on /healthcheck start failing.
Is it possible to have a separate queue for my health checks, or is there another way to do this?import java.io.IOException;
Here is an example server:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
/**
* Based on:
* https://www.eclipse.org/jetty/documentation/9.4.x/embedded-examples.html
*/
public class HealthCheckServer
{
public static void main( String[] args ) throws Exception
{
Server server = new Server(8086);
QueuedThreadPool qtp = (QueuedThreadPool) server.getThreadPool();
qtp.setMaxThreads(6);
ServletHandler handler = new ServletHandler();
server.setHandler(handler);
handler.addServletWithMapping(HelloServlet.class, "/hello");
handler.addServletWithMapping(HealthServlet.class, "/health");
server.start();
server.join();
}
#SuppressWarnings("serial")
public static class HelloServlet extends HttpServlet
{
#Override
protected void doGet( HttpServletRequest request,
HttpServletResponse response ) throws ServletException,
IOException
{
try {
Thread.sleep(10*1000); // 10 sec
} catch (InterruptedException e) {
e.printStackTrace();
}
response.setContentType("text/html");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println("<h1>Hello from HelloServlet</h1>");
}
}
#SuppressWarnings("serial")
public static class HealthServlet extends HttpServlet
{
#Override
protected void doGet( HttpServletRequest request,
HttpServletResponse response ) throws ServletException,
IOException
{
response.setContentType("text/html");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println("all good captain");
}
}
}
If you hit http://localhost:8086/hello 4 times, then http://localhost:8086/health won't be responsive.

seek bar not working when playing mp3 song from server

In my app I am trying to play a media player from server along with a seek bar. When I tried to play the song from server, my app was working fine but the seek bar was not getting moved ! Also, The seekbar is not working....
It's not displaying MediaPlayer progress
also, It is playing multiple songs at the same time
solution needed for 2 bugs
Here is a screenshot of that app
import android.media.MediaPlayer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Button;
import android.widget.SeekBar;
import java.io.IOException;
import java.util.ArrayList;
public class MainActivity2 extends AppCompatActivity {
private ArrayList<SongInfo> _songs = new ArrayList<SongInfo>();
RecyclerView recyclerView;
SeekBar seekBar;
SongAdapter songAdapter;
MediaPlayer mediaPlayer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
seekBar = (SeekBar) findViewById(R.id.seekBar);
SongInfo s = new SongInfo("Cheap Thrills", "sia", "http://176.126.236.250/33Mmt/music/hindi/movies/new/oh_my_god/Go-Go-Govinda_(webmusic.in).mp3");
_songs.add(s);
s = new SongInfo("Cheap Thrills", "sia", "http://176.126.236.250/33Mmt/music/hindi/movies/new/oh_my_god/Go-Go-Govinda_(webmusic.in).mp3");
_songs.add(s);
songAdapter = new SongAdapter(this, _songs);
recyclerView.setAdapter(songAdapter);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
linearLayoutManager.getOrientation());
recyclerView.addItemDecoration(dividerItemDecoration);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(songAdapter);
songAdapter.setOnItemClickListener(new SongAdapter.OnItemClickListener() {
#Override
public void onItemClick(final Button b, View view, SongInfo obj, int position) {
try {
if (b.getText().toString().equals("stop")) {
b.setText("Play");
mediaPlayer.stop();
mediaPlayer.reset();
mediaPlayer.release();
mediaPlayer = null;
}else {
mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(obj.getSongUrl());
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
b.setText("stop");
}
});
}
} catch (IOException e) {
}
}
});
}
}
this is my song adapter code -:
package com.a03.dip.kaliprasadbengalisongs;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import java.util.ArrayList;
public class SongAdapter extends RecyclerView.Adapter<SongAdapter.SongHolder> {
ArrayList<SongInfo> _songs;
Context context;
OnItemClickListener mOnItemClickListener;
SongAdapter(Context context, ArrayList<SongInfo> songs) {
this.context = context;
this._songs = songs;
}
public interface OnItemClickListener {
void onItemClick(Button b ,View view, SongInfo obj, int position);
}
public void setOnItemClickListener(final OnItemClickListener mItemClickListener) {
this.mOnItemClickListener = mItemClickListener;
}
#Override
public SongHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View myView = LayoutInflater.from(context).inflate(R.layout.row_song,viewGroup,false);
return new SongHolder(myView);
}
#Override
public void onBindViewHolder(final SongHolder songHolder, final int i) {
final SongInfo c = _songs.get(i);
songHolder.songName.setText(_songs.get(i).songName());
songHolder.artistName.setText(_songs.get(i).artistName());
songHolder.btnAction.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mOnItemClickListener != null) {
mOnItemClickListener.onItemClick(songHolder.btnAction,v, c, i);
}
}
});
}
#Override
public int getItemCount() {
return _songs.size();
}
public class SongHolder extends RecyclerView.ViewHolder {
TextView songName,artistName;
Button btnAction;
public SongHolder(View itemView) {
super(itemView);
songName = (TextView) itemView.findViewById(R.id.tvSongName);
artistName = (TextView) itemView.findViewById(R.id.tvArtistName);
btnAction = (Button) itemView.findViewById(R.id.btnPlay);
}
}
}
and here is songInfo class -----
package com.a03.dip.kaliprasadbengalisongs;
import android.media.MediaPlayer;
public class SongInfo {
public String songName ,artistName,songUrl;
public SongInfo() {
}
public SongInfo(String songName, String artistName, String songUrl) {
this.songName = songName;
this.artistName = artistName;
this.songUrl = songUrl;
}
public String songName() {
return songName;
}
public String artistName() {
return artistName;
}
public String getSongUrl() {
return songUrl;
}
}
you have to use seekbar listener on ur activity.
seekBar.setOnSeekBarChangeListener(new >SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int >progress,
boolean fromUser) {
if (fromUser) {
mPlayer.seekTo(progress);
}
}

Async request slow performance

I'm making a web based scoring system for a robotic competition. When a point is scored, I want to refresh the page of everybody watching the game. My code is working "correctly".
My problem is that when I test and I open about 5 to 10 web pages, any other pages that I request are not processed until I close some pages. I think that what's happening is that request.startAsync() is not releasing the thread and it's waiting infinitely.
I've tested on both Jetty 9.2.7.v20150116 and Tomcat7. Both have the same slow behavior.
// Display a game with all it's events
// http://stackoverflow.com/questions/10878243/sse-and-servlet-3-0
#WebServlet(urlPatterns = { "/gameRefresh" }, asyncSupported = true)
public class GameRefreshController extends HttpServlet
{
private static final long serialVersionUID = -6890088129187673292L;
private static AtomicBoolean refreshNeeded = new AtomicBoolean();
private final Queue<AsyncContext> ongoingRequests = new ConcurrentLinkedQueue<>();
private ScheduledExecutorService service;
public static void setRefreshNeeded(boolean value)
{
refreshNeeded.set(value);
}
#Override
public void init(ServletConfig config) throws ServletException
{
final Runnable notifier = new Runnable()
{
#Override
public void run()
{
// Don't refresh if it's not needed.
if(!refreshNeeded.get())
{
return;
}
// This var is set by the backend when an event occurs.
setRefreshNeeded(false);
final Iterator<AsyncContext> iterator = ongoingRequests.iterator();
// not using for : in to allow removing items while iterating
while (iterator.hasNext())
{
AsyncContext asyncContext = iterator.next();
final ServletResponse servletResponse = asyncContext.getResponse();
PrintWriter out;
try
{
out = servletResponse.getWriter();
String toOutput = "data: refresh\n\n";
out.write(toOutput);
out.checkError();
}
catch(IOException exception)
{
// iterator is always removed because we refresh the whole page.
}
finally
{
iterator.remove();
}
}
}
};
service = Executors.newScheduledThreadPool(1);
service.scheduleAtFixedRate(notifier, 1, 1, TimeUnit.SECONDS);
}
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setContentType("text/event-stream");
response.setCharacterEncoding("UTF-8");
request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);
final AsyncContext asyncContext = request.startAsync();
asyncContext.setTimeout(0);
asyncContext.addListener(new AsyncListener()
{
#Override
public void onComplete(AsyncEvent event) throws IOException
{
ongoingRequests.remove(asyncContext);
}
#Override
public void onTimeout(AsyncEvent event) throws IOException
{
ongoingRequests.remove(asyncContext);
}
#Override
public void onError(AsyncEvent event) throws IOException
{
ongoingRequests.remove(asyncContext);
}
#Override
public void onStartAsync(AsyncEvent event) throws IOException
{
}
});
ongoingRequests.add(asyncContext);
}
}

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.