看到很多很多人持續在問這個問題。
以前我也聽說,好像kvm底層實現不太支持j2me來做streaming video/audio,但我不知道那人為什麼這麼說。
那麼現在國外有一個人提出下面這種思路,並且號稱在Nokia6260[相關數據:諾基亞 6260 Nokia62602.0 (3.0436.0) SymbianOS7.0s Series602.1 ProfileMIDP-2.0 ConfigurationCLDC-1.0]
上真實實現了(兩種網絡方式:藍牙和GPRS都試驗過),但我懷疑他的前提條件是“你的手機必須允許同時實現player的多個實例進入prefetched狀態(預讀取聲音流)”:
第一步:
聲明兩個Player;
第二步:
HttpConnection開始向服務器請求該audio文件的第一部分字節,我們定這次讀取的字節數為18KB;
第三步:
等第一部分數據到位後,Player A開始realize和prefetch,並開始播放;
第四步:
在Player A播放同時,(18KB的amr數據可以播放10秒鐘),HttpConnection繼續請求第二部分數據(假設GPRS每秒鐘傳輸3KB,那麼18KB需要傳輸6秒,算上前後通訊損失的時間,應該不會超過10秒鐘);
第五步:
第二部分數據到位後,假設Player A還沒有播放完(這需要調整你的每一部份數據字節數來使得假設成立),那麼將數據喂給Player B讓它realize和prefetch;
第六步:
Player A播放完後,得到事件通知,於是讓Player B開始播放。
如此往復。
大家看看此種理論可否。
我自己在nokia 7610上測試了一下,我上面說的前提被證明是可行的:“你的手機必須允許同時實現player的多個實例進入prefetched狀態(預讀取聲音流)”。真實Nokia手機確實可以如此:兩個線程中各自有一個Player,都開始做m_player.realize();和m_player.prefetch();,然後等候。
先播放線程1的Player,等她播放完後,通過
* * 本類實現了PlayerListener接口。通過這個事件來告知媒體已經播放完畢 */ public void playerUpdate(Player player, String event, Object data){ if(event == PlayerListener.END_OF_MEDIA){ try{ System.out.println("playerUpdate>>PlayerListener.END_OF_MEDIA"); stopGauge(); playForeground(); }catch(Exception e){ e.printStackTrace(); } } }
來通知第二個線程的Player播放。
這樣是可以的。
qinjiwy說“可以,不過前提是該音頻文件允許分段播放,有些音頻文件就是不允許的.”,你說得對。確實有很多格式的媒體文件不支持分段播放。我所知道的是wav可以,mp3也可以。
服務端每次只讀取這兩種媒體文件的某一部分,如果是mp3文件的話,我暫時不知道是否每次需要加上特殊的頭信息。
但是如果是WAV文件,那麼肯定每次都要加上WAV特定的頭,要不然Player也無法播放。
這種形式肯定是可行的。因為以前我在VC++上寫Text To Speech程序時,就是這麼做的:WAV文件的前若干個字節肯定是頭信息,這是一定的,隨後跟的全是RAW DATA;我每一次讀取WAV的RAW DATA若干字節後,傳給我的播放線程,他需要給這段RAW DATA前加上一個WAV HEADER,然後就可以正常播放了。
Server side java code:
public void transfer(DataOutputStream output) { try{ int i = 0; int auglis = 50058; //chunk size //if it is wav file, we need to edit header: //audio[4] = (byte)0x8A; // audio[5] = (byte)0xC3; // audio[6] = (byte)0x00; // audio[7] = (byte)0x00; // audio[54] = (byte)0x50; // audio[55] = (byte)0xC3; // audio[56] = (byte)0x00; // audio[57] = (byte)0x00; byte[] tmp = new byte[50058]; int countBytes= 0; int headerup = 32; //mp3 header is 32 bytes. while(i<50058){ tmp[i] = audio[i]; //byte array audio is byte array from mp3 file i++; countBytes++; } output.writeInt(50058); //write to midlet, that chunk size will be 50058 output.write(tmp); //write chunk itself boolean varam = true; //booleand that will become false, when file ends while(varam){ int tmplen = garums - countBytes; //check if it is not last chunk int o=50058; if(tmplen>50058){ //if it is not last chunk o = 50058; } else{ o = tmplen+headerup; // if it is last chunk tmp = new byte[o]; varam = false; //out while loop will end } int z = 0; while(z<32){ //write 32 byte header to chunk tmp[z] = audio[z]; z++; countBytes++; } while(z<o){ //white chunk it self tmp[z] = audio[i]; z++; i++; countBytes++; } headerup = headerup +32; output.writeInt(o); //white size of chunk (typically 50058) output.write(tmp); //white chunk itself } } catch (Exception e) {} }