package com.guo.duoduo.airplayreceiver.httpProcess;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.text.DecimalFormat;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.apache.http.HttpStatus;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import com.guo.duoduo.airplayreceiver.MyApplication;
import com.guo.duoduo.airplayreceiver.constant.Constant;
import com.guo.duoduo.airplayreceiver.http.HTTP;
import com.guo.duoduo.airplayreceiver.http.HTTPHeader;
import com.guo.duoduo.airplayreceiver.http.HTTPRequest;
import com.guo.duoduo.airplayreceiver.http.HTTPRequestListener;
import com.guo.duoduo.airplayreceiver.http.HTTPResponse;
import com.guo.duoduo.airplayreceiver.http.HTTPServerList;
import com.guo.duoduo.airplayreceiver.http.HTTPSocket;
import com.guo.duoduo.airplayreceiver.service.RegisterService;
import com.guo.duoduo.airplayreceiver.ui.VideoPlayerActivity;
import com.guo.duoduo.airplayreceiver.utils.BplistParser;
import com.guo.duoduo.airplayreceiver.utils.Debug;
import com.guo.duoduo.airplayreceiver.utils.NetworkUtils;
import io.vov.vitamio.MediaPlayer;
/**
* Created by Guo.Duo duo on 2015/8/31.
*/
public class HttpProcess implements HTTPRequestListener
{
private static final String tag = HttpProcess.class.getSimpleName();
private InetAddress localAddress;
private String localMac;
private HTTPServerList httpServerList;
private int httpPort = 0;
private HTTPSocket reverseSocket;
private String reverseSessionId;
public static Map<String, byte[]> photoCache = Collections
.synchronizedMap(new HashMap<String, byte[]>());
private boolean isPlayingPhoto = false;
private boolean isSlideShow = false;
public HttpProcess() throws IOException
{
initHttpServer();
}
@Override
public void httpRequestReceived(HTTPRequest httpReq)
{
Debug.d(tag, "http request received = \r\n" + httpReq.toString());
String target = httpReq.getURI();
Debug.d(tag, "http uri = " + httpReq.getURI());
// 播放视频的时候 只有target为play的时候带有sessionId, 图片每一个命令都有sessionId
if (target.equals(Constant.Target.SERVER_INFO))
{
HTTPResponse response = new HTTPResponse();
response.setStatusCode(HttpStatus.SC_OK);
response.setHeader("Content-Type", "text/x-apple-plist+xml");
response.setHeader("Date", new Date().toString());
String content = Constant.getServerInfoResponse(localMac
.toUpperCase(Locale.ENGLISH));
response.setHeader("Content-Length", content.length());
response.setContent("\n" + content);
Debug.d(tag, "server info response = \r\n" + response.toString());
httpReq.post(response);
}
else if (target.equals(Constant.Target.REVERSE))
{
HTTPHeader httpHeader = httpReq.getHeader("X-Apple-Session-ID");
if (httpHeader != null)
{
reverseSessionId = httpHeader.getValue();
Debug.d(tag, "reverse session id = " + reverseSessionId);
}
HTTPHeader purposeHeader = httpReq.getHeader("X-Apple-Purpose");
if(purposeHeader != null)
{
String purpose = purposeHeader.getValue();
Debug.d(tag, "http reverse session purpose = " + purpose);
if(purpose != null && purpose.equals("slideshow"))
{
isSlideShow = true;
}
}
reverseSocket = httpReq.getSocket();
HTTPResponse response = new HTTPResponse();
response.setStatusCode(HttpStatus.SC_SWITCHING_PROTOCOLS);
response.setHeader("Connection", "Upgrade");
response.setHeader("Content-Length", 0);
response.setHeader("Upgrade", "PTTH/1.0");
httpReq.post(response);
Debug.d(tag, "reverse response = \r\n" + response.toString());
}
else if (target.equals(Constant.Target.PHOTO))
{
isPlayingPhoto = true;
HTTPResponse response = new HTTPResponse();
response.setStatusCode(HttpStatus.SC_OK);
response.setHeader("Date", new Date().toString());
Message msg = Message.obtain();
msg.what = Constant.Msg.Msg_Photo;
byte[] entityContent = null;
entityContent = httpReq.getContent();
HTTPHeader assetActionHeader = httpReq.getHeader("X-Apple-AssetAction");
HTTPHeader assetKeyHeader = httpReq.getHeader("X-Apple-AssetKey");
if (assetActionHeader != null && assetKeyHeader != null)
{
String assetAction = assetActionHeader.getValue();
String assetKey = assetKeyHeader.getValue();
if (assetAction != null)
{
if (assetAction.equals("cacheOnly"))
{
if (assetKey != null & entityContent != null)
{
if (!photoCache.containsKey(assetKey))
{
photoCache.put(assetKey, entityContent);
}
}
}
else if (assetAction.equals("displayCached"))
{
if (photoCache.containsKey(assetKey))
{
byte[] pic = photoCache.get(assetKey);
if (pic != null)
{
msg.obj = pic;
MyApplication.broadcastMessage(msg);
}
}
else
{
response.setStatusCode(HttpStatus.SC_PRECONDITION_FAILED);
}
}
}
}
else
{
if (entityContent != null)
{
msg.obj = entityContent;
MyApplication.broadcastMessage(msg);
}
}
httpReq.post(response);
}
else if(target.equals(Constant.Target.SLIDER_SHOW))
{
HTTPResponse response = new HTTPResponse();
String returnContent = "";
response.setStatusCode(HttpStatus.SC_OK);
response.setHeader("Date", new Date().toString());
response.setHeader("Content-Type", "text/x-apple-plist+xml");
response.setHeader("Content-Length", returnContent.length());
httpReq.post(response);
}
else if (target.equals(Constant.Target.STOP))
{
HTTPResponse response = new HTTPResponse();
response.setStatusCode(HttpStatus.SC_OK);
response.addHeader("Date", new Date().toString());
response.setHeader("Content-Length", 0);
httpReq.post(response);
Message msg = Message.obtain();
msg.what = Constant.Msg.Msg_Stop;
MyApplication.broadcastMessage(msg);
photoCache.clear(); //清除缓存
//发送一个post stop 消息给apple client
HTTPRequest httpRequest = new HTTPRequest();
httpRequest.setMethod(HTTP.POST);
httpRequest.setSocket(reverseSocket);
HTTPResponse httpResponse = new HTTPResponse();
httpResponse.setHeader("Content-Type", "text/x-apple-plist+xml");
httpResponse.setHeader("X-Apple-Session-ID", reverseSessionId);
String content;
if (isPlayingPhoto)
{
content = Constant.getImageStopEvent();
Debug.d(tag, "stop photo airplay");
}
else
{
content = Constant.getVideoStopEvent();
Debug.d(tag, "stop video airplay");
}
httpResponse.setHeader("Content-Length", content.length());
httpResponse.setContent(content);
httpRequest.post(httpResponse);
}
else if (target.equals(Constant.Target.PLAY)) //播放视频
{
isPlayingPhoto = false;
HTTPHeader httpHeader = httpReq.getHeader("X-Apple-Session-ID");
if (httpHeader != null)
{
reverseSessionId = httpHeader.getValue();
Debug.d(tag, "reverse session id = " + reverseSessionId);
}
HTTPHeader contentTypeHeader = httpReq.getHeader("Content-Type");
if (contentTypeHeader != null)
{
String playUrl = "";
Double startPos = 0.0;
String contentType = contentTypeHeader.getValue();
//如果是来自 iphone 推送的视频
if (contentType.equalsIgnoreCase("application/x-apple-binary-plist")) //<BINARY PLIST DATA>
{
//爱奇艺的视频推送就是这样的,而且有点乱码的感觉
byte[] content = httpReq.getContent();
if(content != null)
{
try
{
String strContent = new String(content, "utf-8");
HashMap map = BplistParser.parse(content);
if(map != null && map.size() > 0)
{
playUrl = (String) map.get("Content-Location");
startPos = (Double) map.get("Start-Position");
}
else
{
int startIndex = strContent.indexOf("http://");
int endIndex = strContent.indexOf("\"");
playUrl = strContent.substring(startIndex, endIndex);
Debug.d(tag, "爱奇艺 视频地址:" + playUrl);
}
Message msg = Message.obtain();
HashMap<String, String> mapUrl = new HashMap<String, String>();
mapUrl.put(Constant.PlayURL, playUrl);
mapUrl.put(Constant.Start_Pos, Double.toString(startPos));
msg.what = Constant.Msg.Msg_Video_Play;
msg.obj = mapUrl;
MyApplication.getInstance().broadcastMessage(msg);
} catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
}
}
else if (contentType.equalsIgnoreCase("text/parameters")) //iTunes 推送的视频 或者是优酷之类的
{
String requestBody = new String(httpReq.getContent());
if (!TextUtils.isEmpty(requestBody))
{
playUrl = requestBody.substring(
requestBody.indexOf("Content-Location:")
+ "Content-Location:".length(),
requestBody.indexOf("\n",
requestBody.indexOf("Content-Location:")));
startPos = Double.valueOf(requestBody.substring(
requestBody.indexOf("Start-Position:")
+ "Start-Position:".length(),
requestBody.indexOf("\n",
requestBody.indexOf("Start-Position:"))));
playUrl = playUrl.trim();
Debug.d(tag, "airplay playUrl = " + playUrl + "; start Pos ="
+ startPos);
Message msg = Message.obtain();
HashMap<String, String> map = new HashMap<String, String>();
map.put(Constant.PlayURL, playUrl);
map.put(Constant.Start_Pos, Double.toString(startPos));
msg.what = Constant.Msg.Msg_Video_Play;
msg.obj = map;
MyApplication.getInstance().broadcastMessage(msg);
}
else
{
Debug.d(tag, "http content = null");
}
}
}
HTTPResponse response = new HTTPResponse();
response.setStatusCode(HttpStatus.SC_OK);
response.setHeader("Date", new Date().toString());
response.setHeader("Content-Length", 0);
httpReq.post(response);
}
//优酷视频通过这个进行client和server的时间同步
else if (target.startsWith(Constant.Target.SCRUB))
{//post 就是 seek操作,如果是get则是或者播放的position和duration
if (target.indexOf("?position=") > 0)
{//post方法
int index = target.indexOf("?position=") + 10;
float pos = new Float(target.substring(index));
Log.d(tag, "airplay seek position =" + pos); //此时的单位是秒
Message msg = Message.obtain();
msg.what = Constant.Msg.Msg_Video_Seek;
msg.obj = pos;
MyApplication.getInstance().broadcastMessage(msg);
}
else
//get方法 获取播放的duration and position
{
long duration = 0;
long curPos = 0;
if (!VideoPlayerActivity.isVideoActivityFinished())
{
duration = VideoPlayerActivity.getDuration();
curPos = VideoPlayerActivity.getCurrentPosition();
duration = duration < 0 ? 0 : duration;
curPos = curPos < 0 ? 0 : curPos;
Log.d(tag, "airplay get method scrub: duration=" + duration
+ "; position=" + curPos);
//毫秒需要转为秒
DecimalFormat decimalFormat = new DecimalFormat(".000000");//
String strDuration = decimalFormat.format(duration / 1000f);
String strCurPos = decimalFormat.format(curPos / 1000f);
//must have space, duration: **.******, or else, apple client can not syn with android
String returnBody = "duration: " + strDuration + "\nposition: "
+ strCurPos;
Log.d(tag, "airplay return scrub message = " + returnBody);
HTTPResponse response = new HTTPResponse();
response.setStatusCode(HttpStatus.SC_OK);
response.setHeader("Date", new Date().toString());
response.setHeader("Content-Length", returnBody.length());
response.setContent(returnBody);
httpReq.post(response);
}
else
//播放视频的界面退出后,手机端也要退出
{
Debug.d(tag, "get scrub Video Activity is Finished");
//发送一个post消息给apple client
if (reverseSocket != null && reverseSocket.getSocket() != null
&& reverseSocket.getSocket().isConnected())
{
HTTPRequest httpRequest = new HTTPRequest();
httpRequest.setMethod(HTTP.POST);
httpRequest.setSocket(reverseSocket);
HTTPResponse httpResponse = new HTTPResponse();
httpResponse.setHeader("Content-Type", "text/x-apple-plist+xml");
httpResponse.setHeader("X-Apple-Session-ID", reverseSessionId);
String content = Constant.getVideoStopEvent();
httpResponse.setHeader("Content-Length", content.length());
httpResponse.setContent(content);
httpRequest.post(httpResponse);
}
else
{
Debug.d(tag, "get scrub reverse socket is null");
}
}
}
}
else if (target.startsWith(Constant.Target.RATE)) //设置播放的速率(其实就是播放和暂停)
{
int playState = Constant.Msg.Msg_Video_Resume;
String status = Constant.Status.Status_play;
if (target.indexOf("value=1") > 0) //正常速率播放
{
playState = Constant.Msg.Msg_Video_Resume;
status = Constant.Status.Status_play;
}
else if (target.indexOf("value=0") > 0) //暂停播放了
{
playState = Constant.Msg.Msg_Video_Pause;
status = Constant.Status.Status_pause;
}
Message msg = Message.obtain();
msg.what = playState;
MyApplication.getInstance().broadcastMessage(msg);
HTTPResponse response = new HTTPResponse();
response.setStatusCode(HttpStatus.SC_OK);
response.setHeader("Date", new Date().toString());
response.setHeader("Content-Length", 0);
httpReq.post(response);
}
//腾讯视频是发送这个命令的。
else if (target.equalsIgnoreCase(Constant.Target.PLAYBACK_INFO))
{
}
}
private void initHttpServer() throws IOException
{
Log.d(tag, "airplay init http server");
localAddress = NetworkUtils.getLocalIpAddress();
if(localAddress == null)
{
return;
}
String[] str_Array = new String[2];
try
{
str_Array = NetworkUtils.getMACAddress(localAddress);
String strMac = str_Array[0];
localMac = strMac.toUpperCase(Locale.ENGLISH);
Log.d(tag, "airplay local mac = " + localMac);
}
catch (Exception e)
{
e.printStackTrace();
}
InetAddress[] binds = new InetAddress[1];
binds[0] = localAddress;
httpServerList = new HTTPServerList(binds, RegisterService.AIRPLAY_PORT);
}
public int getHTTPPort()
{
return httpPort;
}
public void setHTTPPort(int port)
{
httpPort = port;
}
private HTTPServerList getHTTPServerList()
{
return httpServerList;
}
public void start()
{
stop();
if(localAddress != null)
{
int bindPort = getHTTPPort();
HTTPServerList httpServerList = getHTTPServerList();
httpServerList.open(bindPort);
httpServerList.addRequestListener(this);
httpServerList.start();
}
}
public void stop()
{
HTTPServerList httpServerList = getHTTPServerList();
if(httpServerList != null)
{
httpServerList.stop();
httpServerList.close();
httpServerList.clear();
}
}
}