blob: 37dbadea23fedc56a9b3fcf5c4729236a1bf1258 [file] [log] [blame]
/*
* mbtk_loop_buffer.c
*
* MBTK loop buffer sources.
*
*/
/******************************************************************************
EDIT HISTORY FOR FILE
WHEN WHO WHAT,WHERE,WHY
-------- -------- -------------------------------------------------------
2024/12/5 LiuBin Initial version
******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include "mbtk_str.h"
#include "mbtk_utils.h"
#include "mbtk_log.h"
#include "mbtk_type.h"
#include "mbtk_loop_buffer.h"
typedef struct {
int size;
uint8 *buffer;
int head;
int tail;
int avail_size;
pthread_mutex_t mutex;
} loop_buffer_t;
mbtk_loop_buff_handle* mbtk_loopbuff_get(int size)
{
if(size <= 0) {
LOGE("size error : %d", size);
return NULL;
}
loop_buffer_t *buff = (loop_buffer_t*)malloc(sizeof(loop_buffer_t));
if(buff == NULL) {
LOGE("malloc() fail:%d", errno);
return NULL;
}
memset(buff, 0, sizeof(loop_buffer_t));
buff->buffer = (uint8*)malloc(size);
if(buff == NULL) {
free(buff);
LOGE("malloc() fail:%d", errno);
return NULL;
}
buff->size = buff->avail_size = size;
pthread_mutex_init(&buff->mutex, NULL);
return buff;
}
int mbtk_loopbuff_free(mbtk_loop_buff_handle* handle)
{
if(handle == NULL) {
LOGE("handle is NULL");
return -1;
}
loop_buffer_t *buff = (loop_buffer_t*)handle;
if(buff->buffer) {
free(buff->buffer);
}
pthread_mutex_destroy(&buff->mutex);
free(buff);
return 0;
}
int mbtk_loopbuff_write(mbtk_loop_buff_handle* handle, const void *data, int data_len)
{
if(handle == NULL || data == NULL || data_len <= 0) {
LOGE("ARG error.");
return -1;
}
loop_buffer_t *loop_buff = (loop_buffer_t*)handle;
pthread_mutex_lock(&loop_buff->mutex);
if(loop_buff->avail_size == 0) {
LOGV("Buffer full.");
pthread_mutex_unlock(&loop_buff->mutex);
return -1;
} else {
int size = loop_buff->avail_size >= data_len ? data_len : loop_buff->avail_size;
// h t
// [...xxxxxxx...]
if(loop_buff->tail >= loop_buff->head) {
// h t t
// [...xxxxxxxyyy.]
if(loop_buff->tail + size <= loop_buff->size) {
memcpy(loop_buff->buffer + loop_buff->tail, data, size);
loop_buff->tail += size;
loop_buff->tail %= loop_buff->size;
} else {
// t h t
// [yyy...xxxxyy]
int len_right = loop_buff->size - loop_buff->tail; // len_right < size
memcpy(loop_buff->buffer + loop_buff->tail, data, len_right);
loop_buff->tail = 0;
memcpy(loop_buff->buffer + loop_buff->tail, data + len_right, size - len_right);
loop_buff->tail += (size - len_right);
}
} else {
// t t h
// [xxxyyy...xxxxx]
memcpy(loop_buff->buffer + loop_buff->tail, data, size);
loop_buff->tail += size;
loop_buff->tail %= loop_buff->size;
}
loop_buff->avail_size -= size;
pthread_mutex_unlock(&loop_buff->mutex);
return size;
}
}
int mbtk_loopbuff_writen(mbtk_loop_buff_handle* handle, const void *data, int data_len)
{
int len_count = 0;
// LOGD("mbtk_loopbuff_write() start.");
while(len_count < data_len) {
int len = mbtk_loopbuff_write(handle, data + len_count, data_len - len_count);
if(len > 0) {
#if 0
if(len != data_len - len_count) {
LOGD("%d/%d", len, data_len - len_count);
}
#endif
len_count += len;
} else {
usleep(5000);
}
}
#if 0
if(data_len != len_count) {
LOGD("mbtk_loopbuff_write() xxxxxxxxxxxxxxx fail : %d/%d", len_count, data_len);
}
#endif
return len_count;
}
int mbtk_loopbuff_read(mbtk_loop_buff_handle* handle, void *data, int data_len)
{
if(handle == NULL || data == NULL || data_len <= 0) {
LOGE("ARG error.");
return -1;
}
loop_buffer_t *loop_buff = (loop_buffer_t*)handle;
pthread_mutex_lock(&loop_buff->mutex);
if(loop_buff->avail_size == loop_buff->size) { // Buffer is empty.
pthread_mutex_unlock(&loop_buff->mutex);
LOGV("Buffer is empty.");
return 0;
} else {
int size = (loop_buff->size - loop_buff->avail_size) >= data_len ? data_len :
(loop_buff->size - loop_buff->avail_size);
// h h t
// [...yyyxxxx...]
if(loop_buff->tail > loop_buff->head) {
memcpy(data, loop_buff->buffer + loop_buff->head, size);
loop_buff->head += size;
} else {
// t h h
// [xxxxx.....yyyxx]
if(loop_buff->head + size <= loop_buff->size) {// [xxt...hxxxxxx]
memcpy(data, loop_buff->buffer + loop_buff->head, size);
loop_buff->head += size;
loop_buff->head %= loop_buff->size;
} else {
// h t h
// [yyyxxxx.....yyy]
int len_right = loop_buff->size - loop_buff->head; // len_right < size
memcpy(data, loop_buff->buffer + loop_buff->head, len_right);
loop_buff->head = 0;
memcpy(data + len_right, loop_buff->buffer + loop_buff->head, size - len_right);
loop_buff->head += (size - len_right);
}
}
loop_buff->avail_size += size;
pthread_mutex_unlock(&loop_buff->mutex);
return size;
}
}
int mbtk_loopbuff_readn(mbtk_loop_buff_handle* handle, void *data, int data_len)
{
int len_count = 0;
int read_count = 0;
while(len_count < data_len) {
int len = mbtk_loopbuff_read(handle, data + len_count, data_len - len_count);
if(len > 0) {
len_count += len;
} else {
usleep(5000);
}
read_count++;
if(read_count >= 20)
break;
}
return len_count;
}
// Only for read seek.
int mbtk_loopbuff_seek(mbtk_loop_buff_handle* handle, int offset)
{
if(handle == NULL) {
LOGE("ARG error.");
return -1;
}
if(offset == 0)
return 0;
loop_buffer_t *loop_buff = (loop_buffer_t*)handle;
pthread_mutex_lock(&loop_buff->mutex);
if(/*loop_buff->avail_size == loop_buff->size || */
offset > loop_buff->size || offset < -loop_buff->size) {
pthread_mutex_unlock(&loop_buff->mutex);
return -1;
} else {
if(offset > 0) {
int change = offset > (loop_buff->size - loop_buff->avail_size) ?
(loop_buff->size - loop_buff->avail_size) : offset;
loop_buff->head += change;
loop_buff->head %= loop_buff->size;
} else {
int change = -offset > loop_buff->avail_size ? loop_buff->avail_size : -offset;
loop_buff->head -= change;
if(loop_buff->head < 0)
loop_buff->head = loop_buff->size + loop_buff->head;
}
loop_buff->avail_size += offset;
pthread_mutex_unlock(&loop_buff->mutex);
return 0;
}
}
int mbtk_loopbuff_size(mbtk_loop_buff_handle* handle)
{
if(handle == NULL) {
LOGE("ARG error.");
return -1;
}
loop_buffer_t *loop_buff = (loop_buffer_t*)handle;
int size = 0;
pthread_mutex_lock(&loop_buff->mutex);
size = loop_buff->size - loop_buff->avail_size;
pthread_mutex_unlock(&loop_buff->mutex);
return size;
}
void mbtk_loopbuff_print(mbtk_loop_buff_handle* handle)
{
if(handle == NULL) {
LOGE("ARG error.");
return;
}
loop_buffer_t *loop_buff = (loop_buffer_t*)handle;
pthread_mutex_lock(&loop_buff->mutex);
int data_size = loop_buff->size - loop_buff->avail_size;
if(data_size <= 0) {
LOGD("Buffer is NULL.");
} else {
uint8 *buff = (uint8*)malloc(data_size);
if(buff) {
// h t
// [...xxxxxxx...]
if(loop_buff->tail > loop_buff->head) {
memcpy(buff, loop_buff->buffer + loop_buff->head, data_size);
} else {
// t h
// [xxxxx.....xxxxx]
int len_right = loop_buff->size - loop_buff->head; // len_right < size
memcpy(buff, loop_buff->buffer + loop_buff->head, len_right);
if(data_size - len_right > 0) {
memcpy(buff + len_right, loop_buff->buffer, data_size - len_right);
}
}
LOGD("Head = %d, Tail = %d, Lenght = %d / %d", loop_buff->head, loop_buff->tail,
data_size, loop_buff->size);
log_hex("DATA", buff, data_size);
free(buff);
buff = NULL;
}
}
pthread_mutex_unlock(&loop_buff->mutex);
}