当前位置: 首页 > news >正文

小智机器人关键函数解析,Application::OutputAudio()处理音频数据的输出的函数

以下是对 Application::OutputAudio() 函数的详细解释:
源码:

void Application::OutputAudio() { // 扬声器的输出
    auto now = std::chrono::steady_clock::now();
    auto codec = Board::GetInstance().GetAudioCodec();
    const int max_silence_seconds = 10;

    std::unique_lock<std::mutex> lock(mutex_);
    if (audio_decode_queue_.empty()) {
        // Disable the output if there is no audio data for a long time
        if (device_state_ == kDeviceStateIdle) {
            auto duration = std::chrono::duration_cast<std::chrono::seconds>(now - last_output_time_).count();
            if (duration > max_silence_seconds) {
                codec->EnableOutput(false);
            }
        }
        return;
    }

    if (device_state_ == kDeviceStateListening) {
        audio_decode_queue_.clear();
        return;
    }

    last_output_time_ = now;
    auto opus = std::move(audio_decode_queue_.front());
    audio_decode_queue_.pop_front();
    lock.unlock();

    background_task_->Schedule([this, codec, opus = std::move(opus)]() mutable {
        if (aborted_) {
            return;
        }

        std::vector<int16_t> pcm;
        if (!opus_decoder_->Decode(std::move(opus), pcm)) {
            return;
        }

        // Resample if the sample rate is different
        if (opus_decode_sample_rate_ != codec->output_sample_rate()) {
            int target_size = output_resampler_.GetOutputSamples(pcm.size());
            std::vector<int16_t> resampled(target_size);
            output_resampler_.Process(pcm.data(), pcm.size(), resampled.data());
            pcm = std::move(resampled);
        }
        
        codec->OutputData(pcm);
    });
}

函数概述

Application::OutputAudio() 函数主要负责处理音频数据的输出,通过扬声器播放音频。它会检查音频解码队列的状态,根据不同情况决定是否输出音频、是否禁用输出设备,并且会对音频数据进行解码和重采样处理,最后将处理后的音频数据发送到音频编解码器进行输出。

代码详细解释

1. 时间获取和编解码器获取
auto now = std::chrono::steady_clock::now();
auto codec = Board::GetInstance().GetAudioCodec();
const int max_silence_seconds = 10;
  • now:获取当前时间,用于后续计算音频数据的空闲时长。
  • codec:通过 Board::GetInstance().GetAudioCodec() 获取音频编解码器的实例,用于音频数据的输出。
  • max_silence_seconds:定义了最大允许的静音时长,单位为秒。
2. 加锁并检查音频解码队列
std::unique_lock<std::mutex> lock(mutex_);
if (audio_decode_queue_.empty()) {
    if (device_state_ == kDeviceStateIdle) {
        auto duration = std::chrono::duration_cast<std::chrono::seconds>(now - last_output_time_).count();
        if (duration > max_silence_seconds) {
            codec->EnableOutput(false);
        }
    }
    return;
}
  • std::unique_lock<std::mutex> lock(mutex_):对互斥锁 mutex_ 加锁,确保在访问 audio_decode_queue_ 时线程安全。
  • audio_decode_queue_.empty():检查音频解码队列是否为空。
    • 如果队列为空且设备状态为 kDeviceStateIdle,计算从上次输出音频到现在的时长 duration
    • 如果 duration 超过 max_silence_seconds,调用 codec->EnableOutput(false) 禁用音频输出设备。
    • 无论是否禁用输出设备,只要队列为空,函数直接返回。
3. 检查设备状态
if (device_state_ == kDeviceStateListening) {
    audio_decode_queue_.clear();
    return;
}
  • 如果设备状态为 kDeviceStateListening,清空音频解码队列并返回,不进行音频输出。
4. 更新最后输出时间并取出音频数据
last_output_time_ = now;
auto opus = std::move(audio_decode_queue_.front());
audio_decode_queue_.pop_front();
lock.unlock();
  • last_output_time_ = now:更新最后输出音频的时间。
  • auto opus = std::move(audio_decode_queue_.front()):将队列头部的音频数据(OPUS 格式)移动到 opus 变量中。
  • audio_decode_queue_.pop_front():从队列中移除头部元素。
  • lock.unlock():解锁互斥锁,允许其他线程访问 audio_decode_queue_
5. 调度后台任务处理音频数据
background_task_->Schedule([this, codec, opus = std::move(opus)]() mutable {
    if (aborted_) {
        return;
    }

    std::vector<int16_t> pcm;
    if (!opus_decoder_->Decode(std::move(opus), pcm)) {
        return;
    }

    if (opus_decode_sample_rate_ != codec->output_sample_rate()) {
        int target_size = output_resampler_.GetOutputSamples(pcm.size());
        std::vector<int16_t> resampled(target_size);
        output_resampler_.Process(pcm.data(), pcm.size(), resampled.data());
        pcm = std::move(resampled);
    }

    codec->OutputData(pcm);
});
  • background_task_->Schedule(...):将一个 lambda 函数调度到后台任务中执行。
    • if (aborted_):检查是否已终止操作,如果是则直接返回。
    • opus_decoder_->Decode(std::move(opus), pcm):使用 opus_decoder_ 对 OPUS 格式的音频数据进行解码,解码结果存储在 pcm 向量中。如果解码失败,函数返回。
    • if (opus_decode_sample_rate_ != codec->output_sample_rate()):检查解码后的音频采样率是否与音频编解码器的输出采样率一致。如果不一致,进行重采样处理:
      • output_resampler_.GetOutputSamples(pcm.size()):获取重采样后的样本数量。
      • output_resampler_.Process(pcm.data(), pcm.size(), resampled.data()):执行重采样操作。
      • pcm = std::move(resampled):将重采样后的音频数据移动到 pcm 向量中。
    • codec->OutputData(pcm):将处理后的 PCM 音频数据发送到音频编解码器进行输出。

代码优化建议

  • 错误处理:在 codec->OutputData(pcm) 调用后,可以添加错误处理逻辑,以处理可能的输出错误。
  • 日志记录:在关键步骤添加日志记录,方便调试和监控程序运行状态。
  • 资源管理:确保 opus_decoder_output_resampler_ 在使用完毕后正确释放资源。

相关文章:

  • Unity LOD Group动态精度切换算法(基于视锥+运动速度)技术详解
  • 若依管理系统前后端不分离本地运行新手教学
  • 私域流量池的智能裂变:技术驱动下的流量融合新范式
  • SQLMesh系列教程:基于指标构建一致的分析语义层应用实践
  • 百度一面:SQL的执行顺序是怎样的?
  • SQL Server 2022 官方IOS 下载
  • Tr0ll3靶机通关
  • 基于Java,SpringBoot,Vue,HTML高校社团信息管理系统设计
  • spring如何用三级缓存解决循环依赖问题
  • 构建成功后前端程序如何不重新构建再次指向后端服务
  • 问题的根源还是解题的方案
  • 八股总结(数据库)实时更新!
  • SpringBoot(三)环境隔离/外部化配置/单元测试/可观测性/生命周期
  • 自然语言处理(21:(第六章1.)基于RNN生成文本)
  • Cocos Creator Shader入门实战(七):RGB不同算法效果的实现,及渲染技术、宏定义、属性参数的延伸配置
  • Linux系统下C语言fork函数使用案例
  • 热门索尼S-Log3电影感氛围旅拍LUTS调色预设 Christian Mate Grab - Sony S-Log3 Cinematic LUTs
  • AI 知识库是什么?企业如何构建智能化知识管理体系?
  • YOLOv8-YOLO12目标检测模型的标签格式和数据结构详细说明
  • 在rockylinux9.4安装mongodb报错:缺少:libcrypto.so.10文件库
  • 莆田手表网站/怎么安装百度
  • 有哪些专业做饰品的网站app/做外贸推广
  • 自己做网站步骤 域名/人力资源短期培训班
  • wordpress调整语言/seo云优化软件破解版
  • 郑州英文网站建设/长沙seo网站排名
  • 网页视频怎么下载到电脑桌面/商丘网站seo