#include "audio_output.h" #include #include #include "../base/logger.h" #include "../utils/utils_synchronizer_v2.h" #include "AV/code/base/media_common.h" #include #include #include #include extern "C" { #include #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); // 验证获取的格式是否有效 if (m_audioFormat.sampleRate() <= 0 || m_audioFormat.channelCount() <= 0) { av::Logger::instance().warning("Device returned invalid audio format, using fallback"); av::Logger::instance().warningf("Invalid format: {}Hz, {}ch", m_audioFormat.sampleRate(), m_audioFormat.channelCount()); // 使用默认格式作为后备 m_audioFormat.setSampleRate(44100); m_audioFormat.setChannelCount(2); m_audioFormat.setSampleSize(16); m_audioFormat.setCodec("audio/pcm"); m_audioFormat.setByteOrder(QAudioFormat::LittleEndian); m_audioFormat.setSampleType(QAudioFormat::SignedInt); av::Logger::instance().info("Using fallback audio format: 44100Hz, 2ch, 16bit"); } // 记录实际使用的格式 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"); 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; 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值和时间基准 int64_t audioPts = frame->pts; double timeBase = 1.0 / AV_TIME_BASE; // 假设使用AV_TIME_BASE作为时间基准 m_lastAudioPts = audioPts * timeBase; // 转换为秒用于记录 } // 转换音频帧格式 QByteArray audioData = convertFrame(frame); if (audioData.isEmpty()) { av::Logger::instance().warning("Audio frame conversion failed"); return false; } // 应用音量控制 applyVolume(audioData); // 写入音频设备 - 添加重试机制和异常处理 const int maxRetries = 10; const int retryDelayMs = 5; for (int retry = 0; retry < maxRetries; ++retry) { try { qint64 bytesWritten = m_audioDevice->write(audioData); if (bytesWritten == audioData.size()) { av::Logger::instance().debug("Audio frame written successfully: " + std::to_string(audioData.size()) + " bytes"); return true; } // 写入不完整,记录警告并重试 av::Logger::instance().warning("Audio write incomplete (attempt " + std::to_string(retry + 1) + "/" + std::to_string(maxRetries) + "): " + std::to_string(bytesWritten) + "/" + std::to_string(audioData.size())); // 如果不是最后一次重试,等待一段时间再重试 if (retry < maxRetries - 1) { std::this_thread::sleep_for(std::chrono::milliseconds(retryDelayMs)); } } catch (const std::exception& e) { av::Logger::instance().error("Exception during audio write (attempt " + std::to_string(retry + 1) + "): " + std::string(e.what())); if (retry < maxRetries - 1) { std::this_thread::sleep_for(std::chrono::milliseconds(retryDelayMs)); } } catch (...) { av::Logger::instance().error("Unknown exception during audio write (attempt " + std::to_string(retry + 1) + ")"); if (retry < maxRetries - 1) { std::this_thread::sleep_for(std::chrono::milliseconds(retryDelayMs)); } } } av::Logger::instance().error("Audio write failed after " + std::to_string(maxRetries) + " attempts"); 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; 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; } // 参数验证 if (m_sampleRate <= 0 || m_sampleRate > 192000) { av::Logger::instance().errorf("Invalid input sample rate: {}", m_sampleRate); return false; } if (m_audioFormat.sampleRate() <= 0 || m_audioFormat.sampleRate() > 192000) { av::Logger::instance().errorf("Invalid output sample rate: {}", m_audioFormat.sampleRate()); return false; } if (m_channels <= 0 || m_channels > 32) { av::Logger::instance().errorf("Invalid input channels: {}", m_channels); return false; } if (m_audioFormat.channelCount() <= 0 || m_audioFormat.channelCount() > 32) { av::Logger::instance().errorf("Invalid output channels: {}", m_audioFormat.channelCount()); return false; } // 记录参数信息用于调试 av::Logger::instance().infof("Resampler config: {}Hz,{}ch,{} -> {}Hz,{}ch,S16", m_sampleRate, m_channels, av_get_sample_fmt_name(m_inputFormat), m_audioFormat.sampleRate(), m_audioFormat.channelCount()); // 创建重采样上下文 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()); // 使用分步设置方式替代swr_alloc_set_opts2 av_opt_set_chlayout(m_swrContext, "in_chlayout", &inputLayout, 0); av_opt_set_int(m_swrContext, "in_sample_rate", m_sampleRate, 0); av_opt_set_sample_fmt(m_swrContext, "in_sample_fmt", m_inputFormat, 0); av_opt_set_chlayout(m_swrContext, "out_chlayout", &outputLayout, 0); av_opt_set_int(m_swrContext, "out_sample_rate", m_audioFormat.sampleRate(), 0); av_opt_set_sample_fmt(m_swrContext, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); // 初始化重采样器 int ret = swr_init(m_swrContext); if (ret < 0) { av::Logger::instance().errorf("Failed to initialize resampler: {}", ffmpeg_utils::errorToString(ret)); av::Logger::instance().errorf("Input: {}Hz, {}ch, {}", m_sampleRate, m_channels, av_get_sample_fmt_name(m_inputFormat)); av::Logger::instance().errorf("Output: {}Hz, {}ch, S16", m_audioFormat.sampleRate(), m_audioFormat.channelCount()); 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