Android中的实时音频处理

Android中的实时音频处理,android,audio,real-time,Android,Audio,Real Time,我正试图找出如何编写一个应用程序,可以解码音频莫尔斯电码的飞行。我发现这解释了如何在Android中从麦克风录制音频。我想知道的是,是否可以从麦克风访问原始输入,或者是否必须将其写入/读取到文件中 谢谢。看起来必须先将其转储到文件中 如果你偷看一下, 本机音频数据字节缓冲区不向公共API公开 根据我的经验,为Android构建音频合成器后,很难实现实时性能和保持音频保真度。不过,摩尔斯电码“翻译器”当然是可行的,听起来是个有趣的小项目。祝你好运 如果使用(上面的示例),它会将压缩音频保存到文件中

我正试图找出如何编写一个应用程序,可以解码音频莫尔斯电码的飞行。我发现这解释了如何在Android中从麦克风录制音频。我想知道的是,是否可以从麦克风访问原始输入,或者是否必须将其写入/读取到文件中


谢谢。

看起来必须先将其转储到文件中

如果你偷看一下, 本机音频数据字节缓冲区不向公共API公开

根据我的经验,为Android构建音频合成器后,很难实现实时性能和保持音频保真度。不过,摩尔斯电码“翻译器”当然是可行的,听起来是个有趣的小项目。祝你好运

如果使用(上面的示例),它会将压缩音频保存到文件中

如果使用,可以直接获取音频样本


是的,你想做的事情应该是可能的。

使用录音技术太过分了。只要每隔1000毫秒检查一次MediaRecorder.getMaxAmplificate(),查看噪音和静音

如果你真的需要分析波形,那么是的,你需要录音。获取原始数据,并计算与之相关的原始字节部分的均方根,以了解体积

但是,当MediaRecorder.getMaxAmplificate()更易于使用时,为什么要这么做呢


从这个答案中查看我的代码:

麻省理工学院媒体实验室有一个称为funf的感知框架:
他们已经为音频输入和一些分析(FFT等)创建了类,就我所见,还实现了保存到文件或上传,并且他们处理手机上的大多数传感器。
您还可以从他们编写的代码中获得灵感,我认为这非常好。

我找到了一种方法。基本上,您需要运行一个新线程,在该线程中连续调用
myAndroidRecord.read()
。在这个调用之后,对缓冲区中的所有条目进行循环,您可以一个接一个地实时查看原始值。下面是主要活动的代码示例

package com.example.mainproject;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.core.app.ActivityCompat;


import android.content.pm.PackageManager;
import android.Manifest;

import android.content.Context;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.widget.TextView;
import android.media.AudioManager;
import android.media.AudioFormat;
import android.os.Bundle;



import java.util.Arrays;

public class MainActivity extends AppCompatActivity {

    private AudioManager myAudioManager;
    private static final int REQUEST_RECORD_AUDIO_PERMISSION = 200;
    // Requesting permission to RECORD_AUDIO
    private boolean permissionToRecordAccepted = false;
    private String [] permissions = {Manifest.permission.RECORD_AUDIO};

    private static final int PERMISSION_RECORD_AUDIO = 0;
    Thread mThread;

    @Override
    public void onRequestPermissionsResult(int requestCode,  String[] permissions,  int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode){
            case REQUEST_RECORD_AUDIO_PERMISSION:
                permissionToRecordAccepted  = grantResults[0] == PackageManager.PERMISSION_GRANTED;
                break;
        }
        if (!permissionToRecordAccepted ) finish();

    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if(ContextCompat.checkSelfPermission(this,Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED){
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.RECORD_AUDIO)) {
                // Show an explanation to the user *asynchronously* -- don't block
                // this thread waiting for the user's response! After the user
                // sees the explanation, try again to request the permission.
                ActivityCompat.requestPermissions(this,
                        new String[] { Manifest.permission.RECORD_AUDIO },
                        PERMISSION_RECORD_AUDIO);
                return;
            } else {
                // No explanation needed; request the permission
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.RECORD_AUDIO},
                        1);
                ActivityCompat.requestPermissions(this,
                        new String[] { Manifest.permission.RECORD_AUDIO },
                        PERMISSION_RECORD_AUDIO);

                // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
                // app-defined int constant. The callback method gets the
                // result of the request.
            }
        }else{

            myAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
            String x = myAudioManager.getProperty(AudioManager.PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED);

            runOnUiThread(()->{
                TextView tvAccXValue = findViewById(R.id.raw_available);
                tvAccXValue.setText(x);
            });

            mThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    record();
                }
            });
            mThread.start();
        }
    }

    private void record(){
        int audioSource = MediaRecorder.AudioSource.MIC;
        int samplingRate = 11025;
        int channelConfig = AudioFormat.CHANNEL_IN_DEFAULT;
        int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
        int bufferSize = AudioRecord.getMinBufferSize(samplingRate,channelConfig,audioFormat);

        short[] buffer = new short[bufferSize/4];
        AudioRecord myRecord = new AudioRecord(audioSource,samplingRate,channelConfig,audioFormat,bufferSize);

        myRecord.startRecording();

        int noAllRead = 0;
        while(true){
            int bufferResults = myRecord.read(buffer,0,bufferSize/4);
            noAllRead += bufferResults;
            int ii = noAllRead;
            for (int i = 0;i<bufferResults;i++){
                int val = buffer[i];
                runOnUiThread(()->{
                    TextView raw_value = findViewById(R.id.sensor_value);
                    raw_value.setText(String.valueOf(val));
                    TextView no_read = findViewById(R.id.no_read_val);
                    no_read.setText(String.valueOf(ii));
                });
            }

        }
    }
}
package com.example.main项目;
导入androidx.appcompat.app.appcompat活动;
导入androidx.core.content.ContextCompat;
导入androidx.core.app.ActivityCompat;
导入android.content.pm.PackageManager;
导入android.Manifest;
导入android.content.Context;
导入android.media.AudioRecord;
导入android.media.MediaRecorder;
导入android.widget.TextView;
导入android.media.AudioManager;
导入android.media.AudioFormat;
导入android.os.Bundle;
导入java.util.array;
公共类MainActivity扩展了AppCompatActivity{
私人音频经理myAudioManager;
私有静态最终整数请求\记录\音频\权限=200;
//正在请求录制_音频的许可
private boolean PermissionRecordAccepted=false;
私有字符串[]权限={Manifest.permission.RECORD_AUDIO};
私有静态最终int权限\u记录\u音频=0;
线程mThread;
@凌驾
public void onRequestPermissionsResult(int-requestCode、字符串[]权限、int[]grantResults){
super.onRequestPermissionsResult(请求代码、权限、授权结果);
开关(请求代码){
案例请求\记录\音频\许可:
permissionToRecordAccepted=grantResults[0]==PackageManager.PERMISSION\u已授予;
打破
}
如果(!PermissionRecordAccepted)完成();
}
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(ContextCompat.checkSelfPermission(此,Manifest.permission.RECORD_AUDIO)!=PackageManager.permission_已授予){
如果(活动公司)应显示请求许可理由(此,
清单.权限.记录(音频){
//向用户显示解释*异步*--不阻止
//此线程正在等待用户的响应!在用户
//请查看说明,然后重试请求权限。
ActivityCompat.requestPermissions(此,
新字符串[]{Manifest.permission.RECORD_AUDIO},
许可(录音和音频);
返回;
}否则{
//无需解释;请求许可
ActivityCompat.requestPermissions(此,
新字符串[]{Manifest.permission.RECORD_AUDIO},
1);
ActivityCompat.requestPermissions(此,
新字符串[]{Manifest.permission.RECORD_AUDIO},
许可(录音和音频);
//我的\u权限\u请求\u读取\u联系人是
//应用程序定义的int常量。回调方法获取
//请求的结果。
}
}否则{
myAudioManager=(AudioManager)getSystemService(Context.AUDIO\u服务);
字符串x=myAudioManager.getProperty(AudioManager.PROPERTY\u支持\u音频\u源\u未处理);
runOnUiThread(()->{
TextView tvAccXValue=findViewById(R.id.raw_可用);
tvAccXValue.setText(x);
});
mThread=new Thread(new Runnable()){
@凌驾
公开募捐{
记录();
}
});
mThread.start();
}
}
私人无效记录(){
int audioSource=MediaRecorder.audioSource.MIC;
int-samplingRate=11025;
int channelConfig=AudioFormat.CHANNEL\u默认值;
int audioFormat=audioFormat.ENCODING_PCM_16位;
int bufferSize=AudioRecord.getMinBufferSize(samplingRate、channelConfig、audioFormat);
short[]buffer=新的short[bufferSize/4];
AudioRecord myRecord=新的AudioRec