• Non ci sono risultati.

Il buffer di dejitter statico è stato realizzato creando una serie di aree di memoria e la posizione di ognuna di queste è individuata da un puntatore. La grandezza in termini di byte di queste aree di memoria è decisa durante la fase di instaurazione della connessione in base alla grandezza dei pacchetti che i partecipanti alla conversazione decidono di scambiarsi. Il numero di queste aree di memoria è invece dipendente dall'holding time con cui si stabilisce di lavorare. Quest'ultimo nelle misurazione effettuate riportate nel capitolo 6 è stato fissato a 60 ms.

Quindi ad esempio se i pacchetti della comunicazione che deve instaurata contengono 20 ms di speech signal, il campionamento è avvenuto ad 8 KHz e ogni campione del segnale una volta decodificato è su 16 bit allora ogni area di memoria sarà di:

20 ms

1 /8 KHz16 bit = 2560 bit cioè 320 byte

e l'intero buffer, supponendo l'holding time di 60 ms, sarà perciò composto da tre aree, per un totale di 960 byte .

Ad ogni pacchetto che arriva al ricevitore si estrae il payload basandosi sul campo CSRC count dell'RTP header per capire dove finisce l'intestazione RTP e iniziano i dati. Inoltre si esamina il contenuto del campo sequence number e in base a questo, come meglio spiegato in seguito, si decide

4 Buffer di dejitter statico e buffer di dejitter adattivo

se decodificare e memorizzare il payload del pacchetto in una particolare area di memoria o se scartarlo.

Al momento in cui viene ricevuto il primo pacchetto (first packet) se ne osserva il numero di sequenza, si estrae il payload, lo si decodifica, lo si memorizza nella prima area di memoria di cui è composto il dejitter buffer e si fa partire un timer che misurerà l'holding time. Fintanto che questo è al di sotto del valore fissato si continua a decodificare e memorizzare i pacchetti che arrivano ma non viene passato alcun dato all'applicazione che si preoccuperà di riprodurre i dati. Questi infatti le saranno passati una volta raggiunto l'holding time a blocchi grandi quanto una singola area di memoria e a un rate che dipende dalla dimensione dei pacchetti. Nell'esempio precedente uno ogni 20 ms.

Ogni volta che viene passato un blocco di dati all'applicazione il sistema si preoccupa di liberare l'area di memoria corrispondente, incrementare di uno il valore del sequence number read (contatore che indica quanti pacchetti sono già stati riprodotti) e, giocando con i puntatori, di fare in modo che l'area successiva che sarà inviata all'applicazione sia quella contenente il pacchetto con numero di sequenza successivo a quello che è stato riprodotto all'istante attuale. La scelta dell'area di memoria dove memorizzare il singolo pacchetto ricevuto (o meglio il suo payload decodificato) è infatti basata, come accennato in precedenza, sul suo sequence number. In base a questo numero, al sequence number read e al numero di sequenza del first packet si ottiene un valore che indica in quale area di memoria andare a collocare il pacchetto. In questo modo si effettua un re-ordering dei pacchetti in ricezione che permette di passarli all'applicazione non attenendosi all'ordine in cui sono arrivati, che può essere errato causa la presenza di jitter, ma basandosi sul loro numero di sequenza.

Nel meccanismo finora descritto, causa le condizioni della rete, possono però presentarsi delle situazioni che devono essere prese in considerazione.

Primo problema che può presentarsi è che un pacchetto vada perso e perciò quando l'applicazione va a leggere l'area di memoria, in cui dovrebbe trovarsi il pacchetto con sequence number successivo all'ultimo riprodotto, la trovi vuota. In questo caso entrano in gioco gli algoritmi di Packet Loss Concealment. Per conseguire l'obiettivo di questa tesi ne sono stati implementati più tipi (descritti in seguito nel capitolo 5). Indipendentemente dal tipo usato questi algoritmi permettono di creare un pacchetto sostitutivo a quello andato perso, magari basandosi su quelli più recentemente riprodotti che sono stati salvati in un history buffer dopo aver liberato le aree di memoria in cui erano stati memorizzati. Il pacchetto sintetizzato viene passato all'applicazione, il sequence number read viene incrementato e l'area di memoria successiva che andrà ad essere considerata è quella che dovrebbe

4 Buffer di dejitter statico e buffer di dejitter adattivo

contenere il pacchetto con numero di sequenza successivo a quello che non è arrivato ed è stato ricostruito.

Altro problema che può verificarsi è che un pacchetto sia ricevuto troppo in ritardo o troppo in anticipo. Nel primo caso in base al sequence number del pacchetto e al sequence number read il sistema capisce che l'istante in cui i dati in esso contenuti sarebbero dovuti essere riprodotti è già passato e l'algoritmo di PLC si è perciò già preoccupato di ricostruirlo e passarlo all'applicazione. In questo caso il pacchetto arrivato è a questo punto inutile e perciò viene semplicemente scartato. Nel secondo caso invece arriverà un pacchetto con un sequence number tale da non entrare nel buffer di dejitter perché le aree di memoria disponibili alla sua memorizzazione sono ancora riservate a pacchetti con un sequence number più basso. Questa situazione è causata da una variazione delle condizioni della rete per cui il pacchetto subisce un ritardo end-to-end di minor valore rispetto a quello sperimentato dai pacchetti precedenti e perciò arriva in anticipo rispetto all'istante teorico in cui il sistema si sarebbe aspettato di riceverlo. In questo caso esso decide comunque di memorizzare il pacchetto andandolo a collocare nell'area di memoria adibita al pacchetto con numero di sequenza più alto scalando le altre di conseguenza e scartando così eventuali pacchetti già ricevuti che saranno perciò non passati all'applicazione e quindi praticamente saltati nella riproduzione.

Infine è stato preso in considerazione il caso in cui il ritardo end-to-end creato dalle condizioni della rete abbia all'interno di una certa finestra temporale un andamento a “gradino” come quello raffigurato nella seguente figura.

Figura 4.1: Andamento a gradito del ritardo end-to-end

4 Buffer di dejitter statico e buffer di dejitter adattivo

si ritrova cioè ad avere un buffer di dejitter completamente vuoto e il sistema inizia a sfruttare l'algoritmo di PLC per ricostruire dei pacchetti che in realtà non sono andati persi ma sono semplicemente in ritardo e che al momento che arriveranno saranno scartati perché considerati troppo in ritardo per essere riprodotti. In questo caso il sistema di gestione del dejitter buffer è stato pensato in modo da reinizializzarsi così da permettere un riallineamento alle nuove condizioni di ritardo end- to-end della rete. La soluzione ottimale sarebbe quella di smettere di passare dati all'applicazione e non appena arriva un pacchetto considerarlo il first packet, far partire il timer dell'holding time e ricominciare a passare dati solo al momento in cui questo scade. Purtroppo la situazione in cui il buffer di dejitter si vuota potrebbe essere causata anche da un burst di perdite e agendo in questo modo si perde la possibilità di sfruttare un algoritmo di PLC per la ricostruzione di questi pacchetti. La scelta di gestione è stata quella di trovare un compromesso tra i due problemi; al momento che il sistema si rende conto che il buffer si è svuotato continua a mandare dati all'applicazione sfruttando un algoritmo di PLC finché non arriva un pacchetto, nomina quest'ultimo first packet e fa partire il timer dell'holding time interrompendo la lettura delle aree di memoria e il passaggio di dati all'applicazione finché non scade. Vantaggio è che se il problema del buffer vuoto è dovuto a un burst di perdite si sfrutta l'algoritmo di PLC fino a quando si riceve il primo pacchetto corretto. Svantaggio è che se il buffer si è svuotato causa un aumento del ritardo il sistema si trova a ricostruire dei pacchetti che in realtà in seguito arriveranno e saranno perciò in un certo senso riprodotti due volte; la prima quello ricostruito, la seconda quello reale.

Al momento che il ritardo end-to-end come mostrato in figura 4.1 diminuisce arriverà un burst di pacchetti; a seconda della sua lunghezza alcuni di questi pacchetti non entreranno nel buffer di dejitter perché le aree di memoria disponibili alla loro memorizzazione sono ancora riservate a pacchetti con un sequence number più basso. In questo caso il sistema di gestione si comporta come precedentemente spiegato nel caso di pacchetti arrivati in anticipo rispetto all'istante teorico in cui si sarebbe aspettato di riceverli. Questo meccanismo permette ancora una volta un riallineamento alle nuove condizioni di ritardo della rete.

Il buffer di dejitter statico così costruito introduce un ritardo aggiuntivo end-to-end fisso pari a holding time.

Documenti correlati