326 lines
8.8 KiB
C++
326 lines
8.8 KiB
C++
|
|
/***************************************************************************************
|
||
|
|
*
|
||
|
|
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||
|
|
*
|
||
|
|
* By downloading, copying, installing or using the software you agree to this license.
|
||
|
|
* If you do not agree to this license, do not download, install,
|
||
|
|
* copy or use the software.
|
||
|
|
*
|
||
|
|
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
|
||
|
|
*
|
||
|
|
* Redistribution and use in binary forms, with or without modification, are permitted.
|
||
|
|
*
|
||
|
|
* Unless required by applicable law or agreed to in writing, software distributed
|
||
|
|
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||
|
|
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
|
||
|
|
* language governing permissions and limitations under the License.
|
||
|
|
*
|
||
|
|
****************************************************************************************/
|
||
|
|
|
||
|
|
#include "sys_inc.h"
|
||
|
|
#include "gles_input.h"
|
||
|
|
#include "gles_engine.h"
|
||
|
|
|
||
|
|
#ifdef ANDROID
|
||
|
|
#include <SLES/OpenSLES_AndroidConfiguration.h>
|
||
|
|
#endif
|
||
|
|
|
||
|
|
|
||
|
|
#ifdef ANDROID
|
||
|
|
static void bufferQueueCallback(SLAndroidSimpleBufferQueueItf, void *context)
|
||
|
|
#else
|
||
|
|
static void bufferQueueCallback(SLBufferQueueItf, void *context)
|
||
|
|
#endif
|
||
|
|
{
|
||
|
|
GlesInput *audioInput = reinterpret_cast<GlesInput*>(context);
|
||
|
|
|
||
|
|
audioInput->processBuffer();
|
||
|
|
}
|
||
|
|
|
||
|
|
GlesInput::GlesInput()
|
||
|
|
: m_recorderObject(0)
|
||
|
|
, m_recorder(0)
|
||
|
|
, m_bufferQueue(0)
|
||
|
|
, m_bufferSize(1600)
|
||
|
|
, m_currentBuffer(0)
|
||
|
|
, m_pCallback(NULL)
|
||
|
|
, m_pUserdata(NULL)
|
||
|
|
{
|
||
|
|
#ifdef ANDROID
|
||
|
|
m_recorderPreset = SL_ANDROID_RECORDING_PRESET_GENERIC;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
for (int i = 0; i < NUM_BUFFERS; i++)
|
||
|
|
{
|
||
|
|
m_buffers[i] = NULL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
GlesInput::~GlesInput()
|
||
|
|
{
|
||
|
|
stop();
|
||
|
|
}
|
||
|
|
|
||
|
|
bool GlesInput::start(int samplerete)
|
||
|
|
{
|
||
|
|
bool ret = false;
|
||
|
|
|
||
|
|
if (startRecording(samplerete))
|
||
|
|
{
|
||
|
|
ret = true;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "start audio recoding faild\r\n");
|
||
|
|
|
||
|
|
stopRecording();
|
||
|
|
}
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
void GlesInput::stop()
|
||
|
|
{
|
||
|
|
stopRecording();
|
||
|
|
}
|
||
|
|
|
||
|
|
bool GlesInput::startRecording(int samplerete)
|
||
|
|
{
|
||
|
|
SLEngineItf engine = GlesEngine::instance()->slEngine();
|
||
|
|
if (!engine)
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "No engine\r\n");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
SLresult result;
|
||
|
|
|
||
|
|
// configure audio source
|
||
|
|
SLDataLocator_IODevice loc_dev = { SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
|
||
|
|
SL_DEFAULTDEVICEID_AUDIOINPUT, NULL };
|
||
|
|
SLDataSource audioSrc = { &loc_dev, NULL };
|
||
|
|
|
||
|
|
// configure audio sink
|
||
|
|
#ifdef ANDROID
|
||
|
|
SLDataLocator_AndroidSimpleBufferQueue loc_bq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
|
||
|
|
NUM_BUFFERS };
|
||
|
|
#else
|
||
|
|
SLDataLocator_BufferQueue loc_bq = { SL_DATALOCATOR_BUFFERQUEUE, NUM_BUFFERS };
|
||
|
|
#endif
|
||
|
|
|
||
|
|
SLDataFormat_PCM format_pcm;
|
||
|
|
|
||
|
|
format_pcm.formatType = SL_DATAFORMAT_PCM;
|
||
|
|
format_pcm.numChannels = 2;
|
||
|
|
format_pcm.samplesPerSec = samplerete * 1000;
|
||
|
|
format_pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
|
||
|
|
format_pcm.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16;
|
||
|
|
format_pcm.channelMask = (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT);
|
||
|
|
format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
|
||
|
|
|
||
|
|
SLDataSink audioSnk = { &loc_bq, &format_pcm };
|
||
|
|
|
||
|
|
// create audio recorder
|
||
|
|
// (requires the RECORD_AUDIO permission)
|
||
|
|
#ifdef ANDROID
|
||
|
|
const SLInterfaceID id[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION };
|
||
|
|
const SLboolean req[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
|
||
|
|
#else
|
||
|
|
const SLInterfaceID id[1] = { SL_IID_BUFFERQUEUE };
|
||
|
|
const SLboolean req[1] = { SL_BOOLEAN_TRUE };
|
||
|
|
#endif
|
||
|
|
|
||
|
|
result = (*engine)->CreateAudioRecorder(engine, &m_recorderObject,
|
||
|
|
&audioSrc, &audioSnk,
|
||
|
|
sizeof(req) / sizeof(SLboolean), id, req);
|
||
|
|
if (result != SL_RESULT_SUCCESS)
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "create audio recorder failed\r\n");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef ANDROID
|
||
|
|
// configure recorder source
|
||
|
|
SLAndroidConfigurationItf configItf;
|
||
|
|
result = (*m_recorderObject)->GetInterface(m_recorderObject, SL_IID_ANDROIDCONFIGURATION,
|
||
|
|
&configItf);
|
||
|
|
if (result != SL_RESULT_SUCCESS)
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "get audio configuration interface failed\r\n");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_RECORDING_PRESET,
|
||
|
|
&m_recorderPreset, sizeof(SLuint32));
|
||
|
|
|
||
|
|
SLuint32 presetValue = SL_ANDROID_RECORDING_PRESET_NONE;
|
||
|
|
SLuint32 presetSize = 2*sizeof(SLuint32); // intentionally too big
|
||
|
|
result = (*configItf)->GetConfiguration(configItf, SL_ANDROID_KEY_RECORDING_PRESET,
|
||
|
|
&presetSize, (void*)&presetValue);
|
||
|
|
|
||
|
|
if (result != SL_RESULT_SUCCESS || presetValue == SL_ANDROID_RECORDING_PRESET_NONE)
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "set audio record configuration failed\r\n");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
// realize the audio recorder
|
||
|
|
result = (*m_recorderObject)->Realize(m_recorderObject, SL_BOOLEAN_FALSE);
|
||
|
|
if (result != SL_RESULT_SUCCESS)
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "realize audio record object failed\r\n");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// get the record interface
|
||
|
|
result = (*m_recorderObject)->GetInterface(m_recorderObject, SL_IID_RECORD, &m_recorder);
|
||
|
|
if (result != SL_RESULT_SUCCESS)
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "get audio record object failed\r\n");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// get the buffer queue interface
|
||
|
|
#ifdef ANDROID
|
||
|
|
SLInterfaceID bufferqueueItfID = SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
|
||
|
|
#else
|
||
|
|
SLInterfaceID bufferqueueItfID = SL_IID_BUFFERQUEUE;
|
||
|
|
#endif
|
||
|
|
result = (*m_recorderObject)->GetInterface(m_recorderObject, bufferqueueItfID, &m_bufferQueue);
|
||
|
|
if (result != SL_RESULT_SUCCESS)
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "get audio record buff queue failed\r\n");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// register callback on the buffer queue
|
||
|
|
result = (*m_bufferQueue)->RegisterCallback(m_bufferQueue, ::bufferQueueCallback, this);
|
||
|
|
if (result != SL_RESULT_SUCCESS)
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "set buffer queue callback failed\r\n");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_bufferSize <= 0)
|
||
|
|
{
|
||
|
|
m_bufferSize = (16*2/8)*50*samplerete/1000;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
int minimumBufSize = (16*2/8)*5*samplerete/1000;
|
||
|
|
if (m_bufferSize < minimumBufSize)
|
||
|
|
m_bufferSize = minimumBufSize;
|
||
|
|
}
|
||
|
|
|
||
|
|
// enqueue empty buffers to be filled by the recorder
|
||
|
|
for (int i = 0; i < NUM_BUFFERS; ++i)
|
||
|
|
{
|
||
|
|
m_buffers[i] = (uint8 *)malloc(m_bufferSize);
|
||
|
|
if (NULL == m_buffers[i])
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
memset(m_buffers[i], 0, m_bufferSize);
|
||
|
|
|
||
|
|
result = (*m_bufferQueue)->Enqueue(m_bufferQueue, m_buffers[i], m_bufferSize);
|
||
|
|
if (result != SL_RESULT_SUCCESS)
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "audio record enqueue failed\r\n");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// start recording
|
||
|
|
result = (*m_recorder)->SetRecordState(m_recorder, SL_RECORDSTATE_RECORDING);
|
||
|
|
if (result != SL_RESULT_SUCCESS)
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "set audio record state failed\r\n");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
void GlesInput::stopRecording()
|
||
|
|
{
|
||
|
|
if (m_recorder)
|
||
|
|
{
|
||
|
|
(*m_recorder)->SetRecordState(m_recorder, SL_RECORDSTATE_STOPPED);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_bufferQueue)
|
||
|
|
{
|
||
|
|
(*m_bufferQueue)->Clear(m_bufferQueue);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_recorderObject)
|
||
|
|
{
|
||
|
|
(*m_recorderObject)->Destroy(m_recorderObject);
|
||
|
|
}
|
||
|
|
|
||
|
|
m_recorder = NULL;
|
||
|
|
m_bufferQueue = NULL;
|
||
|
|
m_recorderObject = NULL;
|
||
|
|
|
||
|
|
for (int i = 0; i < NUM_BUFFERS; ++i)
|
||
|
|
{
|
||
|
|
if (m_buffers[i])
|
||
|
|
{
|
||
|
|
free(m_buffers[i]);
|
||
|
|
m_buffers[i] = NULL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
m_currentBuffer = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
void GlesInput::setBufferSize(int value)
|
||
|
|
{
|
||
|
|
m_bufferSize = value;
|
||
|
|
}
|
||
|
|
|
||
|
|
int GlesInput::bufferSize() const
|
||
|
|
{
|
||
|
|
return m_bufferSize;
|
||
|
|
}
|
||
|
|
|
||
|
|
void GlesInput::processBuffer()
|
||
|
|
{
|
||
|
|
uint8 *processedBuffer = m_buffers[m_currentBuffer];
|
||
|
|
|
||
|
|
if (m_pCallback)
|
||
|
|
{
|
||
|
|
m_pCallback(processedBuffer, m_bufferSize, m_pUserdata);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Re-enqueue the buffer
|
||
|
|
SLresult result = (*m_bufferQueue)->Enqueue(m_bufferQueue,
|
||
|
|
processedBuffer,
|
||
|
|
m_bufferSize);
|
||
|
|
|
||
|
|
m_currentBuffer = (m_currentBuffer + 1) % NUM_BUFFERS;
|
||
|
|
|
||
|
|
// If the buffer queue is empty (shouldn't happen), stop recording.
|
||
|
|
#ifdef ANDROID
|
||
|
|
SLAndroidSimpleBufferQueueState state;
|
||
|
|
#else
|
||
|
|
SLBufferQueueState state;
|
||
|
|
#endif
|
||
|
|
result = (*m_bufferQueue)->GetState(m_bufferQueue, &state);
|
||
|
|
if (result != SL_RESULT_SUCCESS || state.count == 0)
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "processBuffer::state.count == 0\r\n");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void GlesInput::setCallback(GlesInputCB cb, void * puser)
|
||
|
|
{
|
||
|
|
m_pCallback = cb;
|
||
|
|
m_pUserdata = puser;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|