package com.github.kmkt.util;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.WebSocketListener;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class WSImageServlet extends WebSocketServlet {
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(WSImageServlet.class);
private final Set<WebSocketCallback> connectedWebSockets = new CopyOnWriteArraySet<WebSocketCallback>();
@Override
public void configure(WebSocketServletFactory factory) {
logger.debug("configure");
factory.setCreator(new WebSocketCreator(){
@Override
public Object createWebSocket(ServletUpgradeRequest req,
ServletUpgradeResponse resp) {
return new WebSocketCallback();
}
});
}
/**
* JPEG フレームデータを供給する。
*
* <pre>
* MJPEG とする JPEG フレームデータを与える。
* 与えられたフレームはGET接続時に MJPEG over HTTP でクライアントに送られる。
* クライアント接続時には pourFrame でフレームデータが与えられ次第、クライアントにその
* フレームが送信される。
* クライアントから接続されていない場合、与えられたフレームデータは破棄される。
* </pre>
*
* @param frame JPEG フレームデータ
*/
public void pourFrame(byte[] frame) {
for (WebSocketCallback socket : connectedWebSockets) {
if (socket.isOpen()) {
socket.sendFrame(frame);
}
}
}
private class WebSocketCallback implements WebSocketListener {
private Session session;
private String remoteAddr;
@Override
public void onWebSocketConnect(Session session) {
this.session = session;
this.remoteAddr = session.getRemote().toString();
connectedWebSockets.add(this);
logger.debug("WebSocket connected from {}", remoteAddr);
}
@Override
public void onWebSocketClose(int close_code, String msg) {
connectedWebSockets.remove(this);
logger.debug("WebSocket closed from {}", remoteAddr);
}
@Override
public void onWebSocketError(Throwable error) {
logger.error("Error on WebSocket {} {}", session.getRemoteAddress(), error);
}
@Override
public void onWebSocketText(String msg) {
logger.debug("Message {} from {}", msg, remoteAddr);
}
@Override
public void onWebSocketBinary(byte[] payload, int offset, int length) {
logger.debug("Message {} bytes from {}", length, remoteAddr);
}
public boolean isOpen() {
return session.isOpen();
}
public void sendFrame(byte[] frame) {
try {
session.getRemote().sendBytes(ByteBuffer.wrap(frame));
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
}
}