audio_output.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  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 = 3;
  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. delete m_audioOutput;
  138. m_audioOutput = nullptr;
  139. }
  140. m_audioOutput = new QAudioOutput(m_audioFormat, this);
  141. if (!m_audioOutput) {
  142. av::Logger::instance().error("Failed to recreate audio output device");
  143. return;
  144. }
  145. m_audioOutput->setBufferSize(32768);
  146. connect(m_audioOutput, &QAudioOutput::stateChanged, this, &AudioOutput::onStateChanged);
  147. // 等待一段时间再重试
  148. std::this_thread::sleep_for(std::chrono::milliseconds(200));
  149. }
  150. m_audioDevice = m_audioOutput->start();
  151. if (!m_audioDevice) {
  152. av::Logger::instance().warning("Failed to start audio output device (attempt " + std::to_string(retryCount + 1) + ")");
  153. retryCount++;
  154. continue;
  155. }
  156. av::Logger::instance().debug("Audio device started, waiting for active state...");
  157. // 写入一些静音数据来激活设备
  158. QByteArray silentData(1024, 0); // 1KB的静音数据
  159. m_audioDevice->write(silentData);
  160. // 等待音频设备进入活动状态
  161. int maxWaitMs = 1000; // 减少等待时间到1秒
  162. int waitMs = 0;
  163. while (m_audioOutput->state() != QAudio::ActiveState && waitMs < maxWaitMs) {
  164. std::this_thread::sleep_for(std::chrono::milliseconds(50));
  165. waitMs += 50;
  166. if (waitMs % 200 == 0) {
  167. av::Logger::instance().debug("Audio output state: " + std::to_string(m_audioOutput->state()) +
  168. " (waited " + std::to_string(waitMs) + "ms)");
  169. }
  170. }
  171. if (m_audioOutput->state() == QAudio::ActiveState) {
  172. deviceStarted = true;
  173. av::Logger::instance().info("Audio device successfully entered active state");
  174. } else {
  175. av::Logger::instance().warning("Audio device failed to enter active state: " + std::to_string(m_audioOutput->state()) + " (attempt " + std::to_string(retryCount + 1) + ")");
  176. m_audioDevice = nullptr;
  177. retryCount++;
  178. }
  179. }
  180. if (!deviceStarted) {
  181. av::Logger::instance().error("Failed to start audio device after " + std::to_string(maxRetries) + " attempts");
  182. return;
  183. }
  184. av::Logger::instance().debug("Audio device entered active state");
  185. // 初始化并启动Synchronizer
  186. if (!m_synchronizer) {
  187. av::utils::SyncConfigV2 syncConfig;
  188. syncConfig.syncStrategy = av::utils::SyncStrategy::AUDIO_MASTER;
  189. syncConfig.audioSyncThreshold = 0.04; // 40ms,与AVPlayer2一致
  190. syncConfig.videoSyncThreshold = 0.04;
  191. m_synchronizer = std::make_shared<av::utils::SynchronizerV2>(syncConfig);
  192. m_synchronizer->initialize();
  193. m_synchronizer->start();
  194. }
  195. m_playing = true;
  196. av::Logger::instance().info("Audio output started successfully");
  197. }
  198. void AudioOutput::stop()
  199. {
  200. QMutexLocker locker(&m_mutex);
  201. if (!m_playing || !m_audioOutput) {
  202. return;
  203. }
  204. m_audioOutput->stop();
  205. m_audioDevice = nullptr;
  206. m_playing = false;
  207. // 停止Synchronizer
  208. if (m_synchronizer) {
  209. m_synchronizer->stop();
  210. }
  211. av::Logger::instance().info("Audio output stopped");
  212. }
  213. void AudioOutput::pause()
  214. {
  215. QMutexLocker locker(&m_mutex);
  216. if (!m_playing || !m_audioOutput) {
  217. return;
  218. }
  219. m_audioOutput->suspend();
  220. av::Logger::instance().info("Audio output paused");
  221. }
  222. void AudioOutput::resume()
  223. {
  224. QMutexLocker locker(&m_mutex);
  225. if (!m_playing || !m_audioOutput) {
  226. return;
  227. }
  228. m_audioOutput->resume();
  229. av::Logger::instance().info("Audio output resumed");
  230. }
  231. bool AudioOutput::writeFrame(const AVFramePtr& frame)
  232. {
  233. if (!frame || !m_playing || !m_audioDevice) {
  234. av::Logger::instance().debug("Audio write failed: frame=" + std::to_string(frame != nullptr) +
  235. ", playing=" + std::to_string(m_playing) + ", device=" + std::to_string(m_audioDevice != nullptr));
  236. return false;
  237. }
  238. // 检查音频设备状态
  239. if (m_audioOutput && m_audioOutput->state() != QAudio::ActiveState) {
  240. av::Logger::instance().warning("Audio device not in active state: " + std::to_string(m_audioOutput->state()));
  241. return false;
  242. }
  243. // 使用Synchronizer进行时间同步
  244. if (frame->pts != AV_NOPTS_VALUE && m_synchronizer) {
  245. // 计算音频PTS(转换为秒)
  246. double audioPts = (double)frame->pts / AV_TIME_BASE;
  247. // 更新音频时钟
  248. m_synchronizer->setAudioClock(audioPts);
  249. // 计算同步延迟
  250. double delay = 0.0;
  251. ErrorCode result = m_synchronizer->shouldPlayAudioFrame(audioPts).action == av::utils::FrameAction::DISPLAY ? ErrorCode::SUCCESS : ErrorCode::PROCESSING_ERROR;
  252. delay = m_synchronizer->shouldPlayAudioFrame(audioPts).delay;
  253. if (result == ErrorCode::SUCCESS && delay > 0) {
  254. // 应用播放速度控制
  255. delay = delay / m_playbackSpeed;
  256. // 限制最大延迟时间,避免异常情况
  257. const double MAX_DELAY = 0.1; // 100ms
  258. if (delay > 0 && delay < MAX_DELAY) {
  259. int delayUs = static_cast<int>(delay * 1000000);
  260. av_usleep(delayUs);
  261. }
  262. }
  263. m_lastAudioPts = audioPts;
  264. }
  265. // 转换音频帧格式
  266. QByteArray audioData = convertFrame(frame);
  267. if (audioData.isEmpty()) {
  268. av::Logger::instance().warning("Audio frame conversion failed");
  269. return false;
  270. }
  271. // 应用音量控制
  272. applyVolume(audioData);
  273. // 写入音频设备 - 添加异常处理
  274. try {
  275. qint64 bytesWritten = m_audioDevice->write(audioData);
  276. if (bytesWritten != audioData.size()) {
  277. av::Logger::instance().warning("Audio write incomplete: " +
  278. std::to_string(bytesWritten) + "/" + std::to_string(audioData.size()));
  279. return false;
  280. }
  281. av::Logger::instance().debug("Audio frame written successfully: " +
  282. std::to_string(audioData.size()) + " bytes");
  283. return true;
  284. } catch (const std::exception& e) {
  285. av::Logger::instance().error("Exception during audio write: " + std::string(e.what()));
  286. return false;
  287. } catch (...) {
  288. av::Logger::instance().error("Unknown exception during audio write");
  289. return false;
  290. }
  291. }
  292. void AudioOutput::setVolume(double volume)
  293. {
  294. m_volume = std::clamp(volume, 0.0, 1.0);
  295. if (m_audioOutput) {
  296. m_audioOutput->setVolume(m_volume);
  297. }
  298. }
  299. double AudioOutput::getVolume() const
  300. {
  301. return m_volume;
  302. }
  303. void AudioOutput::setPlaybackSpeed(double speed)
  304. {
  305. speed = std::max(0.1, std::min(4.0, speed));
  306. m_playbackSpeed = speed;
  307. // 同时更新Synchronizer的播放速度
  308. if (m_synchronizer) {
  309. m_synchronizer->setPlaybackSpeed(speed);
  310. }
  311. av::Logger::instance().debug("Audio playback speed set to: " + std::to_string(speed));
  312. }
  313. double AudioOutput::getPlaybackSpeed() const
  314. {
  315. return m_playbackSpeed;
  316. }
  317. void AudioOutput::flush()
  318. {
  319. QMutexLocker locker(&m_mutex);
  320. if (m_audioOutput) {
  321. m_audioOutput->reset();
  322. }
  323. }
  324. int AudioOutput::getBufferSize() const
  325. {
  326. if (m_audioOutput) {
  327. return m_audioOutput->bufferSize() * 1000 /
  328. (m_audioFormat.sampleRate() * m_audioFormat.channelCount() *
  329. m_audioFormat.sampleSize() / 8);
  330. }
  331. return 0;
  332. }
  333. bool AudioOutput::isPlaying() const
  334. {
  335. return m_playing;
  336. }
  337. void AudioOutput::onStateChanged(QAudio::State state)
  338. {
  339. switch (state) {
  340. case QAudio::ActiveState:
  341. av::Logger::instance().debug("Audio output state: Active");
  342. break;
  343. case QAudio::SuspendedState:
  344. av::Logger::instance().debug("Audio output state: Suspended");
  345. break;
  346. case QAudio::StoppedState:
  347. av::Logger::instance().debug("Audio output state: Stopped");
  348. break;
  349. case QAudio::IdleState:
  350. av::Logger::instance().debug("Audio output state: Idle");
  351. break;
  352. }
  353. }
  354. bool AudioOutput::initResampler()
  355. {
  356. // 检查是否需要重采样
  357. bool needSampleRateConversion = (m_audioFormat.sampleRate() != m_sampleRate);
  358. bool needChannelConversion = (m_audioFormat.channelCount() != m_channels);
  359. bool needFormatConversion = (m_inputFormat != AV_SAMPLE_FMT_S16);
  360. m_needResampling = needSampleRateConversion || needChannelConversion || needFormatConversion;
  361. if (!m_needResampling) {
  362. av::Logger::instance().info("No audio resampling needed");
  363. return true;
  364. }
  365. // 创建重采样上下文
  366. m_swrContext = swr_alloc();
  367. if (!m_swrContext) {
  368. av::Logger::instance().error("Failed to allocate resampler context");
  369. return false;
  370. }
  371. // 设置输入参数
  372. AVChannelLayout inputLayout;
  373. av_channel_layout_default(&inputLayout, m_channels);
  374. // 设置输出参数
  375. AVChannelLayout outputLayout;
  376. av_channel_layout_default(&outputLayout, m_audioFormat.channelCount());
  377. // 配置重采样器
  378. int ret = swr_alloc_set_opts2(&m_swrContext,
  379. &outputLayout, AV_SAMPLE_FMT_S16, m_audioFormat.sampleRate(),
  380. &inputLayout, m_inputFormat, m_sampleRate,
  381. 0, nullptr);
  382. if (ret < 0) {
  383. av::Logger::instance().error("Failed to set resampler options");
  384. swr_free(&m_swrContext);
  385. return false;
  386. }
  387. // 初始化重采样器
  388. ret = swr_init(m_swrContext);
  389. if (ret < 0) {
  390. av::Logger::instance().error("Failed to initialize resampler");
  391. swr_free(&m_swrContext);
  392. return false;
  393. }
  394. av::Logger::instance().info("Audio resampler initialized successfully");
  395. return true;
  396. }
  397. void AudioOutput::cleanupResampler()
  398. {
  399. if (m_swrContext) {
  400. swr_free(&m_swrContext);
  401. m_swrContext = nullptr;
  402. }
  403. }
  404. QByteArray AudioOutput::convertFrame(const AVFramePtr& frame)
  405. {
  406. if (!frame) {
  407. return QByteArray();
  408. }
  409. if (!m_needResampling) {
  410. // 直接复制数据
  411. int dataSize = frame->nb_samples * m_channels * sizeof(int16_t);
  412. return QByteArray(reinterpret_cast<const char*>(frame->data[0]), dataSize);
  413. }
  414. if (!m_swrContext) {
  415. av::Logger::instance().error("Resampler not initialized");
  416. return QByteArray();
  417. }
  418. // 计算输出采样数
  419. int outputSamples = swr_get_out_samples(m_swrContext, frame->nb_samples);
  420. if (outputSamples <= 0) {
  421. return QByteArray();
  422. }
  423. // 分配输出缓冲区
  424. int outputChannels = m_audioFormat.channelCount();
  425. int outputDataSize = outputSamples * outputChannels * sizeof(int16_t);
  426. QByteArray outputData(outputDataSize, 0);
  427. uint8_t* outputBuffer = reinterpret_cast<uint8_t*>(outputData.data());
  428. // 执行重采样
  429. int convertedSamples = swr_convert(m_swrContext,
  430. &outputBuffer, outputSamples,
  431. const_cast<const uint8_t**>(frame->data), frame->nb_samples);
  432. if (convertedSamples < 0) {
  433. av::Logger::instance().error("Audio resampling failed");
  434. return QByteArray();
  435. }
  436. // 调整输出数据大小
  437. int actualDataSize = convertedSamples * outputChannels * sizeof(int16_t);
  438. outputData.resize(actualDataSize);
  439. return outputData;
  440. }
  441. void AudioOutput::applyVolume(QByteArray& data)
  442. {
  443. if (std::abs(m_volume - 1.0) < 0.001) {
  444. return; // 音量为1.0,无需调整
  445. }
  446. int16_t* samples = reinterpret_cast<int16_t*>(data.data());
  447. int sampleCount = data.size() / sizeof(int16_t);
  448. for (int i = 0; i < sampleCount; ++i) {
  449. samples[i] = static_cast<int16_t>(samples[i] * m_volume);
  450. }
  451. }
  452. } // namespace player
  453. } // namespace av