2012-05-27 36 views
32

Tôi muốn lấy bộ đệm byte từ nội dung âm thanh bằng cách sử dụng đối tượng FileDescriptor OpenSL ES, vì vậy tôi có thể enqueue nó lặp đi lặp lại một SimpleBufferQueue, thay vì sử dụng giao diện SL để phát/dừng/tìm kiếm tệp.Có thể lấy bộ đệm byte trực tiếp từ nội dung âm thanh trong OpenSL ES (dành cho Android) không?

Có ba lý do chính khiến tôi muốn quản lý các byte mẫu trực tiếp:

  1. OpenSL sử dụng một lớp AudioTrack để chơi/dừng/etc cho cầu thủ đối tượng. Điều này không chỉ giới thiệu chi phí không mong muốn, nhưng nó cũng có một số lỗi, và khởi động/dừng nhanh chóng của người chơi gây ra rất nhiều vấn đề.
  2. Tôi cần phải thao tác bộ đệm byte trực tiếp cho các hiệu ứng DSP tùy chỉnh.
  3. Các clip tôi sắp phát đều nhỏ và tất cả có thể được tải vào bộ nhớ để tránh phí I/O của tệp. Thêm vào đó, enqueueing bộ đệm của riêng tôi sẽ cho phép tôi giảm độ trễ bằng cách viết 0 cho sink đầu ra, và đơn giản chuyển sang byte mẫu khi chúng đang chơi, thay vì STOPPING, PAUSING và PLAYING AudioTrack.

rồi, do đó biện minh hoàn chỉnh - đây là những gì tôi đã cố gắng - Tôi có một mẫu struct chứa, về cơ bản, một ca khúc đầu vào và đầu ra, và một mảng byte để giữ mẫu. Đầu vào là trình phát FileDescriptor của tôi và đầu ra là một đối tượng SimpleBufferQueue. Dưới đây là cấu trúc của tôi:

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; 

sau khi khởi tạo một cầu thủ tập tin fdPlayerObject và malloc-ing bộ nhớ cho bộ đệm byte của tôi với

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

Tôi nhận được giao diện BufferQueue với

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

Sau đó, tôi khởi tạo trình phát đầu ra đầu ra:

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

Khi tôi muốn chơi mẫu, tôi đang sử dụng:

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

Tuy nhiên, điều này gây ra ứng dụng của tôi để đóng băng và đóng cửa. Có vài điều sai sót ở đây. Cũng, tôi không muốn lấy mẫu từ BufferQueue của Bộ mô tả tệp mỗi lần. Thay vào đó, tôi muốn lưu trữ vĩnh viễn nó trong một mảng byte, và Enqueue rằng đầu ra bất cứ khi nào tôi muốn.

+2

Xin chào khiner, nó sẽ giúp bạn đọc .wav- tệp từ thư mục nội dung trong một byte Java hoặc mảng ngắn và sau đó xử lý thêm? –

+0

Không chắc tôi có thể giúp được bao nhiêu, nhưng chỉ để ghi lại - bạn có đang sử dụng NDK không? Đó có phải là lý do tại sao mã của bạn trong C++? – Erhannis

+2

Có, tôi đang sử dụng NDK, và điều này thực sự là tinh khiết C. Câu hỏi này là nhận được lâu trong răng. Tôi đã thực hiện tấn tiến bộ về điều này và sẽ nhận được xung quanh để thêm một câu trả lời khá. – khiner

Trả lời

5

Giải mã cho PCM có sẵn ở cấp API 14 trở lên.

Khi bạn tạo máy nghe nhạc giải mã bạn cần phải thiết lập hàng đợi đệm đơn giản Android như là dữ liệu chìm:

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

Đối với hàng đợi giải mã bạn cần enqueue một bộ đệm rỗng vào hàng đợi đệm đơn giản Android, mà sẽ được lấp đầy với dữ liệu PCM.

Ngoài ra, bạn cần đăng ký trình xử lý gọi lại với hàng đợi bộ giải mã sẽ được gọi khi dữ liệu PCM sẵn sàng. Trình xử lý gọi lại sẽ xử lý dữ liệu PCM, nạp lại bộ đệm giờ trống, sau đó quay lại.Ứng dụng chịu trách nhiệm theo dõi các bộ đệm đã giải mã; danh sách tham số gọi lại không bao gồm thông tin đầy đủ để cho biết bộ đệm nào đã được lấp đầy hoặc bộ đệm nào để nạp vào tiếp theo.

Giải mã cho PCM hỗ trợ tìm kiếm tạm dừng và tìm kiếm ban đầu. Điều khiển âm lượng, hiệu ứng, vòng lặp và tốc độ phát lại không được hỗ trợ.

Đọc Giải mã âm thanh thành PCM từ OpenSL ES for Android để biết thêm chi tiết.

Các vấn đề liên quan