#include "audio_output.h" #include "../base/logger.h" #include #include #include #include extern "C" { #include #include #include #include } namespace av { namespace player { AudioOutput::AudioOutput(QObject* parent) : QObject(parent) , m_audioOutput(nullptr) , m_audioDevice(nullptr) , m_sampleRate(44100) , m_channels(2) , m_inputFormat(AV_SAMPLE_FMT_S16) , m_swrContext(nullptr) , m_needResampling(false) , m_volume(1.0) , m_playbackSpeed(1.0) , m_lastAudioPts(0.0) , m_initialized(false) , m_playing(false) { } AudioOutput::~AudioOutput() { stop(); cleanupResampler(); if (m_audioOutput) { delete m_audioOutput; m_audioOutput = nullptr; } } bool AudioOutput::initialize(int sampleRate, int channels, AVSampleFormat sampleFormat) { QMutexLocker locker(&m_mutex); if (m_initialized) { av::Logger::instance().warning("Audio output already initialized"); return true; } m_sampleRate = sampleRate; m_channels = channels; m_inputFormat = sampleFormat; // 设置Qt音频格式 m_audioFormat.setSampleRate(sampleRate); m_audioFormat.setChannelCount(channels); m_audioFormat.setSampleSize(16); // 输出16位 m_audioFormat.setCodec("audio/pcm"); m_audioFormat.setByteOrder(QAudioFormat::LittleEndian); m_audioFormat.setSampleType(QAudioFormat::SignedInt); // 检查设备是否支持该格式 QAudioDeviceInfo deviceInfo = QAudioDeviceInfo::defaultOutputDevice(); if (!deviceInfo.isFormatSupported(m_audioFormat)) { av::Logger::instance().warning("Audio format not supported, using nearest format"); m_audioFormat = deviceInfo.nearestFormat(m_audioFormat); // 记录实际使用的格式 av::Logger::instance().info("Using audio format: " + std::to_string(m_audioFormat.sampleRate()) + "Hz, " + std::to_string(m_audioFormat.channelCount()) + "ch, " + std::to_string(m_audioFormat.sampleSize()) + "bit"); } // 创建音频输出设备 m_audioOutput = new QAudioOutput(m_audioFormat, this); if (!m_audioOutput) { av::Logger::instance().error("Failed to create audio output device"); return false; } // 设置缓冲区大小 m_audioOutput->setBufferSize(32768); // 32KB缓冲区 // 连接状态变化信号 connect(m_audioOutput, &QAudioOutput::stateChanged, this, &AudioOutput::onStateChanged); // 记录音频格式信息 av::Logger::instance().info("Audio format: " + std::to_string(m_audioFormat.sampleRate()) + "Hz, " + std::to_string(m_audioFormat.channelCount()) + "ch, " + std::to_string(m_audioFormat.sampleSize()) + "bit, " + m_audioFormat.codec().toStdString()); // 初始化重采样器(如果需要) if (!initResampler()) { av::Logger::instance().error("Failed to initialize audio resampler"); return false; } m_initialized = true; av::Logger::instance().info("Audio output initialized successfully"); return true; } void AudioOutput::start() { QMutexLocker locker(&m_mutex); if (!m_initialized || !m_audioOutput) { av::Logger::instance().error("Audio output not initialized"); return; } if (m_playing) { return; } av::Logger::instance().debug("Starting audio output device..."); av::Logger::instance().debug("Audio output state before start: " + std::to_string(m_audioOutput->state())); // 检查音频格式 QAudioDeviceInfo deviceInfo = QAudioDeviceInfo::defaultOutputDevice(); av::Logger::instance().debug("Default audio device: " + deviceInfo.deviceName().toStdString()); av::Logger::instance().debug("Audio format supported: " + std::to_string(deviceInfo.isFormatSupported(m_audioFormat))); // 确保音频输出设备处于正确状态 if (m_audioOutput->state() == QAudio::StoppedState) { av::Logger::instance().debug("Resetting audio output device"); m_audioOutput->reset(); // 给设备一点时间重置 std::this_thread::sleep_for(std::chrono::milliseconds(50)); } // 如果设备不支持当前格式,尝试使用最接近的格式 if (!deviceInfo.isFormatSupported(m_audioFormat)) { av::Logger::instance().warning("Audio format not supported, using nearest format"); QAudioFormat nearestFormat = deviceInfo.nearestFormat(m_audioFormat); // m_audioOutput->setFormat(nearestFormat); av::Logger::instance().info("Using nearest format: " + std::to_string(nearestFormat.sampleRate()) + "Hz, " + std::to_string(nearestFormat.channelCount()) + "ch, " + std::to_string(nearestFormat.sampleSize()) + "bit"); } m_audioDevice = m_audioOutput->start(); if (!m_audioDevice) { av::Logger::instance().error("Failed to start audio output device"); return; } av::Logger::instance().debug("Audio device started, waiting for active state..."); // 等待音频设备进入活动状态 int maxWaitMs = 2000; // 最多等待2秒 int waitMs = 0; while (m_audioOutput->state() != QAudio::ActiveState && waitMs < maxWaitMs) { std::this_thread::sleep_for(std::chrono::milliseconds(10)); waitMs += 10; if (waitMs % 100 == 0) { av::Logger::instance().debug("Audio output state: " + std::to_string(m_audioOutput->state()) + " (waited " + std::to_string(waitMs) + "ms)"); } } if (m_audioOutput->state() != QAudio::ActiveState) { av::Logger::instance().error("Audio device failed to enter active state: " + std::to_string(m_audioOutput->state())); m_audioDevice = nullptr; return; } av::Logger::instance().debug("Audio device entered active state"); // 初始化并启动Synchronizer if (!m_synchronizer) { av::utils::SyncConfig syncConfig; syncConfig.strategy = av::utils::SyncStrategy::AUDIO_MASTER; syncConfig.syncThreshold = 0.04; // 40ms,与AVPlayer2一致 syncConfig.maxAudioDelay = 0.1; // 100ms m_synchronizer = std::make_shared(syncConfig); m_synchronizer->initialize(); m_synchronizer->start(); } m_playing = true; av::Logger::instance().info("Audio output started successfully"); } void AudioOutput::stop() { QMutexLocker locker(&m_mutex); if (!m_playing || !m_audioOutput) { return; } m_audioOutput->stop(); m_audioDevice = nullptr; m_playing = false; // 停止Synchronizer if (m_synchronizer) { m_synchronizer->stop(); } av::Logger::instance().info("Audio output stopped"); } void AudioOutput::pause() { QMutexLocker locker(&m_mutex); if (!m_playing || !m_audioOutput) { return; } m_audioOutput->suspend(); av::Logger::instance().info("Audio output paused"); } void AudioOutput::resume() { QMutexLocker locker(&m_mutex); if (!m_playing || !m_audioOutput) { return; } m_audioOutput->resume(); av::Logger::instance().info("Audio output resumed"); } bool AudioOutput::writeFrame(const AVFramePtr& frame) { if (!frame || !m_playing || !m_audioDevice) { av::Logger::instance().debug("Audio write failed: frame=" + std::to_string(frame != nullptr) + ", playing=" + std::to_string(m_playing) + ", device=" + std::to_string(m_audioDevice != nullptr)); return false; } // 检查音频设备状态 if (m_audioOutput && m_audioOutput->state() != QAudio::ActiveState) { av::Logger::instance().warning("Audio device not in active state: " + std::to_string(m_audioOutput->state())); return false; } // 使用Synchronizer进行时间同步 if (frame->pts != AV_NOPTS_VALUE && m_synchronizer) { // 计算音频PTS(转换为秒) double audioPts = (double)frame->pts / AV_TIME_BASE; // 更新音频时钟 m_synchronizer->setAudioClock(audioPts); // 计算同步延迟 double delay = 0.0; ErrorCode result = m_synchronizer->synchronizeAudio(audioPts, delay); if (result == ErrorCode::SUCCESS && delay > 0) { // 应用播放速度控制 delay = delay / m_playbackSpeed; // 限制最大延迟时间,避免异常情况 const double MAX_DELAY = 0.1; // 100ms if (delay > 0 && delay < MAX_DELAY) { int delayUs = static_cast(delay * 1000000); av_usleep(delayUs); } } m_lastAudioPts = audioPts; } // 转换音频帧格式 QByteArray audioData = convertFrame(frame); if (audioData.isEmpty()) { av::Logger::instance().warning("Audio frame conversion failed"); return false; } // 应用音量控制 applyVolume(audioData); // 写入音频设备 - 添加异常处理 try { qint64 bytesWritten = m_audioDevice->write(audioData); if (bytesWritten != audioData.size()) { av::Logger::instance().warning("Audio write incomplete: " + std::to_string(bytesWritten) + "/" + std::to_string(audioData.size())); return false; } av::Logger::instance().debug("Audio frame written successfully: " + std::to_string(audioData.size()) + " bytes"); return true; } catch (const std::exception& e) { av::Logger::instance().error("Exception during audio write: " + std::string(e.what())); return false; } catch (...) { av::Logger::instance().error("Unknown exception during audio write"); return false; } } void AudioOutput::setVolume(double volume) { m_volume = std::clamp(volume, 0.0, 1.0); if (m_audioOutput) { m_audioOutput->setVolume(m_volume); } } double AudioOutput::getVolume() const { return m_volume; } void AudioOutput::setPlaybackSpeed(double speed) { speed = std::max(0.1, std::min(4.0, speed)); m_playbackSpeed = speed; // 同时更新Synchronizer的播放速度 if (m_synchronizer) { m_synchronizer->setPlaybackSpeed(speed); } av::Logger::instance().debug("Audio playback speed set to: " + std::to_string(speed)); } double AudioOutput::getPlaybackSpeed() const { return m_playbackSpeed; } void AudioOutput::flush() { QMutexLocker locker(&m_mutex); if (m_audioOutput) { m_audioOutput->reset(); } } int AudioOutput::getBufferSize() const { if (m_audioOutput) { return m_audioOutput->bufferSize() * 1000 / (m_audioFormat.sampleRate() * m_audioFormat.channelCount() * m_audioFormat.sampleSize() / 8); } return 0; } bool AudioOutput::isPlaying() const { return m_playing; } void AudioOutput::onStateChanged(QAudio::State state) { switch (state) { case QAudio::ActiveState: av::Logger::instance().debug("Audio output state: Active"); break; case QAudio::SuspendedState: av::Logger::instance().debug("Audio output state: Suspended"); break; case QAudio::StoppedState: av::Logger::instance().debug("Audio output state: Stopped"); break; case QAudio::IdleState: av::Logger::instance().debug("Audio output state: Idle"); break; } } bool AudioOutput::initResampler() { // 检查是否需要重采样 bool needSampleRateConversion = (m_audioFormat.sampleRate() != m_sampleRate); bool needChannelConversion = (m_audioFormat.channelCount() != m_channels); bool needFormatConversion = (m_inputFormat != AV_SAMPLE_FMT_S16); m_needResampling = needSampleRateConversion || needChannelConversion || needFormatConversion; if (!m_needResampling) { av::Logger::instance().info("No audio resampling needed"); return true; } // 创建重采样上下文 m_swrContext = swr_alloc(); if (!m_swrContext) { av::Logger::instance().error("Failed to allocate resampler context"); return false; } // 设置输入参数 AVChannelLayout inputLayout; av_channel_layout_default(&inputLayout, m_channels); // 设置输出参数 AVChannelLayout outputLayout; av_channel_layout_default(&outputLayout, m_audioFormat.channelCount()); // 配置重采样器 int ret = swr_alloc_set_opts2(&m_swrContext, &outputLayout, AV_SAMPLE_FMT_S16, m_audioFormat.sampleRate(), &inputLayout, m_inputFormat, m_sampleRate, 0, nullptr); if (ret < 0) { av::Logger::instance().error("Failed to set resampler options"); swr_free(&m_swrContext); return false; } // 初始化重采样器 ret = swr_init(m_swrContext); if (ret < 0) { av::Logger::instance().error("Failed to initialize resampler"); swr_free(&m_swrContext); return false; } av::Logger::instance().info("Audio resampler initialized successfully"); return true; } void AudioOutput::cleanupResampler() { if (m_swrContext) { swr_free(&m_swrContext); m_swrContext = nullptr; } } QByteArray AudioOutput::convertFrame(const AVFramePtr& frame) { if (!frame) { return QByteArray(); } if (!m_needResampling) { // 直接复制数据 int dataSize = frame->nb_samples * m_channels * sizeof(int16_t); return QByteArray(reinterpret_cast(frame->data[0]), dataSize); } if (!m_swrContext) { av::Logger::instance().error("Resampler not initialized"); return QByteArray(); } // 计算输出采样数 int outputSamples = swr_get_out_samples(m_swrContext, frame->nb_samples); if (outputSamples <= 0) { return QByteArray(); } // 分配输出缓冲区 int outputChannels = m_audioFormat.channelCount(); int outputDataSize = outputSamples * outputChannels * sizeof(int16_t); QByteArray outputData(outputDataSize, 0); uint8_t* outputBuffer = reinterpret_cast(outputData.data()); // 执行重采样 int convertedSamples = swr_convert(m_swrContext, &outputBuffer, outputSamples, const_cast(frame->data), frame->nb_samples); if (convertedSamples < 0) { av::Logger::instance().error("Audio resampling failed"); return QByteArray(); } // 调整输出数据大小 int actualDataSize = convertedSamples * outputChannels * sizeof(int16_t); outputData.resize(actualDataSize); return outputData; } void AudioOutput::applyVolume(QByteArray& data) { if (std::abs(m_volume - 1.0) < 0.001) { return; // 音量为1.0,无需调整 } int16_t* samples = reinterpret_cast(data.data()); int sampleCount = data.size() / sizeof(int16_t); for (int i = 0; i < sampleCount; ++i) { samples[i] = static_cast(samples[i] * m_volume); } } } // namespace player } // namespace av