| /* |
| * 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); |
| } |
| |