| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- #include "audio_output.h"
- #include "../base/logger.h"
- #include <QAudioDeviceInfo>
- #include <QDebug>
- #include <algorithm>
- #include <cstring>
- extern "C" {
- #include <libavutil/channel_layout.h>
- #include <libswresample/swresample.h>
- }
- 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_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);
- }
-
- // 创建音频输出设备
- m_audioOutput = new QAudioOutput(m_audioFormat, this);
- if (!m_audioOutput) {
- av::Logger::instance().error("Failed to create audio output device");
- return false;
- }
-
- // 连接状态变化信号
- connect(m_audioOutput, &QAudioOutput::stateChanged,
- this, &AudioOutput::onStateChanged);
-
- // 初始化重采样器(如果需要)
- 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;
- }
-
- m_audioDevice = m_audioOutput->start();
- if (!m_audioDevice) {
- av::Logger::instance().error("Failed to start audio output device");
- return;
- }
-
- m_playing = true;
- av::Logger::instance().info("Audio output started");
- }
- 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) {
- return false;
- }
-
- // 转换音频帧格式
- QByteArray audioData = convertFrame(frame);
- if (audioData.isEmpty()) {
- return false;
- }
-
- // 应用音量控制
- applyVolume(audioData);
-
- // 写入音频设备
- qint64 bytesWritten = m_audioDevice->write(audioData);
- if (bytesWritten != audioData.size()) {
- av::Logger::instance().warning("Audio write incomplete");
- return false;
- }
-
- return true;
- }
- 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::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<const char*>(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<uint8_t*>(outputData.data());
-
- // 执行重采样
- int convertedSamples = swr_convert(m_swrContext,
- &outputBuffer, outputSamples,
- const_cast<const uint8_t**>(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<int16_t*>(data.data());
- int sampleCount = data.size() / sizeof(int16_t);
-
- for (int i = 0; i < sampleCount; ++i) {
- samples[i] = static_cast<int16_t>(samples[i] * m_volume);
- }
- }
- } // namespace player
- } // namespace av
- #include "audio_output.moc"
|