赞
踩
- setContentView(R.layout.activity_main);//设置布局文件
-
- controlButton = (Button)findViewById((R.id.capture_control_button));
-
-
- statusView = (TextView)findViewById(R.id.statusView);
{
- private void queryNativeAudioParameters() {
- supportRecording = true;
- AudioManager myAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);//获取audioManager的服务
- if(myAudioMgr == null) {
- supportRecording = false;
- return;
- }
- nativeSampleRate = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);//audio的采样率
- nativeSampleBufSize =myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);//每个sample的大小
- {
音频源:我们可以使用麦克风作为采集音频的数据源。
采样率:一秒钟对声音数据的采样次数,采样率越高,音质越好。
音频通道:单声道,双声道等,
音频格式:一般选用PCM格式,即原始的音频样本。
缓冲区大小:音频数据写入缓冲区的总数,可以通过AudioRecord.getMinBufferSize获取最小的缓冲区。(将音频采集到缓冲区中然后再从缓冲区中读取)
- }
-
- // hardcoded channel to mono: both sides -- C++ and Java sides
- int recBufSize = AudioRecord.getMinBufferSize(
- Integer.parseInt(nativeSampleRate),
- AudioFormat.CHANNEL_IN_MONO,
- AudioFormat.ENCODING_PCM_16BIT);
- if (recBufSize == AudioRecord.ERROR ||
- recBufSize == AudioRecord.ERROR_BAD_VALUE) {
- supportRecording = false;
- }
-
- }
}
queryNativeAudioParameters();
- delaySeekBar = (SeekBar)findViewById(R.id.delaySeekBar);
- curDelayTV = (TextView)findViewById(R.id.curDelay);
- echoDelayProgress = delaySeekBar.getProgress() * 1000 / delaySeekBar.getMax();
设置seekbar的监听器
- delaySeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- float curVal = (float)progress / delaySeekBar.getMax();
- curDelayTV.setText(String.format("%s", curVal));
- {
//设置坐标
- private void setSeekBarPromptPosition(SeekBar seekBar, TextView label) {
- float thumbX = (float)seekBar.getProgress()/ seekBar.getMax() *
- seekBar.getWidth() + seekBar.getX();
- label.setX(thumbX - label.getWidth()/2.0f);
- }
- }
- setSeekBarPromptPosition(delaySeekBar, curDelayTV);
- if (!fromUser) return;
-
- echoDelayProgress = progress * 1000 / delaySeekBar.getMax();
- {
static native boolean configureEcho(int delayInMs, float decay);
- }
- configureEcho(echoDelayProgress, echoDecayProgress);
- }
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {}
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {}
- });
- //当前view 在attachedToWindow之后执行操作
- delaySeekBar.post(new Runnable() {
- @Override
- public void run() {
- setSeekBarPromptPosition(delaySeekBar, curDelayTV);
- }
- });
- private void startEcho() {
- if(!supportRecording){
- return;
- }
- if (!isPlaying) {
- if(!createSLBufferQueueAudioPlayer()) {
- statusView.setText(getString(R.string.player_error_msg));
- return;
- }
- if(!createAudioRecorder()) {
- deleteSLBufferQueueAudioPlayer();
- statusView.setText(getString(R.string.recorder_error_msg));
- return;
- }
- startPlay(); // startPlay() triggers startRecording()
- statusView.setText(getString(R.string.echoing_status_msg));
- } else {
- stopPlay(); // stopPlay() triggers stopRecording()
- updateNativeAudioUI();
- deleteAudioRecorder();
- deleteSLBufferQueueAudioPlayer();
- }
- isPlaying = !isPlaying;
- controlButton.setText(getString(isPlaying ?
- R.string.cmd_stop_echo: R.string.cmd_start_echo));
- }
- /*
- * jni function declarations
- */
- static native void createSLEngine(int rate, int framesPerBuf,
- long delayInMs, float decay);
- static native void deleteSLEngine();
- static native boolean configureEcho(int delayInMs, float decay);
- static native boolean createSLBufferQueueAudioPlayer();
- static native void deleteSLBufferQueueAudioPlayer();
-
- static native boolean createAudioRecorder();
- static native void deleteAudioRecorder();
- static native void startPlay();
- static native void stopPlay();
以上图片引用自:https://www.jianshu.com/p/82da5f87314f
OpensSL ES是无授权费,跨平台的,针对嵌入式精心优化的硬件音频加速API。
对象和接口的概念:
对象:提供一组资源及其状态的抽象
接口:提供特定功能的方法的抽象
对象与接口的关系:
对象暴露的接口,有以下三个方面决定:
1)对象的类型
2)应用程序在对象创建期间的,接口请求。
3)在对象声明周期,接口的添加和移除。
一个对象的类型,表明了它有implicat interfaces,implicat interface的含义是:无论应用程序是否request,它都存在对象暴露的接口函数中。
在对象创建的时候,如果有应用请求才暴露的接口,被称为explicit interfaces。
对象定义的可以动态添加和移除的接口,被称为dynamic interfaces.SLDynamicInterfaceManagementItf
struct EchoAudioEngine { SLmilliHertz fastPathSampleRate_; uint32_t fastPathFramesPerBuf_; uint16_t sampleChannels_; uint16_t bitsPerSample_; SLObjectItf slEngineObj_; SLEngineItf slEngineItf_; AudioRecorder *recorder_; AudioPlayer *player_; AudioQueue *freeBufQueue_; // Owner of the queue AudioQueue *recBufQueue_; // Owner of the queue sample_buf *bufs_; uint32_t bufCount_; uint32_t frameCount_; int64_t echoDelay_; float echoDecay_; AudioDelay *delayEffect_; }; static EchoAudioEngine engine;
SLObjectItf:任何对象都暴露这个接口。每个方法创建一个对象,都返回这个接口SLObjectItf. 销毁对象通过destory().应用程序获取其他的接口,通过type ID 使用GetInterface来返回。通过SLObjectItf接口的Realize和resume来控制状态。
SLEngineItf:应用程序开启一个回话的方式,是通过创建一个engine对象的。Engine对象的创建是通过一个SLCreateEngine()来获取的,返回一个SLObjectItf.
当Engine对象创建后,可以获取它的SLEngineItf。
SLBufferQueueItf:被用于流式的音频数据,填充到一个player object或者record object的buffer队列里面。
1)对于recorder对象,当recorder的状态处于SL_RECORDSTATE_RECORDING时。这个对象被SLRecordItf接口控制添加buffer,来隐含开始填充的进程。如果队列中没有足够的buffer,这个auido的数据的填充将会停止和在buffer队列中的要被录制的audio数据会丢失。这个录制仍旧是SL_RECORDSTATE_RECORDING状态。一旦入队了额外的buffer,
填充音频数据将与当前音频数据一起恢复,而不是从饥饿开始了。如果recorder没有处于录制状态,额外的buffer并没有填充队列中任何buffer.
2)在播放对象中的buffer被就地使用,并不会被设备拷贝。应用程序的开发者应该注意到,修改在已经入队的buffer的内容是无效的和会引起音频数据损坏的。
3)一旦入队列的buffer完成了播放或者填充,有callback进行通知,它是安全删除buffer。它也是安全的用新数据填充buffer,和在在播放对象入队buffer和再次入队buffer在录制对象。
4)状态转换为SL_PLAYSTATE_STOPPED,通过release所有的buffer来清空队列,和设置cursor为0.每一个buffer被释放,都会回调被带有SL_BUFFERQUEUENVENT_STOP的flag.
5)一旦转换为了SL_RECORDSTATE_STOPPED状态,应用程序应该继续放buffer到队列中,来取回系统中剩余的buffer。获取剩余的buffer完成的标志是回调方法带有了SL_BUFFERQUEUEEVNENT_CONTEN_END的事件flag。空的buffer可以被用于下一个录制的回话。录制的cursor被设置为0.
6)一旦转化为SL_PLAYSTATE_PAUSEDor SL_RECORDSTATE_PAUSED,cursor仍旧保留在当前的位置。
- engine.fastPathSampleRate_ = static_cast<SLmilliHertz>(sampleRate) * 1000;
- engine.fastPathFramesPerBuf_ = static_cast<uint32_t>(framesPerBuf);
- engine.sampleChannels_ = AUDIO_SAMPLE_CHANNELS;
- engine.bitsPerSample_ = SL_PCMSAMPLEFORMAT_FIXED_16;
- /*
- SL_API SLresultSLAPIENTRY slCreateEngine(
- SLObjectItf *pEngine,
- SLuint32 numOptions
- const SLEngineOption *pEngineOptions,
- SLuint32 numInterfaces,
- const SLInterfaceID *pInterfaceIds,
- const SLboolean * pInterfaceRequired
- )
-
-
- */
-
-
- result = slCreateEngine(&engine.slEngineObj_, 0, NULL, 0, NULL, NULL);
- SLASSERT(result);
-
- //Realizing the object in synchronous mode. */
-
- result =
- (*engine.slEngineObj_)->Realize(engine.slEngineObj_, SL_BOOLEAN_FALSE);
- SLASSERT(result);
//获取slEngineItf_
- result = (*engine.slEngineObj_)
- ->GetInterface(engine.slEngineObj_, SL_IID_ENGINE,
- &engine.slEngineItf_);
- // compute the RECOMMENDED fast audio buffer size:
- // the lower latency required
- // *) the smaller the buffer should be (adjust it here) AND
- // *) the less buffering should be before starting player AFTER
- // receiving the recorder buffer
- // Adjust the bufSize here to fit your bill [before it busts]
- uint32_t bufSize = engine.fastPathFramesPerBuf_ * engine.sampleChannels_ *
- engine.bitsPerSample_;
- bufSize = (bufSize + 7) >> 3; // bits --> byte
- engine.bufCount_ = BUF_COUNT;
- engine.bufs_ = allocateSampleBufs(engine.bufCount_, bufSize);
- assert(engine.bufs_);
//创建缓冲队列,freeBufQueue是指空闲的buffer队列,主要是提供空的采样数组。recBufQueue是接收缓冲队列,主要是用来存储已采集到的音频数据,同样也是播放数据的来源。引擎初始化完毕之后会初始化freeBufQueue,初始化了16个空的大小为480字节的数组。至此音频引擎的初始化结束。
- engine.freeBufQueue_ = new AudioQueue(engine.bufCount_);
- engine.recBufQueue_ = new AudioQueue(engine.bufCount_);
- assert(engine.freeBufQueue_ && engine.recBufQueue_);
- for (uint32_t i = 0; i < engine.bufCount_; i++) {
- engine.freeBufQueue_->push(&engine.bufs_[i]);
- }
//创建AudioDelay
- engine.echoDelay_ = delayInMs;
- engine.echoDecay_ = decay;
- engine.delayEffect_ = new AudioDelay(
- engine.fastPathSampleRate_, .sampleChannels_, engine.bitsPerSample_,
- engine.echoDelay_, engine.echoDecay_);
- assert(engine.delayEffect_);
SLresult result; assert(sampleFormat); sampleInfo_ = *sampleFormat; /* SLresult (*CreateOutputMix) ( SLEngineItf self, SLObjectItf* pMix, SLuint32 numInterfaces, const SLInterfaceID * pInterfaceIds, const SLboolean * pInterfaceRequired ); 创建混音器的对象 */ result = (*slEngine) ->CreateOutputMix(slEngine, &outputMixObjectItf_, 0, NULL, NULL); SLASSERT(result); // realize the output mix result = (*outputMixObjectItf_)->Realize(outputMixObjectItf_, SL_BOOLEAN_FALSE); SLASSERT(result);
- // configure audio source,配置audio source
- SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {
- SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, DEVICE_SHADOW_BUFFER_QUEUE_LEN};
- SLAndroidDataFormat_PCM_EX format_pcm;
- ConvertToSLSampleFormat(&format_pcm, &sampleInfo_);
- SLDataSource audioSrc = {&loc_bufq, &format_pcm};
- // configure audio sink,配置音频的输出
- SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX,
- outputMixObjectItf_};
- SLDataSink audioSnk = {&loc_outmix, NULL};
/* * create fast path audio player: SL_IID_BUFFERQUEUE and SL_IID_VOLUME * and other non-signal processing interfaces are ok.,创建audioplayer */ SLInterfaceID ids[2] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME}; SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; /* SLresult (*CreateAudioPlayer) ( SLEngineItf self, SLObjectItf* pPlayer, const SLDataSource *pAudioSrc, const SLDataSink *pAudioSnk, SLuint32 numInterfaces, const SLInterfaceID * pInterfaceIds, const SLboolean * pInterfaceRequired ); 创建音频播放器 */ result = (*slEngine)->CreateAudioPlayer( slEngine, &playerObjectItf_, &audioSrc, &audioSnk, sizeof(ids) / sizeof(ids[0]), ids, req); SLASSERT(result);
- // realize the player,实现播放器
- result = (*playerObjectItf_)->Realize(playerObjectItf_, SL_BOOLEAN_FALSE);
- SLASSERT(result);
- // get the play interface,获取播放接口
- result = (*playerObjectItf_)
- ->GetInterface(playerObjectItf_, SL_IID_PLAY, &playItf_);
- SLASSERT(result);
- // get the buffer queue interface,获取bufferq queue的接口
- result = (*playerObjectItf_)
- ->GetInterface(playerObjectItf_, SL_IID_BUFFERQUEUE,
- &playBufferQueueItf_);
- SLASSERT(result);
- // register callback on the buffer queue,在bufferq queue上注册接口
- result = (*playBufferQueueItf_)
- ->RegisterCallback(playBufferQueueItf_, bqPlayerCallback, this);
- SLASSERT(result);
//设置播放状态
- result = (*playItf_)->SetPlayState(playItf_, SL_PLAYSTATE_STOPPED);
- SLASSERT(result);
- // create an empty queue to track deviceQueue
- devShadowQueue_ = new AudioQueue(DEVICE_SHADOW_BUFFER_QUEUE_LEN);
- assert(devShadowQueue_);
-
- silentBuf_.cap_ = (format_pcm.containerSize >> 3) * format_pcm.numChannels *
- sampleInfo_.framesPerBuf_;
- silentBuf_.buf_ = new uint8_t[silentBuf_.cap_];
- memset(silentBuf_.buf_, 0, silentBuf_.cap_);
- silentBuf_.size_ = silentBuf_.cap_;
//首先获取播放状态
SLuint32 state; SLresult result = (*playItf_)->GetPlayState(playItf_, &state); if (result != SL_RESULT_SUCCESS) { return SL_BOOLEAN_FALSE; } if (state == SL_PLAYSTATE_PLAYING) { return SL_BOOLEAN_TRUE; } //先设置播放状态是STOPPED状态 result = (*playItf_)->SetPlayState(playItf_, SL_PLAYSTATE_STOPPED); SLASSERT(result); //然后如队列相应的buffer。 result = (*playBufferQueueItf_) ->Enqueue(playBufferQueueItf_, silentBuf_.buf_, silentBuf_.size_); SLASSERT(result); devShadowQueue_->push(&silentBuf_); //设置播放的状态为playing result = (*playItf_)->SetPlayState(playItf_, SL_PLAYSTATE_PLAYING); SLASSERT(result); return SL_BOOLEAN_TRUE;
注册callback:
- void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *ctx) {
- (static_cast<AudioPlayer *>(ctx))->ProcessSLCallback(bq);
- }
- void AudioPlayer::ProcessSLCallback(SLAndroidSimpleBufferQueueItf bq) {
- #ifdef ENABLE_LOG
- logFile_->logTime();
- #endif
- std::lock_guard<std::mutex> lock(stopMutex_);
-
- // retrieve the finished device buf and put onto the free queue
- // so recorder could re-use it,获取已经完成的device buf,并把它放到空闲队列的缓冲区。recorder可以重复使用它
- sample_buf *buf;
- devShadowQueue_->pop();
-
- if (buf != &silentBuf_) {
- buf->size_ = 0;
- freeQueue_->push(buf);
-
- if (!playQueue_->front(&buf)) {
- #ifdef ENABLE_LOG
- logFile_->log("%s", "====Warning: running out of the Audio buffers");
- #endif
- return;
- }
- devShadowQueue_->push(buf);
- (*bq)->Enqueue(bq, buf->buf_, buf->size_);//在从播放队列中,获取一个buffer并入队列。
- playQueue_->pop();
//如果播放队列的大小小于kickstart buffer的数量。入队列silent数据。
playQueue是播放队列,如果为空的话表示没有缓冲数据,这里回调到用的地方做错误处理,若是成功取出,那么先将其存入中转队列,并且将其传入调用播放的方法中开启播放,最后在播放队列中删除该已经播放的数组,在播放完成之后会进入Player播放队列注册的回调中。
- if (playQueue_->size() < PLAY_KICKSTART_BUFFER_COUNT) {
- (*bq)->Enqueue(bq, buf->buf_, buf->size_);
- devShadowQueue_->push(&silentBuf_);
- return;
- }
//填充要播放的数据。
- for (int32_t idx = 0; idx < PLAY_KICKSTART_BUFFER_COUNT; idx++) {
- playQueue_->front(&buf);
- playQueue_->pop();
- devShadowQueue_->push(buf);//devshadow的queue的作用是中转队列。
- (*bq)->Enqueue(bq, buf->buf_, buf->size_);
- }
SLuint32 state; SLresult result = (*playItf_)->GetPlayState(playItf_, &state); SLASSERT(result); if (state == SL_PLAYSTATE_STOPPED) return; std::lock_guard<std::mutex> lock(stopMutex_); result = (*playItf_)->SetPlayState(playItf_, SL_PLAYSTATE_STOPPED); SLASSERT(result); (*playBufferQueueItf_)->Clear(playBufferQueueItf_); #ifdef ENABLE_LOG if (logFile_) { delete logFile_; logFile_ = nullptr; } #endif
AudioPlayer::~AudioPlayer() { std::lock_guard<std::mutex> lock(stopMutex_); // destroy buffer queue audio player object, and invalidate all associated // interfaces if (playerObjectItf_ != NULL) { (*playerObjectItf_)->Destroy(playerObjectItf_); } // Consume all non-completed audio buffers,消耗掉所有未完成的buffer sample_buf *buf = NULL; while (devShadowQueue_->front(&buf)) { buf->size_ = 0; devShadowQueue_->pop(); if(buf != &silentBuf_) { freeQueue_->push(buf); } } delete devShadowQueue_; //把正在播放的队列,放audiobuffer到freeQueue while (playQueue_->front(&buf)) { buf->size_ = 0; playQueue_->pop(); freeQueue_->push(buf); } //销毁混音器的对象接口 // destroy output mix object, and invalidate all associated interfaces if (outputMixObjectItf_) { (*outputMixObjectItf_)->Destroy(outputMixObjectItf_); } delete[] silentBuf_.buf_; }
//转为SL的格式
- SLresult result;
- sampleInfo_ = *sampleFormat;
- SLAndroidDataFormat_PCM_EX format_pcm;
- ConvertToSLSampleFormat(&format_pcm, &sampleInfo_);
// configure audio source,配置audiosource,SL_DATALOCATOR_IODEVICE Data will be generated or consumed by the
specified IO device. Note: for audio output use
the output mix.
SL_DEFAULTDEVICEID_AUDIOINPUTIdentifier denoting the set of input devicesfrom
whichthe implementation receives audio from by
default.
SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, NULL}; SLDataSource audioSrc = {&loc_dev, NULL};
- // configure audio sink,配置audi sink
- SLDataLocator_AndroidSimpleBufferQueue loc_bq = {
- SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, DEVICE_SHADOW_BUFFER_QUEUE_LEN};
SLDataSink audioSnk = {&loc_bq, &format_pcm};
//创建audiorecorder的object
- // create audio recorder
- // (requires the RECORD_AUDIO permission)
- const SLInterfaceID id[2] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
- SL_IID_ANDROIDCONFIGURATION};
- const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
- result = (*slEngine)->CreateAudioRecorder(
- slEngine, &recObjectItf_, &audioSrc, &audioSnk,
- sizeof(id) / sizeof(id[0]), id, req);
- SLASSERT(result);
// Configure the voice recognition preset which has no // signal processing for lower latency. /* /*---------------------------------------------------------------------------*/ /* Android AudioRecorder configuration */ /*---------------------------------------------------------------------------*/ /** Audio recording preset */ /** Audio recording preset key */ #define SL_ANDROID_KEY_RECORDING_PRESET ((const SLchar*) "androidRecordingPreset") /** Audio recording preset values */ /** preset "none" cannot be set, it is used to indicate the current settings * do not match any of the presets. */ #define SL_ANDROID_RECORDING_PRESET_NONE ((SLuint32) 0x00000000) /** generic recording configuration on the platform */ #define SL_ANDROID_RECORDING_PRESET_GENERIC ((SLuint32) 0x00000001) /** uses the microphone audio source with the same orientation as the camera * if available, the main device microphone otherwise */ #define SL_ANDROID_RECORDING_PRESET_CAMCORDER ((SLuint32) 0x00000002) /** uses the main microphone tuned for voice recognition */ #define SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION ((SLuint32) 0x00000003) /** uses the main microphone tuned for audio communications */ #define SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION ((SLuint32) 0x00000004) /** uses the main microphone unprocessed */ #define SL_ANDROID_RECORDING_PRESET_UNPROCESSED ((SLuint32) 0x00000005) /*---------------------------------------------------------------------------*/ /* Android AudioPlayer configuration */ /*---------------------------------------------------------------------------*/ /** Audio playback stream type */ /** Audio playback stream type key */ #define SL_ANDROID_KEY_STREAM_TYPE ((const SLchar*) "androidPlaybackStreamType") /** Audio playback stream type values */ /* same as android.media.AudioManager.STREAM_VOICE_CALL */ #define SL_ANDROID_STREAM_VOICE ((SLint32) 0x00000000) /* same as android.media.AudioManager.STREAM_SYSTEM */ #define SL_ANDROID_STREAM_SYSTEM ((SLint32) 0x00000001) /* same as android.media.AudioManager.STREAM_RING */ #define SL_ANDROID_STREAM_RING ((SLint32) 0x00000002) /* same as android.media.AudioManager.STREAM_MUSIC */ #define SL_ANDROID_STREAM_MEDIA ((SLint32) 0x00000003) /* same as android.media.AudioManager.STREAM_ALARM */ #define SL_ANDROID_STREAM_ALARM ((SLint32) 0x00000004) /* same as android.media.AudioManager.STREAM_NOTIFICATION */ #define SL_ANDROID_STREAM_NOTIFICATION ((SLint32) 0x00000005) /*---------------------------------------------------------------------------*/ /* Android AudioPlayer and AudioRecorder configuration */ /*---------------------------------------------------------------------------*/ /** Audio Performance mode. * Performance mode tells the framework how to configure the audio path * for a player or recorder according to application performance and * functional requirements. * It affects the output or input latency based on acceptable tradeoffs on * battery drain and use of pre or post processing effects. * Performance mode should be set before realizing the object and should be * read after realizing the object to check if the requested mode could be * granted or not. */ /** Audio Performance mode key */ #define SL_ANDROID_KEY_PERFORMANCE_MODE ((const SLchar*) "androidPerformanceMode") /** Audio performance values */ /* No specific performance requirement. Allows HW and SW pre/post processing. */ #define SL_ANDROID_PERFORMANCE_NONE ((SLuint32) 0x00000000) /* Priority given to latency. No HW or software pre/post processing. * This is the default if no performance mode is specified. */ #define SL_ANDROID_PERFORMANCE_LATENCY ((SLuint32) 0x00000001) /* Priority given to latency while still allowing HW pre and post processing. */ #define SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS ((SLuint32) 0x00000002) /* Priority given to power saving if latency is not a concern. * Allows HW and SW pre/post processing. */ #define SL_ANDROID_PERFORMANCE_POWER_SAVING ((SLuint32) 0x00000003) 在采集选项中包含 xxx_RECORDING_PRESET_GENERIC(通用配置,不知道是啥意思) xxx_RECORDING_PRESET_CAMCORDER(录像中优先使用摄像头同方向的Mic,如果没有同方向的就使用主Mic) xxx_RECORDING_PRESET_VOICE_RECOGNITION(针对语音识别业务进行了优化,可能使用降噪Mic) xxx_RECORDING_PRESET_VOICE_COMMUNICATION(针对电话或网络电话优化,可能会硬件AEC、NS、AGC) xxx_RECORDING_PRESET_UNPROCESSED(使用主Mic采集,不经过任何优化处理) 在渲染选项中包含 xxx_STREAM_VOICE(VoIP或者电话,音量需要通过通话音量调节) xxx_STREAM_SYSTEM(系统音量,我的华为P10没有这个音量选项) xxx_STREAM_RING(铃声音量) xxx_STREAM_MEDIA(媒体音量) xxx_STREAM_ALARM(闹钟音量) ———————————————— 版权声明:本文为CSDN博主「everlastxc」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_29621351/article/details/94562600 */ SLAndroidConfigurationItf inputConfig; result = (*recObjectItf_) ->GetInterface(recObjectItf_, SL_IID_ANDROIDCONFIGURATION, &inputConfig); if (SL_RESULT_SUCCESS == result) { SLuint32 presetValue = SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION; (*inputConfig) ->SetConfiguration(inputConfig, SL_ANDROID_KEY_RECORDING_PRESET, &presetValue, sizeof(SLuint32)); } result = (*recObjectItf_)->Realize(recObjectItf_, SL_BOOLEAN_FALSE); SLASSERT(result);
//获取recordobjectItf
- result =
- (*recObjectItf_)->GetInterface(recObjectItf_, SL_IID_RECORD, &recItf_);
- SLASSERT(result);
//获取对象中的bufferqueue
- result = (*recObjectItf_)
- ->GetInterface(recObjectItf_, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
- &recBufQueueItf_);
- SLASSERT(result);
//注册bufferqueue中的callback回调接口
- result = (*recBufQueueItf_)
- ->RegisterCallback(recBufQueueItf_, bqRecorderCallback, this);
- SLASSERT(result);
//创建中转的缓冲区
- devShadowQueue_ = new AudioQueue(DEVICE_SHADOW_BUFFER_QUEUE_LEN);
- assert(devShadowQueue_);
- // in case already recording, stop recording and clear buffer queue,先暂停录制和情况buffer queue队列
- result = (*recItf_)->SetRecordState(recItf_, SL_RECORDSTATE_STOPPED);
- SLASSERT(result);
- result = (*recBufQueueItf_)->Clear(recBufQueueItf_);
- SLASSERT(result);
- for (int i = 0; i < RECORD_DEVICE_KICKSTART_BUF_COUNT; i++) {
- sample_buf *buf = NULL;
- if (!freeQueue_->front(&buf)) {
- LOGE("=====OutOfFreeBuffers @ startingRecording @ (%d)", i);
- break;
- }
- freeQueue_->pop();
- assert(buf->buf_ && buf->cap_ && !buf->size_);
-
- result = (*recBufQueueItf_)->Enqueue(recBufQueueItf_, buf->buf_, buf->cap_);//把空闲的buffer,输入进去
- SLASSERT(result);
- devShadowQueue_->push(buf);//并把这个buffer放到这个中转队列
- }
//设置录制状态为RECORDING
- result = (*recItf_)->SetRecordState(recItf_, SL_RECORDSTATE_RECORDING);
- SLASSERT(result);
- assert(bq == recBufQueueItf_);
- sample_buf *dataBuf = NULL;
- devShadowQueue_->front(&dataBuf);
- devShadowQueue_->pop();
- dataBuf->size_ = dataBuf->cap_; // device only calls us when it is really
- // full
-
- callback_(ctx_, ENGINE_SERVICE_MSG_RECORDED_AUDIO_AVAILABLE, dataBuf);//callback,audio数据已经存在
- recQueue_->push(dataBuf);
- //重新设置空闲的buffer到如队列
- sample_buf *freeBuf;
- while (freeQueue_->front(&freeBuf) && devShadowQueue_->push(freeBuf)) {
- freeQueue_->pop();
- SLresult result = (*bq)->Enqueue(bq, freeBuf->buf_, freeBuf->cap_);
- SLASSERT(result);
- }
当信号输入进来时,使信号的输出波形比输入滞后设定的时间值比如100ms
把信号持续输入看成一个和时间相关的数据流,设定一个缓冲Buffer,大小根据delay的最大值设定,比如delay最大值为2000ms、那么对于96Khz采样频率的处理来说B u f f e r = 96 ∗ 2000 Buffer = 96 * 2000Buffer=96∗2000; Buffer的大小可能还需要加上DSP一次运算的样本点数比如128,这样最终的数据缓冲值B u f f e r = 192128 Buffer = 192128Buffer=192128;
设定一个结构体,内部含有缓冲区信号样本点输入计数器指针∗ i n P *inP∗inP和样本信号计数器输出指针∗ o u t P *outP∗outP、以及延迟设置值D l y DlyDly;
∗ o u t P *outP∗outP的值根据∗ i n P *inP∗inP和D l y DlyDly之差来确定,要注意∗ i n P *inP∗inP比D l y DlyDly小的情况,这种情况下 ∗ o u t P *outP∗outP的值应该取上一个Buffer的数据,即∗ o u t P *outP∗outP位于∗ i n P *inP∗inP上一个Buffer中而不是同属一个Buffer里面
————————————————
版权声明:本文为CSDN博主「Flynn2019」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/bentengdema/article/details/102495512
- feedbackFactor_ = static_cast<int32_t>(decayWeight_ * kFloatToIntMapFactor);
- liveAudioFactor_ = kFloatToIntMapFactor - feedbackFactor_;
- allocateBuffer();
//转为s
- float floatDelayTime = (float)delayTime_ / kMsPerSec;
- //转为1s的总帧数
- float fNumFrames = floatDelayTime * (float)sampleRate_ / kMsPerSec;
- //总帧数
- size_t sampleCount = static_cast<uint32_t>(fNumFrames + 0.5f) * channelCount_;
//字节数
- uint32_t bytePerSample = format_ / 8;
- assert(bytePerSample <= 4 && bytePerSample);
//每帧的字节数
uint32_t bytePerFrame = channelCount_ * bytePerSample;
- // get bufCapacity in bytes
- bufCapacity_ = sampleCount * bytePerSample;
- bufCapacity_ =
- ((bufCapacity_ + bytePerFrame - 1) / bytePerFrame) * bytePerFrame;//按每帧的字节数对齐
-
- buffer_ = new uint8_t[bufCapacity_];
- assert(buffer_);
-
- memset(buffer_, 0, bufCapacity_);
- curPos_ = 0;
-
- // bufSize_ is in Frames ( not samples, not bytes )
- bufSize_ = bufCapacity_ / bytePerFrame;
- process() filter live audio with "echo" effect:
- * delay time is run-time adjustable
- * decay time could also be adjustable, but not used
- * in this sample, hardcoded to .5
- *
- * @param liveAudio is recorded audio stream
- * @param channelCount for liveAudio, must be 2 for stereo
- * @param numFrames is length of liveAudio in Frames ( not in byte )
- // process every sample,处理每一帧
- int32_t sampleCount = channelCount_ * numFrames;
- int16_t* samples = &static_cast<int16_t*>(buffer_)[curPos_ * channelCount_];
- for (size_t idx = 0; idx < sampleCount; idx++) {
- #if 1
- int32_t curSample =
- (samples[idx] * feedbackFactor_ + liveAudio[idx] * liveAudioFactor_) /
- kFloatToIntMapFactor;
//当前帧和上一阵的根据相应的因素的叠加
- if (curSample > SHRT_MAX)
- curSample = SHRT_MAX;
- else if (curSample < SHRT_MIN)
- curSample = SHRT_MIN;
-
- liveAudio[idx] = samples[idx];
- samples[idx] = static_cast<int16_t>(curSample);
- #else
- // Pure delay
- int16_t tmp = liveAudio[idx];
- liveAudio[idx] = samples[idx];
- samples[idx] = tmp;
- #endif
- }
-
- curPos_ += numFrames;
- lock_.unlock();
- void ConvertToSLSampleFormat(SLAndroidDataFormat_PCM_EX* pFormat,
- SampleFormat* pSampleInfo_) {
- // Only support 2 channels,设置声道数
- // For channelMask, refer to wilhelm/src/android/channels.c for details
- if (pSampleInfo_->channels_ <= 1) {
- pFormat->numChannels = 1;
- pFormat->channelMask = SL_SPEAKER_FRONT_LEFT;
- } else {
- pFormat->numChannels = 2;
- pFormat->channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
- }
- case SL_ANDROID_PCM_REPRESENTATION_FLOAT:
- pFormat->bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_32;//设置每一帧的bit数
- pFormat->containerSize = SL_PCMSAMPLEFORMAT_FIXED_32;//设置container的大小
- pFormat->formatType = SL_ANDROID_DATAFORMAT_PCM_EX;//设置数据类型
- break;
分别创建audioplayer和audio record,同时注册了
engine.player_->SetBufQueue(engine.recBufQueue_, engine.freeBufQueue_);
engine.player_->RegisterCallback(EngineService, (void *)&engine);
engine.recorder_->SetBufQueues(engine.freeBufQueue_, engine.recBufQueue_);
engine.recorder_->RegisterCallback(EngineService, (void *)&engine);
bool EngineService(void *ctx, uint32_t msg, void *data) { assert(ctx == &engine); switch (msg) { case ENGINE_SERVICE_MSG_RETRIEVE_DUMP_BUFS: { *(static_cast<uint32_t *>(data)) = dbgEngineGetBufCount(); break; } case ENGINE_SERVICE_MSG_RECORDED_AUDIO_AVAILABLE: {//当有录制的audio数据时 // adding audio delay effect sample_buf *buf = static_cast<sample_buf *>(data); assert(engine.fastPathFramesPerBuf_ == buf->size_ / engine.sampleChannels_ / (engine.bitsPerSample_ / 8)); engine.delayEffect_->process(reinterpret_cast<int16_t *>(buf->buf_), engine.fastPathFramesPerBuf_);//达到延迟的效果 break; } default: assert(false); return false; } return true; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。