153a5a1b3Sopenharmony_ci/* Copyright (C) 2007 Jean-Marc Valin
253a5a1b3Sopenharmony_ci
353a5a1b3Sopenharmony_ci   File: buffer.c
453a5a1b3Sopenharmony_ci   This is a very simple ring buffer implementation. It is not thread-safe
553a5a1b3Sopenharmony_ci   so you need to do your own locking.
653a5a1b3Sopenharmony_ci
753a5a1b3Sopenharmony_ci   Redistribution and use in source and binary forms, with or without
853a5a1b3Sopenharmony_ci   modification, are permitted provided that the following conditions are
953a5a1b3Sopenharmony_ci   met:
1053a5a1b3Sopenharmony_ci
1153a5a1b3Sopenharmony_ci   1. Redistributions of source code must retain the above copyright notice,
1253a5a1b3Sopenharmony_ci   this list of conditions and the following disclaimer.
1353a5a1b3Sopenharmony_ci
1453a5a1b3Sopenharmony_ci   2. Redistributions in binary form must reproduce the above copyright
1553a5a1b3Sopenharmony_ci   notice, this list of conditions and the following disclaimer in the
1653a5a1b3Sopenharmony_ci   documentation and/or other materials provided with the distribution.
1753a5a1b3Sopenharmony_ci
1853a5a1b3Sopenharmony_ci   3. The name of the author may not be used to endorse or promote products
1953a5a1b3Sopenharmony_ci   derived from this software without specific prior written permission.
2053a5a1b3Sopenharmony_ci
2153a5a1b3Sopenharmony_ci   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2253a5a1b3Sopenharmony_ci   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2353a5a1b3Sopenharmony_ci   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2453a5a1b3Sopenharmony_ci   DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
2553a5a1b3Sopenharmony_ci   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2653a5a1b3Sopenharmony_ci   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2753a5a1b3Sopenharmony_ci   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2853a5a1b3Sopenharmony_ci   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2953a5a1b3Sopenharmony_ci   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
3053a5a1b3Sopenharmony_ci   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3153a5a1b3Sopenharmony_ci   POSSIBILITY OF SUCH DAMAGE.
3253a5a1b3Sopenharmony_ci*/
3353a5a1b3Sopenharmony_ci
3453a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
3553a5a1b3Sopenharmony_ci#include "config.h"
3653a5a1b3Sopenharmony_ci#endif
3753a5a1b3Sopenharmony_ci
3853a5a1b3Sopenharmony_ci
3953a5a1b3Sopenharmony_ci#include "os_support.h"
4053a5a1b3Sopenharmony_ci#include "arch.h"
4153a5a1b3Sopenharmony_ci#include "speex/speex_buffer.h"
4253a5a1b3Sopenharmony_ci
4353a5a1b3Sopenharmony_cistruct SpeexBuffer_ {
4453a5a1b3Sopenharmony_ci   char *data;
4553a5a1b3Sopenharmony_ci   int   size;
4653a5a1b3Sopenharmony_ci   int   read_ptr;
4753a5a1b3Sopenharmony_ci   int   write_ptr;
4853a5a1b3Sopenharmony_ci   int   available;
4953a5a1b3Sopenharmony_ci};
5053a5a1b3Sopenharmony_ci
5153a5a1b3Sopenharmony_ciEXPORT SpeexBuffer *speex_buffer_init(int size)
5253a5a1b3Sopenharmony_ci{
5353a5a1b3Sopenharmony_ci   SpeexBuffer *st = speex_alloc(sizeof(SpeexBuffer));
5453a5a1b3Sopenharmony_ci   st->data = speex_alloc(size);
5553a5a1b3Sopenharmony_ci   st->size = size;
5653a5a1b3Sopenharmony_ci   st->read_ptr = 0;
5753a5a1b3Sopenharmony_ci   st->write_ptr = 0;
5853a5a1b3Sopenharmony_ci   st->available = 0;
5953a5a1b3Sopenharmony_ci   return st;
6053a5a1b3Sopenharmony_ci}
6153a5a1b3Sopenharmony_ci
6253a5a1b3Sopenharmony_ciEXPORT void speex_buffer_destroy(SpeexBuffer *st)
6353a5a1b3Sopenharmony_ci{
6453a5a1b3Sopenharmony_ci   speex_free(st->data);
6553a5a1b3Sopenharmony_ci   speex_free(st);
6653a5a1b3Sopenharmony_ci}
6753a5a1b3Sopenharmony_ci
6853a5a1b3Sopenharmony_ciEXPORT int speex_buffer_write(SpeexBuffer *st, void *_data, int len)
6953a5a1b3Sopenharmony_ci{
7053a5a1b3Sopenharmony_ci   int end;
7153a5a1b3Sopenharmony_ci   int end1;
7253a5a1b3Sopenharmony_ci   char *data = _data;
7353a5a1b3Sopenharmony_ci   if (len > st->size)
7453a5a1b3Sopenharmony_ci   {
7553a5a1b3Sopenharmony_ci      data += len-st->size;
7653a5a1b3Sopenharmony_ci      len = st->size;
7753a5a1b3Sopenharmony_ci   }
7853a5a1b3Sopenharmony_ci   end = st->write_ptr + len;
7953a5a1b3Sopenharmony_ci   end1 = end;
8053a5a1b3Sopenharmony_ci   if (end1 > st->size)
8153a5a1b3Sopenharmony_ci      end1 = st->size;
8253a5a1b3Sopenharmony_ci   SPEEX_COPY(st->data + st->write_ptr, data, end1 - st->write_ptr);
8353a5a1b3Sopenharmony_ci   if (end > st->size)
8453a5a1b3Sopenharmony_ci   {
8553a5a1b3Sopenharmony_ci      end -= st->size;
8653a5a1b3Sopenharmony_ci      SPEEX_COPY(st->data, data+end1 - st->write_ptr, end);
8753a5a1b3Sopenharmony_ci   }
8853a5a1b3Sopenharmony_ci   st->available += len;
8953a5a1b3Sopenharmony_ci   if (st->available > st->size)
9053a5a1b3Sopenharmony_ci   {
9153a5a1b3Sopenharmony_ci      st->available = st->size;
9253a5a1b3Sopenharmony_ci      st->read_ptr = st->write_ptr;
9353a5a1b3Sopenharmony_ci   }
9453a5a1b3Sopenharmony_ci   st->write_ptr += len;
9553a5a1b3Sopenharmony_ci   if (st->write_ptr > st->size)
9653a5a1b3Sopenharmony_ci      st->write_ptr -= st->size;
9753a5a1b3Sopenharmony_ci   return len;
9853a5a1b3Sopenharmony_ci}
9953a5a1b3Sopenharmony_ci
10053a5a1b3Sopenharmony_ciEXPORT int speex_buffer_writezeros(SpeexBuffer *st, int len)
10153a5a1b3Sopenharmony_ci{
10253a5a1b3Sopenharmony_ci   /* This is almost the same as for speex_buffer_write() but using
10353a5a1b3Sopenharmony_ci   SPEEX_MEMSET() instead of SPEEX_COPY(). Update accordingly. */
10453a5a1b3Sopenharmony_ci   int end;
10553a5a1b3Sopenharmony_ci   int end1;
10653a5a1b3Sopenharmony_ci   if (len > st->size)
10753a5a1b3Sopenharmony_ci   {
10853a5a1b3Sopenharmony_ci      len = st->size;
10953a5a1b3Sopenharmony_ci   }
11053a5a1b3Sopenharmony_ci   end = st->write_ptr + len;
11153a5a1b3Sopenharmony_ci   end1 = end;
11253a5a1b3Sopenharmony_ci   if (end1 > st->size)
11353a5a1b3Sopenharmony_ci      end1 = st->size;
11453a5a1b3Sopenharmony_ci   SPEEX_MEMSET(st->data + st->write_ptr, 0, end1 - st->write_ptr);
11553a5a1b3Sopenharmony_ci   if (end > st->size)
11653a5a1b3Sopenharmony_ci   {
11753a5a1b3Sopenharmony_ci      end -= st->size;
11853a5a1b3Sopenharmony_ci      SPEEX_MEMSET(st->data, 0, end);
11953a5a1b3Sopenharmony_ci   }
12053a5a1b3Sopenharmony_ci   st->available += len;
12153a5a1b3Sopenharmony_ci   if (st->available > st->size)
12253a5a1b3Sopenharmony_ci   {
12353a5a1b3Sopenharmony_ci      st->available = st->size;
12453a5a1b3Sopenharmony_ci      st->read_ptr = st->write_ptr;
12553a5a1b3Sopenharmony_ci   }
12653a5a1b3Sopenharmony_ci   st->write_ptr += len;
12753a5a1b3Sopenharmony_ci   if (st->write_ptr > st->size)
12853a5a1b3Sopenharmony_ci      st->write_ptr -= st->size;
12953a5a1b3Sopenharmony_ci   return len;
13053a5a1b3Sopenharmony_ci}
13153a5a1b3Sopenharmony_ci
13253a5a1b3Sopenharmony_ciEXPORT int speex_buffer_read(SpeexBuffer *st, void *_data, int len)
13353a5a1b3Sopenharmony_ci{
13453a5a1b3Sopenharmony_ci   int end, end1;
13553a5a1b3Sopenharmony_ci   char *data = _data;
13653a5a1b3Sopenharmony_ci   if (len > st->available)
13753a5a1b3Sopenharmony_ci   {
13853a5a1b3Sopenharmony_ci      SPEEX_MEMSET(data+st->available, 0, len - st->available);
13953a5a1b3Sopenharmony_ci      len = st->available;
14053a5a1b3Sopenharmony_ci   }
14153a5a1b3Sopenharmony_ci   end = st->read_ptr + len;
14253a5a1b3Sopenharmony_ci   end1 = end;
14353a5a1b3Sopenharmony_ci   if (end1 > st->size)
14453a5a1b3Sopenharmony_ci      end1 = st->size;
14553a5a1b3Sopenharmony_ci   SPEEX_COPY(data, st->data + st->read_ptr, end1 - st->read_ptr);
14653a5a1b3Sopenharmony_ci
14753a5a1b3Sopenharmony_ci   if (end > st->size)
14853a5a1b3Sopenharmony_ci   {
14953a5a1b3Sopenharmony_ci      end -= st->size;
15053a5a1b3Sopenharmony_ci      SPEEX_COPY(data+end1 - st->read_ptr, st->data, end);
15153a5a1b3Sopenharmony_ci   }
15253a5a1b3Sopenharmony_ci   st->available -= len;
15353a5a1b3Sopenharmony_ci   st->read_ptr += len;
15453a5a1b3Sopenharmony_ci   if (st->read_ptr > st->size)
15553a5a1b3Sopenharmony_ci      st->read_ptr -= st->size;
15653a5a1b3Sopenharmony_ci   return len;
15753a5a1b3Sopenharmony_ci}
15853a5a1b3Sopenharmony_ci
15953a5a1b3Sopenharmony_ciEXPORT int speex_buffer_get_available(SpeexBuffer *st)
16053a5a1b3Sopenharmony_ci{
16153a5a1b3Sopenharmony_ci   return st->available;
16253a5a1b3Sopenharmony_ci}
16353a5a1b3Sopenharmony_ci
16453a5a1b3Sopenharmony_ciEXPORT int speex_buffer_resize(SpeexBuffer *st, int len)
16553a5a1b3Sopenharmony_ci{
16653a5a1b3Sopenharmony_ci   int old_len = st->size;
16753a5a1b3Sopenharmony_ci   if (len > old_len)
16853a5a1b3Sopenharmony_ci   {
16953a5a1b3Sopenharmony_ci      st->data = speex_realloc(st->data, len);
17053a5a1b3Sopenharmony_ci      /* FIXME: move data/pointers properly for growing the buffer */
17153a5a1b3Sopenharmony_ci   } else {
17253a5a1b3Sopenharmony_ci      /* FIXME: move data/pointers properly for shrinking the buffer */
17353a5a1b3Sopenharmony_ci      st->data = speex_realloc(st->data, len);
17453a5a1b3Sopenharmony_ci   }
17553a5a1b3Sopenharmony_ci   return len;
17653a5a1b3Sopenharmony_ci}
177