How to Get Accurate Recording Duration from Unity's Microphone

This article is a translated version of my original post on Qiita. Original (Japanese): https://qiita.com/segur/items/6d7b140418ef9adf6e7c

Introduction

I was building a voice recording feature using a smartphone microphone in Unity. The requirement was simple: tap a button to start recording, tap again to stop. However, I ran into a problem — I couldn't get the accurate recording duration. This article explains how I solved it.

Unity's Microphone Class

Unity provides a built-in Microphone class for recording audio. Unity Documentation | Microphone

On iPhone, Android, and Mac, it uses the built-in microphone. On Windows, Unity will detect any connected microphone automatically (probably).

Sample Code (Updated: 2018/10/21)

I created a sample Unity project. Feel free to use it. https://github.com/segurvita/UnityMicrophonePractice

It supports starting/stopping recording and playback via button controls.

Code Walkthrough

Here is the full sample code:

using UnityEngine;

public class RecordManager : MonoBehaviour
{
    // Public variables
    public int maxDuration;                  // Maximum recording duration (e.g., 20 seconds)
    public AudioClip audioClip;              // Audio data

    // Private variables
    private const int sampleRate = 16000;    // Recording sample rate
    private string mic;                      // Microphone device name

    ///-----------------------------------------------------------
    /// <summary>Start recording</summary>
    ///-----------------------------------------------------------
    public void StartRecord()
    {
        // Check if microphone exists
        if (Microphone.devices.Length == 0)
        {
            Debug.Log("No microphone found");
            return;
        }

        // Get microphone name
        mic = Microphone.devices[0];

        // Start recording; store audio data in audioClip
        audioClip = Microphone.Start(mic, false, maxDuration, sampleRate);
    }

    ///-----------------------------------------------------------
    /// <summary>Stop recording</summary>
    ///-----------------------------------------------------------
    public void StopRecord()
    {
        // Get the current recording position
        int position = Microphone.GetPosition(mic);

        // Force stop the microphone
        Microphone.End(mic);

        // Checking the duration shows maxDuration regardless of when we stopped — does it include silence?
        Debug.Log("Recording duration before fix: " + audioClip.length);

        // Allocate a temporary buffer and copy all audio data from audioClip
        float[] soundData = new float[audioClip.samples * audioClip.channels];
        audioClip.GetData(soundData, 0);

        // Create a new buffer sized exactly to the recorded position
        float[] newData = new float[position * audioClip.channels];

        // Copy only the recorded portion
        for (int i = 0; i < newData.Length; i++)
        {
            newData[i] = soundData[i];
        }

        // Create a new AudioClip instance and set the trimmed audio data
        AudioClip newClip = AudioClip.Create(audioClip.name, position, audioClip.channels, audioClip.frequency, false);
        newClip.SetData(newData, 0);

        // Replace the original audioClip with the new one
        AudioClip.Destroy(audioClip);
        audioClip = newClip;

        // Log the corrected duration
        Debug.Log("Recording duration after fix: " + newClip.length);
    }
}

Explaining StartRecord

Starting the recording is straightforward — just call:

audioClip = Microphone.Start(mic, false, maxDuration, sampleRate);

Without explicitly stopping, it will record for maxDuration seconds. The audio data is stored in audioClip, which is an instance of the AudioClip class — Unity's container for audio data. To play it back, pass audioClip to an AudioSource and call Play().

Explaining StopRecord

Stopping mid-recording is where things get complicated.

Calling:

Microphone.End(mic);

stops the recording, but leaves audioClip in an unexpected state. Even if you stopped after 3 seconds, audioClip.length reports the full maxDuration — for example, 20 seconds.

It turns out audioClip.length is fixed to maxDuration the moment Microphone.Start() is called.

Since audioClip.length is read-only, I worked around this by reconstructing the AudioClip instance. I referenced this Q&A for the approach: record dynamic length from microphone

If there's a cleaner way, I'd love to hear it.

Also, note this line:

int position = Microphone.GetPosition(mic);

This must be called before Microphone.End(mic). If called after, position will be 0.

Note: The original version of this code called GetPosition after End, which caused position to always be 0. A reader pointed this out and I confirmed the fix — calling GetPosition before End returns the correct value. The sample code has been updated accordingly. (Updated 2018/08/20)

Summary

Unity's Microphone class makes it easy to record audio, but getting an accurate recording duration requires some extra work — specifically, reconstructing the AudioClip with the correct length after stopping.