1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > 【Android 高性能音频】Oboe 音频流打开后 耳机 / 音箱 插拔事件处理 ( 动态

【Android 高性能音频】Oboe 音频流打开后 耳机 / 音箱 插拔事件处理 ( 动态

时间:2021-07-28 15:23:51

相关推荐

【Android 高性能音频】Oboe 音频流打开后 耳机 / 音箱 插拔事件处理 ( 动态

文章目录

一、动态注册广播接收者监听耳机插拔事件二、jni 层的 Oboe 播放器代码 ( 重新打开 Oboe 音频流 )三、相关资料

基于 【Android 高性能音频】Oboe 开发流程 ( Oboe 完整代码示例 ) 博客中的示例 , 为该示例添加耳机插拔监听 , 监测到耳机插拔后 , 重新打开 Oboe 音频流 ;

一、动态注册广播接收者监听耳机插拔事件

耳机插拔监听 , 需要监听android.intent.action.HEADSET_PLUG广播事件 ;

注意不能使用静态注册的广播接收者监听该事件 , 只能使用代码中动态注册的广播接收者进行监听 ;

还有一点特别注意 , 在 Resume 时 , 也会激活一次耳机插拔事件 , 相当于初始化事件 , 这里屏蔽 Resume 后的第一次耳机插拔事件 , 需要设置标志位 ;

广播接收者代码示例 :

/*** 广播接收者* 监听耳机插拔事件*/val mHeadsetPlugReceiver: BroadcastReceiver = object : BroadcastReceiver(){override fun onReceive(context: Context, intent: Intent) {if (intent.hasExtra("state")) {// resume 第一次忽略耳机插拔事件if(isResumeIgnore){isResumeIgnore = falsereturn}if (intent.getIntExtra("state", 0) == 0) {stringFromJNI()Toast.makeText(context,"耳机拔出", Toast.LENGTH_SHORT).show()} else if (intent.getIntExtra("state", 0) == 1) {stringFromJNI()Toast.makeText(context,"耳机插入", Toast.LENGTH_SHORT).show()}}}}

注册广播接收者 :

val filter = IntentFilter()filter.addAction("android.intent.action.HEADSET_PLUG")registerReceiver(mHeadsetPlugReceiver, filter)

完整代码示例 :

package kim.hsl.oboedemoimport android.content.BroadcastReceiverimport android.content.Contextimport android.content.Intentimport android.content.IntentFilterimport android.os.Bundleimport android.widget.Toastimport androidx.appcompat.app.AppCompatActivityimport kotlinx.android.synthetic.main.activity_main.*class MainActivity : AppCompatActivity() {/*** 每次 Resume 第一次忽略*/var isResumeIgnore = falseoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// 创建 Oboe 音频流并发音sample_text.text = stringFromJNI()val filter = IntentFilter()filter.addAction("android.intent.action.HEADSET_PLUG")registerReceiver(mHeadsetPlugReceiver, filter)}override fun onResume() {super.onResume()isResumeIgnore = true}override fun onPause() {super.onPause()}override fun onDestroy() {super.onDestroy()unregisterReceiver(mHeadsetPlugReceiver)}/*** 广播接收者* 监听耳机插拔事件*/val mHeadsetPlugReceiver: BroadcastReceiver = object : BroadcastReceiver(){override fun onReceive(context: Context, intent: Intent) {if (intent.hasExtra("state")) {// resume 第一次忽略耳机插拔事件if(isResumeIgnore){isResumeIgnore = falsereturn}if (intent.getIntExtra("state", 0) == 0) {stringFromJNI()Toast.makeText(context,"耳机拔出", Toast.LENGTH_SHORT).show()} else if (intent.getIntExtra("state", 0) == 1) {stringFromJNI()Toast.makeText(context,"耳机插入", Toast.LENGTH_SHORT).show()}}}}/*** 重新打开 Oboe 音频流*/external fun stringFromJNI(): Stringcompanion object {init {System.loadLibrary("native-lib")}}}

二、jni 层的 Oboe 播放器代码 ( 重新打开 Oboe 音频流 )

JNI 层代码没有进行修改 ;

Oboe 音频流变量声明为全局变量 , 如果插入耳机 , 再次调用 Java_kim_hsl_oboedemo_MainActivity_stringFromJNI 方法 , 即可重新打开 Oboe 音频流 , 打开时的设备是默认的设备 , 即当前插入的耳机/音箱 ;

// 声明 Oboe 音频流oboe::ManagedStream managedStream = oboe::ManagedStream();

如果拔出耳机 , 再次调用 Java_kim_hsl_oboedemo_MainActivity_stringFromJNI 方法 , 即可重新打开 Oboe 音频流 , 打开时的设备是默认的设备 , 即手机本身自带的扬声器 ;

完整 C++ 代码示例 :

#include <jni.h>#include <string>#include <oboe/Oboe.h>#include "logging_macros.h"// 这部分变量是采样相关的 , 与 Oboe 操作无关// 声道个数 , 2 代表立体声static int constexpr kChannelCount = 2;static int constexpr kSampleRate = 48000;// Wave params, these could be instance variables in order to modify at runtimestatic float constexpr kAmplitude = 0.5f;// 频率static float constexpr kFrequency = 440;// PI 圆周率static float constexpr kPI = M_PI;// 2 PI 两倍圆周率static float constexpr kTwoPi = kPI * 2;// 每次累加的采样值static double constexpr mPhaseIncrement = kFrequency * kTwoPi / (double) kSampleRate;// 追踪当前波形位置float mPhase = 0.0;// Oboe 音频流回调类class MyCallback : public oboe::AudioStreamCallback {public:oboe::DataCallbackResultonAudioReady(oboe::AudioStream *audioStream, void *audioData, int32_t numFrames) {// 需要生成 AudioFormat::Float 类型数据 , 该缓冲区类型也是该类型// 生产者需要检查该格式// oboe::AudioStream *audioStream 已经转换为适当的类型// 获取音频数据缓冲区auto *floatData = static_cast<float *>(audioData);// 生成正弦波数据for (int i = 0; i < numFrames; ++i) {float sampleValue = kAmplitude * sinf(mPhase);for (int j = 0; j < kChannelCount; j++) {floatData[i * kChannelCount + j] = sampleValue;}mPhase += mPhaseIncrement;if (mPhase >= kTwoPi) mPhase -= kTwoPi;}LOGI("回调 onAudioReady");return oboe::DataCallbackResult::Continue;}};// 创建 MyCallback 对象MyCallback myCallback = MyCallback();// 声明 Oboe 音频流oboe::ManagedStream managedStream = oboe::ManagedStream();extern "C" JNIEXPORT jstring JNICALLJava_kim_hsl_oboedemo_MainActivity_stringFromJNI(JNIEnv* env,jobject /* this */) {// 1. 音频流构建器oboe::AudioStreamBuilder builder = oboe::AudioStreamBuilder();// 设置音频流方向builder.setDirection(oboe::Direction::Output);// 设置性能优先级builder.setPerformanceMode(oboe::PerformanceMode::LowLatency);// 设置共享模式 , 独占builder.setSharingMode(oboe::SharingMode::Exclusive);// 设置音频采样格式builder.setFormat(oboe::AudioFormat::Float);// 设置声道数 , 单声道/立体声builder.setChannelCount(oboe::ChannelCount::Stereo);// 设置采样率builder.setSampleRate(48000);// 设置回调对象 , 注意要设置 AudioStreamCallback * 指针类型builder.setCallback(&myCallback);// 2. 通过 AudioStreamBuilder 打开 Oboe 音频流oboe::Result result = builder.openManagedStream(managedStream);LOGI("openManagedStream result : %s", oboe::convertToText(result));// 3. 开始播放result = managedStream->requestStart();LOGI("requestStart result : %s", oboe::convertToText(result));// 返回数据到std::string hello = "Oboe Test " + std::to_string(static_cast<int>(oboe::PerformanceMode::LowLatency)) + " Result : " + oboe::convertToText(result);return env->NewStringUTF(hello.c_str());}

三、相关资料

Oboe GitHub 主页 :GitHub/Oboe

① 简单使用 :Getting Started

② Oboe 全指南 :Full Guide To Oboe

③ Oboe API 参考 :API reference

④ Android 音频框架发展 :Android audio history

Oboe API 参考 :

API 索引 :https://google.github.io/oboe/reference/namespaceoboe.html

Oboe 音频流创建器 :https://google.github.io/oboe/reference/classoboe_1_1_audio_stream_builder.html

Oboe 音频流 :https://google.github.io/oboe/reference/classoboe_1_1_audio_stream.html

Oboe 音频流回调接口 :https://google.github.io/oboe/reference/classoboe_1_1_audio_stream_callback.html

代码示例 :

GitHub 地址 :/han120/OboeDemo

CSDN 源码快照 :

【Android 高性能音频】Oboe 音频流打开后 耳机 / 音箱 插拔事件处理 ( 动态注册广播接收者监听耳机插拔事件 | 重新打开 Oboe 音频流 )

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。