package com.wasu.cs.module;
import android.content.Context;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.text.TextUtils;
import com.wasu.authsdk.AuthSDK;
import com.wasu.authsdk.IAuthInterface;
import com.wasu.cs.utils.Base64;
import com.wasu.module.http.HttpRequestModule;
import com.wasu.module.http.RequestParams;
import com.wasu.module.log.WLog;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;
import basic.app.TvAppLike;
import cn.com.wasu.main.BuildConfig;
import cn.com.wasu.main.ChannelFlavor;
import cn.com.wasu.main.Common;
/**
* 顺序异步执行:
* getPlayUrl ---> get UTC time ---> getVideUrl ---> getPlayUrl
* 外部调用 ---> 获取UTC时间 ---> 获取播放流请求URL ---> 获取并返回播放流(HLS协议)
*
* Created by danxingxi on 2016/5/12.
* 咪咕认证鉴权和播放流获取模块
*/
public class AuthMiguModule {
private static final String TAG = "AuthMiguModule";
private static final int CALLBACK = -1;
/**
* 渠道id
**/
private static final String channelid = "0119_61080001-99000-101400000000001";
/**
* 合作伙伴id
**/
public static final String partnerid = "1002021";
/**
* 产品id
**/
public static final String productid = "2028593060";
/**
* 节目id 由华数WCMS下发,这里为测试用的id
**/
public String contentid = "618765126";
/**
* 第一步验证权限url
**/
public static final String authUrl = "http://aep.cmvideo.cn:1100/streamingapi/getPushUserInfoUrl/v1";
/**
* 第二步获取视频流url
**/
public static final String videoUrl = "http://aep.cmvideo.cn:1100/pushUserInfo/v1";
private static AuthMiguModule mInstance;
/**
* 网络请求线程
**/
private HandlerThread requestThread;
/**
* 网络请求线程的Handler
*/
private Handler requestThreadHandler;
private Context mContext;
private AuthMiguCallBack callBack;
/*是否停止线程*/
private boolean stopThread = false;
/* private的构造函数用于避免外界直接使用new来实例化对象 */
private AuthMiguModule() {
}
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == CALLBACK) {
if (callBack != null) {
if (msg.arg1 == -1) {
callBack.result("-1", "获取播放流失败", "");
} else if (msg.arg1 == 0) {
callBack.result("0", "SUCCESS", playUrl);
}
}
}
}
};
/**
* 获取单例
*
* @return
*/
public static AuthMiguModule getInstance() {
if (null == mInstance) {
synchronized (AuthMiguModule.class) {
if (null == mInstance) {
mInstance = new AuthMiguModule();
}
}
}
return mInstance;
}
public void init(Context context) {
mContext = context;
}
/**
* 获取咪咕视频播放流 对外接口
*
* @param mContentid 资产ID
* @param authMiguCallBack 获取回调
*/
public void getPlayUrl(String mContentid, AuthMiguCallBack authMiguCallBack) {
if (mContentid == null || TextUtils.isEmpty(mContentid) || authMiguCallBack == null) {
throw new IllegalArgumentException("参数不能为空");
}
stopThread = false;
this.contentid = mContentid;
this.callBack = authMiguCallBack;
if (requestThread == null) {
requestThread = new HandlerThread("requestThread");
requestThread.start();
}
if (requestThreadHandler == null) {
requestThreadHandler = new Handler(requestThread.getLooper());
}
requestThreadHandler.post(new GetUTCTask());
}
/**
* 根据contentid请求获取播放流的URL
*
* @param mContentid 资产id
* @param mCreated 实时时间
*/
private void getVideoUrl(String mContentid, String mCreated) {
/**请求header**/
final Map header = new HashMap();
header.put("User-Agent", "Dalvik/v3.1.31 (Linux; U; Android 1.2.0-R-20140505.1720; WASU_A200f Build/JDQ39)");
header.put("Referer", "http://cms.wasu.tv");
/**app请求时产生的一个随机数**/
String Nonce = "6c2e8a85717641a79c71c13109d6d2e6";
/**随机数生成时间**/
String Created = mCreated;
String strTemp = Nonce + Created + Common.miguSecretKey;
String passwordDigest = string2SHA2Base64(strTemp);
/**header部分Authorization参数**/
String Authorization = "WSSE realm=\"SDP\", profile=\"UsernameToken\", type=\"AppKey\"";
/**header部分X-WSSE参数**/
StringBuffer sbXWSSE = new StringBuffer();
sbXWSSE.append(" UsernameToken ");
sbXWSSE.append(" Username = " + "\"" + Common.miguAppKey + "\",");
sbXWSSE.append(" PasswordDigest=" + "\"" + passwordDigest + "\",");
sbXWSSE.append(" Nonce=" + "\"" + Nonce + "\",");
sbXWSSE.append(" Created=" + "\"" + Created + "\"");
WLog.d(TAG, "X-WSSE-->" + sbXWSSE.toString());
header.put("Host", "aep.sdp.com");
header.put("Authorization", Authorization);
header.put("X-WSSE", sbXWSSE.toString());
WLog.d(TAG, "header-->" + header.toString());
/**组装请求body**/
String requestBody = "{\"partnerid\":\"" + partnerid + "\",\"channelid\":\"" + channelid + "\",\"contentid\":\"" +
contentid + "\",\"productid\":\"" + productid + "\",\"ratelevel\":\"3\",\"nettype\":\"4\"}";
RequestParams params = new RequestParams(RequestParams.Method.POST, authUrl, header, requestBody.getBytes(), new RequestParams.RequestListener() {
@Override
public boolean onResponse(int i, String s, int i1, Object o) {
if (s != null) {
try {
JSONObject jsonObject = new JSONObject(s);
String resultcode = jsonObject.optString("resultcode");
String desc = jsonObject.optString("desc", "error");
String url = jsonObject.optString("playurl", "");
if (TextUtils.isEmpty(url)) {
if (callBack != null) {
WLog.e(TAG, "咪咕视频流获取失败,请检查参数后重试!");
callBack.result(resultcode, desc, "");
}
} else {
requestThreadHandler.post(new GetPlayerUrlTask(url, header));
}
} catch (JSONException e) {
e.printStackTrace();
}
} else {
//生成异常并抛出
throw new IllegalArgumentException("请检查请求参数是否正确!");
}
return false;
}
});
HttpRequestModule.getInstance().addTask(params);
}
/**
* 获取视频播放流
*/
String playUrl;
class GetPlayerUrlTask implements Runnable {
String url;
Map header;
public GetPlayerUrlTask(String mUrl, Map mHeader) {
WLog.d(TAG, "IP--->" + TvAppLike.getIpAddress());
String tvid = AuthSDK.getInstance().getValue(IAuthInterface.KEY_TVID);
WLog.d(TAG, "TVID--->" + tvid);
this.url = mUrl + "&Id_type=2" + "&userid=" + tvid + "&ipaddress=" + TvAppLike.getIpAddress();
this.header = mHeader;
}
@Override
public void run() {
if (!stopThread) {
try {
URL url2 = new URL(url);
HttpURLConnection conn = (HttpURLConnection) url2.openConnection();//生成连接对象
conn.setRequestProperty("Host", header.get("Host"));
conn.setRequestProperty("Authorization", header.get("Authorization"));
conn.setRequestProperty("X-WSSE", header.get("X-WSSE"));
conn.setRequestMethod("GET");
/**禁止重定向**/
conn.setInstanceFollowRedirects(false);
conn.connect(); //发出连接
playUrl = conn.getHeaderField("Location");
Message msg = new Message();
msg.what = CALLBACK;
if (playUrl != null && !TextUtils.isEmpty(playUrl)) {
WLog.d(TAG, "Location-->" + playUrl);
/*if (callBack != null) {
callBack.result("0", "SUCCESS", playUrl);
}*/
msg.arg1 = 0;
} else {
/*callBack.result("-1", "获取播放流失败", "");*/
msg.arg1 = -1;
}
handler.sendMessage(msg);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 从网络获取UTC标准时间
*/
class GetUTCTask implements Runnable {
public GetUTCTask() {
}
@Override
public void run() {
if (!stopThread) {
URL url = null;//取得资源对象
String Created = null;
try {
url = new URL((BuildConfig.FLAVOR.equalsIgnoreCase(ChannelFlavor.LETV_MARKET) ? "https://letv-ds.wasu.tv" : "http://tang-ds.cs.wasu.tv") + "/now");
HttpURLConnection uc = (HttpURLConnection) url.openConnection();//生成连接对象
uc.connect(); //发出连接
InputStream inStrm = uc.getInputStream();
String result = getEncodedData(inStrm);
WLog.d(TAG, "result-->" + result);
if (result == null || result.equals("")) {
if (callBack != null) {
callBack.result("-1", "获取UTC时间失败", "");
}
return;
}
inStrm.close();
String strTime = result.split("\\.")[0] + result.split("\\.")[1];
WLog.d(TAG, "strTime-->" + strTime);
long ld = Long.parseLong(strTime.trim());
// long ld = uc.getDate(); //取得网站日期时间
Date date = new Date(ld); //转换为标准时间对象
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
format.setTimeZone(TimeZone.getTimeZone("UTC"));
Created = format.format(date);
if (Created != null) {
WLog.d(TAG, "UTC time:" + Created);
getVideoUrl(contentid, Created);
} else {
if (callBack != null) {
callBack.result("-1", "获取UTC时间失败", "");
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 此方法用于从输入流中获取数据
*
* @param is 接收来自客户端socket对应的输入流
* @return 返回endodedData
* @throws IOException 抛出的异常,统一在run函数处理
*/
private String getEncodedData(InputStream is) throws IOException {
byte[] maxBuffer = new byte[1024 * 64];
int length = 0;
int lengthTemp = 0;
while (-1 != (lengthTemp = is.read(maxBuffer))) {
length += lengthTemp;
if (length >= 1024 * 64) {
WLog.d(TAG, "读入的数据超过1024 * 64");
break;
}
}
byte[] endodedData = new byte[length];
System.arraycopy(maxBuffer, 0, endodedData, 0, length);
return new String(endodedData);
}
/**
* 请求咪咕视频播放流回调接口
*/
public interface AuthMiguCallBack {
/**
* @param resultcode 结果码,0表示成功,其它表示失败。
* @param desc 结果描述信息。
* @param playUrl 播放流,请求成功后返回播放流,请求失败返回""空字符串
*/
public void result(String resultcode, String desc, String playUrl);
}
/**
* 移除回调监听
*/
public void removeCallBackLisenter(){
if(callBack!=null){
callBack = null;
}
}
/**
* 把一个字符串先进行HA256加密,然后转换为Base64的格式
*
* @return
*/
private String string2SHA2Base64(String str) {
if (str != null) {
byte[] passwd = str.getBytes();
MessageDigest alga = null;
try {
alga = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
byte[] strSha = alga.digest(passwd);
return Base64.encodeToString(strSha, false);
} else {
return null;
}
}
/**
* app退出后消废线程
*/
public void destory() {
stopThread = true;
if (requestThread != null) {
requestThread.quit();
requestThread.interrupt();
}
WLog.d(TAG, "destory authmigumodule");
}
}