RTP/RTCP – Realtime Transport/Control Protocol

Ponieważ ostatnio musiałem odświeżyc swoją wiedzę na temat RTP ponizej powtórka z przeszlosci. Poniższy post oparty jest bezpośrednio na dokumencie IETF RFC 3550 specyfikujacym bazowy protokol RTP.

RTP/RTCP są to protokóły przeznaczone do transmisji end2end sygnałów cyfrowych o charakterystyce ‘realtime’, takich jak dzwięk czy video. Został zaprojektowany w celu oddzielenia mechanizmów transmiscji danych i kontroli sesji. Z każdym strumieniem danych skojarzony jest oddzielny kanał RTP/RTCP zawierajaca po jednym porcie RTP i RTCP. RTP jest protokołem odpowiedzialnym za transmisje strumieni danych tak zwanych ‘RTP payload’. RTP samo w sobie nie zapewnia mechanizmów kontorli opoźnień czy stratności ale bazuje na wykorzystywanym protokole transportowym ktorym najcześciej jest to UDP. RTCP skolei jest odpowiedzialne za kontrole jakości swiadczonych uslug poprzez RTP (informowanie o ilosci gubionych pakietow, opoznieniach czy parametrach wykorzystywanych kodekow adaptacyjnych). Opcjonalnie dostarcza możliwość kontroli uczestnikow sesji, ale to najcześciej jest realizowane przez skojarzony z RTP protokół sygnalizacyjny tak jak np SIP.

RTP

Struktura pakietu

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X|  CC   |M|     PT      |       sequence number         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           timestamp                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           synchronization source (SSRC) identifier            |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|            contributing source (CSRC) identifiers             |
|                             ....                              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Pierwsze 12 oktetow wystepuje zawsze, opcjonalne pola CSRC wystepuja gdy na drodze danych jest mixer.

  • version (V): 2 bity – wersja obecnie 2
  • padding (P): 1 bit – wskazuje czy koniec pakietu jest uzupelniony zerami, jesli tak ostatni oktet wskazuje na liczbe oktetow do pominiecia
  • extension (X): 1 bit – wskazuje ze do pakietu dolaczony jest naglowek z rozszerzeniem
  • CSRC count (CC): 4 bity – wskazuje na liczbe identyfikatorw CSRC na koncu naglowka
  • marker (M): 1 bit – umozliwia wskazanie ze jest znaczacy pakiet, wykorzystywane przez profile RTP
  • payload type (PT): 7 bitów – określa format danych
  • sequence number: 16 bitów – numer sekwencyjny pakietu RTP, zwiekszany o jeden za każdym razem
  • timestamp: 32 bity – wartosc bezwgledna informujace o przedziale pomiedzy przesylanymi probkami danych
  • SSRC: 32 bity – identyfikuje zrodlo synchronizacji
  • CSRC list: od 0 tdo 15 , 32 bity każde – listaidentyfikatorow CSRC ktorych dane sa mixowane

RTCP

Zasada dzialanie RTCP polega na cyklicznej wymianie wiadomosci kontrolnych w oparciu o te same mechanizmy dystrubucji co RTP np. uzywajac innego portu udp. RTCP realizuje 4 podstawowe funkcje:
  • informowanie o jakosci dystrybucji danych oraz mozliwosciach adaptacji na poziomie kodowania
  • przenosi parametr CNAME odpowiedzialny za persystentna identyfikacje sesji RTP
  • ustala czestotliowsc wymiany pakietow w zaleznosci od liczby uczestnikow
  • opcjonalnie pozawala przenosic minimalna ilosc informacji identyfikujaca strony

Struktura pakietu

RFC 3550 definiuje pieć rodzajów pakietów, które przenoszą różne informacje kontrolne

  • SR (Sender Report) – statystyki transmisji i odbioru danych od aktywnych uczestnikow
  • RR (Receiver Report ) – statystyki odbioru dla nieaktywnych uczestnikow
  • SDES (Source Description) – parametry informacyjne zródła np CNAME
  • BYE – informuje o razlaczeniu
  • APP – informacje specyficzne dla danej aplikacji
Kazdy pakiet RTCP składa sie ze stałej części oraz następującej po niej czesci o zmiennej długosci, w zależności od typu pakietu wyrówanej do 32 bitów. Kilka pakietów może być szeregowo łączonych tworząc tak zwany złożony pakiet RTP, umieszczany w pakiecie warstwy niższej. Nie ma żadnego konkretnego wymogu na wielkosc pakietu złożonego, gdyż jest ona kontrolowana przez protokół transportowy. Każdy pakiet wchodzący w skład pakietu złożonego jest analizowany niezależnie od innych, stad kolejność i kombinacja pakietów nie są istotne. Tym niemniej aby spełnić wymaganie realizowane przez protokół na strukturę pakietu złożonego zostały nałożone następujące ograniczenia:
  • SR lub RR musza byc wysylane w kazdym pakiecie zlozonym, tak aby statystyki odbioru byly jak najbardziej dokladne
  • SDES z parametrem CNAME musi być wysylany w kazym pakieci zlozonym, tak aby odbiorca jak najszyciej otrzymal informacje o nadawcy
  • liczba pakietów wyslana w pierwszym pakiecie zlozonym powinna byc jak najmniejsza (2) tak aby liczba stalych bitów byla jak najwieksza i prawdopodobienstwo walidacji pakietu najwieksze

Stad tez struktura pakietu zlozonego musi zawierac conajmniej dwa pakiety o nastepujacej formie:

random encryption prefix: losowy 32-bitowy integer
|
|[--------- packet --------][---------- packet ----------][-packet-]
|
|                receiver            chunk        chunk
V                reports           item  item   item  item
--------------------------------------------------------------------
R[SR #sendinfo #site1#site2][SDES #CNAME PHONE #CNAME LOC][BYE##why]
--------------------------------------------------------------------
|                                                                  |
|<-----------------------  compound packet ----------------------->|
|<--------------------------  UDP packet ------------------------->|

#: SSRC/CSRC identifier
  • Encryption prefix – jesli pakiet zlozony jest szyforowany jest poprzedzany 32 bitową wartościa calkowita
  • SR lub RR – zawsze pierwszy pakiet w pakiecie zlozonym to SR lub RR nawet jesli zadne dane nie byly jeszcze wyslane
  • Dodatkowe RR – jesli liczba zrodel dla ktorych generowane sa statystyki przewyzsza 31 i nie moga byc umieszczone w jednym RR lub SS sa one umieszczane w dodatkowych pakietach RR
  • SDES – w kazdym pakiecie zlozonym musi byc dolaczony pakiet zawierajacy parametr CNAME inne parametry sa umieszczane w zalezności od aplikacji
  • BYE lub APP – pozostale pakiety moga sie pojawiac w dowolnej ilosci i kolejnosci z tym wyjatkiem ze pakiet BYE zawierajacy SSRC/CSRC musi byc ostatni
Kazdy uczestnik powinnien wysylac tylko jeden pakiet zlozony w trakcie okresu raportowania aby oszacowanie pasma bylo precyzyjniejsze. Jesli ilosc dodatkowych pakietow RR nie miesci sie w MTU nalezy ograniczyc ich ilosc i przeslac w nastepnej turze, tak by wszystkie zrodla byly raportowane.

Czestotliwosci RTCP

RTP zostalo tak zaprojektowane aby umozliwiac regulowanie ruchu kontrolnego w zaleznosci o ilosci uczestnikow i przyjetej charakterystyki lacza. Z kazda sesja danych RTP zwiazane jest maksymalne dopuszczalne pasmo sesji (session bandwidth) bedace agregacja danych poszczegolnych uczestnikow. Mechanizm doboru pasma sesji moze byc praktycznie dowolny ale najczesniej przyjmuje sie jego wartosc jako nominalna sume pasm zajmowanych przez maksymalna liczbe jednoczesnie aktywnych uczestnikow. Wartosc pasma sesji najczesciej ustalana jest przez warstwe aplikacji odpowiedzialna za zarzadzanie sesja przy czym najczesciej wartosc domyslna ustalana jest jako pasmo odpowiadajace jednemu aktywnemu uzytkownikowi. Wszyscy uczestnicy sesji musza uzywac tego samego pasma tak aby okres retransmisji RTCP byl taki sam. Warto pamietac ze w trakcie obliczania utylizacji dostepnego pasma brane sa pod uwage tez protokoly transportowe (UDP i IP) ale warstwa lacza danych juz nie gdyz te sie od siebie różnia. Ruch kontrolny jest ograniczany zarówno z góry jak i z dołu. Z góry jako czastkowa wartość calkowitego dostepnego pasma (norma 5%) lub jako wartość ilościowa. Z dolu natomiast ustala sie minimalna wartość tak aby nie generować nadmiernego ruchu (norma 5s), istnieja przypadki kiedy ta wartosc moze byc jeszcze bardziej zredukowana i odwrotnie proporcjonalna do dostepnego pasma. Zaleca sie rowniez aby z posrod calego ruchu RTCP, 1/4 byla przypisana do aktywnych uczestnikow, tak aby nowo dolaczajacy sie uzytkownicy szybko dowiadywali sie aktywnych CNAME. Algorytm oblicza czestotliowsci wysylania pakietów zlozonych tak aby dostępne pasmo na ruch kontrolny było równie rozdzielone pomiedzy uczestników. Wyznaczona czestotliwosc skaluje sie liniowe w stosunku do liczby uczestników, co zapewnia stała wartość ruchu kontrolnego. Aby uniknąc pelnej synchronizacji kazdy z uczestnikow posluguje sie lekka wariacja okresu wysylania RTCP oraz losowym opoznienieniem dla pierwszego wysylanego pakietu zlozonego. Dodatkowo obslugiwane sa mechanizmy obslugujace sytuacje wyjatkowe kiedy wielu uczestnikow jednoczesnie dolacza lub opuszcza sesje.

Ilosc Uczestnikow

Wyznaczanie czestotliwosci RTCP bazuje na znajomosci oszacowanej liczby uczestnikow. Uczestnik okreslany jest jako nowy gdy w sesji pojawi sie ruch z nowym identyfikatorem SSRC lub CSRC. Istnieje możliwosc przyjecia ze musi byc zarejstrowanych kilka pakietow by uznac ze pojawil sie nowy uczestnik lub ze musi zostac odebrany pakiet SDES z nowym CNAME. Uczestnika uwaza sie za usunietego gdy wysyla pakiet BYE lub przez okreslony czas nie wysyla pakietow.

Zasady Wysylania i Odbierania pakietow RTCP

Aby zrealizowac powyzsze zalozenia kazdy uzytkownik musi lokalnie przechowywac szereg informacji zwiazanych z realizowana sesja:

  • tp – czas ostatniej transmisji
  • tc- obecny czas
  • tn – czas nastepnej transmisji
  • pmembers – oszacowana liczba uczestnikow podczas podczas ostatniej transmisji
  • members – aktualna oszacowana liczba uczestnikow
  • senders – aktualna oszacowana liczba aktywnych uczestnikow
  • rtcp_bw – pasmo przydzielone dla calego ruchu RTCP wszystkich uczestnikow
  • we_sent – flaga informujaca czy od ostatniego raportu uczestnik wyslal dane
  • avg_rtcp_size – sredni rozmiar wyslanych i odebranych pakietow przez uzytkownika
  • initial – ustawiona na true gdy uzytkownik nie wyslal jeszcze zadnego pakietu RTCP
W trakcie inicjalizacji aplikacji parametry ustawiane sa na wartosci domyslne. Wartosc okresu nadawania wiadomosci kontrolnych jest obliczana na podstawie powyzej wymienionych parameterow. Procedura w efekcie daje przedzial ktory jest losowy i przydziela minimum 1/4 calego dostepnego pasma uzytkownikom aktywnym. Jesli uzytkoników aktywnych jest wiecej niż 1/4 wszystkich uzytkownikow dostepne pasmo jest dytrybuowane po rowno do wszystkich uczestników. Po otrzymaniu pakietu RTP lub RTCP od uczesnika, ktorego SSRC nie jest obecne w tablicy uczestników, jest on dodawany do listy i liczba uczestnikow jest aktualizowana. Kiedy pakiet RTP jest od uczestnika ktory nie znajduje sie na liscie aktywnych uczestnikow jest on do niej dodawany i ich liczba jest aktualizowana. Jak zawsze przy kazdym odebranym i wyslanym pakiecie wartosc avg_rtcp_size jest aktualizowana. Gdy uczestnik odbiera pakiet BYE sprawdza czy na liscie uczestników lub aktywnych uczestników znajduje nadawca pakietu, jesli tak, jest on z niej usuwany, aktualizowane sa parametry oraz czas wyslania nastepnego zlozonego pakietu RTCP. Przynajmniej raz na jeden okres przesylania pakietu kontrolnego uczestnik weryfikuje czy na którejś z list nie nastapil timeout dla danego SSRC. Kiedy uczestnik chce opuscic sesje moze ale nie musi wyslac pakiet BYE, jesli tego nie zrobi nastapi timeout. Jesli liczba uzytkownikow jest mala (zalecane 50) moze wyslac pakiet od razu, w przeciwnym wypadku stosuje mechanizm zapobiegajacy masowemu opuszczaniu sesji przez duza liczbe uczestnikow.

Pakiety SR i RR

W oparciu o pakiety RR odbiorcy informuja o jakosci odbieranych danych, jeśli odbiorca jest uczestnikiem aktywnym i wysyłał dane od ostatniego raportu wykorzystuje pakiet SR zawierajacy dodatkowe informacje o nadawcy. W kazdym pakiecie SR i RR znajduje sie po jednym bloku raportujacym skojarzonym z jednym źródłem synchronizacji. Jeśli zródeł jest wiecej niż 31 powinny zostać umieszczone w kolejnych pakietach RR.
SR składa sie z trzech sekcji obowiazkowych: nagłówka, informacji o nadawcy, listy bloków raportujacych i czwartej opcjonalnej dedykowanej dla konkretnego profilu. opcjonalna cześć jest wykorzystywana gdy profil RTP wymaga przesylania dodatkowych informacji pomiedzy stronami.
        0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
header |V=2|P|    RC   |   PT=SR=200   |             length            |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                         SSRC of sender                        |
       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
sender |              NTP timestamp, most significant word             |
info   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |             NTP timestamp, least significant word             |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                         RTP timestamp                         |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                     sender's packet count                     |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                      sender's octet count                     |
       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
report |                 SSRC_1 (SSRC of first source)                 |
block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  1    | fraction lost |       cumulative number of packets lost       |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |           extended highest sequence number received           |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                      interarrival jitter                      |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                         last SR (LSR)                         |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                   delay since last SR (DLSR)                  |
       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
report |                 SSRC_2 (SSRC of second source)                |
block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  2    :                               ...                             :
       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
       |                  profile-specific extensions                  |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • wersja (V): 2 bity – identyfikuje wersje, tak samo jak RTP 2
  • padding (P): 1 bit – wskazuje czy koniec pakietu jest uzupelniony zerami, jesli tak ostatni oktet wskazuje na liczbe oktetow do pominiecia
  • reception report count (RC): 5 bitów – liczba blokow raportujacych w tym pakiecie
  • packet type (PT): 8 bitów – indentyfikuej pakiet RTCP SR (stala wartosc 200)
  • length: 16 bitów – dlugosc pakietu w 32 bitowych słowach właczając nagłówek i wyrównanie
  • SSRC: 32 bity – identyfikator SSRC zródla pakietu SR
  • NTP timestamp: 64 bity – zegarowy czas wyslania pakietu
  • RTP timestamp: 32 bity – okresowy czas wyslania pakietu
  • sender’s packet count: 32 bity – calkowita liczba pakietow RTP wyslanych przez uczest
  • SSRC_n (source identifier): 32 bity – identyfikator SSRC dla zrodla ktorego dotyczy raport
  • fraction lost: 8 bitów – stosunek pakietow odebranych do pakietow spodziewanych RTP
  • cumulative number of packets lost: 24 bity – calkowita liczba wszystkich zgóbionych pakietów RTP
  • xtended highest sequence number received: 32 bity – najwieszky numer sekwencyjny odebranego pakietu
  • interarrival jitter: 32 bity – roznica pomiedzy odstepem w wysylaniu kolejnych pakietow
  • last SR timestamp (LSR): 32 bity – srodkowe 32 bity otrzymane w SR od nadawcy
  • delay since last SR (DLSR): 32 bity – czas pomiedzy odbiorem pakietu SR od nadawcy a nadaniem tego bloku raportujacego
Struktura pakietu RR jest taka sama jak pakietu SR, z tą różnicą że pakiet RR nie zawiera czesci informacyjnej o nadawcy a pole typu pakietu zawiera wartosc 201:
        0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
header |V=2|P|    RC   |   PT=RR=201   |             length            |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                     SSRC of packet sender                     |
       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
report |                 SSRC_1 (SSRC of first source)                 |
block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  1    | fraction lost |       cumulative number of packets lost       |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |           extended highest sequence number received           |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                      interarrival jitter                      |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                         last SR (LSR)                         |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                   delay since last SR (DLSR)                  |
       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
report |                 SSRC_2 (SSRC of second source)                |
block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  2    :                               ...                             :
       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
       |                  profile-specific extensions                  |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Po otrzymaniu raportu w postaci pakietu SR lub RR nadawca moze zmodyfikować na jego podstawie charakterysytke sesji, określić zakres wystepujących problemów, określić skutecznosc w dostarczaniu raportow itp. Dane raportujace moga byc rowniez agregowane przez aplikacje monitorujace nadzorujace wydajnosc sieci.

Pakiety SDES

Pakiet SDES posiada trzy poziomową strukture, w której skład wchodzi nagłówek, zero lub wiecej fragmentów zawierających atrybuty opisujące zródło identyfikowane w danym fragmencie. Każdy fragment zawiera indentyfikator SSRC/CSRC oraz listę atrybótów. Każdy atrybut zawiera 2 8-śmio bitowe pola wskazujace na jego typ oraz dlugość oraz sam tekst, gdzie tekst nie może być dłuższy niż 255 oktetów
        0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
header |V=2|P|    SC   |  PT=SDES=202  |             length            |
       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
chunk  |                          SSRC/CSRC_1                          |
  1    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                           SDES items                          |
       |                              ...                              |
       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
chunk  |                          SSRC/CSRC_2                          |
  2    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                           SDES items                          |
       |                              ...                              |
       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
  • version (V) – wersja, padding (P) – dopełnienie, length – dlugość
  • packet type (PT): 8 bitów – typ pakietu (202)
  • source count (SC): 5 bitów – liczba fragmentów w pakiecie

autor: Tomasz Zieleniewski

You May Also Like

How to automate tests with Groovy 2.0, Spock and Gradle

This is the launch of the 1st blog in my life, so cheers and have a nice reading!

y u no test?

Couple of years ago I wasn't a big fan of unit testing. It was obvious to me that well prepared unit tests are crucial though. I didn't known why exactly crucial yet then. I just felt they are important. My disliking to write automation tests was mostly related to the effort necessary to prepare them. Also a spaghetti code was easily spotted in test sources.

Some goodies at hand

Now I know! Test are crucial to get a better design and a confidence. Confidence to improve without a hesitation. Moreover, now I have the tool to make test automation easy as Sunday morning... I'm talking about the Spock Framework. If you got here probably already know what the Spock is, so I won't introduce it. Enough to say that Spock is an awesome unit testing tool which, thanks to Groovy AST Transformation, simplifies creation of tests greatly.

An obstacle

The point is, since a new major version of Groovy has been released (2.0), there is no matching version of Spock available yet.

What now?

Well, in a matter of fact there is such a version. It's still under development though. It can be obtained from this Maven repository. We can of course use the Maven to build a project and run tests. But why not to go even more "groovy" way? XML is not for humans, is it? Lets use Gradle.

The build file

Update: at the end of the post is updated version of the build file.
apply plugin: 'groovy'
apply plugin: 'idea'

def langLevel = 1.7

sourceCompatibility = langLevel
targetCompatibility = langLevel

group = 'com.tamashumi.example.testwithspock'
version = '0.1'

repositories {
mavenLocal()
mavenCentral()
maven { url 'http://oss.sonatype.org/content/repositories/snapshots/' }
}

dependencies {
groovy 'org.codehaus.groovy:groovy-all:2.0.1'
testCompile 'org.spockframework:spock-core:0.7-groovy-2.0-SNAPSHOT'
}

idea {
project {
jdkName = langLevel
languageLevel = langLevel
}
}
As you can see the build.gradle file is almost self-explanatory. Groovy plugin is applied to compile groovy code. It needs groovy-all.jar - declared in version 2.0 at dependencies block just next to Spock in version 0.7. What's most important, mentioned Maven repository URL is added at repositories block.

Project structure and execution

Gradle's default project directory structure is similar to Maven's one. Unfortunately there is no 'create project' task and you have to create it by hand. It's not a big obstacle though. The structure you will create will more or less look as follows:
<project root>

├── build.gradle
└── src
├── main
│ ├── groovy
└── test
└── groovy
To build a project now you can type command gradle build or gradle test to only run tests.

How about Java?

You can test native Java code with Spock. Just add src/main/java directory and a following line to the build.gradle:
apply plugin: 'java'
This way if you don't want or just can't deploy Groovy compiled stuff into your production JVM for any reason, still whole goodness of testing with Spock and Groovy is at your hand.

A silly-simple example

Just to show that it works, here you go with a basic example.

Java simple example class:

public class SimpleJavaClass {

public int sumAll(int... args) {

int sum = 0;

for (int arg : args){
sum += arg;
}

return sum;
}
}

Groovy simple example class:

class SimpleGroovyClass {

String concatenateAll(char separator, String... args) {

args.join(separator as String)
}
}

The test, uhm... I mean the Specification:

class JustASpecification extends Specification {

@Unroll('Sums integers #integers into: #expectedResult')
def "Can sum different amount of integers"() {

given:
def instance = new SimpleJavaClass()

when:
def result = instance.sumAll(* integers)

then:
result == expectedResult

where:
expectedResult | integers
11 | [3, 3, 5]
8 | [3, 5]
254 | [2, 4, 8, 16, 32, 64, 128]
22 | [7, 5, 6, 2, 2]
}

@Unroll('Concatenates strings #strings with separator "#separator" into: #expectedResult')
def "Can concatenate different amount of integers with a specified separator"() {

given:
def instance = new SimpleGroovyClass()

when:
def result = instance.concatenateAll(separator, * strings)

then:
result == expectedResult

where:
expectedResult | separator | strings
'Whasup dude?' | ' ' as char | ['Whasup', 'dude?']
'2012/09/15' | '/' as char | ['2012', '09', '15']
'nice-to-meet-you' | '-' as char | ['nice', 'to', 'meet', 'you']
}
}
To run tests with Gradle simply execute command gradle test. Test reports can be found at <project root>/build/reports/tests/index.html and look kind a like this.


Please note that, thanks to @Unroll annotation, test is executed once per each parameters row in the 'table' at specification's where: block. This isn't a Java label, but a AST transformation magic.

IDE integration

Gradle's plugin for Iintellij Idea

I've added also Intellij Idea plugin for IDE project generation and some configuration for it (IDE's JDK name). To generate Idea's project files just run command: gradle idea There are available Eclipse and Netbeans plugins too, however I haven't tested them. Idea's one works well.

Intellij Idea's plugins for Gradle

Idea itself has a light Gradle support built-in on its own. To not get confused: Gradle has plugin for Idea and Idea has plugin for Gradle. To get even more 'pluginated', there is also JetGradle plugin within Idea. However I haven't found good reason for it's existence - well, maybe excluding one. It shows dependency tree. There is a bug though - JetGradle work's fine only for lang level 1.6. Strangely all the plugins together do not conflict each other. They even give complementary, quite useful tool set.

Running tests under IDE

Jest to add something sweet this is how Specification looks when run with jUnit  runner under Intellij Idea (right mouse button on JustASpecification class or whole folder of specification extending classes and select "Run ...". You'll see a nice view like this.

Building web application

If you need to build Java web application and bundle it as war archive just add plugin by typing the line
apply plugin: 'war'
in the build.gradle file and create a directory src/main/webapp.

Want to know more?

If you haven't heard about Spock or Gradle before or just curious, check the following links:

What next?

The last thing left is to write the real production code you are about to test. No matter will it be Groovy or Java, I leave this to your need and invention. Of course, you are welcome to post a comments here. I'll answer or even write some more posts about the subject.

Important update

Spock version 0.7 has been released, so the above build file doesn't work anymore. It's easy to fix it though. Just remove last dash and a word SNAPSHOT from Spock dependency declaration. Other important thing is that now spock-core depends on groovy-all-2.0.5, so to avoid dependency conflict groovy dependency should be changed from version 2.0.1 to 2.0.5.
Besides oss.sonata.org snapshots maven repository can be removed. No obstacles any more and the build file now looks as follows:
apply plugin: 'groovy'
apply plugin: 'idea'

def langLevel = 1.7

sourceCompatibility = langLevel
targetCompatibility = langLevel

group = 'com.tamashumi.example.testwithspock'
version = '0.1'

repositories {
mavenLocal()
mavenCentral()
}

dependencies {
groovy 'org.codehaus.groovy:groovy-all:2.0.5'
testCompile 'org.spockframework:spock-core:0.7-groovy-2.0'
}

idea {
project {
jdkName = langLevel
languageLevel = langLevel
}
}