Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android active noise cancellation

I'm working a somewhat ambitious project to get active noise-reduction achieved on Android with earbuds or headphones on.

My objective is to record ambient noise with the android phone mic, invert the phase (a simple *-1 on the short-value pulled from the Audio Record?), and playback that inverted waveform through the headphones. If the latency and amplitude are close to correct, it should nullify a good amount of mechanical structured noise in the environment.

Here's what I've got so far:

@Override
    public void run()
    {
        Log.i("Audio", "Running Audio Thread");
        AudioRecord recorder = null;
        AudioTrack track = null;
        short[][] buffers  = new short[256][160];
        int ix = 0;

    /*
     * Initialize buffer to hold continuously recorded audio data, start recording, and start
     * playback.
     */
        try
        {
            int N = AudioRecord.getMinBufferSize(8000,AudioFormat.CHANNEL_IN_MONO,AudioFormat.ENCODING_PCM_16BIT);
            recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, N*10);
            //NoiseSuppressor ns = NoiseSuppressor.create(recorder.getAudioSessionId());
            //ns.setEnabled(true);

            track = new AudioTrack(AudioManager.STREAM_MUSIC, 8000,
                    AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, N*10, AudioTrack.MODE_STREAM);
            recorder.startRecording();
            track.play();
        /*
         * Loops until something outside of this thread stops it.
         * Reads the data from the recorder and writes it to the audio track for playback.
         */
            while(!stopped)
            {                    
                short[] buffer = buffers[ix++ % buffers.length];
                N = recorder.read(buffer,0,buffer.length);

                for(int iii = 0;iii<buffer.length;iii++){
                    //Log.i("Data","Value: "+buffer[iii]);
                    buffer[iii] = buffer[iii] *= -1;                        
                }                    
                track.write(buffer, 0, buffer.length);
            }
        }
        catch(Throwable x)
        {
            Log.w("Audio", "Error reading voice audio", x);
        }
    /*
     * Frees the thread's resources after the loop completes so that it can be run again
     */
        finally
        {
            recorder.stop();
            recorder.release();
            track.stop();
            track.release();
        }
    }

I was momentarily excited to find the Android API actually already has a NoiseSuppression algorithm (you'll see it commented out above). I tested with it and found NoiseSuppressor wasn't doing much to null out constant tones which leads me to believe it's actually just performing a band-pass filter at non-vocal frequencies.

So, my questions:

1) The above code takes about 250-500ms from mic record through playback in headphones. This latency sucks and it would be great to reduce it. Any suggestions there would be appreciated.

2) Regardless of how tight the latency is, my understanding is that the playback waveform WILL have phase offset from the actual ambient noise waveform. This suggests I need to execute some kind of waveform matching to calculate this offset and compensate. Thoughts on how that gets calculated?

3) When it comes to compensating for latency, what would that look like? I've got an array of shorts coming in every cycle, so what would a 30ms or 250ms latency look like?

I'm aware of fundamental problems with this approach being that the location of the phone being not next to the head is likely to introduce some error, but I'm hopeful with some either dynamic or fixed latency correction it maybe be possible to overcome it.

Thanks for any suggestions.

like image 997
Raevik Avatar asked Nov 22 '13 20:11

Raevik


People also ask

Does Android have noise cancellation?

Important: Pixel 4 and up phone users always have access to noise cancellation regardless of their Google Workspace edition. On Pixel phones, noise cancellation is device-based instead of cloud-based and is on by default for personal Google accounts.

What is active noise cancellation in Android phone?

Noise Killer is another Android noise cancelling app. It's designed to filter out noises in public spaces such as train stations, airports, or crowded streets. When you activate the app, it will instantly begin noise cancelling. One nice feature it offers is that it works even when your screen is turned off.

How do you use noise cancellation on Android?

Noise cancellation is off by default on Google Meet, and has to be manually turned on before or during a video call. To use the feature on Android and iOS, click on More, select Settings, and tap on Noise cancellation.

How do I activate active noise cancellation?

When you're wearing both AirPods, press and hold the force sensor on either AirPod to switch between Active Noise Cancellation and Transparency mode. You can customize which modes to switch between (Active Noise Cancellation, Transparency mode, and Off) in Bluetooth settings on your iPhone, iPad, or Mac.


1 Answers

Even if you were able to do something about the latency, it's a difficult problem as you don't know the distance of the phone from the ear, plus there's the fact that distance is not fixed (as the user will move the phone), plus the fact that you don't have a microphone for each ear (so you can't know what the wave will be at one ear until after it's got there, even if you have zero latency)

Having said that, you might be able to do something that could cancel highly periodic waveforms. All you could do though is allow the user to manually adjust the time delay for each ear - as you have no microphones near the ears themselves, you can have no way in your code to know if you're making the problem better or worse.

like image 52
Нет войне Avatar answered Sep 18 '22 15:09

Нет войне