speex 라이브러리를 사용하여 오디오 데이터를 인코딩, 디코딩 및 전처리합니다. 나는 speex 라이브러리가 매우 유용하다고 생각하지만, speex 지터 버퍼을 사용하면 몇 가지 문제점이 있습니다. 멀티 스레드를 사용하고 하나의 스레드가 수신 된 데이터를 지터 버퍼에 넣고 다른 스레드가 활성 지터 버퍼에서 데이터를 가져옵니다. 때로는 '점점'스레드가 유효한 데이터를 얻을 수없는 경우가 있는데 특히 ' 퍼팅 데이터 '스레드. 또한 지터 버퍼를 보호하기 위해 뮤텍스를 사용하고 있습니다.speex 지터 버퍼 사용 방법
정확하게 지터 버퍼를 사용하는 방법을 모르겠습니다. 누군가가 나를 도울 수 있기를 바랍니다.
speex_jitter_buffer.h
#include <speex/speex_jitter.h>
#include <speex/speex.h>
/** @defgroup SpeexJitter SpeexJitter: Adaptive jitter buffer specifically for Speex
* This is the jitter buffer that reorders UDP/RTP packets and adjusts the buffer size
* to maintain good quality and low latency. This is a simplified version that works only
* with Speex, but is much easier to use.
* @{
*/
/** Speex jitter-buffer state. Never use it directly! */
typedef struct SpeexJitter {
SpeexBits current_packet; /**< Current Speex packet */
int valid_bits; /**< True if Speex bits are valid */
JitterBuffer *packets; /**< Generic jitter buffer state */
void *dec; /**< Pointer to Speex decoder */
spx_int32_t frame_size; /**< Frame size of Speex decoder */
} SpeexJitter;
/** Initialise jitter buffer
*
* @param jitter State of the Speex jitter buffer
* @param decoder Speex decoder to call
* @param sampling_rate Sampling rate used by the decoder
*/
void speex_jitter_init(SpeexJitter *jitter, void *decoder, int sampling_rate);
/** Destroy jitter buffer */
void speex_jitter_destroy(SpeexJitter *jitter);
/** Put one packet into the jitter buffer */
void speex_jitter_put(SpeexJitter *jitter, char *packet, int len, int timestamp);
/** Get one packet from the jitter buffer */
void speex_jitter_get(SpeexJitter *jitter, spx_int16_t *out, int *start_offset);
/** Get pointer timestamp of jitter buffer */
int speex_jitter_get_pointer_timestamp(SpeexJitter *jitter);
#ifdef __cplusplus
}
#endif
speex_jitter_buffer.cpp 그리고 나는 "speex_jitter_buffer.h"헤더 파일을 사용하고
#include <speex/speex_jitter.h>
#include "speex_jitter_buffer.h"
#ifndef NULL
#define NULL 0
#endif
void speex_jitter_init(SpeexJitter *jitter, void *decoder, int sampling_rate)
{
jitter->dec = decoder;
speex_decoder_ctl(decoder, SPEEX_GET_FRAME_SIZE, &jitter->frame_size);
jitter->packets = jitter_buffer_init(jitter->frame_size);
speex_bits_init(&jitter->current_packet);
jitter->valid_bits = 0;
}
void speex_jitter_destroy(SpeexJitter *jitter)
{
jitter_buffer_destroy(jitter->packets);
speex_bits_destroy(&jitter->current_packet);
}
void speex_jitter_put(SpeexJitter *jitter, char *packet, int len, int timestamp)
{
JitterBufferPacket p;
p.data = packet;
p.len = len;
p.timestamp = timestamp;
p.span = jitter->frame_size;
jitter_buffer_put(jitter->packets, &p);
}
void speex_jitter_get(SpeexJitter *jitter, spx_int16_t *out, int *current_timestamp)
{
int i;
int ret;
spx_int32_t activity;
char data[2048];
JitterBufferPacket packet;
packet.data = data;
if (jitter->valid_bits)
{
/* Try decoding last received packet */
ret = speex_decode_int(jitter->dec, &jitter->current_packet, out);
if (ret == 0)
{
jitter_buffer_tick(jitter->packets);
return;
} else {
jitter->valid_bits = 0;
}
}
ret = jitter_buffer_get(jitter->packets, &packet, jitter->frame_size, NULL);
if (ret != JITTER_BUFFER_OK)
{
/* No packet found */
/*fprintf (stderr, "lost/late frame\n");*/
/*Packet is late or lost*/
speex_decode_int(jitter->dec, NULL, out);
} else {
speex_bits_read_from(&jitter->current_packet, packet.data, packet.len);
/* Decode packet */
ret = speex_decode_int(jitter->dec, &jitter->current_packet, out);
if (ret == 0)
{
jitter->valid_bits = 1;
} else {
/* Error while decoding */
for (i=0;i<jitter->frame_size;i++)
out[i]=0;
}
}
speex_decoder_ctl(jitter->dec, SPEEX_GET_ACTIVITY, &activity);
if (activity < 30)
jitter_buffer_update_delay(jitter->packets, &packet, NULL);
jitter_buffer_tick(jitter->packets);
}
int speex_jitter_get_pointer_timestamp(SpeexJitter *jitter)
{
return jitter_buffer_get_pointer_timestamp(jitter->packets);
}
:
이 내 코드입니다.
'퍼팅'스레드 코드 :
m_jitter_mutex.lock();
speex_jitter_put(&jitter, recvBuf, payloadLength, timestamp);
m_jitter_mutex.unlock();
'점점'스레드 코드 :
while(true)
{
Sleep(20);
m_jitter_mutex.lock();
speex_jitter_get(&jitter, (spx_int16_t*)pcm_short, NULL);
m_pOut->Play(pcm_char, pcm_data_length); // play the pcm data
m_jitter_mutex.lock();
}
나는 또한 에코 제거 작업을 수행 할 Speex가 라이브러리를 사용하고 싶지만, 그렇게하지 정확히 어떻게 우리에게 그것을 알지. 많이 고마워.