3

小規模なネットワークで voip over udp を使用する方法を学習しています。いくつかのメソッド呼び出しで必要なすべてをやり遂げる準備ができているライブラリのバンドルがあることは知っていますが、私が言ったように、私は学んでいるので、それがどのように機能するかを確認するために車輪を再発明する必要があります.

私は現在 DatagramPacket クラスを調査していますが、DatagramPacket クラスにヘッダー情報 (つまり、インターリーブを行うために知っておく必要があるパケット順序シーケンス番号) を設定するメソッドがないことに気付きました。

環境を反映する小さなコード:

byte[] block;
DatagramPacket packet; // UDP packet                

/* x Bytes per block , y blocks per second,
   z ms time block playback duration */

block = recorder.getBlock(); // assume I have class that handles audio
                              // recording and returns speech in a
                              // uncompressed form of bytes

packet = new DatagramPacket(block, block.length, clientIP, PORT);

まず、UDP であるため、送信者はパケットをどこかに投げるという単純な事実以外には何も気にしないと思います。そのため、内部にそのようなメソッドはありません。

第二に、私はそれを自分で行う必要があると思います-パケットのシーケンス番号を含む送信されるバイトブロックに余分なバイトを追加しますか? ただし、それを行う場合、バイトがオーディオバイトではなくヘッダーバイトであるかどうかをどのように認識するのでしょうか? 最初のバイトが数値を表していると仮定できますが、バイトは 258 個の数値しか表すことができないことがわかっています。これまでバイトレベルで実際に作業したことはありません。それとも他のテクニックがあるのでしょうか?

簡単に言うと、インターリーブを行うには、順序付けされていないパケットを順序付けできないため、パケットのシーケンス番号を設定する方法を知る必要があります:-)

ありがとうございました、

4

1 に答える 1

6

プログラムが使用するデータ型をバイト配列にシリアライズ/デシリアライズする必要があります。

RTPについて話していると仮定して、これらのフィールドを含むパケットを送信したいとします。RTP 仕様の第 5 章を見てください。

バージョン = 2 パディング = 0 拡張 = 0 CSRC カウント = 1 マーカー = 0 ペイロード タイプ = 8 (G711 alaw) シーケンス番号 = 1234 タイムスタンプ = 1 1 つの CSRC = 4321

簡単にするために整数を使用するか、符号なしの 32 ビット値を処理する必要がある場合は long を使用して、これらをいくつかの変数に入れましょう。

int version = 2;
int padding = 0;
int extension = 0;
int csrcCount = 1;
int marker = 0;
int payloadType = 8;
int sequenceNumber = 1234;
long timestamp = 1;
long ourCsrc = 4321;

byte buf[] = ...; //allocate this big enough to hold the RTP header + audio data

//assemble the first bytes according to the RTP spec (note, the spec marks version as bit 0 and 1, but
//this is really the high bits of the first byte ...
buf[0] = (byte) ((version & 0x3) << 6 | (padding & 0x1) << 5 | (extension & 0x1) << 4 | (csrcCount & 0xf));

//2.byte
buf[1] = (byte)((marker & 0x1) << 7 | payloadType & 0x7f);

//squence number, 2 bytes, in big endian format. So the MSB first, then the LSB.
buf[2] = (byte)((sequenceNumber & 0xff00) >> 8);
buf[3] = (byte)(sequenceNumber  & 0x00ff);

//packet timestamp , 4 bytes in big endian format
buf[4] = (byte)((timestamp & 0xff000000) >> 24);
buf[5] = (byte)((timestamp & 0x00ff0000) >> 16);
buf[6] = (byte)((timestamp & 0x0000ff00) >> 8);
buf[7] = (byte) (timestamp & 0x000000ff);
//our CSRC , 4 bytes in big endian format
buf[ 8] = (byte)((sequenceNumber & 0xff000000) >> 24);
buf[ 9] = (byte)((sequenceNumber & 0x00ff0000) >> 16);
buf[10] = (byte)((sequenceNumber & 0x0000ff00) >> 8);
buf[11] = (byte) (sequenceNumber & 0x000000ff);

これがヘッダーです。オーディオ バイトを にコピーしbuf、 から開始して 1 つのパケットとしてbuf[12]送信できます。buf

さて、上記はもちろん原則を示すためのものであり、RTP 仕様に従って、RTP パケットの実際のシリアライザーは、さらに多くの処理を行う必要があります (たとえば、いくつかの拡張ヘッダーが必要な場合や、複数の CSRC が必要な場合があります。あなたが持っている音声データのフォーマットに応じて正しいペイロードタイプが必要です。それらの音声データを正しくパケット化し、スケジュールする必要があります。たとえば、G.711Alaw の場合、各 RTP パケットに 160 バイトの音声データを入力して送信する必要があります。パケットは 20 ミリ秒ごとに送信されます。

于 2012-02-01T15:48:55.323 に答える