2012-05-27 2 views
32

OpenSL ES FileDescriptor 객체를 사용하여 오디오 자산에서 바이트 버퍼를 가져오고 싶습니다. 따라서 SL 인터페이스를 사용하여 파일 재생/중지/탐색 대신 반복적으로 SimpleBufferQueue에 큐에 넣을 수 있습니다.OpenSL ES (Android 용)의 오디오 자산에서 직접 바이트 버퍼를 가져올 수 있습니까?

내가 직접 샘플 바이트를 관리하려는 이유 세 가지 이유가 있습니다 :

  1. OpenSL는 플레이어 개체에 대한 등/정지/재생하는 AudioTrack 층을 사용하는가. 이것은 원하지 않는 오버 헤드를 초래할뿐만 아니라 몇 가지 버그가 있으며 플레이어의 빠른 시작/정지로 인해 많은 문제가 발생합니다.
  2. 사용자 정의 DSP 효과를 위해 직접 바이트 버퍼를 조작해야합니다.
  3. 재생할 클립이 작아서 파일 I/O 오버 헤드를 피하기 위해 메모리에 모두로드 할 수 있습니다. 또한 내 버퍼를 대기열에 추가하면 출력 싱크에 0을 쓰고 대기 시간을 줄이고 AudioTrack을 중지, 일시 중지 및 재생하는 대신 재생할 때 샘플 바이트로 간단히 전환 할 수 있습니다. 전체

좋아, 정당화는 - 여기에 내가 무엇을 시도했다입니다 - 나는 본질적으로, 입력 및 출력 트랙을 포함하는 샘플 구조체 및 샘플을 보유하는 바이트 배열을 가지고있다. 입력은 My FileDescriptor 플레이어이고 출력은 SimpleBufferQueue 객체입니다. 여기 내 구조체의 : fdPlayerObject 파일 플레이어 를 초기화 한 후

typedef struct Sample_ { 
    // buffer to hold all samples 
    short *buffer;  
    int totalSamples; 

    SLObjectItf fdPlayerObject; 
    // file descriptor player interfaces 
    SLPlayItf fdPlayerPlay; 
    SLSeekItf fdPlayerSeek; 
    SLMuteSoloItf fdPlayerMuteSolo; 
    SLVolumeItf fdPlayerVolume; 
    SLAndroidSimpleBufferQueueItf fdBufferQueue; 

    SLObjectItf outputPlayerObject; 
    SLPlayItf outputPlayerPlay; 
    // output buffer interfaces 
    SLAndroidSimpleBufferQueueItf outputBufferQueue;   
} Sample; 

및 malloc에 ​​- 보내고

sample->buffer = malloc(sizeof(short)*sample->totalSamples); 

내가

// get the buffer queue interface 
result = (*(sample->fdPlayerObject))->GetInterface(sample->fdPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &(sample->fdBufferQueue)); 
와의 BufferQueue 인터페이스를 얻고 내 바이트 버퍼 메모리를

출력 플레이어 :

를 인스턴스화합니다. 내가 샘플을 재생하려면 16,
// create audio player for output buffer queue 
const SLInterfaceID ids1[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE}; 
const SLboolean req1[] = {SL_BOOLEAN_TRUE}; 
result = (*engineEngine)->CreateAudioPlayer(engineEngine, &(sample->outputPlayerObject), &outputAudioSrc, &audioSnk, 
               1, ids1, req1); 

// realize the output player 
result = (*(sample->outputPlayerObject))->Realize(sample->outputPlayerObject, SL_BOOLEAN_FALSE); 
assert(result == SL_RESULT_SUCCESS); 

// get the play interface 
result = (*(sample->outputPlayerObject))->GetInterface(sample->outputPlayerObject, SL_IID_PLAY, &(sample->outputPlayerPlay)); 
assert(result == SL_RESULT_SUCCESS); 

// get the buffer queue interface for output 
result = (*(sample->outputPlayerObject))->GetInterface(sample->outputPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, 
                &(sample->outputBufferQueue)); 
assert(result == SL_RESULT_SUCCESS);  

    // set the player's state to playing 
result = (*(sample->outputPlayerPlay))->SetPlayState(sample->outputPlayerPlay, SL_PLAYSTATE_PLAYING); 
assert(result == SL_RESULT_SUCCESS); 

, 내가 사용하고 있습니다 :

Sample *sample = &samples[sampleNum]; 
// THIS WORKS FOR SIMPLY PLAYING THE SAMPLE, BUT I WANT THE BUFFER DIRECTLY 
// if (sample->fdPlayerPlay != NULL) { 
//  // set the player's state to playing 
//  (*(sample->fdPlayerPlay))->SetPlayState(sample->fdPlayerPlay, SL_PLAYSTATE_PLAYING); 
// } 

// fill buffer with the samples from the file descriptor 
(*(sample->fdBufferQueue))->Enqueue(sample->fdBufferQueue, sample->buffer,sample->totalSamples*sizeof(short)); 
// write the buffer to the outputBufferQueue, which is already playing 
(*(sample->outputBufferQueue))->Enqueue(sample->outputBufferQueue, sample->buffer, sample->totalSamples*sizeof(short)); 

그러나,이 동결하고 종료하는 내 응용 프로그램을 발생합니다. 뭔가 잘못되었습니다. 또한, 나는 File Descriptor의 BufferQueue에서 매번 샘플을 얻지 않는 것을 선호합니다. 대신, 영구적으로 바이트 배열에 저장하고 원하는 때마다 출력에 큐에 넣고 싶습니다.

+2

안녕하세요 khiner, 자바 바이트 또는 짧은 배열의 자산 폴더에서 .wav 파일을 읽고 더 처리하는 데 도움이 될까요? –

+0

내가 얼마나 도울 수 있는지는 확실하지 않지만 기록만을 위해 - NDK를 사용하고 있습니까? 그게 당신의 코드가 C++에있는 이유입니까? – Erhannis

+2

네, 저는 NDK를 사용하고 있습니다. 이것은 실제로 순수한 C입니다.이 질문은 오랜 시간이 걸리고 있습니다. 나는 이것에 대한 많은 진전을 이뤄 냈으며 괜찮은 대답을 추가하려고 노력할 것입니다. – khiner

답변

5

PCM으로 디코딩하는 것은 API 레벨 14 이상에서 사용할 수 있습니다. 디코더 큐

// For init use something like this: 
SLDataLocator_AndroidFD locatorIn = {SL_DATALOCATOR_ANDROIDFD, decriptor, start, length}; 
SLDataFormat_MIME dataFormat = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED}; 
SLDataSource audioSrc = {&locatorIn, &dataFormat}; 

SLDataLocator_AndroidSimpleBufferQueue loc_bq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; 
SLDataSink audioSnk = { &loc_bq, NULL }; 

const SLInterfaceID ids[2] = {SL_IID_PLAY, SL_IID_ANDROIDSIMPLEBUFFERQUEUE}; 
const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; 

SLresult result = (*engineEngine)->CreateAudioPlayer(engineEngine, &(sample->fdPlayerObject), &outputAudioSrc, &audioSnk, 2, ids1, req1); 

당신이 채워집니다 안드로이드 간단한 버퍼 큐에 빈 버퍼 세트를 대기열에 필요하면 디코더 플레이어를 만들 때 데이터가 침몰로

당신은 안드로이드 간단한 버퍼 큐를 설정 필요 PCM 데이터.

은 또한 당신은 PCM 데이터가 준비가되어있을 때 호출 될 디코더 큐와 콜백 핸들러를 등록해야합니다. 콜백 처리기는 PCM 데이터를 처리하고 현재 비어있는 버퍼를 다시 대기열에 넣은 다음 반환해야합니다.애플리케이션은 디코딩 된 버퍼를 추적해야한다. 콜백 매개 변수 목록에는 채워진 버퍼 또는 다음에 대기시킬 버퍼를 나타내는 데 필요한 충분한 정보가 없습니다.

PCM 디코드는 일시 중지 및 초기 탐색을 지원합니다. 볼륨 조절, 효과, 루핑 및 재생 속도는 지원되지 않습니다.

자세한 내용은 OpenSL ES for Android에서 까지의 오디오 디코드 오디오를 읽으십시오.