audio_output.cpp 21 KB

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