Android 4.4中AudioRecord用例 - 录制系统内置声音
http://blog.csdn.net/jinzhuojun/article/details/33748031?utm_source=tuicool&utm_medium=referral
通过API 19新加的MediaRecorder.AudioSource.REMOTE_SUBMIX参数可以让系统App录制系统内置的声音,也就是扬声器的声音。下面是一个巨简单的例子来示例如何通过AudioRecord配合REMOTE_SUBMIX参数进行录制。
Android 4.2 Wifi Display 之 Settings 源码分析(2)
http://blog.csdn.net/mznewfacer/article/details/8268930
frameworks/base/services/java/com/android/server/display/WifiDisplayController.java
接下来,我们将重点看一看updateConnection()函数,此函数是建立Wifidisplay连接,监听RTSP连接的核心实现函数。
private void updateConnection() {
//在尝试连接到新设备时,需要通知系统这里已经与旧的设备断开连接
if (mRemoteDisplay != null && mConnectedDevice != mDesiredDevice) {
...
mRemoteDisplay.dispose(); //释放NativeRemoteDisplay资源停止监听
mRemoteDisplay = null; //监听返回对象置为空
mRemoteDisplayInterface = null; //监听端口置为空
mRemoteDisplayConnected = false; //连接标识为未连接
mHandler.removeCallbacks(mRtspTimeout);//将挂起的mRtspTimeout线程从消息队列中移除
setRemoteSubmixOn(false); //关闭远程混音重建模式
unadvertiseDisplay();
}
if (mConnectedDevice != null && mConnectedDevice != mDesiredDevice) {
...
unadvertiseDisplay();
final WifiP2pDevice oldDevice = mConnectedDevice;
mWifiP2pManager.removeGroup(mWifiP2pChannel, new ActionListener() {
@Override
public void onSuccess() {
...
next();
}
@Override
public void onFailure(int reason) {
...
next();
}
private void next() {
if (mConnectedDevice == oldDevice) { //确保连接设备已经不是旧的设备否则递归调用该函数
mConnectedDevice = null;
updateConnection();
}
}
});
return;
}
if (mConnectingDevice != null && mConnectingDevice != mDesiredDevice) {
...
unadvertiseDisplay();
mHandler.removeCallbacks(mConnectionTimeout);
final WifiP2pDevice oldDevice = mConnectingDevice;
mWifiP2pManager.cancelConnect(mWifiP2pChannel, new ActionListener() { //在尝试连接到新设备之前,取消正在进行的p2p连接
@Override
public void onSuccess() {
...
next();
}
@Override
public void onFailure(int reason) {
...
next();
}
private void next() {
if (mConnectingDevice == oldDevice) {
mConnectingDevice = null;
updateConnection();
}
}
});
return;
}
// 如果想断开连接,则任务结束
if (mDesiredDevice == null) {
unadvertiseDisplay();
return;
}
if (mConnectedDevice == null && mConnectingDevice == null) {
Slog.i(TAG, "Connecting to Wifi display: " + mDesiredDevice.deviceName);
mConnectingDevice = mDesiredDevice;
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = mConnectingDevice.deviceAddress;
config.groupOwnerIntent = WifiP2pConfig.MIN_GROUP_OWNER_INTENT;
WifiDisplay display = createWifiDisplay(mConnectingDevice);
advertiseDisplay(display, null, 0, 0, 0);
final WifiP2pDevice newDevice = mDesiredDevice;
mWifiP2pManager.connect(mWifiP2pChannel, config, new ActionListener() {
//以特定的配置信息开启P2P连接,如果当前设备不是P2P组的一部分,会建立P2P小组并发起连接请求;如果当前设备是现存P2P组的一部分,则加入该组的邀请会发送至该配对设备。
@Override
public void onSuccess() {
//为了防止连接还没有建立成功,这里设定了等待处理函数,如果在定长时间内还没有接受到WIFI_P2P_CONNECTION_CHANGED_ACTION广播,则按照handleConnectionFailure(true)处理。
Slog.i(TAG, "Initiated connection to Wifi display: " + newDevice.deviceName);
mHandler.postDelayed(mConnectionTimeout, CONNECTION_TIMEOUT_SECONDS * 1000);
}
@Override
public void onFailure(int reason) {
if (mConnectingDevice == newDevice) {
Slog.i(TAG, "Failed to initiate connection to Wifi display: "
+ newDevice.deviceName + ", reason=" + reason);
mConnectingDevice = null;
handleConnectionFailure(false);
}
}
});
return;
}
// 根据连接的网络地址和端口号监听Rtsp流连接
if (mConnectedDevice != null && mRemoteDisplay == null) {
Inet4Address addr = getInterfaceAddress(mConnectedDeviceGroupInfo);
if (addr == null) {
Slog.i(TAG, "Failed to get local interface address for communicating "
+ "with Wifi display: " + mConnectedDevice.deviceName);
handleConnectionFailure(false);
return; // done
}
setRemoteSubmixOn(true);
final WifiP2pDevice oldDevice = mConnectedDevice;
final int port = getPortNumber(mConnectedDevice);
final String iface = addr.getHostAddress() + ":" + port;
mRemoteDisplayInterface = iface;
Slog.i(TAG, "Listening for RTSP connection on " + iface
+ " from Wifi display: " + mConnectedDevice.deviceName);
mRemoteDisplay = RemoteDisplay.listen(iface, new RemoteDisplay.Listener() {
//开始监听连接上的接口
@Override
public void onDisplayConnected(Surface surface,
int width, int height, int flags) {
if (mConnectedDevice == oldDevice && !mRemoteDisplayConnected) {
Slog.i(TAG, "Opened RTSP connection with Wifi display: "
+ mConnectedDevice.deviceName);
mRemoteDisplayConnected = true;
mHandler.removeCallbacks(mRtspTimeout);
final WifiDisplay display = createWifiDisplay(mConnectedDevice);
advertiseDisplay(display, surface, width, height, flags);
}
}
@Override
public void onDisplayDisconnected() {
if (mConnectedDevice == oldDevice) {
Slog.i(TAG, "Closed RTSP connection with Wifi display: "
+ mConnectedDevice.deviceName);
mHandler.removeCallbacks(mRtspTimeout);
disconnect();
}
}
@Override
public void onDisplayError(int error) {
if (mConnectedDevice == oldDevice) {
Slog.i(TAG, "Lost RTSP connection with Wifi display due to error "
+ error + ": " + mConnectedDevice.deviceName);
mHandler.removeCallbacks(mRtspTimeout);
handleConnectionFailure(false);
}
}
}, mHandler);
mHandler.postDelayed(mRtspTimeout, RTSP_TIMEOUT_SECONDS * 1000);
}
}
http://blog.csdn.net/michaelcao1980/article/details/42290747
audio_policy.conf文件分析
不同的Android产品在音频的设计上通常是存在差异的,而这些差异可以同过Audio的配置文件audio_policy.conf来获得。在Android系统中音频配置文件存放路径有两处,存放地址可以从AudioPolicyManagerBase.cpp文件中知道:
http://blog.csdn.net/michaelcao1980/article/details/42426169
android4.3之系统SetSpeakerphoneOn实现的Audio Output Path切换
http://blog.csdn.net/michaelcao1980/article/details/42290747
在通话过程中要切换Audio Output Path从蓝牙耳机到Speaker,但是却第一次却切换到了earpiece,再切换一次
才切到Speaker,我就根据这个bug的分析,来熟悉下音频通道的切换过程;
首先还是需要看下google对于Android audio系统架构分析;
http://source.android.com/devices/audio.html
android的HAL(Hardware Abstraction Layer)是连接上层的audio-specific framework APIs和底层的audio驱动和硬体的关键;
下面这张图展示了这样的架构以及每层的代码分布:
一、Application framework
在Application framework层级是app层的code,是通过android.media提供的API来与audio硬件进行交互动作,这部分的代码是通过
audio JNI来调用native代码从而达到影响硬件的效果;
android_platform_frameworks_base/media/java/android/media/IAudioService.aidl
oneway void setRemoteSubmixOn(boolean on, int address);