본문 바로가기

Developement/eLinux

ALSA + mpg123 출력시 clicking noise 발생 대처 방안.

 요즘 대부분의 Embedded Linux 환경이 좋아져서 개발 환경이 매우 용이해 졌습니다. 심지어 F*사 쪽은 Kernel 을 3.14 로 올리는 시대가 왔습니다만, 모든 환경이 그렇게 우아하게 좋을리가 없다는게 또 현실이 아닐까 합니다.


 근래 하는 일 중에 ALSA 를 통해 mp3 를 재생 하는 일을 수행 하는 중, 다음과 같은 문제가 발생 하였습니다.

  • 사용된 mpg123 은 최신 버젼 (1.17.0 )
  • mpg123 를 ALSA 와 붙이기 위해 mpg123 재생 예제를 응용하여 pthread로 play 부분을 처리.
  • 실제 Windows 환경에서는 문제가 발생 하지 않지만 Embedded Linux 상에서 mpg123 으로 decode 된 PCM buffer 를 재생시 최초 와 재생 종료시 clicking noise 나, 잘못 재생 되는 buffer 가 발생.

 대체 이 문제는 왜 생기는 것인지 알 방법이 없는 것이, 의심이 가는 것은 ALSA 뿐 이었기 때문 입니다. 원본 소스로 사용한 mp3 를 Audacity 와 같은 tool 로 확인해 봐도 노이즈가 앞뒤로 들어 있지 않기 때문 이었기 때문 입니다.

 이를 해결 하기 위해서는 다음과 같이 NULL audio buffer 전송이란 방법을 사용하였습니다.


방법은 간단하게, Mp3 를 Load 하면 mpg123 lib 을 통해 다음 정보를 알 수 있습니다.

한 frame 의 크기를 얻어서 이를 실제 mp3 재생 전, 후 에 재생 함 으로서 ALSA audio 재생에 발생하는 알수 없는 Noise 를 해결 한다는 취지 였습니다.


먼저 아무것도 들리지 않는 버퍼를 하나 만들어야 하는데, 이는 다음처럼 만들었습니다.


struct mpg123_frameinfo mInfo = {0};

mpg123_info( mh, &mInfo );


unsigned int nullaudiosize = mInfo.bitrate * 1024;

unsigned char* nullaudiobuff = (unsigned char*)malloc( nullaudiosize );

memset( nullaudiobuff, 0, nullaudiosize );


실제 bitrate 는 KBPS 를 의미 하므로 초당 1024*8 을 곱하던가 해야 할듯 하지만, 실제 ALSA buffer 에 전달하기 위한 형태로 버퍼의 크기는 최소 형태 보다 크면 될 듯 하여 문제가 되지 않았습니다.

그래서 mpg123_decode() 를 반복적으로 수행 하기 전에 다음처럼 구동 했습니다. ( mpg123 소스를 사용 )


int play_null(void)
{
    if ( ( ao != NULL ) && ( nullaudiobuffer != NULL ) && ( nullaudiosize > 0 ) )
    {
        if ( flush_output( ao, nullaudiobuffer, nullaudiosize ) < (int)nullaudiosize )
        {
             error1("NULL audio buffer can not flushed ! ( size = %d )", nullaudiosize );
             return -1;
         }
    }
    return 0;
}


위의 접힌 부분의 문제는 ALSA audio 출력을 설정 하기 전에 flush 를 할 경우 발생 하는 문제였습니다. (해결)