153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2013 Matthias Wabersich 553a5a1b3Sopenharmony_ci Copyright 2013 Hajime Fujita 653a5a1b3Sopenharmony_ci 753a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 853a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as published 953a5a1b3Sopenharmony_ci by the Free Software Foundation; either version 2.1 of the License, 1053a5a1b3Sopenharmony_ci or (at your option) any later version. 1153a5a1b3Sopenharmony_ci 1253a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1353a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1453a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1553a5a1b3Sopenharmony_ci General Public License for more details. 1653a5a1b3Sopenharmony_ci 1753a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1853a5a1b3Sopenharmony_ci along with PulseAudio; if not, write to the Free Software 1953a5a1b3Sopenharmony_ci Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 2053a5a1b3Sopenharmony_ci USA. 2153a5a1b3Sopenharmony_ci***/ 2253a5a1b3Sopenharmony_ci 2353a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2453a5a1b3Sopenharmony_ci#include <config.h> 2553a5a1b3Sopenharmony_ci#endif 2653a5a1b3Sopenharmony_ci 2753a5a1b3Sopenharmony_ci#include <stdlib.h> 2853a5a1b3Sopenharmony_ci#include <stdint.h> 2953a5a1b3Sopenharmony_ci#include <limits.h> 3053a5a1b3Sopenharmony_ci 3153a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 3253a5a1b3Sopenharmony_ci 3353a5a1b3Sopenharmony_ci#include <pulsecore/core-error.h> 3453a5a1b3Sopenharmony_ci#include <pulsecore/macro.h> 3553a5a1b3Sopenharmony_ci 3653a5a1b3Sopenharmony_ci#include "raop-packet-buffer.h" 3753a5a1b3Sopenharmony_ci 3853a5a1b3Sopenharmony_cistruct pa_raop_packet_buffer { 3953a5a1b3Sopenharmony_ci pa_memchunk *packets; 4053a5a1b3Sopenharmony_ci pa_mempool *mempool; 4153a5a1b3Sopenharmony_ci 4253a5a1b3Sopenharmony_ci size_t size; 4353a5a1b3Sopenharmony_ci size_t count; 4453a5a1b3Sopenharmony_ci 4553a5a1b3Sopenharmony_ci uint16_t seq; 4653a5a1b3Sopenharmony_ci size_t pos; 4753a5a1b3Sopenharmony_ci}; 4853a5a1b3Sopenharmony_ci 4953a5a1b3Sopenharmony_cipa_raop_packet_buffer *pa_raop_packet_buffer_new(pa_mempool *mempool, const size_t size) { 5053a5a1b3Sopenharmony_ci pa_raop_packet_buffer *pb = pa_xnew0(pa_raop_packet_buffer, 1); 5153a5a1b3Sopenharmony_ci 5253a5a1b3Sopenharmony_ci pa_assert(mempool); 5353a5a1b3Sopenharmony_ci pa_assert(size > 0); 5453a5a1b3Sopenharmony_ci 5553a5a1b3Sopenharmony_ci pb->count = 0; 5653a5a1b3Sopenharmony_ci pb->size = size; 5753a5a1b3Sopenharmony_ci pb->mempool = mempool; 5853a5a1b3Sopenharmony_ci pb->packets = pa_xnew0(pa_memchunk, size); 5953a5a1b3Sopenharmony_ci pb->seq = pb->pos = 0; 6053a5a1b3Sopenharmony_ci 6153a5a1b3Sopenharmony_ci return pb; 6253a5a1b3Sopenharmony_ci} 6353a5a1b3Sopenharmony_ci 6453a5a1b3Sopenharmony_civoid pa_raop_packet_buffer_free(pa_raop_packet_buffer *pb) { 6553a5a1b3Sopenharmony_ci size_t i; 6653a5a1b3Sopenharmony_ci 6753a5a1b3Sopenharmony_ci pa_assert(pb); 6853a5a1b3Sopenharmony_ci 6953a5a1b3Sopenharmony_ci for (i = 0; pb->packets && i < pb->size; i++) { 7053a5a1b3Sopenharmony_ci if (pb->packets[i].memblock) 7153a5a1b3Sopenharmony_ci pa_memblock_unref(pb->packets[i].memblock); 7253a5a1b3Sopenharmony_ci pa_memchunk_reset(&pb->packets[i]); 7353a5a1b3Sopenharmony_ci } 7453a5a1b3Sopenharmony_ci 7553a5a1b3Sopenharmony_ci pa_xfree(pb->packets); 7653a5a1b3Sopenharmony_ci pb->packets = NULL; 7753a5a1b3Sopenharmony_ci pa_xfree(pb); 7853a5a1b3Sopenharmony_ci} 7953a5a1b3Sopenharmony_ci 8053a5a1b3Sopenharmony_civoid pa_raop_packet_buffer_reset(pa_raop_packet_buffer *pb, uint16_t seq) { 8153a5a1b3Sopenharmony_ci size_t i; 8253a5a1b3Sopenharmony_ci 8353a5a1b3Sopenharmony_ci pa_assert(pb); 8453a5a1b3Sopenharmony_ci pa_assert(pb->packets); 8553a5a1b3Sopenharmony_ci 8653a5a1b3Sopenharmony_ci pb->pos = 0; 8753a5a1b3Sopenharmony_ci pb->count = 0; 8853a5a1b3Sopenharmony_ci pb->seq = (!seq) ? UINT16_MAX : seq - 1; 8953a5a1b3Sopenharmony_ci for (i = 0; i < pb->size; i++) { 9053a5a1b3Sopenharmony_ci if (pb->packets[i].memblock) 9153a5a1b3Sopenharmony_ci pa_memblock_unref(pb->packets[i].memblock); 9253a5a1b3Sopenharmony_ci pa_memchunk_reset(&pb->packets[i]); 9353a5a1b3Sopenharmony_ci } 9453a5a1b3Sopenharmony_ci} 9553a5a1b3Sopenharmony_ci 9653a5a1b3Sopenharmony_cipa_memchunk *pa_raop_packet_buffer_prepare(pa_raop_packet_buffer *pb, uint16_t seq, const size_t size) { 9753a5a1b3Sopenharmony_ci pa_memchunk *packet = NULL; 9853a5a1b3Sopenharmony_ci size_t i; 9953a5a1b3Sopenharmony_ci 10053a5a1b3Sopenharmony_ci pa_assert(pb); 10153a5a1b3Sopenharmony_ci pa_assert(pb->packets); 10253a5a1b3Sopenharmony_ci 10353a5a1b3Sopenharmony_ci if (seq == 0) { 10453a5a1b3Sopenharmony_ci /* 0 means seq reached UINT16_MAX and has been wrapped... */ 10553a5a1b3Sopenharmony_ci pa_assert(pb->seq == UINT16_MAX); 10653a5a1b3Sopenharmony_ci pb->seq = 0; 10753a5a1b3Sopenharmony_ci } else { 10853a5a1b3Sopenharmony_ci /* ...otherwise, seq MUST have be increased! */ 10953a5a1b3Sopenharmony_ci pa_assert(seq == pb->seq + 1); 11053a5a1b3Sopenharmony_ci pb->seq++; 11153a5a1b3Sopenharmony_ci } 11253a5a1b3Sopenharmony_ci 11353a5a1b3Sopenharmony_ci i = (pb->pos + 1) % pb->size; 11453a5a1b3Sopenharmony_ci 11553a5a1b3Sopenharmony_ci if (pb->packets[i].memblock) 11653a5a1b3Sopenharmony_ci pa_memblock_unref(pb->packets[i].memblock); 11753a5a1b3Sopenharmony_ci pa_memchunk_reset(&pb->packets[i]); 11853a5a1b3Sopenharmony_ci 11953a5a1b3Sopenharmony_ci pb->packets[i].memblock = pa_memblock_new(pb->mempool, size); 12053a5a1b3Sopenharmony_ci pb->packets[i].length = size; 12153a5a1b3Sopenharmony_ci pb->packets[i].index = 0; 12253a5a1b3Sopenharmony_ci 12353a5a1b3Sopenharmony_ci packet = &pb->packets[i]; 12453a5a1b3Sopenharmony_ci 12553a5a1b3Sopenharmony_ci if (pb->count < pb->size) 12653a5a1b3Sopenharmony_ci pb->count++; 12753a5a1b3Sopenharmony_ci pb->pos = i; 12853a5a1b3Sopenharmony_ci 12953a5a1b3Sopenharmony_ci return packet; 13053a5a1b3Sopenharmony_ci} 13153a5a1b3Sopenharmony_ci 13253a5a1b3Sopenharmony_cipa_memchunk *pa_raop_packet_buffer_retrieve(pa_raop_packet_buffer *pb, uint16_t seq) { 13353a5a1b3Sopenharmony_ci pa_memchunk *packet = NULL; 13453a5a1b3Sopenharmony_ci size_t delta, i; 13553a5a1b3Sopenharmony_ci 13653a5a1b3Sopenharmony_ci pa_assert(pb); 13753a5a1b3Sopenharmony_ci pa_assert(pb->packets); 13853a5a1b3Sopenharmony_ci 13953a5a1b3Sopenharmony_ci if (seq == pb->seq) 14053a5a1b3Sopenharmony_ci packet = &pb->packets[pb->pos]; 14153a5a1b3Sopenharmony_ci else { 14253a5a1b3Sopenharmony_ci if (seq < pb->seq) { 14353a5a1b3Sopenharmony_ci /* Regular case: pb->seq did not wrapped since seq. */ 14453a5a1b3Sopenharmony_ci delta = pb->seq - seq; 14553a5a1b3Sopenharmony_ci } else { 14653a5a1b3Sopenharmony_ci /* Tricky case: pb->seq wrapped since seq! */ 14753a5a1b3Sopenharmony_ci delta = pb->seq + (UINT16_MAX - seq); 14853a5a1b3Sopenharmony_ci } 14953a5a1b3Sopenharmony_ci 15053a5a1b3Sopenharmony_ci /* If the requested packet is too old, do nothing and return */ 15153a5a1b3Sopenharmony_ci if (delta > pb->count) 15253a5a1b3Sopenharmony_ci return NULL; 15353a5a1b3Sopenharmony_ci 15453a5a1b3Sopenharmony_ci i = (pb->size + pb->pos - delta) % pb->size; 15553a5a1b3Sopenharmony_ci 15653a5a1b3Sopenharmony_ci if (delta < pb->size && pb->packets[i].memblock) 15753a5a1b3Sopenharmony_ci packet = &pb->packets[i]; 15853a5a1b3Sopenharmony_ci } 15953a5a1b3Sopenharmony_ci 16053a5a1b3Sopenharmony_ci return packet; 16153a5a1b3Sopenharmony_ci} 162