2012-02-29 6 views
4

내 VOIP 애플리케이션 용 Java에서 적응 형 지터 버퍼 구현을 찾고 있습니다. 내 애플리케이션 용 고정 지터 버퍼를 작성했지만 네트워크의 품질이 좋지 않아 버퍼 언더런이나 버퍼 오버런 문제가 발생합니다.Java에서 지터 버퍼 구현

내 애플리케이션에서 직접 사용하거나 참조 용으로 사용할 수있는 적응 형 지터 버퍼의 Java 기반 구현이 있습니까?

도움을 주시면 감사하겠습니다.

감사

+0

정확히 무엇이 문제입니까? 예상 버퍼 크기가 필요하십니까? (큐잉 이론이 도움이 될 수 있습니다.) 또는 동적 메모리 할당? 또는 다른 것? – Matthias

+0

현재 지터를 기준으로 버퍼 크기를 변경할 수 있기를 원합니다. –

+0

그리고 어디서 붙어 있나요? – Matthias

답변

8
나는 잠시 동안 (하지만 C에서) 바로이 문제에서 일한지

, 나는 나는 그것을 생각하면 그냥 인터넷이 사용 중이거나 다른 곳의 변화와 붐을 얻는다! 다시 고르지 못한 오디오. 잘. 나는 지금 그것을 핥았다고 확신한다.

아래의 알고리즘을 사용하여 실제로 음질이 정말 좋습니다. 필자는 같은 네트워크 조건에서 실행 한 다른 소프트 폰과 비교해 보았습니다.

내가 할 일은 우리가 등록하고있는 PBX 또는 다른 SIP 프록시가 UA (소프트 폰)가있는 로컬 네트워크에 있는지 여부를 확인하는 것입니다.

그렇다면 지터 버퍼를 100ms로 정의하고 그렇지 않은 경우 200ms를 사용합니다. 그렇게하면 가능한 경우 대기 시간을 제한합니다. 심지어 200ms는 눈에 띄는 회화 문제 나 과장을 일으키지 않습니다.

So. 그런 다음 사용할 수있는 유형의 시스템 카운터를 사용합니다. Windows = GetTickCount64(), 첫 번째 패킷이 재생을 위해 들어온 밀리 초 정밀 시간으로 변수를 채 웁니다. 변수 "x"를 호출 해 봅시다.

그런 다음 ((GetTickCount64() - x)> jitterbuffer)이 참일 때 해당 버퍼에서 재생을 시작합니다.

스트레이트 포워드 고정 길이 지터 버퍼 구현. 여기 까다 롭습니다.

재생할 때 RTP 프레임 (muLaw에서 PCM까지와 같이)을 버퍼링하는 동안 오디오 프레임의 평균 절대 진폭을 계산하여 재생할 프레임과 함께 저장합니다.

I 그래서 같은 구조체를 구비하여이를 수행

typedef struct tagCCONNECTIONS { 
    char binuse; 
    struct sockaddr_in client; 
    SOCKET socket; 
    unsigned short media_index; 
    UINT32 media_ts; 
    long ssrc; 
    unsigned long long lasttimestamp; 
    int frames_buffered; 
    int buffer_building; 
    int starttime; 
    int ssctr; 
    struct { 
      short pcm[160]; 
    } jb[AUDIO_BUFFER]; /* Buffered Audio frame array */ 
    char jbstatus[AUDIO_BUFFER]; /* An array containing the status of the data in the  CCONNETIONS::jb array */ 
    char jbsilence[AUDIO_BUFFER]; 
    int jbr,jbw; /* jbr = read position in CCONNECTIONS::jb array, jbw = write position  */ 
    short pcms[160]; 
    char status; 
    /* These members are only used to buffer playback */ 
    PCMS *outraw; 
    char *signal; 
    WAVEHDR *preparedheaders; 
    /**************************************************/ 
    DIALOGITEM *primary; 
    int readptr; 
    int writeptr; 
} CCONNECTIONS; 

좋아, tagCCONNECTIONS 통지 :: jbsilence [AUDIO_BUFFER] 구조체 부재. 이렇게하면 tagCCONNECTIONS :: jb [x] .pcm []에있는 모든 디코딩 된 오디오 프레임에 대해 해당 프레임이 들리는 지 여부에 대한 해당 데이터가 있습니다.

즉, 재생하려고하는 모든 오디오 프레임에 대해 해당 프레임이 들리는 지 여부에 대한 정보가 있습니다. 또한

...

#define READY 1 
#define EMPTY 0 

tagCCONNECTIONS는 :: jbstatus는 [AUDIO_BUFFER] 필드는 우리가 연주에 대해 생각하고있는 특정 오디오 프레임이 준비 나 빈 상태 (empty)의 경우 우리가 알고하자. 버퍼 언더 플로의 이론적 인 경우에는 빈 상태 여야합니다.이 경우 보통 준비가 완료 될 때까지 기다렸다가 재생을 시작합니다 ...

이제 오디오를 재생하는 루틴에서 ... 주요 기능. 하나는 pushframe()이고 다른 하나는 popframe()입니다.

네트워크 연결을 열어 muLaw를 PCM으로 변환하는 RTP 호출 푸시 프레임()을 수신하는 스레드가 프레임의 평균 절대 크기를 계산하고 소리가 들리지 않으면 조용하게 표시하고 다음을 표시합니다. jbstatus [X] READY

다음

jitterbuffer 시간은 다음

if ((GetTickCount64() - x) > jitterbuffer) {...} 

에 의해, 다시 만료 된 경우 다음 프레임이 재생 될 경우 오디오를 재생 내 스레드에서, 우리는 먼저 우리가 확인 확인 등 READY (실제로 채워 졌음을 의미)입니다.

그런 다음 AFTER THAT FRAME (AFTER THAT FRAME)도 준비되어 있는지, 그리고 AUDIBLE인지 SILENT인지 확인합니다.

는 *** 중요

는 기본적으로, 우리는 200ms의 지터 버퍼 10 20ms의 오디오 프레임을 저장할 수있는 것을 알고있다.

처음 200 밀리 초 지터 버퍼 지연 (오디오 저장) 이후에 우리가 대기 한 오디오 프레임 수가 10 개 (또는 지터 버퍼/20) 아래로 떨어지면 "buffer_building"모드로 들어갑니다. 재생할 예정인 다음 오디오 프레임이 조용한 경우, 지터 버퍼가 아직 가득 차 있지 않다는 것을 프로그램에 알려주고, 아직 20 밀리 초가 채워져 있지만, 프레임을 재생합니다. 지금은 NEXT 프레임이기 때문에 "조용한"것입니다 ... 다시 한 번. 우리는 조용한 프레임을 재생하지 않고 침묵 기간을 사용하여 인바운드 프레임에서 버퍼를 다시 채 웁니다.

tagCCONNECTIONS::lasttimestamp = GetTickCount64() - (jitterbuffer-20); 

이었을 것입니다 무슨 동안 완전한 침묵의 기간이있을 것이다 침묵을 "가정"하지만, 그 자체를 보충 할 수있는 버퍼를 할 수 있습니다. 그런 다음 전체 전체 10 프레임을 다시 가져올 때 "buffer_building"모드를 종료하고 오디오 만 재생합니다.

우리는 풀 버퍼에서 짧은 한 프레임 인 경우에도 "buffer_building"모드로 들어갑니다. 왜냐하면 장황한 사람이 말하고 많은 침묵이 없기 때문입니다. 이는 "buffer_building"모드 중에도 버퍼를 빠르게 고갈시킬 수 있습니다.

지금 ... "침묵이란 무엇입니까?" 나는 당신이 묻는 것을 듣는다.

int total_pcm_val=0; 
/* int jbn= whatever frame we're on */ 
for (i=0;i<160;i++) { 
    total_pcm_val+=ABS(cc->jb[jbn].pcm[i]); 
} 
total_pcm_val/=160; 
if (total_pcm_val < 200) { 
    cc->jbsilence[jbn] = 1; 
} 

을 지금은 실제로 유지 계획하고있어, 다음과 같이 나의 장난, 나는 열심히 미만 (200)의 평균 절대 16 비트 PCM 진폭 어떤 프레임으로 침묵을 코딩 한 나는이 그림 현재 오디오 프레임의 진폭이 전체 평균 진폭의 5 % 이하인 경우 프레임을 조용하게 또는 2 %로 간주합니다 ... 잘 모르겠습니다. , 그런 식으로 바람이나 배경 소음이 많으면 "침묵"의 정의가 적용될 수 있습니다. 나는 그걸 가지고 놀아야 만하지만 지터 버퍼를 보충하는 열쇠라고 생각합니다.

중요한 정보가없는 경우에 수행하고 실제 정보 (음성)를 맑게 유지하십시오.

이 정보가 도움이되기를 바랍니다. 내가 설명하는 것에 관해서는 조금 산발적이지만, VoIP 응용 프로그램의 소리가 매우 마음에 듭니다.

+0

지속적인 사운드 소스 (예 : 음악 스트리밍)에 대한 고갈을 처리하기위한 합리적인 방법을 알고 계십시오. –

+0

실제 도움이되는 기사! 단일 프레임 (첫 번째 프레임)을 재생 한 후에도 프로그램이 PLAY 모드에서 "버퍼 구축"모드로 전환된다고 말씀 하시겠습니까? 이 경우 프로그램은 첫 번째 프레임을 재생할 때마다 재생 모드에서 버퍼 작성 모드로 계속 전환합니다. 좀 더 명확히 해 주시겠습니까? –