#include "audio_output.h" #include "../base/logger.h" #include "../utils/utils_synchronizer_v2.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"); } // 尝试多次启动音频设备 int retryCount = 0; const int maxRetries = 5; // 增加重试次数 bool deviceStarted = false; while (retryCount < maxRetries && !deviceStarted) { if (retryCount > 0) { av::Logger::instance().info("Retrying audio device start (attempt " + std::to_string(retryCount + 1) + "/" + std::to_string(maxRetries) + ")"); // 重新创建音频输出设备 if (m_audioOutput) { m_audioOutput->stop(); delete m_audioOutput; m_audioOutput = nullptr; } // 等待更长时间让系统释放音频资源 std::this_thread::sleep_for(std::chrono::milliseconds(500)); m_audioOutput = new QAudioOutput(m_audioFormat, this); if (!m_audioOutput) { av::Logger::instance().error("Failed to recreate audio output device"); return; } m_audioOutput->setBufferSize(32768); connect(m_audioOutput, &QAudioOutput::stateChanged, this, &AudioOutput::onStateChanged); } // 检查音频设备可用性 QAudioDeviceInfo deviceInfo = QAudioDeviceInfo::defaultOutputDevice(); if (deviceInfo.isNull()) { av::Logger::instance().error("No audio output device available"); return; } av::Logger::instance().debug("Starting audio device (attempt " + std::to_string(retryCount + 1) + ")"); m_audioDevice = m_audioOutput->start(); if (!m_audioDevice) { av::Logger::instance().warning("Failed to start audio output device (attempt " + std::to_string(retryCount + 1) + ")"); retryCount++; continue; } av::Logger::instance().debug("Audio device started, waiting for active state..."); // 写入一些静音数据来激活设备 QByteArray silentData(2048, 0); // 增加静音数据大小 qint64 written = m_audioDevice->write(silentData); av::Logger::instance().debug("Written silent data: " + std::to_string(written) + " bytes"); // 等待音频设备进入活动状态 int maxWaitMs = 2000; // 增加等待时间到2秒 int waitMs = 0; while (m_audioOutput->state() != QAudio::ActiveState && waitMs < maxWaitMs) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); waitMs += 100; if (waitMs % 500 == 0) { av::Logger::instance().debug("Audio output state: " + std::to_string(m_audioOutput->state()) + " (waited " + std::to_string(waitMs) + "ms)"); // 尝试再次写入数据激活设备 if (m_audioDevice && m_audioOutput->state() == QAudio::IdleState) { QByteArray moreData(1024, 0); m_audioDevice->write(moreData); } } } if (m_audioOutput->state() == QAudio::ActiveState) { deviceStarted = true; av::Logger::instance().info("Audio device successfully entered active state"); } else if (m_audioOutput->state() == QAudio::IdleState) { // IdleState也可以接受,表示设备已准备好但暂时没有数据 deviceStarted = true; av::Logger::instance().info("Audio device in idle state, ready for playback"); } else { av::Logger::instance().warning("Audio device failed to enter active/idle state: " + std::to_string(m_audioOutput->state()) + " (attempt " + std::to_string(retryCount + 1) + ")"); m_audioDevice = nullptr; retryCount++; } } if (!deviceStarted) { av::Logger::instance().error("Failed to start audio device after " + std::to_string(maxRetries) + " attempts"); m_initialized = false; return; } av::Logger::instance().debug("Audio device entered active state"); // 初始化并启动Synchronizer if (!m_synchronizer) { av::utils::SyncConfigV2 syncConfig; syncConfig.syncStrategy = av::utils::SyncStrategy::AUDIO_MASTER; syncConfig.audioSyncThreshold = 0.04; // 40ms,与AVPlayer2一致 syncConfig.videoSyncThreshold = 0.04; 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; } // 检查是否是EOF帧,EOF帧不需要处理,直接返回成功 if (!frame->data[0] && frame->nb_samples == 0) { av::Logger::instance().debug("Received EOF frame in audio output, ignoring"); return true; } // 检查音频设备状态 - 允许ActiveState和IdleState if (m_audioOutput) { QAudio::State currentState = m_audioOutput->state(); if (currentState != QAudio::ActiveState && currentState != QAudio::IdleState) { av::Logger::instance().warning("Audio device not in playable state: " + std::to_string(currentState)); // 尝试重新启动设备 if (currentState == QAudio::StoppedState) { av::Logger::instance().info("Attempting to restart stopped audio device"); m_audioDevice = m_audioOutput->start(); if (!m_audioDevice) { av::Logger::instance().error("Failed to restart audio device"); return false; } // 写入静音数据激活设备 QByteArray silentData(1024, 0); m_audioDevice->write(silentData); // 短暂等待设备状态更新 std::this_thread::sleep_for(std::chrono::milliseconds(50)); currentState = m_audioOutput->state(); if (currentState != QAudio::ActiveState && currentState != QAudio::IdleState) { av::Logger::instance().error("Audio device restart failed, state: " + std::to_string(currentState)); return false; } } else { 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->shouldPlayAudioFrame(audioPts).action == av::utils::FrameAction::DISPLAY ? ErrorCode::SUCCESS : ErrorCode::PROCESSING_ERROR; delay = m_synchronizer->shouldPlayAudioFrame(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) { av::Logger::instance().error("convertFrame: null frame pointer"); return QByteArray(); } // 检查帧数据有效性 if (!frame->data[0] || frame->nb_samples <= 0) { av::Logger::instance().error("convertFrame: invalid frame data, nb_samples=" + std::to_string(frame->nb_samples)); return QByteArray(); } av::Logger::instance().debug("convertFrame: input samples=" + std::to_string(frame->nb_samples) + ", channels=" + std::to_string(m_channels) + ", format=" + std::to_string(m_inputFormat) + ", need_resampling=" + std::to_string(m_needResampling)); if (!m_needResampling) { // 直接复制数据 int dataSize = frame->nb_samples * m_channels * sizeof(int16_t); av::Logger::instance().debug("convertFrame: direct copy, size=" + std::to_string(dataSize)); return QByteArray(reinterpret_cast(frame->data[0]), dataSize); } if (!m_swrContext) { av::Logger::instance().error("convertFrame: resampler not initialized"); return QByteArray(); } // 计算输出采样数 int outputSamples = swr_get_out_samples(m_swrContext, frame->nb_samples); if (outputSamples <= 0) { av::Logger::instance().error("convertFrame: invalid output samples=" + std::to_string(outputSamples)); 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()); av::Logger::instance().debug("convertFrame: resampling " + std::to_string(frame->nb_samples) + " -> " + std::to_string(outputSamples) + " samples"); // 执行重采样 int convertedSamples = swr_convert(m_swrContext, &outputBuffer, outputSamples, const_cast(frame->data), frame->nb_samples); if (convertedSamples < 0) { char errorBuf[256]; av_strerror(convertedSamples, errorBuf, sizeof(errorBuf)); av::Logger::instance().error("convertFrame: resampling failed with error " + std::to_string(convertedSamples) + ": " + std::string(errorBuf)); return QByteArray(); } // 调整输出数据大小 int actualDataSize = convertedSamples * outputChannels * sizeof(int16_t); outputData.resize(actualDataSize); av::Logger::instance().debug("convertFrame: successfully converted " + std::to_string(convertedSamples) + " samples, output size=" + std::to_string(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