Android 오디오 및 비디오 주제 (2) AudioRecord 및 AudioTrack API를 사용하여 Android 플랫폼에서 오디오 PCM 데이터를 수집 및 재생하고 오디오 wav 파일 읽기 및 쓰기를 실현합니다.

1. AudioTrack의 기본 사용

AudioTrack 클래스는 Android 플랫폼에서 오디오 데이터를 출력하는 작업을 완료 할 수 있습니다. AudioTrack에는 완전히 다른 두 사용 시나리오에 해당하는 데이터로드 모드 및 오디오 스트림 유형에 해당하는 두 가지 데이터로드 모드 (MODE_STREAM 및 MODE_STATIC)가 있습니다.

  • MODE_STREAM :이 모드에서 오디오 데이터는 쓰기를 통해 AudioTrack에 반복해서 기록됩니다. 이는 일반적으로 쓰기 시스템 호출을 통해 파일에 데이터를 쓰는 것과 유사하지만이 작업 방식은 매번 사용자가 제공 한 버퍼의 데이터를 AudioTrack 내부의 버퍼로 복사해야하므로 어느 정도 지연이 발생합니다. . 이 문제를 해결하기 위해 AudioTrack은 두 번째 모드를 도입했습니다.
  • MODE_STATIC :이 모드에서는 재생하기 전에 쓰기 호출을 통해 AudioTrack의 내부 버퍼로 모든 데이터를 전송하기 만하면되고 이후 데이터를 전송할 필요는 없습니다. 이 모드는 메모리 사용량이 적고 벨소리와 같이 대기 시간이 긴 파일에 적합합니다. 그러나 한 번에 너무 많은 데이터를 쓸 수 없다는 단점도 있습니다. 그렇지 않으면 시스템이 모든 데이터를 저장할 충분한 메모리를 할당 할 수 없습니다.

1.1 MODE_STATIC 모드

MODE_STATIC 모드에서 오디오를 출력하는 방법은 다음과 같습니다. ( 참고 : STATIC 모드를 사용하는 경우 먼저 write를 호출하여 데이터를 쓴 다음 play를 호출해야합니다. ) :

코드 복사

공용 클래스 AudioTrackPlayerDemoActivity는 활동 구현을 확장합니다.
        OnClickListener {

    private static final String TAG = "AudioTrackPlayerDemoActivity";
    개인 버튼 버튼;
    개인 바이트 [] audioData;
    개인 AudioTrack audioTrack;

    @우세하다
    public void onCreate (Bundle savedInstanceState) {
        super.onCreate (savedInstanceState);
        super.setContentView (R.layout.main);
        this.button = (버튼) super.findViewById (R.id.play);
        this.button.setOnClickListener (this);
        this.button.setEnabled (false);
        new AsyncTask <Void, Void, Void> () {
            @우세하다
            protected Void doInBackground (Void ... params) {
                {
                    InputStream in = getResources (). openRawResource (R.raw.ding);
                    {
                        ByteArrayOutputStream out = new ByteArrayOutputStream (
                                264848);
                        for (int b; (b = in.read ())! = -1;) {
                            out.write (b);
                        }
                        Log.d (TAG, "데이터 확인");
                        audioData = out.toByteArray ();
                    } 드디어 {
                        넣다();
                    }
                } catch (IOException e) {
                    Log.wtf (TAG, "읽지 못했습니다", e);
                }
                null을 반환합니다.
            }

            @우세하다
            protected void onPostExecute (Void v) {
                Log.d (TAG, "트랙 생성 중 ...");
                button.setEnabled (true);
                Log.d (TAG, "사용 버튼");
            }
        } .execute ();
    }

    public void onClick (View view) {
        this.button.setEnabled (false);
        this.releaseAudioTrack ();
        this.audioTrack = new AudioTrack (AudioManager.STREAM_MUSIC, 44100,
                AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT,
                audioData.length, AudioTrack.MODE_STATIC);
        Log.d (TAG, "오디오 데이터 쓰기 ...");
        this.audioTrack.write (audioData, 0, audioData.length);
        Log.d (TAG, "재생 시작");
        audioTrack.play ();
        Log.d (TAG, "재생 중");
        this.button.setEnabled (true);
    }

    private void releaseAudioTrack () {
        if (this.audioTrack! = null) {
            Log.d (TAG, "중지");
            audioTrack.stop ();
            Log.d (TAG, "해제");
            audioTrack.release ();
            Log.d (TAG, "널링");
        }
    }

    public void onPause () {
        super.onPause ();
        this.releaseAudioTrack ();
    }
}

코드 복사

1.2 MODE_STREAM 모드

MODE_STREAM 모드에서 오디오를 출력하는 방법은 다음과 같습니다.

코드 복사

byte [] tempBuffer = 새로운 byte [bufferSize];
int readCount = 0;
while (dis.available ()> 0) {
    readCount = dis.read (tempBuffer);
    if (readCount == AudioTrack.ERROR_INVALID_OPERATION || readCount == AudioTrack.ERROR_BAD_VALUE) {
        계속하다;
    }
    if (readCount! = 0 && readCount! = -1) {
        audioTrack.play ();
        audioTrack.write (tempBuffer, 0, readCount);
    }

코드 복사

둘째, AudioTrack 상세

 2.1 오디오 스트림 유형

AudioTrack 생성자에서 AudioManager.STREAM_MUSIC 매개 변수가 노출됩니다. 그 의미는 Android 시스템에 의한 오디오 스트림의 관리 및 분류와 관련이 있습니다.

Android는 시스템 사운드를 여러 스트림 유형으로 나눕니다. 다음은 몇 가지 일반적인 유형입니다.

· STREAM_ALARM : 경고음

· STREAM_MUSIC : 음악 등의 음악 사운드

· STREAM_RING : 벨소리

· STREAM_SYSTEM : 배터리 부족 프롬프트, 잠금 화면 소리 등과 같은 시스템 소리

· STREAM_VOCIE_CALL : 호출음

참고 : 위의 분할 유형은 오디오 데이터 자체와 관련이 없습니다. 예를 들어 MUSIC 및 RING 형식은 모두 특정 MP3 곡이 될 수 있습니다. 또한 사운드 스트림 유형 선택에 대한 고정 된 기준이 없으며, 예를 들어 벨소리 미리보기의 벨소리를 MUSIC 유형으로 설정할 수 있습니다. 오디오 스트림 유형의 구분은 오디오 시스템의 오디오 관리 전략과 관련이 있습니다.

 

2.2 버퍼 할당과 프레임 개념

버퍼 할당 크기를 계산할 때 우리가 자주 사용하는 방법은 getMinBufferSize입니다. 이 함수는 애플리케이션 계층이 할당하는 데이터 버퍼의 양을 결정합니다.

AudioTrack.getMinBufferSize (8000, // 8K 샘플 / 초                              
        AudioFormat.CHANNEL_CONFIGURATION_STEREO, // 듀얼 채널                  
        AudioFormat.ENCODING_PCM_16BIT);

AudioTrack.getMinBufferSize에서 시작하여 코드를 추적하면 기본 코드에 매우 중요한 개념 인 Frame이 있음을 알 수 있습니다. 프레임은 데이터의 양을 설명하는 데 사용되는 단위입니다. 프레임 단위는 샘플 포인트의 바이트 수 × 채널 수와 같습니다 (예 : PCM16, 두 채널의 프레임은 2 × 2 = 4 바이트). 하나의 샘플링 포인트는 하나의 채널에만 해당되지만 실제로는 하나 이상의 채널이있을 수 있습니다. 모든 채널에 대해 한 번에 샘플링되는 데이터의 양을 나타내는 데 독립적 인 단위를 사용할 수 없기 때문에 프레임 개념이 도입되었습니다. 프레임의 크기는 샘플링 포인트의 바이트 수 × 채널 수입니다. 또한 현재의 사운드 카드 드라이버에서는 프레임을 단위로 내부 버퍼도 할당 및 관리하고 있습니다.

다음은 네이티브 레이어로 다시 추적되는 메서드입니다.

코드 복사

 // minBufCount는 최소 버퍼 수를 나타내며 프레임을 단위로 사용합니다.
   uint32_t minBufCount = afLatency / ((1000 * afFrameCount) / afSamplingRate);
    if (minBufCount <2) minBufCount = 2; // 버퍼 2 개 이상
 
   // 최소 프레임 수 계산
   uint32_tminFrameCount =               
         (afFrameCount * sampleRateInHertz * minBufCount) / afSamplingRate;
  // 다음은 가장 작은 FrameCount를 기준으로 가장 작은 버퍼 크기를 계산합니다.   
   intminBuffSize = minFrameCount // 계산 방법은 이전의 Frame 소개와 완전히 일치합니다.
           * (audioFormat == javaAudioTrackFields.PCM16? 2 : 1)
           * nbChannels;
 
    returnminBuffSize;

코드 복사

getMinBufSize는 최소 버퍼 크기에 도달하기 위해 하드웨어 상황 (예 : 샘플링 속도 지원 여부, 하드웨어 자체의 지연 등)을 포괄적으로 고려합니다. 일반적으로 할당하는 버퍼 크기는 정수배입니다.

2.3 AudioTrack 구성 프로세스

각 오디오 스트림은 AudioTrack 클래스의 인스턴스에 해당합니다. 각 AudioTrack은 생성 될 때 AudioFlinger에 등록되고 AudioFlinger는 모든 AudioTrack (Mixer)을 믹싱 한 다음 재생을 위해 AudioHardware로 전송합니다. 현재 Android는 32 개의 오디오 스트림을 생성합니다. 즉, Mixer는 최대 32 개의 AudioTrack 데이터 스트림을 동시에 처리합니다. 

3. AudioTrack과 MediaPlayer의 비교

사운드를 재생하려면 MediaPlayer 및 AudioTrack을 사용할 수 있습니다. 둘 다 애플리케이션 개발자가 사용할 수있는 Java API를 제공합니다. 둘 다 소리를 재생할 수 있지만 둘 사이에는 여전히 큰 차이가 있습니다.

3.1 차이점

가장 큰 차이점은 MediaPlayer는 MP3, AAC, WAV, OGG, MIDI 등과 같은 여러 형식의 사운드 파일을 재생할 수 있다는 것입니다. MediaPlayer는 프레임 워크 레이어에 해당 오디오 디코더를 생성합니다. AudioTrack은 디코딩 된 PCM 스트림 만 재생할 수 있습니다. 지원되는 파일 형식을 비교하면 대부분의 wav 형식 오디오 파일이 PCM 스트림이기 때문에 AudioTrack은 wav 형식 오디오 파일 만 지원합니다. AudioTrack은 디코더를 생성하지 않으므로 디코딩 할 필요가없는 wav 파일 만 재생할 수 있습니다.

3.2 문의

MediaPlayer는 여전히 프레임 워크 레이어에서 AudioTrack을 생성하고 디코딩 된 PCM 스트림을 AudioTrack으로 전달한 다음 믹싱을 위해 AudioFlinger로 전달한 다음 재생을 위해 하드웨어로 전달하므로 MediaPlayer에 AudioTrack이 포함됩니다.

3.3 SoundPool

Android 오디오 재생 API에 접속할 때 SoundPool을 사용하여 오디오를 재생할 수도 있음을 발견했습니다. 다음은 세 가지 사용 시나리오입니다 .MediaPlayer는 백그라운드에서 오랫동안 로컬 음악 파일 또는 온라인 스트리밍 리소스를 재생하는 데 더 적합합니다. SoundPool은 게임 사운드, 버튼 사운드, 벨소리와 같은 비교적 짧은 오디오 클립을 재생하는 데 적합합니다. 등 여러 오디오를 동시에 재생할 수 있습니다 .AudioTrack은 하단 레이어에 더 가깝고 매우 강력한 제어 기능을 제공하며 지연 시간이 짧은 재생을 지원하며 스트리밍 미디어 및 VoIP 음성 통화와 같은 시나리오에 적합합니다.

넷째, 소스 코드 

https://github.com/renhui/AudioDemo 

추천

출처blog.csdn.net/xfb1989/article/details/113348396