有個項目涉及到多媒體訊息的收發, 於是研究了下wm上面該如何收發多媒體訊息, 得到的結論令人非常的遺憾, 系統沒有提供這樣的直接的介面, 也很難找到變通的辦法, 因為在wm平台上, 多媒體訊息程式是由硬體廠商來實現的.
也就是說我不得不自己從頭到尾的來實現多媒體訊息的收發.
一 WM上多媒體訊息的發送
多媒體訊息是建立在wap協議之上的一種應用, 所以要發送多媒體訊息首先要在裝置上建立wap串連.(是不是一定要建立wap串連, 是不是一定要走wap協議, 實際上這取決於網路服務商的wap網關和多媒體訊息伺服器, 比如廣州移動在前段時間是支援http發送多媒體訊息的, 目前的廣州聯通支援net網路下wsp發送多媒體訊息).
但是為了保證我們的程式能夠更具有通用性, 最好是選擇wap串連, 並且走wap協議用wsp發送.
1 http方式發送
原則上, 只要網關支援wap2.0協議, 就可以用http發送的. 用http發送時, 先與網關建立tcp/ip串連(目前移動和聯通的http網關都是10.0.0.172:80), 然後發送一個post請求.下面便是一個在廣州移動發送成功的post請求.(現在不知道為什麼發不成功了)
//MmscName為多媒體訊息伺服器, 移動為"http://mmsc.monternet.com", 聯通為"http://mmsc.myuni.com.cn"
string headerBuffer = "POST http://" + MmscName + " /HTTP /1.1/r/n";
headerBuffer += "Accept: image/png, image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*/r/n";
//網關地址, 目前移動聯通都是 10.0.0.172:80
headerBuffer += "Host: 10.0.0.172:80/r/n";
headerBuffer += "X-Online-Host: " + MmscName + "/r/n";
headerBuffer += "Pragma: no-cache/r/n";
headerBuffer += "Cache-Control: no-cache/r/n";
headerBuffer += "Connection: Keep-Alive/r/n";
headerBuffer += "Accept-Encoding: deflate, gzip/r/n";
headerBuffer += "User-Agent: SAMSUNG-SGH-E908/NetFront 3.2/WAP2.0 Profile/MIDP-2.0 Configuration/CLDC-1.1/r/n";
headerBuffer += "Accept: application/vnd.wap.mms-message, image/vnd.wap.wbmp, image/png, image/jpeg, image/gif, text/x-iMelody, text/x-imelody, application/x-midi, audio/midi, audio/mid, audio/x-mid, image/bmp, audio/mp3, audio/x-midi, audio/amr, application/vnd.smaf, application/vnd.wap.mms-message x-wap-profile:http://wap.samsungmobile.com/uaprof/e908_10.xml/r/n";
//s_length 為多媒體訊息包的長度
headerBuffer += "Content-Length:" + s_length + "/r/n";
headerBuffer += "Content-Type:application/vnd.wap.mms-message/r/n/r/n";
//在/r/n/r/n之後接的就是多媒體訊息包資料了
發送完成之後, 等待網關的響應, 返回200 ok, 表明多媒體訊息發送成功, 否則就是發送失敗. 失敗的原因有可能是http頭組錯了, 也可能是mms包錯了, 但更可能的原因還是網關不支援.
2 wsp方式發送
wsp的發送要複雜一些, 需要瞭解wap wtp wsp 這一套協議. WAP-230-WSP-20010705-a, WAP-224-WTP-20010710-a 這兩份文檔中有詳細的描述.
wsp方式發送完成之後, 網關也會返回結果, 但是有時候解析出來的結果表明沒有發送成功, 但是對方卻正確的收到了多媒體訊息.不知道是wsp發送有問題, 還是mms包組得有問題.
使用wsp方式放送時, 使用的網關連接埠是1920.
3 mms的打包
mms有兩種打包方式, 比較簡單的是application/vnd.wap.multipart.mixed, 複雜一點的是 application/vnd.wap.multipart.related. 我的多媒體訊息程式實際上是要發送一個附件檔案給對方, 所以只需要application/vnd.wap.multipart.mixed方式就可以了,所以我只研究了這種簡單的方式.
使用application/vnd.wap.multipart.mixed方式組裝的MM 顧名思義是所有的訊息內容混合在一起沒有時間上的順序,所有的訊息內容MMSContent所指向的之間是沒有任何關係的如果說有關係的話就是存放在MM中的時間上的先後但是在顯示這些訊息內容的時候可能就沒有時間上的之後很有可能就是一次顯示出來.
這種方式只需要填寫一些主要的關鍵字, 然後接上多媒體訊息附件資料就可以了.
下面是一個簡單的mms包, 打包過程
//X-Mms-Message-Type(0x8c): m-send-req(0x80)
BYTE* pCurPos = pBuffContent;
*pCurPos = 0x8c; pCurPos++;
*pCurPos = 0x80; pCurPos++;
//ID
*pCurPos = 0x98; pCurPos++;
char* pID = NULL;
GetID( &pID );
strcpy( (char*)pCurPos, pID );
pCurPos += strlen( pID);
*pCurPos = 0x00; pCurPos++;
//X-Mms-MMS-Version(0x8d):v1.0(0x90)
*pCurPos = 0x8d; pCurPos++;
*pCurPos = 0x90; pCurPos++;
//from
*pCurPos = 0x89; pCurPos++;
*pCurPos = 0x01; pCurPos++;
*pCurPos = 0x81; pCurPos++;
//To(0x97)
TCHAR szToCombin[50];
_stprintf( szToCombin, _T("%s%s%s"), _T("+86"), szTo,_T("/TYPE=PLMN") );
*pCurPos = 0x97; pCurPos++;
char* pTo = NULL;
String_WCharToMByte( szToCombin, &pTo );
strcpy( (char*)pCurPos, pTo );
pCurPos += strlen(pTo);
*pCurPos = 0x00; pCurPos++;
//subject
*pCurPos = 0x96; pCurPos++;
char* pSubject = NULL;
String_WCharToMByte( szSubject, &pSubject );
//pSubject = "MmsTest";
strcpy( (char*)pCurPos, pSubject );
pCurPos += strlen(pSubject);
*pCurPos = 0x00; pCurPos++;
//Content-Type: application/vnd.wap.multipart.mixed
*pCurPos = 0x84; pCurPos++;
*pCurPos = 0xa3; pCurPos++;
//multipart,count
*pCurPos = 0x01; pCurPos++;
//headerslen
*pCurPos = 0x0f; pCurPos++;
//附件資料
char* pAttachData = NULL;
String_WCharToMByte( szXmlData, &pAttachData );
//DataLen, 附件資料長度
int iDataTextLen = strlen(pAttachData) + 1;
int iByteLen = 0;
BYTE* pDataLen = encodeUintvar( iDataTextLen, iByteLen );
strncpy( (char*)pCurPos, (char*)pDataLen, iByteLen );
pCurPos += iByteLen;
//*pCurPos = (unsigned char)iDataTextLen; pCurPos++;
//headlen
*pCurPos = 5 + _tcslen(szXmlFileName); pCurPos++;
//uft-8
*pCurPos = 0x83; pCurPos++;
*pCurPos = 0x85; pCurPos++;
//attach file name
char* pAttachFile = NULL;
String_WCharToMByte( szXmlFileName, &pAttachFile );
//pAttachFile = "phone.xml";
strcpy( (char*)pCurPos, pAttachFile );
pCurPos += strlen(pAttachFile);
*pCurPos = 0x00; pCurPos++;
//Charset utf-8
*pCurPos = 0x81; pCurPos++;
*pCurPos = 0xea; pCurPos++;
//attach file content
strcpy( (char*)pCurPos, pAttachData );
pCurPos += strlen( pAttachData );
*pCurPos = 0x00; pCurPos++;
//多媒體訊息包實際長度
iRealLen = pCurPos - pBuffContent;
二 WM上多媒體訊息的接收
個人認為, 在Windows Mobile平台上多媒體訊息的接收比發送更加麻煩. 因為攔截多媒體訊息通知很麻煩, 還得與系統內建的多媒體訊息程式搶時間, 因為如果系統內建的多媒體訊息程式接收完多媒體訊息之後回了ack, 這時我還沒有接收的話那我就收不到了.
1 多媒體訊息通知的攔截.
多媒體訊息通知實際上是一條特殊的簡訊, 在系統的收件匣肯定是看不到得了, 也就是說用普通的mapi從收件匣擷取這條多媒體訊息通知簡訊肯定是不行的了.
我嘗試了用mapirule攔截簡訊的方式來攔截, 發現這條通知簡訊壓根就沒到那個地方.
在網上查到資料有一套api(PushRouter_RegisterClient)是專門用來攔截push訊息的, sdk下還有個sample, 但是我試了兩天, 始終沒有成功.
後來用RIL, 攔截RIL_NOTIFY_MESSAGE訊息, 終於攔到了, 不過總覺得這個辦法不太好.
多媒體訊息通知實際上一段壓縮二進位編碼資料, 在這段資料中包含了多媒體訊息發送方, 主題, 以及url. 這個url實際上就是多媒體訊息的存放地址. 解析這段二進位編碼擷取到url就可以去取多媒體訊息了.
2 多媒體訊息的擷取
多媒體訊息的擷取也需要與wap網關打交道, 自然也需要先建立wap網路連接, 然後與網關(也是192.168.0.172:80) 建立tcp/ip串連, 向網關發送一個get請求就可以了.
char szGetString[MAX_PATH] = ""; //pUrlMbyte 就是上一步擷取到的url多媒體訊息地址
sprintf( szGetString, "GET %s HTTP/1.1/r/n/r/n", pUrlMByte );
網關會給這個get請求響應, 如果發送成功, 會得到如下的響應
HTTP/1.1 200 ok
Content-Type: application/vnd.wap.mms-message
Content-Length: 1301
Connection: Keep-Alive
Proxy-Connection: Keep-Alive
Keep-Alive: timeout=15, max=49
Via: HTTP/1.1 SDJN-PS-WAP2-GW07(infoX-WISG, Huawei Technologies)
Server: mmsc-jn4-rsv.monternet.com
x-mmsc-msg-from: mm1
???9kN4I0hTkVR0???062117015591007101190? J=?+? ?+8613207008167/TYPE=PLMN?8615206300005/TYPE=PLMN? ? <RDWNPB id='3063' />??????? ??<start>?application/smil ?l ???<PHONEBOOK> <NODE name="¥?????¥??(¥??)" cont="5551012
上面的那段明文就是http頭,看到200 ok就表示接收成功了, 在兩個分行符號的後面就是mms資料了, 取出這部分資料進行解析就是了.
3 到這裡並沒有完, 還要給多媒體訊息伺服器回一個ack, 不然多媒體訊息伺服器會認為我們沒有收到多媒體訊息, 會再次發多媒體訊息通知過來.
回ack也是post一個請求到網關.
http://hi.baidu.com/gdoupanguoqing/blog/item/e772fcd00302b086a0ec9c05.html