2015年3月11日 星期三

[Android] MediaPlayer RTSP 串流

MediaPlayer如果要播放串流,只要在setDataSource()裡設定串流路徑即可,
但,如果是需要帳號和密碼呢?
加密有二種格式:
1. Basic Authentication

Context context = getApplicationContext();  
sUrl = "rtsp://xxxx";  
sAccount = "xx";  
sPassword = "xx";  
Uri source = Uri.parse(sUrl);  
Map<String, String> headers = getRtspHeaders();  
mediaPlayer.setDataSource(context, source, headers);

Map<String, String> getRtspHeaders() {  
  Map<String, String> headers = new HashMap<String, String>();  
   String basicAuthValue = getBasicAuthValue(sAccount, sPassword);  
   headers.put("Authorization", basicAuthValue);  
   return headers;  
}  
private String getBasicAuthValue(String usr, String pwd) {  
   String credentials = usr + ":" + pwd;  
   int flags = Base64.URL_SAFE | Base64.NO_WRAP;  
   byte[] bytes = credentials.getBytes();  
   return "Basic " + Base64.encodeToString(bytes, flags);       
}    
上面是處理basic authentication的方式,
另外一個簡單的方式,是在路徑裡直接給定帳號和密號,例如: sUrl = "rtsp://admin:pwd@xxxx";

2. Digest Authentication
原本以為,如果是digest authentication,用sUrl = "rtsp://admin:pwd@xxxx"可能也可以, 
但總是得到"error 100, Media server died"之類的錯誤訊息,
  查了一下網路,得到的大都是 MediaPlayer不支援rtsp digest authentication的答案, 
原本想放棄了,某天心血來潮,想說用Wireshark來抓一下封包看看,
結果發現,
在RTSP DESCRIBE封包裡,它的格式都對啊,也支援digest authentication,
那為何還是得到"401 unauthorized"的Reply呢?
 (以上的截圖,有可能不是原來用MediaPlayer時所抓的,日子久了,有點忘記,但以下的分析的確是MediaPlayer的)
研究了一下DESCRIBE封包,username沒錯,uri沒錯,nonce是前一次發DESCRIBE時,RTSP server reply回來的,比了一下,也沒錯,
難道,是response算錯了?
response= md5(md5(username:realm:password):nonce:md5(uri));
自己手動算了一下,耶?真的有問題...
自己算的response和DESCEIBE 封包裡的response不一樣,
沒辦法,只好去看一下android裡的有關authentication 的 source codes,
原來在ARTSPConnection.cpp裡,它在算response時,
所用的realm不是從RTSP server Reply時取出的,
而是hard code成"Streaming Server",
難怪算出來的response不對,
雖然發現原因了,但好像也不能幹嘛,
因為我們只能透過 setDataSource(), 之後的事,有問題,也無能為力...
看來,要用RTSP Digest Authentication,只能放棄 MediaPlayer,改採它法

沒有留言:

張貼留言