您的位置:首页 > 移动开发 > Android开发

android remote submix 录制系统内置的声音

2016-05-07 22:57 1016 查看

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参数进行录制。

public class MainActivity extends Activity { private static String TAG = "JZJ"; AudioRecord mRecord = null; boolean mReqStop = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); (new Thread() { @Override public void run() { recordAndPlay(); } }).start(); } private final int kSampleRate = 44100; private final int kChannelMode = AudioFormat.CHANNEL_IN_STEREO; private final int kEncodeFormat = AudioFormat.ENCODING_PCM_16BIT; private void init() { int minBufferSize = AudioRecord.getMinBufferSize(kSampleRate, kChannelMode, kEncodeFormat); mRecord = new AudioRecord(MediaRecorder.AudioSource.REMOTE_SUBMIX, kSampleRate, kChannelMode, kEncodeFormat, minBufferSize * 2); } private final int kFrameSize = 2048; private String filePath = "/sdcard/voice.pcm"; private void recordAndPlay() { FileOutputStream os = null; mRecord.startRecording(); try { os = new FileOutputStream(filePath); byte[] buffer = new byte[kFrameSize]; int num = 0; while (!mReqStop) { num = mRecord.read(buffer, 0, kFrameSize); Log.d(TAG, "buffer = " + buffer.toString() + ", num = " + num); os.write(buffer, 0, num); } Log.d(TAG, "exit loop"); os.close(); } catch (IOException e) { e.printStackTrace(); Log.e(TAG, "Dump PCM to file failed"); } mRecord.stop(); mRecord.release(); mRecord = null; Log.d(TAG, "clean up"); } public void stop(View view) { mReqStop = true; Button stopBtn = (Button) findViewById(R.id.stopBtn); stopBtn.setText("Stopped"); stopBtn.setEnabled(false); } }

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);
}
}

How to record submix on android device in realtime? (if it's possible)

http://stackoverflow.com/questions/26363669/how-to-record-submix-on-android-device-in-realtime-if-its-possible

I'm trying to record a submix from device for monitoring and I have some issues with that. I'm using
AudioRecord
instance and audio source is
MediaRecorder.AudioSource.REMOTE_SUBMIX
. I found in internet information that I must use
android.permission.CAPTURE_AUDIO_OUTPUT
permission but it's said "not for use by third-party apps". I tried to launch my application but it throws an exception:

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);



Android Capture Android System Audio

http://www.cnblogs.com/fansen/p/5127931.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: