| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668 |
- #include "audio_output.h"
- #include <QAudioDeviceInfo>
- #include <QDebug>
- #include "../base/logger.h"
- #include "../utils/utils_synchronizer_v2.h"
- #include "AV/code/base/media_common.h"
- #include <algorithm>
- #include <chrono>
- #include <cstring>
- #include <thread>
- extern "C" {
- #include <libavutil/channel_layout.h>
- #include <libavutil/avutil.h>
- #include <libavutil/time.h>
- #include <libavutil/opt.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_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<const char*>(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<uint8_t*>(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<const uint8_t**>(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<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
|