欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 运维知识 > Android >内容正文

Android

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

发布时间:2025/6/17 Android 42 豆豆

文章目录

  • 一、动态注册广播接收者监听耳机插拔事件
  • 二、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.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter import android.os.Bundle import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import 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 runtime static 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 JNICALL Java_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 地址 : https://github.com/han1202012/OboeDemo

  • CSDN 源码快照 :

总结

以上是生活随笔为你收集整理的【Android 高性能音频】Oboe 音频流打开后 耳机 / 音箱 插拔事件处理 ( 动态注册广播接收者监听耳机插拔事件 | 重新打开 Oboe 音频流 )的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。