我用OpenSL ES录制了一个非常简单的音频,但遇到了一些问题,在某些手机上它可以工作并录制,但在其他手机上,尤其是Android 8似乎在音量/增益方面存在问题。
问题是,仅当我通过蓝牙连接到设备时才进行记录,在第一次连接时它会起作用,但是当我断开与蓝牙设备的连接并再次连接时,该记录似乎不再起作用。如果将手机直接放在扬声器的顶部,似乎只能拾取音频。有什么想法会影响从蓝牙设备连接/断开连接时的音量或增益?在每个连接和断开过程中,都会调用start / stop方法,以便按相反的顺序销毁对象,然后对象应该可以重新启动,但由于某种原因未正确初始化。任何想法或建议将不胜感激
#include "Configuration.h"
#include "Trace.h"
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
AndroidRecord::AndroidRecord() {}
int AndroidRecord::initialize(buffer_ready_cb cb_fct, void* cb_obj)
{
clean();
signal_proc_cb = cb_fct;
signal_proc_obj = cb_obj;
return kOK;
}
int AndroidRecord::startRecording()
{
if(SL_RESULT_SUCCESS != slCreateEngine(&engine_obj, 0, nullptr, 0, nullptr, nullptr))
{
return error;
}
if(SL_RESULT_SUCCESS != (*engine_obj)->Realize(engine_obj, SL_BOOLEAN_FALSE))
{
return error;
}
if(SL_RESULT_SUCCESS != (*engine_obj)->GetInterface(engine_obj, SL_IID_ENGINE, &engine_itf))
{
return error;
}
SLAndroidDataFormat_PCM_EX pcm_format = {0};
pcm_format.formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
pcm_format.numChannels = 1;
pcm_format.sampleRate = config.record_sample_rate * 1000;
pcm_format.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_32;
pcm_format.containerSize = sizeof(recordedAudio) * 8;
pcm_format.channelMask = SL_SPEAKER_FRONT_CENTER;
pcm_format.endianness = SL_BYTEORDER_LITTLEENDIAN;
pcm_format.representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT;
SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};
SLDataSource audio_src = {&loc_dev, NULL};
SLDataLocator_AndroidSimpleBufferQueue loc_bq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, record_buffer_count};
SLDataSink audio_snk = {&loc_bq, &pcm_format};
const SLInterfaceID id[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
const SLboolean req[1] = {SL_BOOLEAN_TRUE};
// create audio recorder (requires the RECORD_AUDIO permission)
if(SL_RESULT_SUCCESS != (*engine_itf)->CreateAudioRecorder(engine_itf, &record_obj, &audio_src, &audio_snk, 1, id, req))
{
return error;
}
// realize the audio recorder
if(SL_RESULT_SUCCESS != (*record_obj)->Realize(record_obj, SL_BOOLEAN_FALSE))
{
return error;
}
// get the record interface
if(SL_RESULT_SUCCESS != (*record_obj)->GetInterface(record_obj, SL_IID_RECORD, &record_itf))
{
return error;
}
// get the buffer queue interface
if(SL_RESULT_SUCCESS != (*record_obj)->GetInterface(record_obj, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &record_buff_queue))
{
return error;
}
// register callback on the buffer queue
if(SL_RESULT_SUCCESS != (*record_buff_queue)->RegisterCallback(record_buff_queue, opensl_record_callback, this))
{
return error;
}
SLAndroidSimpleBufferQueueState qState;
if(SL_RESULT_SUCCESS != (*record_buff_queue)->GetState(record_buff_queue, &qState))
{
return error;
}
// Create the recording buffer
for(int i = 0; i < record_buffer_count; i++)
{
record_buffers[i].reset(new recordedAudio[config.record_sample_count]);
if (SL_RESULT_SUCCESS != (*record_buff_queue)->Enqueue(record_buff_queue, record_buffers[i].get(), record_sample_count * sizeof(AudioSample)))
{
return error;
}
}
// Activate the recording
if(SL_RESULT_SUCCESS != (*record_itf)->SetRecordState(record_itf, SL_RECORDSTATE_RECORDING))
{
return error;
}
return kOK;
}
int AndroidRecord::stopRecording()
{
int result = kOK;
// Stop the recording
if(SL_RESULT_SUCCESS != (*record_itf)->SetRecordState(record_itf, SL_RECORDSTATE_STOPPED))
{
result = error;
}
if (SL_RESULT_SUCCESS != (*record_buff_queue)->Clear(record_buff_queue))
{
result = error;
}
cleanup();
return result;
}
int AndroidRecord::clean()
{
record_buff_queue = nullptr;
record_obj = nullptr;
record_itf = nullptr;
record_buffer_index = 0;
record_buffers->reset();
engine_itf = nullptr;
if(engine_obj != nullptr)
(*engine_obj)->Destroy(engine_obj);
engine_obj = nullptr;
return kOK;
}
void AndroidRecord::opensl_record_callback(SLAndroidSimpleBufferQueueItf record_buff_queue, void *context)
{
AndroidRecordInterface *inst = reinterpret_cast<AndroidRecordInterface *>(context);
auto index = inst->record_buffer_index % inst->record_buffer_count;
SLAndroidSimpleBufferQueueState qState;
if(SL_RESULT_SUCCESS != (*inst->record_buff_queue)->GetState(inst->record_buff_queue, &qState))
{
return;
}
auto obj = reinterpret_cast<AndroidRecordInterface*>(inst->signal_proc_obj);
(obj->*(inst->signal_proc_cb))(inst->record_buffers[index].get(), inst->record_sample_count);
if(SL_RESULT_SUCCESS != (*record_buff_queue)->Enqueue(record_buff_queue, inst->record_buffers[index].get(), inst->record_sample_count * sizeof(AudioSample)))
{
return;
}
inst->record_buffer_index++;
}