【Unity中Pico设备(Android平台)实现录音和回放功能的解决方案】

由于项目需求,需要做个在Pico里录音和回放的功能,但没要求持久化存储,那么直接放内存里一次性;
最后使用Unity的Microphone类和AudioSource组件实现
UI部分根据代码建立即可,我这就随便建了一个很简单的
在这里插入图片描述
在这里插入图片描述

在做的过程中还是出现了一些bug
以下是优化完之后的代码,有兴趣的朋友可以在我的基础上再优化扩展

using UnityEngine;
using UnityEngine.Android;
using UnityEngine.UI;
using System.Collections;

public class OptimizedAudioRecorder : MonoBehaviour
{
    [Header("UI References")]
    public Button recordButton;
    public Button stopRecordButton;
    public Button playButton;
    public Button stopPlayButton;
    public Text durationText;         // 显示当前设置的录音时长
    public Text elapsedTimeText;      // 显示已录音时长
    public Text statusText;

    [Header("Settings")]
    public float minDuration = 1f;    // 最小录音时长(秒)
    public float maxDuration = 60f;   // 最大录音时长(秒)
    public float updateInterval = 0.1f; // 时长更新频率(秒)

    private AudioSource audioSource;
    private AudioClip recordedClip;
    private bool isRecording = false;
    private bool isPlaying = false;
    private string microphoneDevice;
    private float currentDuration = 10f; // 当前设置的录音时长
    private float recordingStartTime;   // 录音开始时间
    private Coroutine recordingTimerCoroutine; // 录音计时协程
    private Coroutine playbackTimerCoroutine;  // 播放计时协程
    private float actualRecordedDuration = 0f; // 实际录音时长

    void Start()
    {
        audioSource = gameObject.AddComponent<AudioSource>();
        audioSource.playOnAwake = false;

        currentDuration = Mathf.Clamp(currentDuration, minDuration, maxDuration);

        InitializeUI();

        CheckMicrophonePermission();

        if (Microphone.devices.Length > 0)
        {
            microphoneDevice = Microphone.devices[0];
            statusText.text = "准备就绪";
        }
        else
        {
            statusText.text = "未检测到麦克风";
            SetButtonsInteractable(false);
        }

        UpdateDurationDisplay();
    }

    /// <summary>
    /// 初始化UI组件和事件监听
    /// </summary>
    void InitializeUI()
    {
        recordButton.onClick.AddListener(() => StartRecording(currentDuration));
        stopRecordButton.onClick.AddListener(StopRecording);
        playButton.onClick.AddListener(PlayRecording);
        stopPlayButton.onClick.AddListener(StopPlayback);

        stopRecordButton.interactable = false;
        stopPlayButton.interactable = false;
        playButton.interactable = false;

        elapsedTimeText.text = "已录音: 0.0s";
    }

    /// <summary>
    /// 检查并请求麦克风权限
    /// </summary>
    void CheckMicrophonePermission()
    {
        if (!Permission.HasUserAuthorizedPermission(Permission.Microphone))
        {
            Permission.RequestUserPermission(Permission.Microphone);
            statusText.text = "请求麦克风权限...";
        }
    }

    /// <summary>
    /// 更新时长显示
    /// </summary>
    void UpdateDurationDisplay()
    {
        durationText.text = $"设置时长: {currentDuration:F1}秒";
    }

    /// <summary>
    /// 开始录音
    /// </summary>
    /// <param name="duration">录音时长(秒)</param>
    public void StartRecording(float duration)
    {
        if (isRecording) return;

        if (!Permission.HasUserAuthorizedPermission(Permission.Microphone))
        {
            statusText.text = "麦克风权限未授予!";
            return;
        }

        if (recordedClip != null)
        {
            Destroy(recordedClip);
            recordedClip = null;
        }

        try
        {
            recordedClip = Microphone.Start(
                microphoneDevice,
                false,
                Mathf.CeilToInt(duration),
                44100
            );

            isRecording = true;
            recordingStartTime = Time.time;
            actualRecordedDuration = 0f; 

            if (recordingTimerCoroutine != null)
                StopCoroutine(recordingTimerCoroutine);
            recordingTimerCoroutine = StartCoroutine(UpdateRecordingTime());

            statusText.text = $"录音中... (最长: {duration:F1}秒)";
            recordButton.interactable = false;
            stopRecordButton.interactable = true;
            playButton.interactable = false;
            stopPlayButton.interactable = false;
        }
        catch (System.Exception e)
        {
            statusText.text = $"录音启动失败: {e.Message}";
            isRecording = false;
            recordButton.interactable = true;
            stopRecordButton.interactable = false;
        }
    }

    /// <summary>
    /// 停止录音
    /// </summary>
    public void StopRecording()
    {
        if (!isRecording) return;

        try
        {
            Microphone.End(microphoneDevice);
            isRecording = false;

            if (recordingTimerCoroutine != null)
            {
                StopCoroutine(recordingTimerCoroutine);
                recordingTimerCoroutine = null;
            }

            statusText.text = $"录音已停止 (实际: {actualRecordedDuration:F1}秒)";
            recordButton.interactable = true;
            stopRecordButton.interactable = false;
            playButton.interactable = true;

            elapsedTimeText.text = $"已录音: {actualRecordedDuration:F1}s";
        }
        catch (System.Exception e)
        {
            statusText.text = $"停止录音失败: {e.Message}";
        }
    }

    /// <summary>
    /// 播放录音
    /// </summary>
    public void PlayRecording()
    {
        if (recordedClip == null)
        {
            statusText.text = "没有可播放的录音";
            return;
        }

        try
        {
            audioSource.Stop();
            audioSource.clip = recordedClip;
            audioSource.Play();
            isPlaying = true;

            if (playbackTimerCoroutine != null)
                StopCoroutine(playbackTimerCoroutine);
            playbackTimerCoroutine = StartCoroutine(UpdatePlaybackTime());

            statusText.text = "播放中...";
            playButton.interactable = false;
            stopPlayButton.interactable = true;
            recordButton.interactable = false;
        }
        catch (System.Exception e)
        {
            statusText.text = $"播放失败: {e.Message}";
        }
    }

    /// <summary>
    /// 停止播放
    /// </summary>
    public void StopPlayback()
    {
        if (!isPlaying) return;

        try
        {
            audioSource.Stop();
            isPlaying = false;

            if (playbackTimerCoroutine != null)
            {
                StopCoroutine(playbackTimerCoroutine);
                playbackTimerCoroutine = null;
            }

            statusText.text = "播放已停止";
        }
        catch (System.Exception e)
        {
            statusText.text = $"停止播放失败: {e.Message}";
        }
        finally
        {
            playButton.interactable = true;
            stopPlayButton.interactable = false;
            recordButton.interactable = true;
        }
    }

    /// <summary>
    /// 更新录音时长的协程
    /// </summary>
    private IEnumerator UpdateRecordingTime()
    {
        float startTime = Time.time;

        while (isRecording)
        {
            float elapsedTime = Time.time - startTime;
            actualRecordedDuration = elapsedTime;
            Debug.Log(actualRecordedDuration);

            elapsedTimeText.text = $"已录音: {elapsedTime:F1}s";

            if (elapsedTime >= currentDuration)
            {
                StopRecording();
                yield break;
            }

            yield return new WaitForSeconds(updateInterval);
        }
    }

    /// <summary>
    /// 更新播放进度的协程
    /// </summary>
    private IEnumerator UpdatePlaybackTime()
    {
        float startTime = Time.time;
        float playbackDuration = actualRecordedDuration > 0 ? actualRecordedDuration : recordedClip.length;

        while (isPlaying && audioSource.isPlaying)
        {
            float elapsedTime = Time.time - startTime;

            elapsedTimeText.text = $"播放中: {elapsedTime:F1}s / {playbackDuration:F1}s";

            // 检查是否播放完成
            if (elapsedTime >= playbackDuration)
            {
                elapsedTimeText.text = $"播放中: {playbackDuration:F1}s / {playbackDuration:F1}s";
                StopPlayback();
                yield break;
            }

            yield return new WaitForSeconds(updateInterval);
        }

        // 如果播放被外部中断(如用户停止)
        if (isPlaying)
        {
            StopPlayback();
        }
    }

    /// <summary>
    /// 设置按钮交互状态
    /// </summary>
    private void SetButtonsInteractable(bool state)
    {
        recordButton.interactable = state;
        stopRecordButton.interactable = false;
        playButton.interactable = false;
        stopPlayButton.interactable = false;
    }

    void OnDestroy()
    {
        if (isRecording)
        {
            Microphone.End(microphoneDevice);
        }

        if (isPlaying)
        {
            audioSource.Stop();
        }

        if (recordedClip != null)
        {
            Destroy(recordedClip);
        }
    }
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

魔法师干脆面

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值