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;
+    }
+}
+
+