Add mbtk_loopbuff and rtp support.
Change-Id: Idc80af4efb8ff76c4afc59fdf1d3896b453e6ff4
diff --git a/mbtk/libmbtk_lib/Makefile b/mbtk/libmbtk_lib/Makefile
index 91c38de..90fc89f 100755
--- a/mbtk/libmbtk_lib/Makefile
+++ b/mbtk/libmbtk_lib/Makefile
@@ -18,7 +18,8 @@
-I$(LOCAL_PATH)/tcpip \
-I$(LOCAL_PATH)/ril/inc \
-I$(LOCAL_PATH)/sleep \
- -I$(LOCAL_PATH)/wifi
+ -I$(LOCAL_PATH)/wifi \
+ -I$(BUILD_ROOT)/mbtk_rtpd/inc
LIB_DIR +=
@@ -67,7 +68,8 @@
common/mbtk_version.c \
common/mbtk_gpio.c \
common/mbtk_adc.c \
- common/mbtk_debug.c
+ common/mbtk_debug.c \
+ common/mbtk_loopbuff.c
# audio
LOCAL_SRC_FILES += \
@@ -77,6 +79,10 @@
audio/mbtk_wav.c \
audio/mbtk_audio_ubus.c
+# rtp
+LOCAL_SRC_FILES += \
+ rtp/mbtk_rtp.c
+
# coap
LOCAL_SRC_FILES += \
coap/mbtk_coap.c \
diff --git a/mbtk/libmbtk_lib/audio/mbtk_audio_internal.h b/mbtk/libmbtk_lib/audio/mbtk_audio_internal.h
index b4b3dc2..0f020b7 100755
--- a/mbtk/libmbtk_lib/audio/mbtk_audio_internal.h
+++ b/mbtk/libmbtk_lib/audio/mbtk_audio_internal.h
@@ -46,10 +46,9 @@
audio_hw_device_t *audio_ahw_dev_ubus;
mbtk_audio_direction_enum direction;
- union {
- audio_play_info_t play;
- audio_recorder_info_t recorder;
- }info;
+
+ audio_play_info_t play;
+ audio_recorder_info_t recorder;
} audio_inter_info_t;
#endif /* _MBTK_AUDIO_INTERNAL_H */
diff --git a/mbtk/libmbtk_lib/audio/mbtk_pcm_stream.c b/mbtk/libmbtk_lib/audio/mbtk_pcm_stream.c
index 40f89e5..9e5f8ce 100755
--- a/mbtk/libmbtk_lib/audio/mbtk_pcm_stream.c
+++ b/mbtk/libmbtk_lib/audio/mbtk_pcm_stream.c
@@ -1,3 +1,21 @@
+/*
+* mbtk_pcm_stream.c
+*
+* MBTK audio playback/record PCM source.
+*
+*/
+/******************************************************************************
+
+ EDIT HISTORY FOR FILE
+
+ WHEN WHO WHAT,WHERE,WHY
+-------- -------- -------------------------------------------------------
+2024/03/23 LiuBin Initial version.
+2024/10/15 LiuBin Add PA and volume control API.
+2024/11/30 LiuBin Add get/send PCM from/to the end of voice(RTP).
+
+******************************************************************************/
+
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -78,28 +96,28 @@
int len, frames = 0;
char buff[MBTK_PCM_WB_BUF_SIZE];
- audio_info->info.recorder.state = AUDIO_RECORDER_STATE_RUNNING;
- pthread_mutex_init(&audio_info->info.recorder.mutex, NULL);
- pthread_cond_init(&audio_info->info.recorder.cond, NULL);
+ audio_info->recorder.state = AUDIO_RECORDER_STATE_RUNNING;
+ pthread_mutex_init(&audio_info->recorder.mutex, NULL);
+ pthread_cond_init(&audio_info->recorder.cond, NULL);
while (TRUE) {
/* Playback loop */
- pthread_mutex_lock(&audio_info->info.recorder.mutex);
- if(audio_info->info.recorder.state == AUDIO_RECORDER_STATE_STOP) {
+ pthread_mutex_lock(&audio_info->recorder.mutex);
+ if(audio_info->recorder.state == AUDIO_RECORDER_STATE_STOP) {
LOGD("Stop recorder...");
- pthread_mutex_unlock(&audio_info->info.recorder.mutex);
+ pthread_mutex_unlock(&audio_info->recorder.mutex);
break;
- } else if(audio_info->info.recorder.state == AUDIO_RECORDER_STATE_PAUSE) {
- pthread_cond_wait(&audio_info->info.recorder.cond, &audio_info->info.recorder.mutex);
- pthread_mutex_unlock(&audio_info->info.recorder.mutex);
+ } else if(audio_info->recorder.state == AUDIO_RECORDER_STATE_PAUSE) {
+ pthread_cond_wait(&audio_info->recorder.cond, &audio_info->recorder.mutex);
+ pthread_mutex_unlock(&audio_info->recorder.mutex);
continue;
} else {
- pthread_mutex_unlock(&audio_info->info.recorder.mutex);
+ pthread_mutex_unlock(&audio_info->recorder.mutex);
}
//record the needed format stream from the device.
//only read pcm stream, no send command.
- len = audio_info->info.recorder.stream_in->read(audio_info->info.recorder.stream_in, buff,
+ len = audio_info->recorder.stream_in->read(audio_info->recorder.stream_in, buff,
audio_info->playback_size);
if (len <= 0) {
LOGE("%s: error reading!", __FUNCTION__);
@@ -108,45 +126,44 @@
AUDIO_LOG("Recorder data : len - %d", len);
- if(audio_info->info.recorder.recorder_cb) {
- audio_info->info.recorder.recorder_cb(buff, len);
+ if(audio_info->recorder.recorder_cb) {
+ audio_info->recorder.recorder_cb(buff, len);
}
- LOGD("%s: No.%d frame playback.", __FUNCTION__, ++frames);
+ AUDIO_LOG("%s: No.%d frame playback.", __FUNCTION__, ++frames);
}
thread_end:
- pthread_mutex_destroy(&audio_info->info.recorder.mutex);
- pthread_cond_destroy(&audio_info->info.recorder.cond);
+ pthread_mutex_destroy(&audio_info->recorder.mutex);
+ pthread_cond_destroy(&audio_info->recorder.cond);
- audio_info->info.recorder.stream_in->common.standby(&audio_info->info.recorder.stream_in->common);
- audio_info->audio_ahw_dev_ubus->close_input_stream(audio_info->audio_ahw_dev_ubus, audio_info->info.recorder.stream_in);
+ audio_info->recorder.stream_in->common.standby(&audio_info->recorder.stream_in->common);
+ audio_info->audio_ahw_dev_ubus->close_input_stream(audio_info->audio_ahw_dev_ubus, audio_info->recorder.stream_in);
VCMDeinit();//close the fd of audiostub_ctl when exit the thread.
- audio_info->info.recorder.stream_in = NULL;
+ audio_info->recorder.stream_in = NULL;
LOGD("%s: finished pcm playback.", __FUNCTION__);
// Notify audio recorder data end.
- if(audio_info->info.recorder.recorder_cb) {
- audio_info->info.recorder.recorder_cb(NULL, 0);
+ if(audio_info->recorder.recorder_cb) {
+ audio_info->recorder.recorder_cb(NULL, 0);
}
return;
}
-static int config_parameters(mbtk_audio_direction_enum direction, mbtk_audio_sample_rate_enum NBWB)
+// srcdst = 1;/* 0-None, 1-Near end, 2-Far end, 3-Both ends */
+// priority = 1;/* 0-Do not combine(override), 1-Combine */
+// dest = 1;/* 0-Near codec, 1-Near Vocoder */
+static int config_parameters(mbtk_audio_direction_enum direction, mbtk_audio_sample_rate_enum NBWB,
+ unsigned int srcdst, unsigned int priority, unsigned int dest)
{
- unsigned int srcdst, priority, dest;
char kvpair[128];
struct str_parms *param = NULL;
int data[5];
const char *key = NULL;
bool update_vcm = false;
- srcdst = 1;/* 0-None, 1-Near end, 2-Far end, 3-Both ends */
- priority = 1;/* 0-Do not combine(override), 1-Combine */
- dest = 1;/* 0-Near codec, 1-Near Vocoder */
-
if(direction == MBTK_AUDIO_DIRECTION_OUTPUT){//output
if(NBWB == MBTK_AUDIO_SAMPLE_RATE_8000)
audio_info->playback_size = MBTK_PCM_NB_BUF_SIZE;
@@ -272,7 +289,7 @@
return 0;
}
-int mbtk_audio_pcm_play_start()
+int audio_pcm_play_start(unsigned int srcdst, unsigned int priority, unsigned int dest)
{
if(!audio_info) {
LOGE("Not inited.");
@@ -284,18 +301,18 @@
return -1;
}
- config_parameters(MBTK_AUDIO_DIRECTION_OUTPUT, audio_info->sample_rate);
+ config_parameters(MBTK_AUDIO_DIRECTION_OUTPUT, audio_info->sample_rate, srcdst, priority, dest);
int rc = audio_info->audio_ahw_dev_ubus->open_output_stream(audio_info->audio_ahw_dev_ubus, 0,
audio_info->audio_ahw_dev_ubus->get_supported_devices(audio_info->audio_ahw_dev_ubus),
- AUDIO_OUTPUT_FLAG_DIRECT, NULL, &(audio_info->info.play.stream_out), 0);
+ AUDIO_OUTPUT_FLAG_DIRECT, NULL, &(audio_info->play.stream_out), 0);
if (rc < 0) {
LOGE("Open output device fail:%d", rc);
goto play_start_fail;
}
audio_info->direction = MBTK_AUDIO_DIRECTION_OUTPUT;
- audio_info->info.play.buff_remain_len = 0;
+ audio_info->play.buff_remain_len = 0;
audio_pcm_write_count = 0;
return 0;
@@ -304,6 +321,39 @@
return -1;
}
+// Send PCM to the other end of the voice.
+int mbtk_audio_voice_pcm_playback_start()
+{
+ // direction = 0;/* 0-play, 1-record */
+ // type = 0/1; /* 0:PCM_NB_BUF_SIZE, 1:PCM_WB_BUF_SIZE */
+ // srcdst = 2;/* 0-None, 1-Near end, 2-Far end, 3-Both ends */
+ // priority = 0;/* 0-Do not combine(override), 1-Combine */
+ // dest = 0;/* 0-Near codec, 1-Near Vocoder */
+ return audio_pcm_play_start(2, 0, 0);
+#if 0
+ if(!audio_info) {
+ LOGE("Not inited.");
+ return -1;
+ }
+
+ if(!audio_info->audio_ahw_dev_ubus) {
+ LOGE("audio_info->audio_ahw_dev_ubus is NULL.");
+ return -1;
+ }
+
+ config_parameters(MBTK_AUDIO_DIRECTION_OUTPUT, audio_info->sample_rate, 2, 0, 0);
+ audio_info->play.is_voip = TRUE;
+
+ return 0;
+#endif
+}
+
+// Send PCM to location SPK.
+int mbtk_audio_pcm_play_start()
+{
+ return audio_pcm_play_start(1, 1, 1);
+}
+
int mbtk_audio_pcm_play_data_send(const void* data,uint32 data_len)
{
UNUSED(data);
@@ -314,25 +364,25 @@
return -1;
}
- if(!audio_info->info.play.stream_out) {
+ if(!audio_info->play.stream_out) {
LOGE("Output device not open.");
return -1;
}
uint32 index = 0;
// There are remaining data from the previous package。
- if(audio_info->info.play.buff_remain_len > 0) {
+ if(audio_info->play.buff_remain_len > 0) {
// Too less for one package.
- if(data_len + audio_info->info.play.buff_remain_len < audio_info->playback_size) {
+ if(data_len + audio_info->play.buff_remain_len < audio_info->playback_size) {
AUDIO_LOG("Save remain data : len - %d", data_len);
- memcpy(audio_info->info.play.buff_remain + audio_info->info.play.buff_remain_len, data, data_len);
- audio_info->info.play.buff_remain_len += data_len;
+ memcpy(audio_info->play.buff_remain + audio_info->play.buff_remain_len, data, data_len);
+ audio_info->play.buff_remain_len += data_len;
return data_len;
} else {
- AUDIO_LOG("Write remain data : %d + %d", audio_info->info.play.buff_remain_len, audio_info->playback_size - audio_info->info.play.buff_remain_len);
- memcpy(audio_info->info.play.buff_remain + audio_info->info.play.buff_remain_len, data, audio_info->playback_size - audio_info->info.play.buff_remain_len);
+ AUDIO_LOG("Write remain data : %d + %d", audio_info->play.buff_remain_len, audio_info->playback_size - audio_info->play.buff_remain_len);
+ memcpy(audio_info->play.buff_remain + audio_info->play.buff_remain_len, data, audio_info->playback_size - audio_info->play.buff_remain_len);
- int rc = audio_info->info.play.stream_out->write(audio_info->info.play.stream_out, audio_info->info.play.buff_remain, audio_info->playback_size);
+ int rc = audio_info->play.stream_out->write(audio_info->play.stream_out, audio_info->play.buff_remain, audio_info->playback_size);
if (rc < 0) {
LOGE("%s: error writing (child).", __FUNCTION__);
goto send_fail;
@@ -357,14 +407,14 @@
}
}
- index += (audio_info->playback_size - audio_info->info.play.buff_remain_len);
- audio_info->info.play.buff_remain_len = 0;
+ index += (audio_info->playback_size - audio_info->play.buff_remain_len);
+ audio_info->play.buff_remain_len = 0;
}
}
while(data_len - index >= audio_info->playback_size) {
AUDIO_LOG("Package : %d -> %d", index, index + audio_info->playback_size - 1);
- int rc = audio_info->info.play.stream_out->write(audio_info->info.play.stream_out, (const char*)data + index, audio_info->playback_size);
+ int rc = audio_info->play.stream_out->write(audio_info->play.stream_out, (const char*)data + index, audio_info->playback_size);
if (rc < 0) {
LOGE("%s: error writing (child).", __FUNCTION__);
goto send_fail;
@@ -380,8 +430,8 @@
// Save to buffer audio_info->play_buff_remain
if(data_len - index > 0) {
AUDIO_LOG("Save remain data : len - %d", data_len - index);
- memcpy(audio_info->info.play.buff_remain, data + index, data_len - index);
- audio_info->info.play.buff_remain_len = data_len - index;
+ memcpy(audio_info->play.buff_remain, data + index, data_len - index);
+ audio_info->play.buff_remain_len = data_len - index;
}
return data_len;
@@ -396,20 +446,20 @@
return -1;
}
- if(!audio_info->info.play.stream_out) {
+ if(!audio_info->play.stream_out) {
LOGE("Output device not open.");
return -1;
}
// Write last package.
- if(audio_info->info.play.buff_remain_len > 0) {
+ if(audio_info->play.buff_remain_len > 0) {
char buf[MBTK_PCM_WB_BUF_SIZE];
memset(buf, 0x00, sizeof(buf));
- memcpy(buf, audio_info->info.play.buff_remain, audio_info->info.play.buff_remain_len);
+ memcpy(buf, audio_info->play.buff_remain, audio_info->play.buff_remain_len);
- LOGD("len %d is smaller than needed %d, so fill the buffer with 0.", audio_info->info.play.buff_remain_len, audio_info->playback_size);
+ LOGD("len %d is smaller than needed %d, so fill the buffer with 0.", audio_info->play.buff_remain_len, audio_info->playback_size);
- int rc = audio_info->info.play.stream_out->write(audio_info->info.play.stream_out, buf, audio_info->playback_size);
+ int rc = audio_info->play.stream_out->write(audio_info->play.stream_out, buf, audio_info->playback_size);
if (rc < 0) {
LOGE("%s: error writing (child).", __FUNCTION__);
//goto send_fail;
@@ -417,7 +467,7 @@
LOGW("%s: wrote less than buffer size, rc=%d.", __FUNCTION__, rc);
//goto send_fail;
}
- audio_info->info.play.buff_remain_len = 0;
+ audio_info->play.buff_remain_len = 0;
}
// Close PA
@@ -427,15 +477,15 @@
vcm_playback_drain(80);//wait for drain the AP audiostub queue.
usleep(80000);//delay 80ms until DSP play out its buffered data.
- audio_info->info.play.stream_out->common.standby(&(audio_info->info.play.stream_out->common));
- audio_info->audio_ahw_dev_ubus->close_output_stream(audio_info->audio_ahw_dev_ubus, audio_info->info.play.stream_out);
+ audio_info->play.stream_out->common.standby(&(audio_info->play.stream_out->common));
+ audio_info->audio_ahw_dev_ubus->close_output_stream(audio_info->audio_ahw_dev_ubus, audio_info->play.stream_out);
- audio_info->info.play.stream_out = NULL;
+ audio_info->play.stream_out = NULL;
return 0;
}
-
-int mbtk_audio_pcm_recorder_start(mbtk_recorder_callback_func recorder_cb)
+static int audio_pcm_recorder_start(mbtk_recorder_callback_func recorder_cb,
+ unsigned int srcdst, unsigned int priority, unsigned int dest)
{
if(!audio_info) {
LOGE("Not inited.");
@@ -447,25 +497,25 @@
return -1;
}
- if(audio_info->info.recorder.state != AUDIO_RECORDER_STATE_STOP) {
+ if(audio_info->recorder.state != AUDIO_RECORDER_STATE_STOP) {
LOGW("Audio is recorder...");
return -1;
}
- config_parameters(MBTK_AUDIO_DIRECTION_INPUT, audio_info->sample_rate);
+ config_parameters(MBTK_AUDIO_DIRECTION_INPUT, audio_info->sample_rate, srcdst, priority, dest);
VCMInit();
int rc = audio_info->audio_ahw_dev_ubus->open_input_stream(audio_info->audio_ahw_dev_ubus, 0,
audio_info->audio_ahw_dev_ubus->get_supported_devices(audio_info->audio_ahw_dev_ubus),
- NULL, &(audio_info->info.recorder.stream_in), 0, 0, AUDIO_SOURCE_VOICE_CALL);
+ NULL, &(audio_info->recorder.stream_in), 0, 0, AUDIO_SOURCE_VOICE_CALL);
if (rc < 0) {
LOGE("Open input device fail:%d", rc);
goto recorder_start_fail;
}
audio_info->direction = MBTK_AUDIO_DIRECTION_INPUT;
- audio_info->info.recorder.recorder_cb = recorder_cb;
+ audio_info->recorder.recorder_cb = recorder_cb;
pthread_attr_t thread_attr;
pthread_attr_init(&thread_attr);
@@ -486,32 +536,70 @@
return -1;
}
+// Get PCM from the other end of the voice.
+int mbtk_audio_voice_pcm_record_start(mbtk_recorder_callback_func recorder_cb)
+{
+ // direction = 1;/* 0-play, 1-record */
+ // type = 0/1; /* 0:PCM_NB_BUF_SIZE, 1:PCM_WB_BUF_SIZE */
+ // srcdst = 2;/* 0-None, 1-Near end, 2-Far end, 3-Both ends */
+ // priority = 0;/* 0-Do not combine(override), 1-Combine */
+ // dest = 0;/* 0-Near codec, 1-Near Vocoder */
+ return audio_pcm_recorder_start(recorder_cb, 2, 0, 0);
+#if 0
+ if(!audio_info) {
+ LOGE("Not inited.");
+ return -1;
+ }
+
+ if(!audio_info->audio_ahw_dev_ubus) {
+ LOGE("audio_info->audio_ahw_dev_ubus is NULL.");
+ return -1;
+ }
+
+ if(audio_info->recorder.state != AUDIO_RECORDER_STATE_STOP) {
+ LOGW("Audio is recorder...");
+ return -1;
+ }
+
+ config_parameters(MBTK_AUDIO_DIRECTION_INPUT, audio_info->sample_rate, 2, 0, 0);
+ audio_info->recorder.is_voip = TRUE;
+
+ return 0;
+#endif
+}
+
+// Get PCM from location MIC.
+int mbtk_audio_pcm_recorder_start(mbtk_recorder_callback_func recorder_cb)
+{
+ return audio_pcm_recorder_start(recorder_cb, 1, 1, 1);
+}
+
int mbtk_audio_pcm_recorder_pause()
{
int result = 0;
- pthread_mutex_lock(&audio_info->info.recorder.mutex);
- if(audio_info->info.recorder.state == AUDIO_RECORDER_STATE_RUNNING) {
- audio_info->info.recorder.state = AUDIO_RECORDER_STATE_PAUSE;
+ pthread_mutex_lock(&audio_info->recorder.mutex);
+ if(audio_info->recorder.state == AUDIO_RECORDER_STATE_RUNNING) {
+ audio_info->recorder.state = AUDIO_RECORDER_STATE_PAUSE;
} else {
result = -1;
- LOGW("Audio state : %d", audio_info->info.recorder.state);
+ LOGW("Audio state : %d", audio_info->recorder.state);
}
- pthread_mutex_unlock(&audio_info->info.recorder.mutex);
+ pthread_mutex_unlock(&audio_info->recorder.mutex);
return result;
}
int mbtk_audio_pcm_recorder_resume()
{
int result = 0;
- pthread_mutex_lock(&audio_info->info.recorder.mutex);
- if(audio_info->info.recorder.state == AUDIO_RECORDER_STATE_PAUSE) {
- audio_info->info.recorder.state = AUDIO_RECORDER_STATE_RUNNING;
- pthread_cond_signal(&audio_info->info.recorder.cond);
+ pthread_mutex_lock(&audio_info->recorder.mutex);
+ if(audio_info->recorder.state == AUDIO_RECORDER_STATE_PAUSE) {
+ audio_info->recorder.state = AUDIO_RECORDER_STATE_RUNNING;
+ pthread_cond_signal(&audio_info->recorder.cond);
} else {
result = -1;
- LOGW("Audio state : %d", audio_info->info.recorder.state);
+ LOGW("Audio state : %d", audio_info->recorder.state);
}
- pthread_mutex_unlock(&audio_info->info.recorder.mutex);
+ pthread_mutex_unlock(&audio_info->recorder.mutex);
return result;
}
@@ -519,13 +607,13 @@
int mbtk_audio_pcm_recorder_stop()
{
int result = 0;
- pthread_mutex_lock(&audio_info->info.recorder.mutex);
- if(audio_info->info.recorder.state == AUDIO_RECORDER_STATE_PAUSE || audio_info->info.recorder.state == AUDIO_RECORDER_STATE_RUNNING) {
- if(audio_info->info.recorder.state == AUDIO_RECORDER_STATE_PAUSE) {
- pthread_cond_signal(&audio_info->info.recorder.cond);
+ pthread_mutex_lock(&audio_info->recorder.mutex);
+ if(audio_info->recorder.state == AUDIO_RECORDER_STATE_PAUSE || audio_info->recorder.state == AUDIO_RECORDER_STATE_RUNNING) {
+ if(audio_info->recorder.state == AUDIO_RECORDER_STATE_PAUSE) {
+ pthread_cond_signal(&audio_info->recorder.cond);
}
- audio_info->info.recorder.state = AUDIO_RECORDER_STATE_STOP;
- pthread_mutex_unlock(&audio_info->info.recorder.mutex);
+ audio_info->recorder.state = AUDIO_RECORDER_STATE_STOP;
+ pthread_mutex_unlock(&audio_info->recorder.mutex);
LOGD("Waitting recorder thread exit...");
if (pthread_join(recorder_thread_play, NULL)) {
@@ -534,9 +622,9 @@
}
LOGD("Recorder thread exit success.");
} else {
- pthread_mutex_unlock(&audio_info->info.recorder.mutex);
+ pthread_mutex_unlock(&audio_info->recorder.mutex);
result = -1;
- LOGW("Audio state : %d", audio_info->info.recorder.state);
+ LOGW("Audio state : %d", audio_info->recorder.state);
}
return result;
diff --git a/mbtk/libmbtk_lib/common/mbtk_loopbuff.c b/mbtk/libmbtk_lib/common/mbtk_loopbuff.c
new file mode 100755
index 0000000..37dbade
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/mbtk_loopbuff.c
@@ -0,0 +1,309 @@
+/*
+* 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);
+}
+
diff --git a/mbtk/libmbtk_lib/rtp/mbtk_rtp.c b/mbtk/libmbtk_lib/rtp/mbtk_rtp.c
new file mode 100755
index 0000000..961b9c5
--- /dev/null
+++ b/mbtk/libmbtk_lib/rtp/mbtk_rtp.c
@@ -0,0 +1,312 @@
+/*
+* mbtk_rtp.c
+*
+* MBTK RTP(VOIP) API source. This source depend on mbtk_rtpd server.
+*
+*/
+/******************************************************************************
+
+ EDIT HISTORY FOR FILE
+
+ WHEN WHO WHAT,WHERE,WHY
+-------- -------- -------------------------------------------------------
+2024/12/2 LiuBin Initial version
+
+******************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <time.h>
+#include <arpa/inet.h>
+
+#include "mbtk_rtp_internal.h"
+#include "mbtk_log.h"
+#include "mbtk_str.h"
+
+static int rtp_cli_fd = -1;
+
+static char* rtp_cmd_exec(const char* cmd, char *rsp, int rsp_len)
+{
+ if(rtp_cli_fd < 0) {
+ LOGW("RTP client not inited.");
+ return NULL;
+ }
+
+ int len = write(rtp_cli_fd, cmd, strlen(cmd));
+ if(len != strlen(cmd)) {
+ LOGE("write() fail(%d) : %d/%d", errno, len, strlen(cmd));
+ return NULL;
+ }
+ LOGD("Write cmd[%s] success.", cmd);
+
+ memset(rsp, 0, rsp_len);
+ len = read(rtp_cli_fd, rsp, rsp_len);
+ if(len <= 0) {
+ LOGE("read() fail(%d) : len = %d", errno, len);
+ return NULL;
+ }
+ LOGD("Read rsp[%s] success.", rsp);
+
+ if(rsp[0] == MBTK_IND_START_FLAG && rsp[len - 1] == MBTK_IND_END_FLAG) {
+ rsp[len - 1] = '\0';
+ return rsp + 1;
+ } else {
+ log_hex("RSP_ERR", rsp, len);
+ return NULL;
+ }
+}
+
+
+int mbtk_rtp_init()
+{
+ if(rtp_cli_fd > 0) {
+ LOGW("RTP client has inited.");
+ return 0;
+ }
+
+ rtp_cli_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+ if(rtp_cli_fd < 0)
+ {
+ LOGE("socket() fail[%d].", errno);
+ goto error;
+ }
+
+ struct sockaddr_un cli_addr;
+ memset(&cli_addr, 0, sizeof(cli_addr));
+ cli_addr.sun_family = AF_LOCAL;
+ strcpy(cli_addr.sun_path, RTP_IPC_SOCK_PATH);
+ if(connect(rtp_cli_fd, (struct sockaddr *)&cli_addr, sizeof(cli_addr)))
+ {
+ LOGE("connect() fail[%d].", errno);
+ goto error;
+ }
+
+ return 0;
+error:
+ if(rtp_cli_fd > 0) {
+ close(rtp_cli_fd);
+ rtp_cli_fd = -1;
+ }
+
+ return -1;
+}
+
+int mbtk_rtp_deinit()
+{
+ if(rtp_cli_fd < 0) {
+ LOGW("RTP client not inited.");
+ return -1;
+ }
+
+ close(rtp_cli_fd);
+ rtp_cli_fd = -1;
+
+ return 0;
+}
+
+int mbtk_rtp_enable(bool enable)
+{
+ if(rtp_cli_fd < 0) {
+ LOGW("RTP client not inited.");
+ return -1;
+ }
+
+ // gnss_init:x
+ char cmd[100] = {0};
+ char rsp[100] = {0};
+ snprintf(cmd, sizeof(cmd), "rtp_mode %d", enable ? 1 : 0); // rtp_mode <0/1>
+ char *result = rtp_cmd_exec(cmd, rsp, sizeof(rsp));
+ if(!result) {
+ return -1;
+ }
+
+ // rtp_mode:<err>
+ if(strcmp(result, "rtp_mode:0") == 0) {
+ return 0;
+ } else {
+ LOGE("CMD exec error:%s", result);
+ return -1;
+ }
+}
+
+int mbtk_rtp_volume_set(int volume)
+{
+ if(rtp_cli_fd < 0) {
+ LOGW("RTP client not inited.");
+ return -1;
+ }
+
+ // gnss_init:x
+ char cmd[100] = {0};
+ char rsp[100] = {0};
+ snprintf(cmd, sizeof(cmd), "volume %d", volume); // volume <0-7>
+ char *result = rtp_cmd_exec(cmd, rsp, sizeof(rsp));
+ if(!result) {
+ return -1;
+ }
+
+ // volume:<err>
+ if(strcmp(result, "volume:0") == 0) {
+ return 0;
+ } else {
+ LOGE("CMD exec error:%s", result);
+ return -1;
+ }
+}
+
+int mbtk_rtp_remote_ip_set(const char *ipv4)
+{
+ if(rtp_cli_fd < 0) {
+ LOGW("RTP client not inited.");
+ return -1;
+ }
+
+ uint32 IPAddr;
+ if(str_empty(ipv4) || inet_pton(AF_INET, ipv4, &IPAddr) < 0) {
+ LOGE("inet_pton() fail.");
+ return -1;
+ }
+
+ // gnss_init:x
+ char cmd[100] = {0};
+ char rsp[100] = {0};
+ snprintf(cmd, sizeof(cmd), "remote_ip %s", ipv4); // remote_ip xxx.xxx.xxx.xxx
+ char *result = rtp_cmd_exec(cmd, rsp, sizeof(rsp));
+ if(!result) {
+ return -1;
+ }
+
+ // rtp_mode:<err>
+ if(strcmp(result, "remote_ip:0") == 0) {
+ return 0;
+ } else {
+ LOGE("CMD exec error:%s", result);
+ return -1;
+ }
+}
+
+int mbtk_rtp_server_port_set(int port)
+{
+ if(rtp_cli_fd < 0) {
+ LOGW("RTP client not inited.");
+ return -1;
+ }
+
+#if 0
+ if(53248 != port) {
+ LOGE("Only support 53248 port[For GXX].");
+ return -1;
+ }
+#endif
+
+ // gnss_init:x
+ char cmd[100] = {0};
+ char rsp[100] = {0};
+ snprintf(cmd, sizeof(cmd), "server_port %d", port); // server_port <port>
+ char *result = rtp_cmd_exec(cmd, rsp, sizeof(rsp));
+ if(!result) {
+ return -1;
+ }
+
+ // volume:<err>
+ if(strcmp(result, "server_port:0") == 0) {
+ return 0;
+ } else {
+ LOGE("CMD exec error:%s", result);
+ return -1;
+ }
+}
+
+int mbtk_rtp_client_port_set(int port)
+{
+ if(rtp_cli_fd < 0) {
+ LOGW("RTP client not inited.");
+ return -1;
+ }
+
+ // gnss_init:x
+ char cmd[100] = {0};
+ char rsp[100] = {0};
+ snprintf(cmd, sizeof(cmd), "client_port %d", port); // client_port <port>
+ char *result = rtp_cmd_exec(cmd, rsp, sizeof(rsp));
+ if(!result) {
+ return -1;
+ }
+
+ // volume:<err>
+ if(strcmp(result, "client_port:0") == 0) {
+ return 0;
+ } else {
+ LOGE("CMD exec error:%s", result);
+ return -1;
+ }
+}
+
+int mbtk_rtp_sample_rate_set(int sample_rate)
+{
+ if(rtp_cli_fd < 0) {
+ LOGW("RTP client not inited.");
+ return -1;
+ }
+
+ if(sample_rate != 8000 && sample_rate != 16000) {
+ LOGE("Only support 8000/16000.");
+ return -1;
+ }
+
+ // gnss_init:x
+ char cmd[100] = {0};
+ char rsp[100] = {0};
+ snprintf(cmd, sizeof(cmd), "sample_rate %d", sample_rate); // sample_rate <sample_rate>
+ char *result = rtp_cmd_exec(cmd, rsp, sizeof(rsp));
+ if(!result) {
+ return -1;
+ }
+
+ // volume:<err>
+ if(strcmp(result, "sample_rate:0") == 0) {
+ return 0;
+ } else {
+ LOGE("CMD exec error:%s", result);
+ return -1;
+ }
+}
+
+int mbtk_rtp_channel_set(int channel)
+{
+ if(rtp_cli_fd < 0) {
+ LOGW("RTP client not inited.");
+ return -1;
+ }
+
+ if(channel != 1) {
+ LOGE("Only support 1 channel.");
+ return -1;
+ }
+
+ // gnss_init:x
+ char cmd[100] = {0};
+ char rsp[100] = {0};
+ snprintf(cmd, sizeof(cmd), "channel %d", channel); // channel <channel>
+ char *result = rtp_cmd_exec(cmd, rsp, sizeof(rsp));
+ if(!result) {
+ return -1;
+ }
+
+ // volume:<err>
+ if(strcmp(result, "channel:0") == 0) {
+ return 0;
+ } else {
+ LOGE("CMD exec error:%s", result);
+ return -1;
+ }
+}
+
+