Java UDP audio

cs_eikichi Messages postés 9 Date d'inscription mercredi 26 mars 2003 Statut Membre Dernière intervention 9 mai 2011 - 25 avril 2007 à 12:37
cs_couco Messages postés 2 Date d'inscription mercredi 17 mars 2004 Statut Membre Dernière intervention 26 avril 2007 - 26 avril 2007 à 15:51
Bonjour a tous,

Je cherche à transférer un flux audio en utilisant des sockets en UDP.

Le flux est déjà subdivisé en plusieurs petits paquets UDP que j'envoie
en permanence du Client vers le Serveur, les données envoyées sont de
type byte[].

Cependant je me demande si les objets Datagrampacket peuvent être
identifiés par un numéro de séquence (méthode renvoyant le num du
paquet)  ou si je dois moi-même donner un numéro de séquence (en byte
toujours) pour chaque paquet transmis, dans ce cas comment puis-je
fusionner deux arrays byte[] (un pour le numéro de séquence et un pour
les données audio) dans un seul que je transmettrai dans le
Datagrampacket?


Merci d'avance pour vos réponses.


Si jamais voilà le bout de code pour l'applic client:


tout se passe dans la classe audioInputBlockReady qui reçoit ce bout de
flux audio (inputbuffer) et qui le convertit en paquet UDP.


public void audioInputBlockReady(AudioThread audiothread, byte[] inputbuffer){

        /*

         * TODO

         *

         * When the AudioThread is running, this method is periodically called

         * by the AudioThread to indicate that new block of audio data is ready.

         * Note that this method is actually executed within the AudioThread

         * thread - don't forget to synchronize your objects.

         *

         * Imagine you are using audio block of 800 bytes (=400 samples). Since

         * we are sampling at 8000 samples per second (given by AudioThread),

         * such a block would correspond to 50 ms. Hence, this method would be

         * called 20 times per second with an "inputbuffer" containing 800

         * bytes.

         *

         * In this method you may process, package and send these samples. Note

         * that you should not use the inputbuffer object outside of this

         * function. If you want to send its contents in a UDP datagram, for

         * instance, you should rather copy the buffer to a new buffer, i.e.

         *

         * System.arraycopy(inputbuffer, 0, udpdatagram.getData(), ...,

         * inputbuffer.length);

         */

        InetAddress  IPAddress = null;

        //byte[] sequenceNumber = new byte[2];

       

       

       

        try {

            clientSocket = new DatagramSocket();

        } catch (SocketException e) {

            e.printStackTrace();

        }

       

        try {

            IPAddress = InetAddress.getByName("host");

        } catch (UnknownHostException e) {

            e.printStackTrace();

        }

       

        byte[] sendData = new byte[inputbuffer.length]; //data ready to send

         System.arraycopy(inputbuffer, 0, sendData, 0, inputbuffer.length);

         /*Question: est ce que je dois faire le seqNumber moi-même ou est-ce

          * que c'est déjà compris dans l'objet Socket??*/

        byte[] receiveData = new byte[1024];

        DatagramPacket sendPacket = new DatagramPacket(sendData,

                sendData.length, IPAddress, portNumber);

        try {

            clientSocket.send(sendPacket);

            countSentPackets++;

        } catch (IOException e) {

           

            e.printStackTrace();

        }

       

        DatagramPacket receivePacket =

            new DatagramPacket(receiveData, receiveData.length);

       

        try {

            clientSocket.receive(receivePacket);

        } catch (IOException e) {

            e.printStackTrace();

        }

        LogSink.defaultLog.println("New input block of " + String.valueOf(inputbuffer.length) + " bytes available!");

   

    }

4 réponses

Twinuts Messages postés 5375 Date d'inscription dimanche 4 mai 2003 Statut Modérateur Dernière intervention 14 juin 2023 111
25 avril 2007 à 12:54
Salut,

si ton but c'est d'envoyer l'audio en UDP tu peux te baser sur RTP qui est fait pour et ajouter le RTP header soit :

(ici je ne gère que les formats audio alaw et ulaw)

public final class RTPHeader {
    private short            sequenceNum   = 0x0;
    private int                timeStamp         = 0x0;
    private int                syncSourceId     = 0x0;
    private byte[]           rtpHeader          = null;
    private byte             version               = (byte) -128;
    private byte             padding              = 0;
    private byte             extention            = 0;
    private byte             contribute           = 0;
    private byte             payload               = 0;
    private byte             marker                = 0;

    public RTPHeader() {
        Random r = new Random();
        this.sequenceNum = 0x0;
        this.timeStamp = 0x0;
        this.syncSourceId = r.nextInt();
    }

    public byte[] getHeader(byte[] voiceData, boolean alaw) {
        rtpHeader = new byte[12];
        if (alaw)
                payload = 8;
        else
                payload = 0;
        rtpHeader[0] = (byte) (version | padding | extention | contribute);
        rtpHeader[1] = (byte) (marker | payload);
        rtpHeader[2] = (byte) (sequenceNum >> 8);
        rtpHeader[3] = (byte) (sequenceNum >> 0);
        rtpHeader[4] = (byte) (timeStamp >> 24);
        rtpHeader[5] = (byte) (timeStamp >> 16);
        rtpHeader[6] = (byte) (timeStamp >> 8);
        rtpHeader[7] = (byte) (timeStamp >> 0);
        rtpHeader[8] = (byte) (syncSourceId >> 24);
        rtpHeader[9] = (byte) (syncSourceId >> 16);
        rtpHeader[10] = (byte) (syncSourceId >> 8);
        rtpHeader[11] = (byte) (syncSourceId >> 0);
        this.sequenceNum++;
        this.timeStamp += voiceData.length;
       //concaténation de l'entete et de la voix
        ByteArrayOutputStream out = new ByteArrayOutputStream(
                voiceData.length + 12);
        out.write(rtpHeader, 0, 12);
        out.write(voiceData, 0, voiceData.length);
        return out.toByteArray();
    }
}

pour le reste il te faut changer ton code et envoyer des paquets régulier soit :
toutes les :
    10 ms la voix fait 80 octets + 12 octets de header soit un paquet de 92 octets
    20 ms la voix fait 160 octets + 12 octets de header soit un paquet de 172 octets
    30 ms la voix fait 240 octets + 12 octets de header soit un paquet de 252 octets

------------------------------------
"On n'est pas au resto : ici on ne fait pas dans les plats tout cuits ..."

WORA
0
cs_eikichi Messages postés 9 Date d'inscription mercredi 26 mars 2003 Statut Membre Dernière intervention 9 mai 2011
25 avril 2007 à 14:41
Merci pour le conseil ça paraît plus propre qu'avec la méthode classique, mais malheureusement on m'impose les Sockets, le prog sera une sorte de Skype-like. Mais la fin de ton listing va beaucoup me servir, au fait ça me fait venir à une autre question: un Datagrampacket c'est juste un tableau de bytes en fait rien de plus donc si je veux rajouter des en-têtes genre numero de sequence, ip source/destination, ports, etc... c'est à moi de les implémenter?
0
Twinuts Messages postés 5375 Date d'inscription dimanche 4 mai 2003 Statut Modérateur Dernière intervention 14 juin 2023 111
25 avril 2007 à 15:18
Salut,

RTP reste sur UDP

Concernant ta questrion, oui tu dois mettre toi meme le CSEQ, pour ce qui est de l'ip src/dest et des port c'est dans la couche IP donc tu n'as pas à les rajouter.

Pour ce qui et de skype il passe la voix sur RTP.

------------------------------------
"On n'est pas au resto : ici on ne fait pas dans les plats tout cuits ..."

WORA
0
cs_couco Messages postés 2 Date d'inscription mercredi 17 mars 2004 Statut Membre Dernière intervention 26 avril 2007
26 avril 2007 à 15:51
Merci ça va m'eclaierer

 couco
0
Rejoignez-nous