From 7fc86f559055e7d159c51914ae542ccaf6461fcb Mon Sep 17 00:00:00 2001 From: cqm Date: Fri, 4 Jul 2025 16:15:15 +0800 Subject: [PATCH 1/2] port for windows --- CMakeLists.txt | 11 +++- examples/generic/CMakeLists.txt | 5 +- examples/generic/main.c | 30 +++++------ examples/generic/reader.c | 1 - src/address.h | 3 ++ src/agent.c | 3 +- src/agent.h | 2 - src/dtls_srtp.c | 1 - src/mdns.c | 3 ++ src/peer.c | 1 - src/peer_connection.c | 1 - src/peer_signaling.c | 1 - src/ports.c | 92 ++++++++++++++++++++++++++++++++- src/rtp.h | 4 +- src/sctp.c | 3 +- src/socket.c | 2 - src/ssl_transport.c | 3 +- src/stun.c | 1 - tests/CMakeLists.txt | 6 ++- tests/test_dtls.c | 2 - tests/test_peer_connection.c | 18 +++++-- 21 files changed, 150 insertions(+), 43 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 83789d06..584cdf88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,9 @@ endif() project(peer) option(ENABLE_TESTS "Enable tests" OFF) +if (WIN32) +set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) +endif() option(BUILD_SHARED_LIBS "Build shared libraries" ON) option(ADDRESS_SANITIZER "Build with AddressSanitizer." OFF) option(MEMORY_SANITIZER "Build with MemorySanitizer." OFF) @@ -59,7 +62,12 @@ if(UNDEFINED_BEHAVIOR_SANITIZER) enableSanitizer("undefined") endif() -add_definitions("-Wunused-variable -Werror=sequence-point -Werror=pointer-sign -Werror=return-type -Werror=sizeof-pointer-memaccess -Wincompatible-pointer-types -DHTTP_DO_NOT_USE_CUSTOM_CONFIG -DMQTT_DO_NOT_USE_CUSTOM_CONFIG") +add_definitions("-DHTTP_DO_NOT_USE_CUSTOM_CONFIG -DMQTT_DO_NOT_USE_CUSTOM_CONFIG") +if(NOT WIN32) +add_definitions("-Wunused-variable -Werror=sequence-point -Werror=pointer-sign -Werror=return-type -Werror=sizeof-pointer-memaccess -Wincompatible-pointer-types") +else() +add_definitions("-D__BYTE_ORDER=1234") +endif() add_subdirectory(src) add_subdirectory(examples) @@ -105,6 +113,7 @@ ExternalProject_Add(usrsctp CMAKE_ARGS -DCMAKE_C_FLAGS="-fPIC" -Dsctp_build_programs=off + -Dsctp_werror=off -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/dist -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} ) diff --git a/examples/generic/CMakeLists.txt b/examples/generic/CMakeLists.txt index de023db3..b6e46e8b 100644 --- a/examples/generic/CMakeLists.txt +++ b/examples/generic/CMakeLists.txt @@ -6,5 +6,8 @@ include_directories(${CMAKE_SOURCE_DIR}/src) add_executable(sample ${SRCS}) -target_link_libraries(sample peer pthread) +target_link_libraries(sample peer) +if(NOT WIN32) + target_link_libraries(sample pthread) +endif() diff --git a/examples/generic/main.c b/examples/generic/main.c index 8fc13ffd..40672096 100644 --- a/examples/generic/main.c +++ b/examples/generic/main.c @@ -1,12 +1,18 @@ -#include #include #include #include -#include -#include - +#include "ports.h" #include "peer.h" #include "reader.h" +#ifdef WIN32 +#include +#define pthread_t HANDLE +#define pthread_create(th, attr, func, arg) (*(th) = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(func), (arg), 0, NULL)) +#define pthread_join(th, res) WaitForSingleObject((th), INFINITE) +#define pthread_exit(res) ExitThread(0) +#else +#include +#endif int g_interrupted = 0; PeerConnection* g_pc = NULL; @@ -39,27 +45,19 @@ static void signal_handler(int signal) { static void* peer_singaling_task(void* data) { while (!g_interrupted) { peer_signaling_loop(); - usleep(1000); + ports_sleep_ms(1); } - pthread_exit(NULL); } static void* peer_connection_task(void* data) { while (!g_interrupted) { peer_connection_loop(g_pc); - usleep(1000); + ports_sleep_ms(1); } - pthread_exit(NULL); } -static uint64_t get_timestamp() { - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec * 1000 + tv.tv_usec / 1000; -} - void print_usage(const char* prog_name) { printf("Usage: %s -u [-t ]\n", prog_name); } @@ -126,7 +124,7 @@ int main(int argc, char* argv[]) { while (!g_interrupted) { if (g_state == PEER_CONNECTION_COMPLETED) { - curr_time = get_timestamp(); + curr_time = ports_get_epoch_time(); // FPS 25 if (curr_time - video_time > 40) { @@ -147,7 +145,7 @@ int main(int argc, char* argv[]) { audio_time = curr_time; } } - usleep(1000); + ports_sleep_ms(1); } pthread_join(peer_singaling_thread, NULL); diff --git a/examples/generic/reader.c b/examples/generic/reader.c index 85ef8a57..72e2b983 100644 --- a/examples/generic/reader.c +++ b/examples/generic/reader.c @@ -2,7 +2,6 @@ #include #include #include -#include static int g_video_size = 0; static int g_audio_size = 0; diff --git a/src/address.h b/src/address.h index 6f8eb781..3de81a5f 100644 --- a/src/address.h +++ b/src/address.h @@ -4,6 +4,9 @@ #include "config.h" #if CONFIG_USE_LWIP #include +#elif defined(WIN32) +#include +#include #else #include #include diff --git a/src/agent.c b/src/agent.c index 57de5c95..92e4a367 100644 --- a/src/agent.c +++ b/src/agent.c @@ -1,8 +1,9 @@ #include #include #include +#ifndef WIN32 #include -#include +#endif #include "agent.h" #include "base64.h" diff --git a/src/agent.h b/src/agent.h index 382d5a4e..9a00c26b 100644 --- a/src/agent.h +++ b/src/agent.h @@ -4,9 +4,7 @@ #include #include #include -#include -#include "base64.h" #include "ice.h" #include "socket.h" #include "stun.h" diff --git a/src/dtls_srtp.c b/src/dtls_srtp.c index dd546169..22c7828c 100644 --- a/src/dtls_srtp.c +++ b/src/dtls_srtp.c @@ -1,7 +1,6 @@ #include #include #include -#include #include "address.h" #include "config.h" diff --git a/src/mdns.c b/src/mdns.c index 6d7881cb..007542ba 100644 --- a/src/mdns.c +++ b/src/mdns.c @@ -2,8 +2,10 @@ #include #include #include +#ifndef WIN32 #include #include +#endif #include "address.h" #include "socket.h" #include "utils.h" @@ -53,6 +55,7 @@ static int mdns_add_hostname(const char* hostname, uint8_t* buf, int size) { buf[offset++] = 0x00; return offset; } + static int mdns_parse_answer(uint8_t* buf, int size, Address* addr, const char* hostname) { int flags_qr, offset; DnsHeader* header; diff --git a/src/peer.c b/src/peer.c index f24bf9df..f14bc25d 100644 --- a/src/peer.c +++ b/src/peer.c @@ -1,7 +1,6 @@ #include #include #include -#include #include "peer.h" #include "sctp.h" diff --git a/src/peer_connection.c b/src/peer_connection.c index c763e806..d56810c2 100644 --- a/src/peer_connection.c +++ b/src/peer_connection.c @@ -1,7 +1,6 @@ #include #include #include -#include #include "agent.h" #include "config.h" diff --git a/src/peer_signaling.c b/src/peer_signaling.c index f5dbd838..9d277189 100644 --- a/src/peer_signaling.c +++ b/src/peer_signaling.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include diff --git a/src/ports.c b/src/ports.c index 2346f609..a3f300db 100644 --- a/src/ports.c +++ b/src/ports.c @@ -1,9 +1,11 @@ #include #include + +#ifndef WIN32 #include #include #include - +#endif #include "config.h" #if CONFIG_USE_LWIP @@ -11,6 +13,12 @@ #include "lwip/netdb.h" #include "lwip/netif.h" #include "lwip/sys.h" +#elif WIN32 +#include +// Windows implementation using GetAdaptersAddresses +#include +#pragma comment(lib, "iphlpapi.lib") +#pragma comment(lib, "ws2_32.lib") #else #include #include @@ -51,6 +59,73 @@ int ports_get_host_addr(Address* addr, const char* iface_prefix) { break; } } +#elif WIN32 + ULONG out_buf_len = 15000; + IP_ADAPTER_ADDRESSES* addresses = (IP_ADAPTER_ADDRESSES *)malloc(out_buf_len); + if (addresses == NULL) { + LOGE("Memory allocation failed for IP_ADAPTER_ADDRESSES struct"); + return -1; + } + + DWORD dwRetVal = GetAdaptersAddresses(addr->family, + GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, + NULL, addresses, &out_buf_len); + + if (dwRetVal == ERROR_BUFFER_OVERFLOW) { + free(addresses); + addresses = (IP_ADAPTER_ADDRESSES *)malloc(out_buf_len); + if (addresses == NULL) { + LOGE("Memory allocation failed for IP_ADAPTER_ADDRESSES struct"); + return -1; + } + dwRetVal = GetAdaptersAddresses(addr->family, + GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, + NULL, addresses, &out_buf_len); + } + + if (dwRetVal != NO_ERROR) { + LOGE("GetAdaptersAddresses() failed: %ld", dwRetVal); + free(addresses); + return ret; + } + + for (IP_ADAPTER_ADDRESSES* addr_ptr = addresses; addr_ptr != NULL; addr_ptr = addr_ptr->Next) { + if (iface_prefix && strlen(iface_prefix) > 0) { + if (strncmp(addr_ptr->AdapterName, iface_prefix, strlen(iface_prefix)) != 0) { + continue; + } + } else { + if (addr_ptr->OperStatus != IfOperStatusUp) { + continue; + } + if (addr_ptr->IfType == IF_TYPE_SOFTWARE_LOOPBACK) { + continue; + } + } + + IP_ADAPTER_UNICAST_ADDRESS *unicast = addr_ptr->FirstUnicastAddress; + for (; unicast != NULL; unicast = unicast->Next) { + if (unicast->Address.lpSockaddr->sa_family != addr->family) + continue; + + switch (addr->family) { + case AF_INET6: + memcpy(&addr->sin6, unicast->Address.lpSockaddr, sizeof(struct sockaddr_in6)); + break; + case AF_INET: + default: + memcpy(&addr->sin, unicast->Address.lpSockaddr, sizeof(struct sockaddr_in)); + break; + } + ret = 1; + break; + } + if (ret) + break; + } + + free(addresses); + #else struct ifaddrs *ifaddr, *ifa; @@ -144,13 +219,28 @@ int ports_resolve_addr(const char* host, Address* addr) { uint32_t ports_get_epoch_time() { struct timeval tv; +#if WIN32 + FILETIME ft; + ULARGE_INTEGER uli; + GetSystemTimeAsFileTime(&ft); + uli.LowPart = ft.dwLowDateTime; + uli.HighPart = ft.dwHighDateTime; + // FILETIME is in 100-nanosecond intervals since Jan 1, 1601 (UTC) + // Convert to milliseconds since Unix epoch (Jan 1, 1970) + uint64_t epoch = (uli.QuadPart - 116444736000000000ULL) / 10000ULL; + tv.tv_sec = (long)(epoch / 1000); + tv.tv_usec = (long)((epoch % 1000) * 1000); +#else gettimeofday(&tv, NULL); +#endif return (uint32_t)tv.tv_sec * 1000 + tv.tv_usec / 1000; } void ports_sleep_ms(int ms) { #if CONFIG_USE_LWIP sys_msleep(ms); +#elif WIN32 + Sleep(ms); #else usleep(ms * 1000); #endif diff --git a/src/rtp.h b/src/rtp.h index 4f946145..e5fbd7d3 100644 --- a/src/rtp.h +++ b/src/rtp.h @@ -53,13 +53,13 @@ typedef struct RtpHeader { uint16_t seq_number; uint32_t timestamp; uint32_t ssrc; - uint32_t csrc[0]; + //uint32_t csrc[0]; } RtpHeader; typedef struct RtpPacket { RtpHeader header; - uint8_t payload[0]; + uint8_t payload[1]; } RtpPacket; diff --git a/src/sctp.c b/src/sctp.c index 644f8d8e..663dd69f 100644 --- a/src/sctp.c +++ b/src/sctp.c @@ -184,7 +184,7 @@ void sctp_parse_data_channel_open(Sctp* sctp, uint16_t sid, char* data, size_t l char* label = (char*)(data + 12); // copy and null-terminate - char label_str[label_length + 1]; + char* label_str = malloc(label_length + 1); memcpy(label_str, label, label_length); label_str[label_length] = '\0'; @@ -195,6 +195,7 @@ void sctp_parse_data_channel_open(Sctp* sctp, uint16_t sid, char* data, size_t l sctp_add_stream_mapping(sctp, label_str, sid); char ack = DATA_CHANNEL_ACK; sctp_outgoing_data(sctp, &ack, 1, DATA_CHANNEL_PPID_CONTROL, sid); + free(label_str); } } diff --git a/src/socket.c b/src/socket.c index 6f7d8ef2..60aaeee3 100644 --- a/src/socket.c +++ b/src/socket.c @@ -1,7 +1,5 @@ #include #include -#include - #include "socket.h" #include "utils.h" diff --git a/src/ssl_transport.c b/src/ssl_transport.c index 9847616f..7c4a6863 100644 --- a/src/ssl_transport.c +++ b/src/ssl_transport.c @@ -7,8 +7,9 @@ #include "mbedtls/debug.h" #include "mbedtls/entropy.h" #include "mbedtls/ssl.h" - +#ifndef WIN32 #include +#endif #include "config.h" #include "ports.h" #include "ssl_transport.h" diff --git a/src/stun.c b/src/stun.c index d3872410..616c0c4d 100644 --- a/src/stun.c +++ b/src/stun.c @@ -2,7 +2,6 @@ #include #include #include -#include #include "stun.h" #include "utils.h" diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6c0c6dfd..07902192 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -8,8 +8,10 @@ foreach(sourcefile ${SRCS}) string(REPLACE ".c" "" appname ${sourcefile}) string(REPLACE "${PROJECT_SOURCE_DIR}/" "" appname ${appname}) add_executable(${appname} ${sourcefile}) - target_link_libraries(${appname} peer pthread) + target_link_libraries(${appname} peer) endforeach(sourcefile ${TEST_SRCS}) target_link_libraries(test_peer_connection cjson) - +if(NOT WIN32) + target_link_libraries(test_peer_connection pthread) +endif() diff --git a/tests/test_dtls.c b/tests/test_dtls.c index 635c0e80..eb933364 100644 --- a/tests/test_dtls.c +++ b/tests/test_dtls.c @@ -1,8 +1,6 @@ #include #include #include -#include - #include "dtls_srtp.h" void test_handshake(int argc, char* argv[]) { diff --git a/tests/test_peer_connection.c b/tests/test_peer_connection.c index 55526259..5d16981c 100644 --- a/tests/test_peer_connection.c +++ b/tests/test_peer_connection.c @@ -1,9 +1,17 @@ -#include #include #include -#include - #include "peer.h" +#include "ports.h" +#ifdef WIN32 +#include +#define pthread_t HANDLE +#define pthread_create(th, attr, func, arg) (*(th) = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(func), (arg), 0, NULL)) +#define pthread_join(th, res) WaitForSingleObject((th), INFINITE) +#define pthread_exit(res) ExitThread(0) +#else +#include +#include +#endif #define MAX_CONNECTION_ATTEMPTS 25 #define OFFER_DATACHANNEL_MESSAGE "Hello World" @@ -52,7 +60,7 @@ static void* peer_connection_task(void* user_data) { while (!test_complete) { peer_connection_loop(peer_connection); - usleep(1000); + ports_sleep_ms(1); } pthread_exit(NULL); @@ -118,7 +126,7 @@ int main(int argc, char* argv[]) { peer_connection_datachannel_send(test_user_data.answer_peer_connection, ANSWER_DATACHANNEL_MESSAGE, sizeof(ANSWER_DATACHANNEL_MESSAGE)); attempts++; - usleep(250000); + ports_sleep_ms(250); } if (strcmp(DATACHANNEL_NAME, peer_connection_lookup_sid_label(test_user_data.answer_peer_connection, 0)) != 0) { From 463326ad808987433be313a53f5af956e075737c Mon Sep 17 00:00:00 2001 From: cqm Date: Mon, 22 Jun 2026 16:13:54 +0800 Subject: [PATCH 2/2] RtpDecoder add nal_buff --- src/peer_connection.c | 5 +++- src/rtp.c | 55 ++++++++++++++++++++++++++++--------------- src/rtp.h | 4 +++- 3 files changed, 43 insertions(+), 21 deletions(-) diff --git a/src/peer_connection.c b/src/peer_connection.c index d56810c2..01f31af0 100644 --- a/src/peer_connection.c +++ b/src/peer_connection.c @@ -162,7 +162,8 @@ PeerConnection* peer_connection_create(PeerConfiguration* config) { agent_create(&pc->agent); memset(&pc->sctp, 0, sizeof(pc->sctp)); - + memset(&pc->artp_encoder, 0, sizeof(pc->artp_encoder)); + memset(&pc->vrtp_encoder, 0, sizeof(pc->vrtp_encoder)); if (pc->config.audio_codec) { rtp_encoder_init(&pc->artp_encoder, pc->config.audio_codec, peer_connection_outgoing_rtp_packet, (void*)pc); @@ -184,6 +185,8 @@ PeerConnection* peer_connection_create(PeerConfiguration* config) { void peer_connection_destroy(PeerConnection* pc) { if (pc) { + rtp_decoder_destory(&pc->vrtp_decoder); + rtp_decoder_destory(&pc->artp_decoder); sctp_destroy_association(&pc->sctp); dtls_srtp_deinit(&pc->dtls_srtp); agent_destroy(&pc->agent); diff --git a/src/rtp.c b/src/rtp.c index 0a3136ad..04e4cfe7 100644 --- a/src/rtp.c +++ b/src/rtp.c @@ -8,10 +8,8 @@ #include "utils.h" typedef enum RtpH264Type { - NALU = 23, FU_A = 28, - } RtpH264Type; typedef struct NaluHeader { @@ -222,19 +220,18 @@ int rtp_encoder_encode(RtpEncoder* rtp_encoder, const uint8_t* buf, size_t size) static int rtp_decode_h264(RtpDecoder* rtp_decoder, uint8_t* buf, size_t size) { static const uint32_t nalu_start_4bytecode = 0x01000000; - static uint8_t nalu_buf[CONFIG_MAX_NALU_SIZE]; - static int offset = 0; + uint8_t* nalu_buf = rtp_decoder->nal_buff; RtpPacket* rtp_packet = (RtpPacket*)buf; uint8_t nalu_type = *rtp_packet->payload & 0x1f; int payload_size = size - sizeof(RtpHeader); if (nalu_type > 0 && nalu_type < 24) { // NALU type 1-23 are single NALUs memcpy(nalu_buf, &nalu_start_4bytecode, sizeof(nalu_start_4bytecode)); - offset = sizeof(nalu_start_4bytecode); - memcpy(nalu_buf + offset, rtp_packet->payload, payload_size); - offset += payload_size; + rtp_decoder->offset = sizeof(nalu_start_4bytecode); + memcpy(nalu_buf + rtp_decoder->offset, rtp_packet->payload, payload_size); + rtp_decoder->offset += payload_size; if (rtp_decoder->on_packet != NULL) { - rtp_decoder->on_packet(nalu_buf, offset, rtp_decoder->user_data); + rtp_decoder->on_packet(nalu_buf, rtp_decoder->offset, rtp_decoder->user_data); } return (int)size; } else { @@ -246,20 +243,28 @@ static int rtp_decode_h264(RtpDecoder* rtp_decoder, uint8_t* buf, size_t size) { payload_size -= sizeof(NaluHeader) + sizeof(FuHeader); if (fu_header->s) { memcpy(nalu_buf, &nalu_start_4bytecode, sizeof(nalu_start_4bytecode)); - offset = sizeof(nalu_start_4bytecode); - memcpy(nalu_buf + offset, &reconstructed_nalu_type, 1); - offset += 1; - memcpy(nalu_buf + offset, rtp_packet->payload + 2, payload_size); - offset += payload_size; - } else if (offset < CONFIG_MAX_NALU_SIZE) { - memcpy(nalu_buf + offset, rtp_packet->payload + 2, payload_size); - offset += payload_size; + rtp_decoder->offset = sizeof(nalu_start_4bytecode); + memcpy(nalu_buf + rtp_decoder->offset, &reconstructed_nalu_type, 1); + rtp_decoder->offset += 1; + memcpy(nalu_buf + rtp_decoder->offset, rtp_packet->payload + 2, payload_size); + rtp_decoder->offset += payload_size; + } else { + if (rtp_decoder->offset + payload_size > rtp_decoder->size) { + rtp_decoder->size = rtp_decoder->size * 2; + rtp_decoder->nal_buff = realloc(rtp_decoder->nal_buff, rtp_decoder->size); + if (rtp_decoder->nal_buff == NULL) { + LOGE("Failed to realloc nal buffer"); + return -1; + } + } + memcpy(nalu_buf + rtp_decoder->offset, rtp_packet->payload + 2, payload_size); + rtp_decoder->offset += payload_size; if (fu_header->e) { // end of fragmented NALU if (rtp_decoder->on_packet != NULL) { - rtp_decoder->on_packet(nalu_buf, offset, rtp_decoder->user_data); + rtp_decoder->on_packet(nalu_buf, rtp_decoder->offset, rtp_decoder->user_data); } - offset = 0; // reset for next NALU + rtp_decoder->offset = 0; // reset for next NALU } } } @@ -277,10 +282,13 @@ static int rtp_decode_generic(RtpDecoder* rtp_decoder, uint8_t* buf, size_t size void rtp_decoder_init(RtpDecoder* rtp_decoder, MediaCodec codec, RtpOnPacket on_packet, void* user_data) { rtp_decoder->on_packet = on_packet; rtp_decoder->user_data = user_data; - + rtp_decoder->nal_buff = NULL; + rtp_decoder->offset = 0; switch (codec) { case CODEC_H264: rtp_decoder->decode_func = rtp_decode_h264; + rtp_decoder->size = CONFIG_MAX_NALU_SIZE; + rtp_decoder->nal_buff = malloc(rtp_decoder->size); break; case CODEC_PCMA: case CODEC_PCMU: @@ -296,3 +304,12 @@ int rtp_decoder_decode(RtpDecoder* rtp_decoder, const uint8_t* buf, size_t size) return -1; return rtp_decoder->decode_func(rtp_decoder, (uint8_t*)buf, size); } + +void rtp_decoder_destory(RtpDecoder* rtp_decoder){ + if(rtp_decoder && rtp_decoder->nal_buff != NULL){ + free(rtp_decoder->nal_buff); + rtp_decoder->nal_buff = NULL; + rtp_decoder->size = 0; + rtp_decoder->offset = 0; + } +} diff --git a/src/rtp.h b/src/rtp.h index e5fbd7d3..8b887742 100644 --- a/src/rtp.h +++ b/src/rtp.h @@ -79,6 +79,8 @@ struct RtpDecoder { RtpOnPacket on_packet; int (*decode_func)(RtpDecoder* rtp_decoder, uint8_t* data, size_t size); void* user_data; + uint8_t* nal_buff; + uint32_t offset, size; }; struct RtpEncoder { @@ -100,7 +102,7 @@ void rtp_encoder_init(RtpEncoder* rtp_encoder, MediaCodec codec, RtpOnPacket on_ int rtp_encoder_encode(RtpEncoder* rtp_encoder, const uint8_t* data, size_t size); void rtp_decoder_init(RtpDecoder* rtp_decoder, MediaCodec codec, RtpOnPacket on_packet, void* user_data); - +void rtp_decoder_destory(RtpDecoder* rtp_decoder); int rtp_decoder_decode(RtpDecoder* rtp_decoder, const uint8_t* data, size_t size); uint32_t rtp_get_ssrc(uint8_t* packet);