audio_output.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. #include "audio_output.h"
  2. #include "../base/logger.h"
  3. #include "../utils/utils_synchronizer_v2.h"
  4. #include <QAudioDeviceInfo>
  5. #include <QDebug>
  6. #include <algorithm>
  7. #include <cstring>
  8. extern "C" {
  9. #include <libavutil/channel_layout.h>
  10. #include <libavutil/avutil.h>
  11. #include <libavutil/time.h>
  12. #include <libswresample/swresample.h>
  13. }
  14. namespace av {
  15. namespace player {
  16. AudioOutput::AudioOutput(QObject* parent)
  17. : QObject(parent)
  18. , m_audioOutput(nullptr)
  19. , m_audioDevice(nullptr)
  20. , m_sampleRate(44100)
  21. , m_channels(2)
  22. , m_inputFormat(AV_SAMPLE_FMT_S16)
  23. , m_swrContext(nullptr)
  24. , m_needResampling(false)
  25. , m_volume(1.0)
  26. , m_playbackSpeed(1.0)
  27. , m_lastAudioPts(0.0)
  28. , m_initialized(false)
  29. , m_playing(false)
  30. {
  31. }
  32. AudioOutput::~AudioOutput()
  33. {
  34. stop();
  35. cleanupResampler();
  36. if (m_audioOutput) {
  37. delete m_audioOutput;
  38. m_audioOutput = nullptr;
  39. }
  40. }
  41. bool AudioOutput::initialize(int sampleRate, int channels, AVSampleFormat sampleFormat)
  42. {
  43. QMutexLocker locker(&m_mutex);
  44. if (m_initialized) {
  45. av::Logger::instance().warning("Audio output already initialized");
  46. return true;
  47. }
  48. m_sampleRate = sampleRate;
  49. m_channels = channels;
  50. m_inputFormat = sampleFormat;
  51. // 设置Qt音频格式
  52. m_audioFormat.setSampleRate(sampleRate);
  53. m_audioFormat.setChannelCount(channels);
  54. m_audioFormat.setSampleSize(16); // 输出16位
  55. m_audioFormat.setCodec("audio/pcm");
  56. m_audioFormat.setByteOrder(QAudioFormat::LittleEndian);
  57. m_audioFormat.setSampleType(QAudioFormat::SignedInt);
  58. // 检查设备是否支持该格式
  59. QAudioDeviceInfo deviceInfo = QAudioDeviceInfo::defaultOutputDevice();
  60. if (!deviceInfo.isFormatSupported(m_audioFormat)) {
  61. av::Logger::instance().warning("Audio format not supported, using nearest format");
  62. m_audioFormat = deviceInfo.nearestFormat(m_audioFormat);
  63. // 记录实际使用的格式
  64. av::Logger::instance().info("Using audio format: " +
  65. std::to_string(m_audioFormat.sampleRate()) + "Hz, " +
  66. std::to_string(m_audioFormat.channelCount()) + "ch, " +
  67. std::to_string(m_audioFormat.sampleSize()) + "bit");
  68. }
  69. // 创建音频输出设备
  70. m_audioOutput = new QAudioOutput(m_audioFormat, this);
  71. if (!m_audioOutput) {
  72. av::Logger::instance().error("Failed to create audio output device");
  73. return false;
  74. }
  75. // 设置缓冲区大小
  76. m_audioOutput->setBufferSize(32768); // 32KB缓冲区
  77. // 连接状态变化信号
  78. connect(m_audioOutput, &QAudioOutput::stateChanged,
  79. this, &AudioOutput::onStateChanged);
  80. // 记录音频格式信息
  81. av::Logger::instance().info("Audio format: " +
  82. std::to_string(m_audioFormat.sampleRate()) + "Hz, " +
  83. std::to_string(m_audioFormat.channelCount()) + "ch, " +
  84. std::to_string(m_audioFormat.sampleSize()) + "bit, " +
  85. m_audioFormat.codec().toStdString());
  86. // 初始化重采样器(如果需要)
  87. if (!initResampler()) {
  88. av::Logger::instance().error("Failed to initialize audio resampler");
  89. return false;
  90. }
  91. m_initialized = true;
  92. av::Logger::instance().info("Audio output initialized successfully");
  93. return true;
  94. }
  95. void AudioOutput::start()
  96. {
  97. QMutexLocker locker(&m_mutex);
  98. if (!m_initialized || !m_audioOutput) {
  99. av::Logger::instance().error("Audio output not initialized");
  100. return;
  101. }
  102. if (m_playing) {
  103. return;
  104. }
  105. av::Logger::instance().debug("Starting audio output device...");
  106. av::Logger::instance().debug("Audio output state before start: " + std::to_string(m_audioOutput->state()));
  107. // 检查音频格式
  108. QAudioDeviceInfo deviceInfo = QAudioDeviceInfo::defaultOutputDevice();
  109. av::Logger::instance().debug("Default audio device: " + deviceInfo.deviceName().toStdString());
  110. av::Logger::instance().debug("Audio format supported: " + std::to_string(deviceInfo.isFormatSupported(m_audioFormat)));
  111. // 确保音频输出设备处于正确状态
  112. if (m_audioOutput->state() == QAudio::StoppedState) {
  113. av::Logger::instance().debug("Resetting audio output device");
  114. m_audioOutput->reset();
  115. // 给设备一点时间重置
  116. std::this_thread::sleep_for(std::chrono::milliseconds(50));
  117. }
  118. // 如果设备不支持当前格式,尝试使用最接近的格式
  119. if (!deviceInfo.isFormatSupported(m_audioFormat)) {
  120. av::Logger::instance().warning("Audio format not supported, using nearest format");
  121. QAudioFormat nearestFormat = deviceInfo.nearestFormat(m_audioFormat);
  122. // m_audioOutput->setFormat(nearestFormat);
  123. av::Logger::instance().info("Using nearest format: " +
  124. std::to_string(nearestFormat.sampleRate()) + "Hz, " +
  125. std::to_string(nearestFormat.channelCount()) + "ch, " +
  126. std::to_string(nearestFormat.sampleSize()) + "bit");
  127. }
  128. // 尝试多次启动音频设备
  129. int retryCount = 0;
  130. const int maxRetries = 5; // 增加重试次数
  131. bool deviceStarted = false;
  132. while (retryCount < maxRetries && !deviceStarted) {
  133. if (retryCount > 0) {
  134. av::Logger::instance().info("Retrying audio device start (attempt " + std::to_string(retryCount + 1) + "/" + std::to_string(maxRetries) + ")");
  135. // 重新创建音频输出设备
  136. if (m_audioOutput) {
  137. m_audioOutput->stop();
  138. delete m_audioOutput;
  139. m_audioOutput = nullptr;
  140. }
  141. // 等待更长时间让系统释放音频资源
  142. std::this_thread::sleep_for(std::chrono::milliseconds(500));
  143. m_audioOutput = new QAudioOutput(m_audioFormat, this);
  144. if (!m_audioOutput) {
  145. av::Logger::instance().error("Failed to recreate audio output device");
  146. return;
  147. }
  148. m_audioOutput->setBufferSize(32768);
  149. connect(m_audioOutput, &QAudioOutput::stateChanged, this, &AudioOutput::onStateChanged);
  150. }
  151. // 检查音频设备可用性
  152. QAudioDeviceInfo deviceInfo = QAudioDeviceInfo::defaultOutputDevice();
  153. if (deviceInfo.isNull()) {
  154. av::Logger::instance().error("No audio output device available");
  155. return;
  156. }
  157. av::Logger::instance().debug("Starting audio device (attempt " + std::to_string(retryCount + 1) + ")");
  158. m_audioDevice = m_audioOutput->start();
  159. if (!m_audioDevice) {
  160. av::Logger::instance().warning("Failed to start audio output device (attempt " + std::to_string(retryCount + 1) + ")");
  161. retryCount++;
  162. continue;
  163. }
  164. av::Logger::instance().debug("Audio device started, waiting for active state...");
  165. // 写入一些静音数据来激活设备
  166. QByteArray silentData(2048, 0); // 增加静音数据大小
  167. qint64 written = m_audioDevice->write(silentData);
  168. av::Logger::instance().debug("Written silent data: " + std::to_string(written) + " bytes");
  169. // 等待音频设备进入活动状态
  170. int maxWaitMs = 2000; // 增加等待时间到2秒
  171. int waitMs = 0;
  172. while (m_audioOutput->state() != QAudio::ActiveState && waitMs < maxWaitMs) {
  173. std::this_thread::sleep_for(std::chrono::milliseconds(100));
  174. waitMs += 100;
  175. if (waitMs % 500 == 0) {
  176. av::Logger::instance().debug("Audio output state: " + std::to_string(m_audioOutput->state()) +
  177. " (waited " + std::to_string(waitMs) + "ms)");
  178. // 尝试再次写入数据激活设备
  179. if (m_audioDevice && m_audioOutput->state() == QAudio::IdleState) {
  180. QByteArray moreData(1024, 0);
  181. m_audioDevice->write(moreData);
  182. }
  183. }
  184. }
  185. if (m_audioOutput->state() == QAudio::ActiveState) {
  186. deviceStarted = true;
  187. av::Logger::instance().info("Audio device successfully entered active state");
  188. } else if (m_audioOutput->state() == QAudio::IdleState) {
  189. // IdleState也可以接受,表示设备已准备好但暂时没有数据
  190. deviceStarted = true;
  191. av::Logger::instance().info("Audio device in idle state, ready for playback");
  192. } else {
  193. av::Logger::instance().warning("Audio device failed to enter active/idle state: " + std::to_string(m_audioOutput->state()) + " (attempt " + std::to_string(retryCount + 1) + ")");
  194. m_audioDevice = nullptr;
  195. retryCount++;
  196. }
  197. }
  198. if (!deviceStarted) {
  199. av::Logger::instance().error("Failed to start audio device after " + std::to_string(maxRetries) + " attempts");
  200. m_initialized = false;
  201. return;
  202. }
  203. av::Logger::instance().debug("Audio device entered active state");
  204. // 初始化并启动Synchronizer
  205. if (!m_synchronizer) {
  206. av::utils::SyncConfigV2 syncConfig;
  207. syncConfig.syncStrategy = av::utils::SyncStrategy::AUDIO_MASTER;
  208. syncConfig.audioSyncThreshold = 0.04; // 40ms,与AVPlayer2一致
  209. syncConfig.videoSyncThreshold = 0.04;
  210. m_synchronizer = std::make_shared<av::utils::SynchronizerV2>(syncConfig);
  211. m_synchronizer->initialize();
  212. m_synchronizer->start();
  213. }
  214. m_playing = true;
  215. av::Logger::instance().info("Audio output started successfully");
  216. }
  217. void AudioOutput::stop()
  218. {
  219. QMutexLocker locker(&m_mutex);
  220. if (!m_playing || !m_audioOutput) {
  221. return;
  222. }
  223. m_audioOutput->stop();
  224. m_audioDevice = nullptr;
  225. m_playing = false;
  226. // 停止Synchronizer
  227. if (m_synchronizer) {
  228. m_synchronizer->stop();
  229. }
  230. av::Logger::instance().info("Audio output stopped");
  231. }
  232. void AudioOutput::pause()
  233. {
  234. QMutexLocker locker(&m_mutex);
  235. if (!m_playing || !m_audioOutput) {
  236. return;
  237. }
  238. m_audioOutput->suspend();
  239. av::Logger::instance().info("Audio output paused");
  240. }
  241. void AudioOutput::resume()
  242. {
  243. QMutexLocker locker(&m_mutex);
  244. if (!m_playing || !m_audioOutput) {
  245. return;
  246. }
  247. m_audioOutput->resume();
  248. av::Logger::instance().info("Audio output resumed");
  249. }
  250. bool AudioOutput::writeFrame(const AVFramePtr& frame)
  251. {
  252. if (!frame || !m_playing || !m_audioDevice) {
  253. av::Logger::instance().debug("Audio write failed: frame=" + std::to_string(frame != nullptr) +
  254. ", playing=" + std::to_string(m_playing) + ", device=" + std::to_string(m_audioDevice != nullptr));
  255. return false;
  256. }
  257. // 检查是否是EOF帧,EOF帧不需要处理,直接返回成功
  258. if (!frame->data[0] && frame->nb_samples == 0) {
  259. av::Logger::instance().debug("Received EOF frame in audio output, ignoring");
  260. return true;
  261. }
  262. // 检查音频设备状态 - 允许ActiveState和IdleState
  263. if (m_audioOutput) {
  264. QAudio::State currentState = m_audioOutput->state();
  265. if (currentState != QAudio::ActiveState && currentState != QAudio::IdleState) {
  266. av::Logger::instance().warning("Audio device not in playable state: " + std::to_string(currentState));
  267. // 尝试重新启动设备
  268. if (currentState == QAudio::StoppedState) {
  269. av::Logger::instance().info("Attempting to restart stopped audio device");
  270. m_audioDevice = m_audioOutput->start();
  271. if (!m_audioDevice) {
  272. av::Logger::instance().error("Failed to restart audio device");
  273. return false;
  274. }
  275. // 写入静音数据激活设备
  276. QByteArray silentData(1024, 0);
  277. m_audioDevice->write(silentData);
  278. // 短暂等待设备状态更新
  279. std::this_thread::sleep_for(std::chrono::milliseconds(50));
  280. currentState = m_audioOutput->state();
  281. if (currentState != QAudio::ActiveState && currentState != QAudio::IdleState) {
  282. av::Logger::instance().error("Audio device restart failed, state: " + std::to_string(currentState));
  283. return false;
  284. }
  285. } else {
  286. return false;
  287. }
  288. }
  289. }
  290. // 使用Synchronizer进行时间同步
  291. if (frame->pts != AV_NOPTS_VALUE && m_synchronizer) {
  292. // 计算音频PTS(转换为秒)
  293. double audioPts = (double)frame->pts / AV_TIME_BASE;
  294. // 更新音频时钟
  295. m_synchronizer->setAudioClock(audioPts);
  296. // 计算同步延迟
  297. double delay = 0.0;
  298. ErrorCode result = m_synchronizer->shouldPlayAudioFrame(audioPts).action == av::utils::FrameAction::DISPLAY ? ErrorCode::SUCCESS : ErrorCode::PROCESSING_ERROR;
  299. delay = m_synchronizer->shouldPlayAudioFrame(audioPts).delay;
  300. if (result == ErrorCode::SUCCESS && delay > 0) {
  301. // 应用播放速度控制
  302. delay = delay / m_playbackSpeed;
  303. // 限制最大延迟时间,避免异常情况
  304. const double MAX_DELAY = 0.1; // 100ms
  305. if (delay > 0 && delay < MAX_DELAY) {
  306. int delayUs = static_cast<int>(delay * 1000000);
  307. av_usleep(delayUs);
  308. }
  309. }
  310. m_lastAudioPts = audioPts;
  311. }
  312. // 转换音频帧格式
  313. QByteArray audioData = convertFrame(frame);
  314. if (audioData.isEmpty()) {
  315. av::Logger::instance().warning("Audio frame conversion failed");
  316. return false;
  317. }
  318. // 应用音量控制
  319. applyVolume(audioData);
  320. // 写入音频设备 - 添加异常处理
  321. try {
  322. qint64 bytesWritten = m_audioDevice->write(audioData);
  323. if (bytesWritten != audioData.size()) {
  324. av::Logger::instance().warning("Audio write incomplete: " +
  325. std::to_string(bytesWritten) + "/" + std::to_string(audioData.size()));
  326. return false;
  327. }
  328. av::Logger::instance().debug("Audio frame written successfully: " +
  329. std::to_string(audioData.size()) + " bytes");
  330. return true;
  331. } catch (const std::exception& e) {
  332. av::Logger::instance().error("Exception during audio write: " + std::string(e.what()));
  333. return false;
  334. } catch (...) {
  335. av::Logger::instance().error("Unknown exception during audio write");
  336. return false;
  337. }
  338. }
  339. void AudioOutput::setVolume(double volume)
  340. {
  341. m_volume = std::clamp(volume, 0.0, 1.0);
  342. if (m_audioOutput) {
  343. m_audioOutput->setVolume(m_volume);
  344. }
  345. }
  346. double AudioOutput::getVolume() const
  347. {
  348. return m_volume;
  349. }
  350. void AudioOutput::setPlaybackSpeed(double speed)
  351. {
  352. speed = std::max(0.1, std::min(4.0, speed));
  353. m_playbackSpeed = speed;
  354. // 同时更新Synchronizer的播放速度
  355. if (m_synchronizer) {
  356. m_synchronizer->setPlaybackSpeed(speed);
  357. }
  358. av::Logger::instance().debug("Audio playback speed set to: " + std::to_string(speed));
  359. }
  360. double AudioOutput::getPlaybackSpeed() const
  361. {
  362. return m_playbackSpeed;
  363. }
  364. void AudioOutput::flush()
  365. {
  366. QMutexLocker locker(&m_mutex);
  367. if (m_audioOutput) {
  368. m_audioOutput->reset();
  369. }
  370. }
  371. int AudioOutput::getBufferSize() const
  372. {
  373. if (m_audioOutput) {
  374. return m_audioOutput->bufferSize() * 1000 /
  375. (m_audioFormat.sampleRate() * m_audioFormat.channelCount() *
  376. m_audioFormat.sampleSize() / 8);
  377. }
  378. return 0;
  379. }
  380. bool AudioOutput::isPlaying() const
  381. {
  382. return m_playing;
  383. }
  384. void AudioOutput::onStateChanged(QAudio::State state)
  385. {
  386. switch (state) {
  387. case QAudio::ActiveState:
  388. av::Logger::instance().debug("Audio output state: Active");
  389. break;
  390. case QAudio::SuspendedState:
  391. av::Logger::instance().debug("Audio output state: Suspended");
  392. break;
  393. case QAudio::StoppedState:
  394. av::Logger::instance().debug("Audio output state: Stopped");
  395. break;
  396. case QAudio::IdleState:
  397. av::Logger::instance().debug("Audio output state: Idle");
  398. break;
  399. }
  400. }
  401. bool AudioOutput::initResampler()
  402. {
  403. // 检查是否需要重采样
  404. bool needSampleRateConversion = (m_audioFormat.sampleRate() != m_sampleRate);
  405. bool needChannelConversion = (m_audioFormat.channelCount() != m_channels);
  406. bool needFormatConversion = (m_inputFormat != AV_SAMPLE_FMT_S16);
  407. m_needResampling = needSampleRateConversion || needChannelConversion || needFormatConversion;
  408. if (!m_needResampling) {
  409. av::Logger::instance().info("No audio resampling needed");
  410. return true;
  411. }
  412. // 创建重采样上下文
  413. m_swrContext = swr_alloc();
  414. if (!m_swrContext) {
  415. av::Logger::instance().error("Failed to allocate resampler context");
  416. return false;
  417. }
  418. // 设置输入参数
  419. AVChannelLayout inputLayout;
  420. av_channel_layout_default(&inputLayout, m_channels);
  421. // 设置输出参数
  422. AVChannelLayout outputLayout;
  423. av_channel_layout_default(&outputLayout, m_audioFormat.channelCount());
  424. // 配置重采样器
  425. int ret = swr_alloc_set_opts2(&m_swrContext,
  426. &outputLayout, AV_SAMPLE_FMT_S16, m_audioFormat.sampleRate(),
  427. &inputLayout, m_inputFormat, m_sampleRate,
  428. 0, nullptr);
  429. if (ret < 0) {
  430. av::Logger::instance().error("Failed to set resampler options");
  431. swr_free(&m_swrContext);
  432. return false;
  433. }
  434. // 初始化重采样器
  435. ret = swr_init(m_swrContext);
  436. if (ret < 0) {
  437. av::Logger::instance().error("Failed to initialize resampler");
  438. swr_free(&m_swrContext);
  439. return false;
  440. }
  441. av::Logger::instance().info("Audio resampler initialized successfully");
  442. return true;
  443. }
  444. void AudioOutput::cleanupResampler()
  445. {
  446. if (m_swrContext) {
  447. swr_free(&m_swrContext);
  448. m_swrContext = nullptr;
  449. }
  450. }
  451. QByteArray AudioOutput::convertFrame(const AVFramePtr& frame)
  452. {
  453. if (!frame) {
  454. av::Logger::instance().error("convertFrame: null frame pointer");
  455. return QByteArray();
  456. }
  457. // 检查帧数据有效性
  458. if (!frame->data[0] || frame->nb_samples <= 0) {
  459. av::Logger::instance().error("convertFrame: invalid frame data, nb_samples=" + std::to_string(frame->nb_samples));
  460. return QByteArray();
  461. }
  462. av::Logger::instance().debug("convertFrame: input samples=" + std::to_string(frame->nb_samples) +
  463. ", channels=" + std::to_string(m_channels) +
  464. ", format=" + std::to_string(m_inputFormat) +
  465. ", need_resampling=" + std::to_string(m_needResampling));
  466. if (!m_needResampling) {
  467. // 直接复制数据
  468. int dataSize = frame->nb_samples * m_channels * sizeof(int16_t);
  469. av::Logger::instance().debug("convertFrame: direct copy, size=" + std::to_string(dataSize));
  470. return QByteArray(reinterpret_cast<const char*>(frame->data[0]), dataSize);
  471. }
  472. if (!m_swrContext) {
  473. av::Logger::instance().error("convertFrame: resampler not initialized");
  474. return QByteArray();
  475. }
  476. // 计算输出采样数
  477. int outputSamples = swr_get_out_samples(m_swrContext, frame->nb_samples);
  478. if (outputSamples <= 0) {
  479. av::Logger::instance().error("convertFrame: invalid output samples=" + std::to_string(outputSamples));
  480. return QByteArray();
  481. }
  482. // 分配输出缓冲区
  483. int outputChannels = m_audioFormat.channelCount();
  484. int outputDataSize = outputSamples * outputChannels * sizeof(int16_t);
  485. QByteArray outputData(outputDataSize, 0);
  486. uint8_t* outputBuffer = reinterpret_cast<uint8_t*>(outputData.data());
  487. av::Logger::instance().debug("convertFrame: resampling " + std::to_string(frame->nb_samples) +
  488. " -> " + std::to_string(outputSamples) + " samples");
  489. // 执行重采样
  490. int convertedSamples = swr_convert(m_swrContext,
  491. &outputBuffer, outputSamples,
  492. const_cast<const uint8_t**>(frame->data), frame->nb_samples);
  493. if (convertedSamples < 0) {
  494. char errorBuf[256];
  495. av_strerror(convertedSamples, errorBuf, sizeof(errorBuf));
  496. av::Logger::instance().error("convertFrame: resampling failed with error " +
  497. std::to_string(convertedSamples) + ": " + std::string(errorBuf));
  498. return QByteArray();
  499. }
  500. // 调整输出数据大小
  501. int actualDataSize = convertedSamples * outputChannels * sizeof(int16_t);
  502. outputData.resize(actualDataSize);
  503. av::Logger::instance().debug("convertFrame: successfully converted " + std::to_string(convertedSamples) +
  504. " samples, output size=" + std::to_string(actualDataSize));
  505. return outputData;
  506. }
  507. void AudioOutput::applyVolume(QByteArray& data)
  508. {
  509. if (std::abs(m_volume - 1.0) < 0.001) {
  510. return; // 音量为1.0,无需调整
  511. }
  512. int16_t* samples = reinterpret_cast<int16_t*>(data.data());
  513. int sampleCount = data.size() / sizeof(int16_t);
  514. for (int i = 0; i < sampleCount; ++i) {
  515. samples[i] = static_cast<int16_t>(samples[i] * m_volume);
  516. }
  517. }
  518. } // namespace player
  519. } // namespace av