Pertanyaan Apakah mungkin untuk mendapatkan buffer byte langsung dari aset audio di OpenSL ES (untuk Android)?


Saya ingin mendapatkan buffer byte dari aset audio menggunakan objek OpenSL ES FileDescriptor, jadi saya bisa memasukkannya berulang kali ke SimpleBufferQueue, daripada menggunakan SL interface untuk memainkan / menghentikan / mencari file.

Ada tiga alasan utama mengapa saya ingin mengelola sampel byte secara langsung:

  1. OpenSL menggunakan layer AudioTrack untuk memainkan / menghentikan / etc untuk Player Objects. Ini tidak hanya memperkenalkan overhead yang tidak diinginkan, tetapi juga memiliki beberapa bug, dan mulai / berhenti cepat dari pemain menyebabkan banyak masalah.
  2. Saya perlu memanipulasi buffer byte secara langsung untuk efek DSP kustom.
  3. Klip yang akan saya mainkan berukuran kecil, dan semuanya dapat dimuat ke dalam memori untuk menghindari overhead I / O file. Plus, enqueueing buffer saya sendiri akan memungkinkan saya untuk mengurangi latensi dengan menulis 0 ke sink output, dan hanya beralih ke byte sampel ketika mereka bermain, daripada BERHENTI, MENGGAMBAR dan MEMUTAR AudioTrack.

Oke, jadi pembenaran selesai - inilah yang saya coba - saya punya Mencicipi struct yang berisi, pada dasarnya, jalur input dan output, dan array byte untuk menahan sampel. Masukannya adalah pemain FileDescriptor saya, dan hasilnya adalah objek SimpleBufferQueue. Inilah struct saya:

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;

setelah menginisialisasi pemutar file fdPlayerObject, dan memori malloc-ing untuk buffer byte saya dengan

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

Saya mendapatkan antarmuka BufferQueue dengan

// get the buffer queue interface
result = (*(sample->fdPlayerObject))->GetInterface(sample->fdPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &(sample->fdBufferQueue));

Kemudian saya memberi contoh pemain keluaran:

// 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);

Ketika saya ingin memainkan sampel, saya menggunakan:

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));

Namun, ini menyebabkan aplikasi saya membeku dan mati. Ada yang salah di sini. Juga, Saya lebih memilih untuk tidak mendapatkan sampel dari BufferQueue File Descriptor setiap kali. Sebaliknya, saya ingin menyimpannya secara permanen dalam susunan byte, dan Enqueue itu ke output kapan pun saya suka.


32
2018-05-27 01:18


asal


Jawaban:


Decoding to PCM tersedia di API level 14 dan lebih tinggi.

Saat Anda membuat pemutar decoder, Anda perlu mengatur antrean buffer sederhana Android sebagai data sink:

// 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);

Untuk antrean decoder, Anda perlu memasukkan satu set buffer kosong ke antrean buffer sederhana Android, yang akan diisi dengan data PCM.

Anda juga perlu mendaftar penangan callback dengan antrian decoder yang akan dipanggil ketika data PCM akan siap. Penangan callback harus memproses data PCM, memasukkan kembali buffer yang sekarang kosong, dan kemudian kembali. Aplikasi ini bertanggung jawab untuk melacak buffer yang telah di-decode; daftar parameter callback tidak termasuk informasi yang cukup untuk menunjukkan buffer mana yang diisi atau buffer mana yang akan di-enqueue berikutnya.

Dekode ke PCM mendukung jeda dan pencarian awal. Kontrol volume, efek, perulangan, dan tingkat pemutaran tidak didukung.

Baca baca Decode audio ke PCM dari OpenSL ES untuk Android untuk lebih jelasnya.


5
2017-09-18 04:22