.Audio Focus机制以及AudioManager的使用

音频焦点 Android Audio Focus 当多个应用需要播放音频时,音频焦点确保用户听到的内容不会混乱(如多个音乐应用同时播放)。通话属于高优先级音频场景,系统会强制其他应用让出音频焦点。当通话结束时,电话应用释放焦点,音乐播放器可能重新获得焦点(需主动重新请求),恢复播放。电话应用的音频焦点请求由系统自动处理,开发者无需手动实现。除通话外,导航提示、警报声等也会通过音频焦点机制中断音乐,处理逻辑一致。当其他应用请求焦点时,当前应用需根据情况暂停播放、停止播放或降低音量。类型的焦点(短暂独占),以确保通话音频的独占性。请求焦点,并监听焦点变化。 阅读详情

原文地址:http://tanxiaoya105.blog.163.com/blog/static/210328019201272295457523/

大纲:

一、介绍Audio Focus机制

二、AudioManager的一般使用

 

Android是多任务系统,Audio系统是竞争资源。( because there is only one audio output and there may be several media services competing for its use)因为在只有一个音频输出,然而可能有很多的媒体程序去竞争使用它,这样就需要一种机制来管理。Android2.2之前,没有内建的机制来解决多个程序竞争Audio的问题,2.2引入了称作AudioFocus的机制来管理对Audio资源的竞争的管理与协调。

按照AudioFocus的机制,在使用Audio之前,需要申请AudioFocus,在获得AudioFocus之后才可以使用Audio;如果有别的程序竞争你正在使用的Audio,你的程序需要在收到通知之后做停止播放或者降低声音的处理。值得指出的是,这种机制是需要合作完成的,需要所有使用Audio资源的程序都按照这种机制来做,而如果有程序在它失去AudioFocus的时候仍然在使用Audio,AudioFocus拿它也没办法。而这一点对于开放系统的Android来说很致命的:用户可能安装没遵守这种机制的程序,或者版本太老还没引入这种机制的程序,这最终会导致很差的用户体验。

一、AudioFocus的申请与释放

下面看与AudioFocus的相关的类:

获取/放弃AudioFocus的方法都在android.media.AudioManager中,获取AudioFocus用requestAudioFocus();用完之后,放弃AudioFocus,用bandonAudioFocus()。

Audio Focus机制以及AudioManager的使用 - Corio - 谭晓雅  requestAudioFocus

public int requestAudioFocus (AudioManager.OnAudioFocusChangeListener l, int streamType, int durationHint)
Since: API Level 8
Request audio focus. Send a request to obtain the audio focus
Parameters:

l

 

the listener to be notified of audio focus changes

streamType

 

the main audio stream type affected by the focus request

durationHint

 use 
AUDIOFOCUS_GAIN_TRANSIENT
 to indicate this focus request is temporary, and focus will be abandonned shortly. Examples of transient requests are for the playback of driving directions, or notifications sounds. Use
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
 to indicate also that it's ok for the previous focus owner to keep playing if it ducks its audio output. Use 
AUDIOFOCUS_GAIN
 for a focus request of unknown duration such as the playback of a song or a video.


Returns
AUDIOFOCUS_REQUEST_FAILED
 or 
AUDIOFOCUS_REQUEST_GRANTED

其中,参数:


 streamType是《Android中的Audio播放:音量和远程播放控制》中说明的AudioStream,其值取决于AudioManager中的STREAM_xxx,在AudioStream的裁决机制中并未有什么实际意义; 
 durationHint是持续性的指示: 
AUDIOFOCUS_GAIN
指示申请得到的Audio Focus不知道会持续多久,一般是长期占有; 
AUDIOFOCUS_GAIN_TRANSIENT
指示要申请的AudioFocus是暂时性的,会很快用完释放的; 
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK不但说要申请的AudioFocus是暂时性的,还指示当前正在使用AudioFocus的可以继续播放,只是要“duck”一下(降低音量)。
 AudioManager.OnAudioFocusChangeListener是申请成功之后监听AudioFocus使用情况的Listener,后续如果有别的程序要竞争AudioFocus,都是通过这个Listener的onAudioFocusChange()方法来通知这个Audio Focus的使用者的。

返回值,可能是:


 AUDIOFOCUS_REQUEST_GRANTED:申请成功; 
 AUDIOFOCUS_REQUEST_FAILED:申请失败。


 Audio Focus机制以及AudioManager的使用 - Corio - 谭晓雅  public int abandonAudioFocus (AudioManager.OnAudioFocusChangeListener l)

 

二、AudioFocus被抢占与重新获得

由上节中知道,申请/释放AudioFocus时传入了AudioManager.OnAudioFocusChangeListener这个参数,其onAudioFocusChange()方法是Audio Focus被抢占与再次获得通知的地方。所以,每个要使用AudioFocus的程序都要小心实现这个函数,保证AudioFocus实现的一致性。

onAudioFocusChange()方法的focusChange参数指示了该AudioFocus的竞争者对AudioFocus的拥有情况,取值如下:


 AUDIOFOCUS_GAIN:获得了Audio Focus; 
 AUDIOFOCUS_LOSS:失去了Audio Focus,并将会持续很长的时间。这里因为可能会停掉很长时间,所以不仅仅要停止Audio的播放,最好直接释放掉Media资源。而因为停止播放Audio的时间会很长,如果程序因为这个原因而失去AudioFocus,最好不要让它再次自动获得AudioFocus而继续播放,不然突然冒出来的声音会让用户感觉莫名其妙,感受很不好。这里直接放弃AudioFocus,当然也不用再侦听远程播放控制【如下面代码的处理】。要再次播放,除非用户再在界面上点击开始播放,才重新初始化Media,进行播放。 
 AUDIOFOCUS_LOSS_TRANSIENT:暂时失去Audio Focus,并会很快再次获得。必须停止Audio的播放,但是因为可能会很快再次获得AudioFocus,这里可以不释放Media资源; 
 
AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:暂时失去AudioFocus,但是可以继续播放,不过要在降低音量。

下面是onAudioFocusChange()方法处理的代码片段:
OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {  
    public void onAudioFocusChange(int focusChange) {  
        if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT  
            // Pause playback   
        } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {  
            am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);  
            am.abandonAudioFocus(afChangeListener);  
            // Stop playback   
        } else if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {  
            // Lower the volume   
        } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {  
            // Resume playback or Raise it back to normal   
        }  
    }  
};  

OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {      public void onAudioFocusChange(int focusChange) {          if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT              // Pause playback          } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {              am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);              am.abandonAudioFocus(afChangeListener);              // Stop playback          } else if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {              // Lower the volume          } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {              // Resume playback or Raise it back to normal          }      }  };


 

三、典型的应用AudioFocus的场景

下面的时序图描述了AudioFocus被抢占与再次获取的典型场景:

AudioFocus Sequence

Audio Focus被抢占与再次获取的时序图

注意:为了描述简单,此图中除了两个竞争Audio Focus的App之外,只用AudioManager表征了Android的AudioFocus机制中内部参与的对象,实际AudioManager只是外部的表象,内部参与的对象很多,回调函数也并非简单的直接由AudioManager调用,其中还包含了复杂的IPC机制。

图中:
AudioFocus Client通过requestAudioFocus()获取AudioFocus,在获得AudioFocus之后,开始播放Audio[Step#1 ~ #2]; 
其它程序(Other App)也通过requestAudioFocus()获取AudioFocus [Step#3] 
AudioFocus Client失去了Audio Focus,在onAudioFocusChanged()中,根据focusChange【focusChange的值与Other App申请时的durationHint相反,即focusChange = -1*durationHint】的值,做第二节中所描述的处理[Step#4]; 
其它程序(Other App)获取Audio Focus之后,开始播放Audio[Step#5]; 
其它程序(Other App)使用Audio之后,通过abandonAudioFocus()归还AudioFocus [Step#6]; 
AudioFocus Client重新获得了Audio Focus,可做进一步的处理 [Step#7] 

小结

Audio Focus机制要参与各方充分理解并统一遵照施行,有没有遵照者或者实现有误的程序存在就可能打破这一机制,带来糟糕的用户体验。在保证Built-in程序没问题的前提下,如果进入AndroidMarket之前的程序都严格执行了AudioFocus相关的测试,应该也没问题。

使用Audio的程序要做到:

使用前,用requestAudioFocus()申请AudioFocus,并根据应用的实际选取恰当的durationHint值; 
正确的在AudioManager.OnAudioFocusChangeListener中响应AudioFocus失去和重新获取事件; 
Audio使用结束,用
abandonAudioFocus()
归还AudioFocus。

 

二、AudioManager的一般使用

AudioManager除了能在Audio Focus中使用外,最主要的是它能控制声音和铃声

AudioManager provides access to volume and ringer mode control.

AudioManager类位于android.Media 包中,该类提供访问控制音量和钤声模式的操作。
通过getSystemService(Context.AUDIO_SERVICE)方法获得AudioManager实例对象。

AudioManager audiomanage = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);

audiomanager就是我们定义的控制系统声音的对象。


这里只讲述几个比较常用到的方法:
adjustVolume(int direction, int flags) ——用来控制手机音量大小,当传入的第一个参数为 AudioManager.ADJUST_LOWER 时,可将音量调小一个单位,传入AudioManager.ADJUST_RAISE 时,则可以将音量调大一个单位。
adjustStreamVolume(int streamType, int direction, int flags)——(以步长)调节手机音量大小
参数1:声音类型,可取为STREAM_VOICE_CALL(通话)、STREAM_SYSTEM(系统声音)、STREAM_RING(铃声)、STREAM_MUSIC(音乐)、STREAM_ALARM(闹铃声)
参数2:调整音量的方向,可取ADJUST_LOWER(降低)、ADJUST_RAISE(升高)、ADJUST_SAME
参数3:可选的标志位
setStreamVolume(int streamType, int index, int flags)——直接设置音量大小
getMode() ——返回当前音频模式,如 NORMAL(普通), RINGTONE(铃声), or IN_CALL(通话)
setMode()——设置声音模式,可取值NORMAL(普通), RINGTONE(铃声), or IN_CALL(通话)
getRingerMode() ——返回当前的铃声模式。如RINGER_MODE_NORMAL(普通)、RINGER_MODE_SILENT(静音)、RINGER_MODE_VIBRATE(震动)
setRingerMode(int ringerMode) ——改变铃声模式
getStreamVolume(int streamType) ——取得当前手机的音量,最大值为7,最小值为0,当为0时,手机自动将模式调整为“震动模式”。
getStreamMaxVolume(int streamType)——获得当前手机最大铃声。
setStreamMute(int streamType, boolean state
//音量控制,初始化定义
AudioManager mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
//最大音量
int  maxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
//当前音量
int  currentVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
直接控制音量的多少:

以一步步长控制音量的增减,并弹出系统默认音量控制条:

 


//降低音量,调出系统音量控制
if(flag ==0){
  mAudioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,AudioManager.ADJUST_LOWER,
                            AudioManager.FX_FOCUS_NAVIGATION_UP);

                 }
//增加音量,调出系统音量控制
else if
(flag ==1){
  mAudioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,AudioManager.ADJUST_RAISE,
                            AudioManager.FX_FOCUS_NAVIGATION_UP);
              }


常用方法:
android audioManager获取音量:
先获取AudioManager实例,
AudioManager mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

//通话音量

int max = mAudioManager.getStreamMaxVolume( AudioManager.STREAM_VOICE_CALL ); 

int current = mAudioManager.getStreamVolume( AudioManager.STREAM_VOICE_CALL ); 

//系统音量

int max = mAudioManager.getStreamMaxVolume( AudioManager.STREAM_SYSTEM ); 

current = mAudioManager.getStreamVolume( AudioManager.STREAM_SYSTEM ); 

//铃声音量

max = mAudioManager.getStreamMaxVolume( AudioManager.STREAM_RING ); 

current = mAudioManager.getStreamVolume( AudioManager.STREAM_RING ); 

//音乐音量

max = mAudioManager.getStreamMaxVolume( AudioManager.STREAM_MUSIC ); 

current = mAudioManager.getStreamVolume( AudioManager.STREAM_MUSIC ); 


 

//提示声音音量

max = mAudioManager.getStreamMaxVolume( AudioManager.STREAM_ALARM ); 

current = mAudioManager.getStreamVolume( AudioManager.STREAM_ALARM ); 


 

 

 一个即时音效的例子

上一小节介绍了SoundPool 类的常用方法,接下来将带领读者写一个即时音效的例子。具体步骤如下。

(1)打开Eclipse,导入本章源代码中名为Sample3_1的项目。

 
图3-1 raw 文件夹示意图

(2)在res 目录下有一个名为raw 的文件夹,其中包含本项目中所用到的声音文件,如图3-1 所示。

(3)下面将介绍layout 目录下的main.xml 文件的代码内容,在其中设置控件的布局。

代码位置:本书随书光盘中源代码\第3 章\Sample3_1\res\layout\main.xml。

1 <?xml version="1.0" encoding="utf-8"?> 
2 <LinearLayout xmlns:android="
http://schemas.android.com/apk/res/android" 
3 android:orientation="vertical" 
4 android:layout_width="fill_parent" 
5 android:layout_height="fill_parent" 
6 > 
7 <Button 
8 android:text="播放音效1" 
9 android:id="@+id/Button01" 
10 android:layout_width="fill_parent" 
11 android:layout_height="wrap_content"> 
12 </Button> <!--添加一个Button 控件--> 
13 <Button 
14 android:text="播放音效2" 
15 android:id="@+id/Button02" 
16 android:layout_width="fill_parent" 
17 android:layout_height="wrap_content"> 
18 </Button> <!--添加一个Button 控件--> 
19 <Button 
20 android:text="暂停音效1" 
21 android:id="@+id/Button1Pause" 
22 android:layout_width="fill_parent" 
23 android:layout_height="wrap_content"> 
24 </Button> <!--添加一个Button 控件--> 
25 <Button 
26 android:text="暂停音效2" 
27 android:id="@+id/Button2Pause" 
28 android:layout_width="fill_parent" 
29 android:layout_height="wrap_content"> 
30 </Button> <!--添加一个Button 控件--> 
31 </LinearLayout> 

第2~6 行定义一个垂直方向上的线性布局。

第7~18 行为一个播放音效1 的按钮,以及一个播放音效2 的按钮。

第19~30 行为一个暂停播放音效1 的按钮,以及一个暂停播放音效2 的按钮。

(4)接着介绍在src 目录下的wyf.zcl 包中的MyActivity.java 类。

代码位置:本书随书光盘中源代码\第3 章\Sample3_1\src\wyf\zcl\MyActivity.java。

1 package wyf.zcl;  
2 import java.util.HashMap; //引入相关包  
3 ……//此处省略部分不重要代码,读者可在光盘源代码中查看  
4 import android.widget.Button;  
5 public class MyActivity extends Activity { //Activity 创建时调用  
6 SoundPool sp; //得到一个声音池引用  
7 HashMap<Integer,Integer> spMap; //得到一个map 的引用  
8 Button b1; //声音播放控制按钮  
9 Button b1Pause; //声音暂停控制按钮  
10 Button b2; //声音播放控制按钮  
11 Button b2Pause; //声音暂停控制按钮  
12 @Override  
13 public void onCreate(Bundle savedInstanceState){  
14 super.onCreate(savedInstanceState);  
15 setContentView(R.layout.main);  
16 initSoundPool(); //初始化声音池  
17 b1=(Button)findViewById(R.id.Button01); //声音播放控制按钮实例化  
18 b2=(Button)findViewById(R.id.Button02); //声音播放控制按钮实例化  
19 b1Pause=(Button)findViewById(R.id.Button1Pause);  
20 b2Pause=(Button)findViewById(R.id.Button2Pause);  
21 b1.setOnClickListener(new View.OnClickListener() {  
22 @Override  
23 public void onClick(View v) {  
24 playSound(1,1); //播放第一首音效,循环一遍  
25 Toast.makeText(MyActivity.this, "播放音效1", 
Toast.LENGTH_SHORT). show();  
26 }});  
27 b1Pause.setOnClickListener(new View.OnClickListener() {  
28 @Override  
29 public void onClick(View v) {  
30 sp.pause(spMap.get(1));  
31 Toast.makeText(MyActivity.this, "暂停音效1", 
Toast.LENGTH_SHORT). show();  
32 }});  
33 b2.setOnClickListener(new View.OnClickListener() {  
34 @Override  
35 public void onClick(View v) {  
36 playSound(2,1); //播放第二首音效,循环一遍  
37 Toast.makeText(MyActivity.this, "播放音效2", 
Toast.LENGTH_SHORT). show();  
38 }});  
39 b2Pause.setOnClickListener(new View.OnClickListener() {  
40 @Override  
41 public void onClick(View v) {  
42 sp.pause(spMap.get(2));  
43 Toast.makeText(MyActivity.this, "暂停音效2",
Toast.LENGTH_SHORT). show();  
44 }});  
45 }  
46 public void initSoundPool(){ //初始化声音池  
47 sp=new SoundPool(  
48 5, //该参数为设置同时能够播放多少音效  
49 AudioManager.STREAM_MUSIC, //该参数设置音频类型  
50 0 //该参数设置音频文件的质量,目前还没有效果,设置为0(默认值)  
51 );  
52 spMap=new HashMap<Integer,Integer>();  
53 spMap.put(1, sp.load(this, R.raw.attack02, 1));  
54 spMap.put(2, sp.load(this, R.raw.attack14, 1));  
55 }  
56 public void playSound(int sound,int number){  
57 AudioManager am= //实例化AudioManager 对象  
58 (AudioManager)this.getSystemService(this.AUDIO_SERVICE);  
59 float audioMaxVolumn= //返回当前AudioManager 对象的最大音量值  
60 am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);  
61 float audioCurrentVolumn= //返回当前AudioManager 对象的音量值  
62 am.getStreamVolume(AudioManager.STREAM_MUSIC);  
63 float volumnRatio=  
64 audioCurrentVolumn/audioMaxVolumn;  
65 sp.play(  
66 spMap.get(sound), //播放的音乐ID  
67 volumnRatio, //左声道音量  
68 volumnRatio, //右声道音量  
69 1, //优先级,0 为最低  
70 number, //循环次数,0 无不循环,-1 无永远循环  
71 1 //回放速度 ,该值在0.5~2.0 之间,1 为正常速度  
72 );  
73 }} 

第2~11 行引入程序中所使用的相关包,以及声明相关引用。

第13 行为Activity 的onCreate()方法。当创建MyActivity 时调用该方法。

第21~44 行为播放音效1、播放音效2、暂停播放音效1、暂停播放音效2 的初始化及监听方法。

第46~55 行为初始化声音池,SoundPool 调用load()方法可加载音频文件,然后将加载了音频文件的SoundPool 添加到一个HashMap 中,提供给以后的调用。

第56~73 行为播放音效,调用SoundPool 中的play 方法,播放声音,参数sound是播放音效的ID,参数number 是播放音效的次数。该方法的使用上一小节已经做了详细介绍,此处不再赘述了。

(5)最终效果如图3-2 所示,单击播放音效1/播放音效2,将播放音效,单击暂停音效1/暂停音效2,将暂停正在播放的音效。

 
图3-2(a) 播放音效1 效果图
 
图3-2(b) 暂停音效2 效果图
Android10.0AudioFocus之如何使用(一) 前言 对于音频焦点,很多人会感到很陌生,也很迷惑,不清楚音频焦点到底处理什么的,怎么用。有人说要播放音乐,必须先申请焦点,只有拿到焦点后才能播放音乐,可叶有人说我不申请音频焦点也能播放音乐,因此,今天我们就来说说到底什么是音频焦点, 正文 AudioFocus机制实在Android2.2引入的,当初是为了协调各应用之间竞争Audio资源的问题,举个简单例子QQ音乐要播放音乐,优酷要播放视频。对于手... 阅读详情

相关推荐

Android音频焦点机制深度解析与最佳实践

音频焦点(Audio Focus)是Android系统协调多个应用同时访问音频设备的机制,确保在特定时刻只有一个应用能主导音频播放,避免声音混叠。

斗锋在干嘛的博客 1781

android 管理类,Android焦点管理类AudioFocusManager

前言大家都知道,从Android 8开始 焦点的申请方式变了,因此,为了兼容不同的Android版本,因此整理在AudioFocusManager中统一管理。正文其实代码就是 根据当前Android系统版本的判断,然使用不同的参数进行申请焦点和释放焦点,这样用户使用时就不需要考虑版本不同。直接上代码AudioFocusManager.javapackage com.la.audiotools;im...

weixin_30638387的博客 629

音频焦点 Android Audio Focus 进阶

focusLossForGainRequest 方法,用于根据请求的焦点增益类型和当前焦点状态,确定应该发送给当前焦点所有者的焦点丢失类型使用focusLossForGainRequest来确定丢失类型,然后调用handleFocusLoss实际处理焦点丢失,并返回丢失是否为永久性的。

aningxiaoxixi的博客 873

Audio Focus机制以及AudioManager的使用

原文地址:http://tanxiaoya105.blog.163.com/blog/static/210328019201272295457523/ 大纲: 一、介绍Audio Focus机制 二、AudioManager的一般使用   Android是多任务系统,Audio系统是竞争资源。( because there is only one audio outp

夜空里荡秋千的女孩 870

Android 蓝牙 A2dp Audio Service框架介绍

Android 蓝牙A2dp-Avrcp初始化-连接-播放源码分析文档大全-点击下载 android-蓝牙A2dp-avrcp-hfp-opp-配对流程-ble-rfcomm源码流程 一、Android音频系统框架 二、Framework JAVA层 AudioTrack.java 提供给App使用的JAVA层接口,用于PCM格式音频的播放; AudioRecord.java 提供给App使用的JAVA层接口,用于PCM格式音频的录制; AudioManager.java 提供给.

手机-手表蓝牙开发工程师的博客 2182

AMEsim柱塞泵的建模学习

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录前言一、为什么要对柱塞泵进行仿真?二、Amesim中柱塞泵的模型1.amesim中自己的定排量五柱塞的斜盘柱塞泵2.压力、流量仿真总结 前言 最近在学习Amesim进行柱塞泵的仿真学习,顺便在这里记录我的学习过程,这是我的初衷 提示:以下是本篇文章正文内容,下面案例可供参考 一、为什么要对柱塞泵进行仿真? 柱塞泵是功能和动力学比较复杂的流体机械。而在实际实验中,往往没有条件或者需要对柱塞泵做一些优化,所以需要我们利用仿真...

innocent_cft的博客 8183

Android开发中audio focus的处理

Android从2008年推出至今已有4年多,我最近才上手了android开发,我已经属于了开发者中的小弟了,有很多前辈在这系统上做了很多深入的开发和研究。http://developer.android.com 作为Android开发官网,上面有比较详细的介绍,可惜是英文的,我辈还是需要花点力气去读读的,上面将media & camera分成了5个部分, Media playbackS

luckydedong的专栏 759

全志 mipi屏幕和触摸驱动调试记录

mipi屏幕与触摸调试记录

u011996684的博客 3219

Android中的Audio播放:竞争Audio之Audio Focus的应用

Android是多任务系统,Audio系统是竞争资源。Android2.2之前,没有内建的机制来解决多个程序竞争Audio的问题,2.2引入了称作AudioFocus的机制来管理对Audio资源的竞争的管理与协调。本文主要讲解AudioFocus的使用。 按照AudioFocus的机制,在使用Audio之前,需要申请AudioFocus,在获得AudioFocus之后才可以使用Audio;如

u011361576的专栏 639

LDA模型参数优化实战:从auto设置到passes调优

本文深入探讨了LDA主题模型的参数优化实战,重点解析了如何通过设置alpha='auto'与eta='auto'让模型自适应语料,并详细阐述了passes参数对训练效果的核心影响。文章提供了系统的调优方法与评估策略,旨在帮助用户从“能用”到“用好”LDA,产出清晰、可解释的主题分析结果。

weixin_29163797的博客 118

LangChain学习及应用(超详细)

Model I/O 部分是与语言模型进行交互的核心组件,包括输入提示(Prompt Template)、调用模型(Model)、输出解析(Output Parser)。简单来说,就是输入、处理、输出这三个步骤。LLM 因其具有海量参数,需要花费相当的物力与时间成本进行预训练和微调,同时商用 LLM 还需要进行各种安全测试与风险评估等。因此 LLM 会存在知识滞后的问题。在专有领域,LLM 无法学习到所有的专业知识细节,因此在面向专业领域知识的提问时,无法给出可靠准确的回答。

weixin_39764056的博客 4253

Managing Audio Playback之Managing Audio Focus

同一时间可能要好多个app在播放audio,Android用audio focus 来避免app之前互相影响.只有持有audio focus的app才可以播放audio. 可以用requestAudioFocus()来获取对应audio stream的audio focus.如果返回值是AUDIOFOCUS_REQUEST_GRANTED的话,即说明成功获得audio focus. Audio

jason的笔记 595

DreamerV3实战:如何用世界模型在Minecraft中自动挖钻石(附完整训练流程)

本文详细介绍了如何使用DreamerV3世界模型在Minecraft中训练AI智能体自动完成挖钻石的复杂任务。文章深入分析了该任务对强化学习的挑战,提供了从环境配置、模型训练到结果评估的完整实战流程,并分享了关键的调优技巧与问题解决方案,展示了基于模型的强化学习在解决稀疏奖励问题上的强大能力。

weixin_29050271的博客 192

android audio manager focus 规则

Android是多任务系统,Audio系统是竞争资源。Android2.2之前,没有内建的机制来解决多个程序竞争Audio的问题,2.2引入了称作AudioFocus的机制来管理对Audio资源的竞争的管理与协调。本文主要讲解AudioFocus的使用。按照AudioFocus的机制,在使用AudioStream之前,需要申请AudioFocus,在获得AudioFocus之后才可以使用相应的Au

jingchuanhu的专栏 409

从零上手:基于RK3588平台的RKISP Tuner实战配置与核心功能解析

本文详细介绍了在RK3588平台上使用RKISP Tuner工具进行图像信号处理器(ISP)调试的完整实战流程。从MATLAB运行时环境搭建、服务端部署到核心连接,逐步解析如何通过图形化界面实时调节白平衡、锐化、降噪等参数以优化图像质量。文章重点阐述了实时预览、参数调试、抓图对比及参数保存等核心功能,为开发智能摄像头、机器人等AIoT设备的工程师提供了实用的配置指南与进阶技巧。

js777的博客 631

【机器学习】Anaconda安装后打不开jupyter notebook(网页不自动跳出)

anaconda安装成功以后,jupyter notebook可以出现打开的路径,能够手动复制粘贴地址路径打开,却不能自动跳转到网页。解决的办法是在配置文件中加入指定的浏览器配置信息。

weixin_43416960的博客 4万+

Android Audio 音频架构详解

Android 17音频架构摘要 Android 17音频系统采用7层架构设计。应用框架层包含核心组件:AudioManager负责音频焦点管理、设备路由和空间音频控制,支持多应用并发策略;AudioTrack提供低延迟音频播放,支持PCM数据写入和硬件直通。系统服务层通过AudioFlinger管理音频流混合和路由。HAL层抽象硬件接口,支持多设备适配。架构强调动态设备感知、高解析度音频和空间音频支持,为应用开发者提供丰富的音频控制API,包括播放状态管理、音量调节和全局音频监控等功能。

qq_45146250的博客 308

微信小程序 - 解决报错 operateAudio:fail audioInstance is not set(wx.getRecorderManager苹果ios真机调试运行,播放音频播放出错解决)

微信小程序,苹果ios系统,真机测试报错,播放音频报错operateAudio:fail audioInstance not exist,errCode: -1,小程序生成音频播放报错errMsg,真机调试报错开发者工具没问题,wx.getRecorderManager,音频实例,InnerAudioContext,各种方法都试了不行,只有ios苹果手机有这个问题,IOS 出现 operateAudio,在iOS无法播放的解决方案,更新到最新版本了还是不行,链接没有特殊字符,微信小程序全局音频设置,手机上播

🏆 前端领域优质创作者 1万+
上一篇: Android中低电量的处置方法
下一篇: 自定义Toast 可以根据自己的需求 设置显示时间
bingbing1110
博客等级 码龄16年 5粉丝 2原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值