私はVOIPアプリケーション用のJavaで適応ジッタバッファの実装を探しています。私はアプリケーション用の固定ジッタバッファを書きましたが、ネットワークの品質が悪いため、バッファアンダーランまたはバッファオーバーランの問題に遭遇します。Javaでのジッタバッファの実装
適応型ジッタバッファのJavaベースの実装は、アプリケーションで直接使用することも、参照として使用することもできます。
ご協力いただければ幸いです。
おかげ
私はVOIPアプリケーション用のJavaで適応ジッタバッファの実装を探しています。私はアプリケーション用の固定ジッタバッファを書きましたが、ネットワークの品質が悪いため、バッファアンダーランまたはバッファオーバーランの問題に遭遇します。Javaでのジッタバッファの実装
適応型ジッタバッファのJavaベースの実装は、アプリケーションで直接使用することも、参照として使用することもできます。
ご協力いただければ幸いです。
おかげ
私はしばらくの間、(Cけれども中)この非常に問題に取り組んできた、と私はそれを持っていると思うちょうどその時、インターネットが忙しいか、そうでなければ、どこかの変更やブームを取得!もう少し不安定なオーディオ。まあ。私は今それが舐められていると確信しています。
以下のアルゴリズムを使用して、私は本当に良い音質のサウンドを得ています。私はそれを同じネットワーク条件で実行した他のソフトフォンと比較しています。
私がまず行うことは、登録しているPBXや他のSIPプロキシがUA(ソフトフォン)のローカルネットワーク上にあるかどうかを調べることです。
そうであれば、自分のジッタバッファを100msと定義し、そうでなければ200msを使用します。そうすれば、できる限り私の待ち時間を制限することができます。 200ミリ秒でさえ、顕著な会話上のトラブルやオーバートークを引き起こしません。
So.次に、あなたが利用できるタイプのシステムカウンタを使用します。 Windows = GetTickCount64()は、最初のパケットが再生のために入ったミリ秒の精度で変数を埋めます。その変数 "x"を呼んでみましょう。
Then((GetTickCount64() - x)> jitterbuffer)がtrueの場合、そのバッファで再生を開始します。
ストレートフォワード固定長ジッタバッファの実装。ここでトリッキーなビットです。
私は再生するためにバッファリングするためにmuLawからPCMのようなRTPフレームをデコードしていますが、オーディオフレームの平均絶対振幅を計算し、再生のためにフレームと共に保存します。
私はそうのような構造体を持っていることによって、この操作を行います。
はtypedef struct tagCCONNECTIONS {
char binuse;
struct sockaddr_in client;
SOCKET socket;
unsigned short media_index;
UINT32 media_ts;
long ssrc;
unsigned long long lasttimestamp;
int frames_buffered;
int buffer_building;
int starttime;
int ssctr;
struct {
short pcm[160];
} jb[AUDIO_BUFFER]; /* Buffered Audio frame array */
char jbstatus[AUDIO_BUFFER]; /* An array containing the status of the data in the CCONNETIONS::jb array */
char jbsilence[AUDIO_BUFFER];
int jbr,jbw; /* jbr = read position in CCONNECTIONS::jb array, jbw = write position */
short pcms[160];
char status;
/* These members are only used to buffer playback */
PCMS *outraw;
char *signal;
WAVEHDR *preparedheaders;
/**************************************************/
DIALOGITEM *primary;
int readptr;
int writeptr;
} CCONNECTIONS;
[OK]を、tagCCONNECTIONSに気づく:: jbsilence [AUDIO_BUFFER]構造体のメンバ。このようにして、tagCCONNECTIONS :: jb [x] .pcm []のデコードされたオーディオフレームごとに、そのフレームが可聴であるかどうかに対応するデータがあります。
これは、再生しようとしているオーディオフレームごとに、そのフレームが聞こえるかどうかに関する情報があることを意味します。
また...
#define READY 1
#define EMPTY 0
tagCCONNECTIONS :: jbstatus [AUDIO_BUFFER]フィールドには、私たちが演奏を考えている特定のオーディオフレームがREADYまたは空の場合、私たちは知ってみましょう。バッファアンダーフローの理論的なケースでは、空でなければなりません。その場合、通常はREADYになるのを待ってから再生を開始します...
私のルーチンでは、主な機能。 1つはpushframe()、もう1つはpopframe()です。
ネットワーク接続を開き、muLawをPCMに変換するRTPコールpushframe()を受信するスレッドは、フレームの平均絶対振幅を計算し、聞こえないほど静かであればサイレントとマークし、:: jbstatus [x]はREADY
その後jitterbuffer時間が続い
if ((GetTickCount64() - x) > jitterbuffer) {...}
によって、再び、期限が切れている場合は、次のフレームを再生する場合、音声を果たしている私のスレッドで、私たちはまず、我々がチェックチェックなどREADY(実際にいっぱいになったことを意味する)です。
次に、AFTER THAT FRAMEがREADYであるかどうか、またAUDIBLEかSILENTかどうかを確認します。
***重要
基本的に、我々は200msのジッタバッファが10枚の20msの音声フレームを保持できることを知っています。
私たちがキューに入れたオーディオフレームの数が最初の200msのジッタバッファ遅延(オーディオの保存)の後であれば、私は「buffer_building」モードと呼ばれるものに入ります。再生予定の次のオーディオフレームが無音の場合、ジッタバッファがまだいっぱいではなく、まだ20ミリ秒離れていますが、私たちは前のフレームを再生します今は「NEXTフレーム」なので、それは「サイレント」です...もう一度。サイレントフレームを再生せずに、沈黙の期間を使用してインバウンドフレームを待ってバッファをリフィルします。
tagCCONNECTIONS::lasttimestamp = GetTickCount64() - (jitterbuffer-20);
これは沈黙を「仮定」されていたであろうものを中に完全な沈黙の期間を持っていますが、バッファは、それ自体を補充することができます。それから私はフル10フレームがいっぱいになったら、 "buffer_building"モードから出て、オーディオを再生します。
長時間の人が話している可能性があり、静かにすることができないため、フルバッファから1フレーム短い場合でも、「buffer_building」モードに入ります。これにより、 "buffer_building"モード中であってもバッファが急速に使い果たされる可能性があります。
今...「沈黙とは何ですか?」私はあなたが聞くのを聞きます。
int total_pcm_val=0;
/* int jbn= whatever frame we're on */
for (i=0;i<160;i++) {
total_pcm_val+=ABS(cc->jb[jbn].pcm[i]);
}
total_pcm_val/=160;
if (total_pcm_val < 200) {
cc->jbsilence[jbn] = 1;
}
を今、私は実際に保つことを計画しています、次のように私はいじりでは、私はハード200未満の平均ABSOLUTE 16ビットPCM振幅を持つ任意のフレームとして沈黙をコード化されてきた私はこれを理解します現在のオーディオフレームの振幅が全体の平均振幅の5%以下であれば、そのフレームは無音と考えられます。しかし、そのような風や背景のノイズが多い場合、 "沈黙"の定義は適応することができます。私はそれに取り組まなければなりませんが、それがあなたのジッタバッファを補充する鍵だと信じています。
重要な情報が聞こえない場合や、実際の情報(声)がはっきりと表示されないようにしてください。
こちらがお役に立てば幸いです。私は物事を説明することになると少しばかり気になりますが、私はVoIPアプリケーションの音に非常に満足しています。
継続的な音源(音楽のストリーミングなど)の枯渇を処理するための合理的なスキームについて知っている –
本当の有用な記事! 1つのフレーム(最初のフレーム)でも再生した後、プログラムがPLAYモードから「バッファ構築」モードに切り替わるとはどういう意味ですか?その場合、プログラムは最初のフレームを再生するたびに、再生モードからバッファ構築モードに切り替えるだけです。あなたは明確にしていただけますか? –
あなたの問題は何ですか?推定バッファサイズが必要ですか? (キューイングの理論が役立つかもしれません)か、動的メモリ割り当てですか?または、他の何か? – Matthias
現在のジッタに基づいてバッファサイズを変えたいと思っています。 –
あなたはどこに詰まっていますか? – Matthias