【问题标题】:How to trigger Vibration on Sound Input?如何触发声音输入的振动?
【发布时间】:2016-02-22 13:28:20
【问题描述】:

我正在尝试创建一个 android 应用程序,在其中过滤一个特定频率的哔哔声并让手机振动。

我从手机的 MIC 中获取输入并使用 MediaRecorder 类,通过使用这个类,我可以记录、保存和播放输入。现在我需要我的手机在发出哔哔声/或任何声音时振动。

输入是通过一根电线连接到手机的耳机插孔,所以我知道只有一个频率在输入。

我有一个按钮,点击它开始录制。 我已经在我的清单文件中获得了振动和录音的权限。

record.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    isRecording=true;
                    myAudioRecorder.prepare();
                    myAudioRecorder.start();
...
}

我也尝试在互联网上搜索并找到类似的问题here,但我找不到任何正确答案。

但是,我可以让手机在单击另一个按钮时振动,这是代码片段,

 Vibrator vibrate;
    vibrate = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);

        Btn1.setOnClickListener(new View.OnClickListener()

                                {
                                    @Override
                                    public void onClick(View v) {
                                       vibrate.vibrate(800);
                                    }
                                }

我尝试在 recorder.start(); 中调用 Vibrator;功能,但这会使手机即使在没有声音的情况下也会振动。 我也尝试从this question 获得帮助,所以每当有静音时,手机不应该振动,但我很困惑,我不知何故明白应该有一个布尔值,当有声音并让手机振动时,它会变为真,但是我无法将此逻辑放入代码中。 请让我知道在这种情况下我可以做什么以及我应该朝哪个方向搜索?

更新 我发现this toturial 用于显示带有输入声音幅度的进度条,它工作正常,我试图让手机在缓冲区中有一些值时振动,现在即使幅度为零它也会振动,我猜那是因为事实上,每次振动都会产生噪音,从而导致手机振动。我无法通过 TOAST 检查函数,因为 java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()。有什么建议吗?

【问题讨论】:

    标签: android audio mediarecorder vibration android-vibration


    【解决方案1】:

    对于您的主要问题,也许您可​​以检查声音的幅度,并且仅在达到最小阈值时才振动。像这样的:

    private class DetectAmplitude extends AsyncTask<Void, Void, Void> {
    
        private MediaRecorder mRecorder = null;
        private final static int MAX_AMPLITUDE = 32768;
        //TODO: Investigate what is the ideal value for this parameter
        private final static int MINIMUM_REQUIRED_AVERAGE = 5000;
    
        @Override
        protected Void doInBackground(Void... params) {
            Boolean soundStarted = true;
            if (mRecorder == null) {
                mRecorder = new MediaRecorder();
                mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
                mRecorder.setOutputFile("/dev/null");
                try {
                    mRecorder.prepare();
                } catch (IllegalStateException e) {
                    soundStarted = false;
                    Log.e(TAG, "Could not detect background noise. Error preparing recorder: " + e.getMessage());
                } catch (IOException e) {
                    soundStarted = false;
                    Log.e(TAG, "Could not detect background noise. Error preparing recorder: " + e.getMessage());
                }
                try {
                    mRecorder.start();
                } catch (RuntimeException e) {
                    Log.e(TAG, "Could not detect background noise. Error starting recorder: " + e.getMessage());
                    soundStarted = false;
                    mRecorder.release();
                    mRecorder = null;
                }
            }
    
            if (soundStarted) {
                // Compute a simple average of the amplitude over one
                // second
                int nMeasures = 100;
                int sumAmpli = 0;
                mRecorder.getMaxAmplitude(); // First call returns 0
                int n = 0;
                for (int i = 0; i < nMeasures; i++) {
                    if (mRecorder != null) {
                        int maxAmpli = mRecorder.getMaxAmplitude();
                        if (maxAmpli > 0) {
                            sumAmpli += maxAmpli;
                            n++;
                        }
                    } else {
                        return null;
                    }
                    try {
                        Thread.sleep(1000 / nMeasures);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                mRecorder.stop();
                mRecorder.release();
                mRecorder = null;
    
                final float avgAmpli = (float) sumAmpli / n;
    
                if (avgAmpli > MINIMUM_REQUIRED_AVERAGE) {
                    //TODO: Vibrate the device here
                }
            }
            return null;
        }
    } 
    

    有关声级检测的更多信息,请参考以下内容:

    关于异常java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare(),这是因为Toast 需要在您的应用程序的主线程上运行。如果您的Thread 代码(如AsyncTask)在Activity 内,您可以尝试以下操作:

    runOnUiThread(new Runnable() {
            @Override
            public void run() {
                //Call your Toast here
            }
        });
    

    否则,您需要以某种方式将方法的结论传递给Activity,以便它运行Toast

    编辑:

    如果你想从Button 使用它,你可以在你的ActivityonCreate() 调用上设置它的OnClickListener 并在那里执行AsyncTask。例如:

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.your_layout);
        Button button = (Button)findViewById(R.id.your_button_id);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new DetectAmplitude().execute(new Void[]{});
            }
        });
    }
    

    我建议您在生产代码中使用它之前先查看how AsyncTask works

    【讨论】:

    • 您好,这听起来不错,但我无法找到一种方法来开始录制按钮单击,您是否建议在 AsyncTask 中使用按钮 onclicklistener 方法,然后是受保护的 Void doInBackground(Void.. . 里面的参数?
    • 嗨@MomoPomo 我用一个用法示例编辑了我的答案。希望对您有所帮助。
    【解决方案2】:

    您想要对音频进行采样,并立即对其进行分析。

    MediaRecorder 似乎是高级别的,它只捕获到文件。您可能想改用AudioRecorder,因为它可以直接访问输入样本。

    为了检测特定音调,您可以在输入样本上使用Goertzel algorithm。这是我多年前做过的C++ implementation,可以作为示例。

    为了检测任何超过特定阈值的声音,您可以对输入样本使用Root Mean Square 分析,并使其在响度达到阈值时触发。这是一个Python example,它会对麦克风发出的巨大噪音做出反应。

    【讨论】:

    • 您可以在MediaRecorder 上使用setOutputFile("/dev/null") 来避免文件输出。此外,为了检测是否有噪音,媒体记录器只需检查一小段时间的声音幅度就可以了。
    • 您的回答很好,但是由于我需要开发 android 以及其他几个初学者,如果只引入 android 实现就太好了,但是对于逻辑来说它非常好,我仍然有我需要的逻辑已经是实现它的语法。同样出于学习目的,没有必要在没有彻底实施的情况下更改使用的类。
    【解决方案3】:

    试试这个:

    Btn1.setOnClickListener(new View.OnClickListener() {
    
            @Override
            public void onClick(View v) {
                v.post(new Runnable() {
    
                    @Override
                    public void run() {
    
                        vibrate.vibrate(800);
                    }
                });
    
            }
        });
    

    【讨论】:

    • 谢谢你的回复,但是我需要让手机在有声音的时候振动,而不是点击,我已经可以做到了。请再次阅读问题。
    【解决方案4】:

    你可以试试这个:

        Handler handler;
        Runnable r;
    
                handler = new Handler();
                    r = new Runnable() {
                        public void run() {
    
                        Vibrator vib = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
                        vib.vibrate(500);
                        handler.postDelayed(r, 1000);
    
                        }
                    };
                handler.post(r);
    

    【讨论】:

    • 请您解释一下代码,我是android新手,对所有概念都不熟悉。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-08
    • 2015-08-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多