audio_output.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. #include "audio_output.h"
  2. #include "../base/logger.h"
  3. #include <QAudioDeviceInfo>
  4. #include <QDebug>
  5. #include <algorithm>
  6. #include <cstring>
  7. extern "C" {
  8. #include <libavutil/channel_layout.h>
  9. #include <libswresample/swresample.h>
  10. }
  11. namespace av {
  12. namespace player {
  13. AudioOutput::AudioOutput(QObject* parent)
  14. : QObject(parent)
  15. , m_audioOutput(nullptr)
  16. , m_audioDevice(nullptr)
  17. , m_sampleRate(44100)
  18. , m_channels(2)
  19. , m_inputFormat(AV_SAMPLE_FMT_S16)
  20. , m_swrContext(nullptr)
  21. , m_needResampling(false)
  22. , m_volume(1.0)
  23. , m_initialized(false)
  24. , m_playing(false)
  25. {
  26. }
  27. AudioOutput::~AudioOutput()
  28. {
  29. stop();
  30. cleanupResampler();
  31. if (m_audioOutput) {
  32. delete m_audioOutput;
  33. m_audioOutput = nullptr;
  34. }
  35. }
  36. bool AudioOutput::initialize(int sampleRate, int channels, AVSampleFormat sampleFormat)
  37. {
  38. QMutexLocker locker(&m_mutex);
  39. if (m_initialized) {
  40. av::Logger::instance().warning("Audio output already initialized");
  41. return true;
  42. }
  43. m_sampleRate = sampleRate;
  44. m_channels = channels;
  45. m_inputFormat = sampleFormat;
  46. // 设置Qt音频格式
  47. m_audioFormat.setSampleRate(sampleRate);
  48. m_audioFormat.setChannelCount(channels);
  49. m_audioFormat.setSampleSize(16); // 输出16位
  50. m_audioFormat.setCodec("audio/pcm");
  51. m_audioFormat.setByteOrder(QAudioFormat::LittleEndian);
  52. m_audioFormat.setSampleType(QAudioFormat::SignedInt);
  53. // 检查设备是否支持该格式
  54. QAudioDeviceInfo deviceInfo = QAudioDeviceInfo::defaultOutputDevice();
  55. if (!deviceInfo.isFormatSupported(m_audioFormat)) {
  56. av::Logger::instance().warning("Audio format not supported, using nearest format");
  57. m_audioFormat = deviceInfo.nearestFormat(m_audioFormat);
  58. }
  59. // 创建音频输出设备
  60. m_audioOutput = new QAudioOutput(m_audioFormat, this);
  61. if (!m_audioOutput) {
  62. av::Logger::instance().error("Failed to create audio output device");
  63. return false;
  64. }
  65. // 连接状态变化信号
  66. connect(m_audioOutput, &QAudioOutput::stateChanged,
  67. this, &AudioOutput::onStateChanged);
  68. // 初始化重采样器(如果需要)
  69. if (!initResampler()) {
  70. av::Logger::instance().error("Failed to initialize audio resampler");
  71. return false;
  72. }
  73. m_initialized = true;
  74. av::Logger::instance().info("Audio output initialized successfully");
  75. return true;
  76. }
  77. void AudioOutput::start()
  78. {
  79. QMutexLocker locker(&m_mutex);
  80. if (!m_initialized || !m_audioOutput) {
  81. av::Logger::instance().error("Audio output not initialized");
  82. return;
  83. }
  84. if (m_playing) {
  85. return;
  86. }
  87. m_audioDevice = m_audioOutput->start();
  88. if (!m_audioDevice) {
  89. av::Logger::instance().error("Failed to start audio output device");
  90. return;
  91. }
  92. m_playing = true;
  93. av::Logger::instance().info("Audio output started");
  94. }
  95. void AudioOutput::stop()
  96. {
  97. QMutexLocker locker(&m_mutex);
  98. if (!m_playing || !m_audioOutput) {
  99. return;
  100. }
  101. m_audioOutput->stop();
  102. m_audioDevice = nullptr;
  103. m_playing = false;
  104. av::Logger::instance().info("Audio output stopped");
  105. }
  106. void AudioOutput::pause()
  107. {
  108. QMutexLocker locker(&m_mutex);
  109. if (!m_playing || !m_audioOutput) {
  110. return;
  111. }
  112. m_audioOutput->suspend();
  113. av::Logger::instance().info("Audio output paused");
  114. }
  115. void AudioOutput::resume()
  116. {
  117. QMutexLocker locker(&m_mutex);
  118. if (!m_playing || !m_audioOutput) {
  119. return;
  120. }
  121. m_audioOutput->resume();
  122. av::Logger::instance().info("Audio output resumed");
  123. }
  124. bool AudioOutput::writeFrame(const AVFramePtr& frame)
  125. {
  126. if (!frame || !m_playing || !m_audioDevice) {
  127. return false;
  128. }
  129. // 转换音频帧格式
  130. QByteArray audioData = convertFrame(frame);
  131. if (audioData.isEmpty()) {
  132. return false;
  133. }
  134. // 应用音量控制
  135. applyVolume(audioData);
  136. // 写入音频设备
  137. qint64 bytesWritten = m_audioDevice->write(audioData);
  138. if (bytesWritten != audioData.size()) {
  139. av::Logger::instance().warning("Audio write incomplete");
  140. return false;
  141. }
  142. return true;
  143. }
  144. void AudioOutput::setVolume(double volume)
  145. {
  146. m_volume = std::clamp(volume, 0.0, 1.0);
  147. if (m_audioOutput) {
  148. m_audioOutput->setVolume(m_volume);
  149. }
  150. }
  151. double AudioOutput::getVolume() const
  152. {
  153. return m_volume;
  154. }
  155. void AudioOutput::flush()
  156. {
  157. QMutexLocker locker(&m_mutex);
  158. if (m_audioOutput) {
  159. m_audioOutput->reset();
  160. }
  161. }
  162. int AudioOutput::getBufferSize() const
  163. {
  164. if (m_audioOutput) {
  165. return m_audioOutput->bufferSize() * 1000 /
  166. (m_audioFormat.sampleRate() * m_audioFormat.channelCount() *
  167. m_audioFormat.sampleSize() / 8);
  168. }
  169. return 0;
  170. }
  171. bool AudioOutput::isPlaying() const
  172. {
  173. return m_playing;
  174. }
  175. void AudioOutput::onStateChanged(QAudio::State state)
  176. {
  177. switch (state) {
  178. case QAudio::ActiveState:
  179. av::Logger::instance().debug("Audio output state: Active");
  180. break;
  181. case QAudio::SuspendedState:
  182. av::Logger::instance().debug("Audio output state: Suspended");
  183. break;
  184. case QAudio::StoppedState:
  185. av::Logger::instance().debug("Audio output state: Stopped");
  186. break;
  187. case QAudio::IdleState:
  188. av::Logger::instance().debug("Audio output state: Idle");
  189. break;
  190. }
  191. }
  192. bool AudioOutput::initResampler()
  193. {
  194. // 检查是否需要重采样
  195. bool needSampleRateConversion = (m_audioFormat.sampleRate() != m_sampleRate);
  196. bool needChannelConversion = (m_audioFormat.channelCount() != m_channels);
  197. bool needFormatConversion = (m_inputFormat != AV_SAMPLE_FMT_S16);
  198. m_needResampling = needSampleRateConversion || needChannelConversion || needFormatConversion;
  199. if (!m_needResampling) {
  200. av::Logger::instance().info("No audio resampling needed");
  201. return true;
  202. }
  203. // 创建重采样上下文
  204. m_swrContext = swr_alloc();
  205. if (!m_swrContext) {
  206. av::Logger::instance().error("Failed to allocate resampler context");
  207. return false;
  208. }
  209. // 设置输入参数
  210. AVChannelLayout inputLayout;
  211. av_channel_layout_default(&inputLayout, m_channels);
  212. // 设置输出参数
  213. AVChannelLayout outputLayout;
  214. av_channel_layout_default(&outputLayout, m_audioFormat.channelCount());
  215. // 配置重采样器
  216. int ret = swr_alloc_set_opts2(&m_swrContext,
  217. &outputLayout, AV_SAMPLE_FMT_S16, m_audioFormat.sampleRate(),
  218. &inputLayout, m_inputFormat, m_sampleRate,
  219. 0, nullptr);
  220. if (ret < 0) {
  221. av::Logger::instance().error("Failed to set resampler options");
  222. swr_free(&m_swrContext);
  223. return false;
  224. }
  225. // 初始化重采样器
  226. ret = swr_init(m_swrContext);
  227. if (ret < 0) {
  228. av::Logger::instance().error("Failed to initialize resampler");
  229. swr_free(&m_swrContext);
  230. return false;
  231. }
  232. av::Logger::instance().info("Audio resampler initialized successfully");
  233. return true;
  234. }
  235. void AudioOutput::cleanupResampler()
  236. {
  237. if (m_swrContext) {
  238. swr_free(&m_swrContext);
  239. m_swrContext = nullptr;
  240. }
  241. }
  242. QByteArray AudioOutput::convertFrame(const AVFramePtr& frame)
  243. {
  244. if (!frame) {
  245. return QByteArray();
  246. }
  247. if (!m_needResampling) {
  248. // 直接复制数据
  249. int dataSize = frame->nb_samples * m_channels * sizeof(int16_t);
  250. return QByteArray(reinterpret_cast<const char*>(frame->data[0]), dataSize);
  251. }
  252. if (!m_swrContext) {
  253. av::Logger::instance().error("Resampler not initialized");
  254. return QByteArray();
  255. }
  256. // 计算输出采样数
  257. int outputSamples = swr_get_out_samples(m_swrContext, frame->nb_samples);
  258. if (outputSamples <= 0) {
  259. return QByteArray();
  260. }
  261. // 分配输出缓冲区
  262. int outputChannels = m_audioFormat.channelCount();
  263. int outputDataSize = outputSamples * outputChannels * sizeof(int16_t);
  264. QByteArray outputData(outputDataSize, 0);
  265. uint8_t* outputBuffer = reinterpret_cast<uint8_t*>(outputData.data());
  266. // 执行重采样
  267. int convertedSamples = swr_convert(m_swrContext,
  268. &outputBuffer, outputSamples,
  269. const_cast<const uint8_t**>(frame->data), frame->nb_samples);
  270. if (convertedSamples < 0) {
  271. av::Logger::instance().error("Audio resampling failed");
  272. return QByteArray();
  273. }
  274. // 调整输出数据大小
  275. int actualDataSize = convertedSamples * outputChannels * sizeof(int16_t);
  276. outputData.resize(actualDataSize);
  277. return outputData;
  278. }
  279. void AudioOutput::applyVolume(QByteArray& data)
  280. {
  281. if (std::abs(m_volume - 1.0) < 0.001) {
  282. return; // 音量为1.0,无需调整
  283. }
  284. int16_t* samples = reinterpret_cast<int16_t*>(data.data());
  285. int sampleCount = data.size() / sizeof(int16_t);
  286. for (int i = 0; i < sampleCount; ++i) {
  287. samples[i] = static_cast<int16_t>(samples[i] * m_volume);
  288. }
  289. }
  290. } // namespace player
  291. } // namespace av
  292. #include "audio_output.moc"