CAudioStream.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. #include "CAudioStream.h"
  2. #include <cassert>
  3. #include <iostream>
  4. #include <math.h>
  5. extern int g_AudioVolume;
  6. extern bool g_KeepRunning;
  7. using namespace WallpaperEngine::Audio;
  8. // callback for sdl to play our audio
  9. void audio_callback (void* userdata, uint8_t* stream, int length)
  10. {
  11. auto audioStream = static_cast <CAudioStream*> (userdata);
  12. int len1, audio_size;
  13. static uint8_t audio_buf[(MAX_AUDIO_FRAME_SIZE * 3) / 2];
  14. static unsigned int audio_buf_size = 0;
  15. static unsigned int audio_buf_index = 0;
  16. while (length > 0 && g_KeepRunning)
  17. {
  18. if (audio_buf_index >= audio_buf_size)
  19. {
  20. /* We have already sent all our data; get more */
  21. audio_size = audioStream->decodeFrame (audio_buf, sizeof (audio_buf));
  22. if (audio_size < 0)
  23. {
  24. /* If error, output silence */
  25. audio_buf_size = 1024; // arbitrary?
  26. memset(audio_buf, 0, audio_buf_size);
  27. }
  28. else
  29. {
  30. audio_buf_size = audio_size;
  31. }
  32. audio_buf_index = 0;
  33. }
  34. len1 = audio_buf_size - audio_buf_index;
  35. if (len1 > length)
  36. len1 = length;
  37. // mix the audio so the volume is right
  38. SDL_MixAudio (stream, (uint8_t*) audio_buf + audio_buf_index, len1, g_AudioVolume);
  39. length -= len1;
  40. stream += len1;
  41. audio_buf_index += len1;
  42. if (audioStream->isInitialized () == false)
  43. break;
  44. }
  45. }
  46. int audio_read_thread (void* arg)
  47. {
  48. CAudioStream* stream = static_cast <CAudioStream*> (arg);
  49. AVPacket* packet = av_packet_alloc ();
  50. int ret = 0;
  51. while (ret >= 0 && g_KeepRunning == true)
  52. {
  53. ret = av_read_frame (stream->getFormatContext (), packet);
  54. if (ret == AVERROR_EOF)
  55. {
  56. // seek to the beginning of the file again
  57. av_seek_frame (stream->getFormatContext (), stream->getAudioStream (), 0, AVSEEK_FLAG_FRAME);
  58. avcodec_flush_buffers (stream->getContext ());
  59. continue;
  60. }
  61. // TODO: PROPERLY IMPLEMENT THIS
  62. if (packet->stream_index == stream->getAudioStream ())
  63. stream->queuePacket (packet);
  64. else
  65. av_packet_unref (packet);
  66. if (stream->isInitialized () == false)
  67. break;
  68. }
  69. // stop the audio too just in case
  70. stream->stop ();
  71. return 0;
  72. }
  73. static int audio_read_data_callback (void* streamarg, uint8_t* buffer, int buffer_size)
  74. {
  75. auto stream = static_cast <CAudioStream*> (streamarg);
  76. int left = stream->getLength () - stream->getPosition ();
  77. buffer_size = FFMIN (buffer_size, left);
  78. memcpy (buffer, (uint8_t*) stream->getBuffer () + stream->getPosition (), buffer_size);
  79. // update position
  80. stream->setPosition (stream->getPosition () + buffer_size);
  81. return buffer_size;
  82. }
  83. int64_t audio_seek_data_callback (void* streamarg, int64_t offset, int whence)
  84. {
  85. auto stream = static_cast <CAudioStream*> (streamarg);
  86. if (whence & AVSEEK_SIZE)
  87. return stream->getLength ();
  88. switch (whence)
  89. {
  90. case SEEK_CUR:
  91. stream->setPosition (stream->getPosition () + offset);
  92. break;
  93. case SEEK_SET:
  94. stream->setPosition (offset);
  95. break;
  96. }
  97. return offset;
  98. }
  99. CAudioStream::CAudioStream (const std::string& filename)
  100. {
  101. // do not do anything if sdl audio was not initialized
  102. if (SDL_WasInit (SDL_INIT_AUDIO) != SDL_INIT_AUDIO)
  103. return;
  104. this->loadCustomContent (filename.c_str ());
  105. }
  106. CAudioStream::CAudioStream (const void* buffer, int length)
  107. {
  108. // do not do anything if sdl audio was not initialized
  109. if (SDL_WasInit (SDL_INIT_AUDIO) != SDL_INIT_AUDIO)
  110. return;
  111. // setup a custom context first
  112. this->m_formatContext = avformat_alloc_context ();
  113. if (this->m_formatContext == nullptr)
  114. throw std::runtime_error ("Cannot allocate format context");
  115. this->m_buffer = buffer;
  116. this->m_length = length;
  117. this->m_position = 0;
  118. // setup custom io for it
  119. this->m_formatContext->pb = avio_alloc_context (
  120. static_cast <uint8_t*> (av_malloc (4096)),
  121. 4096,
  122. 0,
  123. static_cast <void*> (this),
  124. &audio_read_data_callback,
  125. nullptr,
  126. &audio_seek_data_callback
  127. );
  128. if (this->m_formatContext->pb == nullptr)
  129. throw std::runtime_error ("Cannot create avio context");
  130. // continue the normal load procedure
  131. this->loadCustomContent ();
  132. }
  133. CAudioStream::CAudioStream(AVCodecContext* context)
  134. : m_context (context),
  135. m_queue (new PacketQueue)
  136. {
  137. // do not do anything if sdl audio was not initialized
  138. if (SDL_WasInit (SDL_INIT_AUDIO) != SDL_INIT_AUDIO)
  139. return;
  140. this->initialize ();
  141. }
  142. void CAudioStream::loadCustomContent (const char* filename)
  143. {
  144. const AVCodec* aCodec = nullptr;
  145. AVCodecContext* avCodecContext = nullptr;
  146. if (avformat_open_input (&this->m_formatContext, filename, nullptr, nullptr) != 0)
  147. throw std::runtime_error ("Cannot open audio file");
  148. if (avformat_find_stream_info (this->m_formatContext, nullptr) < 0)
  149. throw std::runtime_error ("Cannot determine file format");
  150. // find the audio stream
  151. for (int i = 0; i< this->m_formatContext->nb_streams; i ++)
  152. {
  153. if (this->m_formatContext->streams [i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && this->m_audioStream < 0)
  154. this->m_audioStream = i;
  155. }
  156. if (this->m_audioStream == -1)
  157. throw std::runtime_error ("Cannot find audio stream in file");
  158. // get the decoder for it and alloc the required context
  159. aCodec = avcodec_find_decoder (this->m_formatContext->streams [this->m_audioStream]->codecpar->codec_id);
  160. if (aCodec == nullptr)
  161. throw std::runtime_error ("Cannot initialize audio decoder");
  162. // alocate context
  163. avCodecContext = avcodec_alloc_context3 (aCodec);
  164. if (avcodec_parameters_to_context (avCodecContext, this->m_formatContext->streams [this->m_audioStream]->codecpar) != 0)
  165. throw std::runtime_error ("Cannot initialize audio decoder parameters");
  166. // finally open
  167. avcodec_open2 (avCodecContext, aCodec, nullptr);
  168. // initialize default data
  169. this->m_context = avCodecContext;
  170. this->m_queue = new PacketQueue;
  171. this->initialize ();
  172. // initialize an SDL thread to read the file
  173. SDL_CreateThread (audio_read_thread, this);
  174. }
  175. void CAudioStream::initialize ()
  176. {
  177. // allocate the FIFO buffer
  178. this->m_queue->packetList = av_fifo_alloc (sizeof (MyAVPacketList));
  179. // setup the queue information
  180. this->m_queue->mutex = SDL_CreateMutex ();
  181. this->m_queue->cond = SDL_CreateCond ();
  182. // take control of the audio device
  183. SDL_AudioSpec requestedSpec, finalSpec;
  184. // Set audio settings from codec info
  185. requestedSpec.freq = this->m_context->sample_rate;
  186. requestedSpec.format = AUDIO_S16SYS;
  187. requestedSpec.channels = this->m_context->channels;
  188. requestedSpec.silence = 0;
  189. requestedSpec.samples = SDL_AUDIO_BUFFER_SIZE;
  190. requestedSpec.callback = audio_callback;
  191. requestedSpec.userdata = this;
  192. if (SDL_OpenAudio (&requestedSpec, &finalSpec) < 0) {
  193. std::cerr << "SDL_OpenAudio: " << SDL_GetError () << std::endl;
  194. return;
  195. }
  196. SDL_PauseAudio (0);
  197. this->m_initialized = true;
  198. }
  199. void CAudioStream::queuePacket(AVPacket *pkt)
  200. {
  201. // clone the packet
  202. AVPacket* clone = av_packet_alloc ();
  203. if (clone == nullptr)
  204. {
  205. av_packet_unref (clone);
  206. return;
  207. }
  208. av_packet_move_ref (clone, pkt);
  209. SDL_LockMutex (this->m_queue->mutex);
  210. bool gotQueued = this->doQueue (clone);
  211. SDL_UnlockMutex (this->m_queue->mutex);
  212. if (gotQueued == false)
  213. av_packet_free (&pkt);
  214. }
  215. bool CAudioStream::doQueue (AVPacket* pkt)
  216. {
  217. MyAVPacketList entry;
  218. // ensure the FIFO has enough space to hold the new entry
  219. if (av_fifo_space (this->m_queue->packetList) < sizeof (entry))
  220. {
  221. if (av_fifo_grow (this->m_queue->packetList, sizeof (entry)) < 0)
  222. {
  223. return false;
  224. }
  225. }
  226. entry.packet = pkt;
  227. // write to the FIFO
  228. av_fifo_generic_write (this->m_queue->packetList, &entry, sizeof (entry), nullptr);
  229. this->m_queue->nb_packets ++;
  230. this->m_queue->size += entry.packet->size + sizeof (entry);
  231. this->m_queue->duration += entry.packet->duration;
  232. SDL_CondSignal (this->m_queue->cond);
  233. return true;
  234. }
  235. void CAudioStream::dequeuePacket (AVPacket* output)
  236. {
  237. MyAVPacketList entry;
  238. SDL_LockMutex (this->m_queue->mutex);
  239. while (g_KeepRunning)
  240. {
  241. // enough data available, read it
  242. if (av_fifo_size (this->m_queue->packetList) >= sizeof (entry))
  243. {
  244. av_fifo_generic_read (this->m_queue->packetList, &entry, sizeof (entry), nullptr);
  245. this->m_queue->nb_packets --;
  246. this->m_queue->size -= entry.packet->duration;
  247. // move the reference and free the old one
  248. av_packet_move_ref (output, entry.packet);
  249. av_packet_free (&entry.packet);
  250. break;
  251. }
  252. // make the thread wait if nothing was available
  253. SDL_CondWaitTimeout (this->m_queue->cond, this->m_queue->mutex, 1000);
  254. }
  255. SDL_UnlockMutex (this->m_queue->mutex);
  256. }
  257. AVCodecContext* CAudioStream::getContext ()
  258. {
  259. return this->m_context;
  260. }
  261. AVFormatContext* CAudioStream::getFormatContext ()
  262. {
  263. return this->m_formatContext;
  264. }
  265. int CAudioStream::getAudioStream ()
  266. {
  267. return this->m_audioStream;
  268. }
  269. bool CAudioStream::isInitialized ()
  270. {
  271. return this->m_initialized;
  272. }
  273. void CAudioStream::setRepeat (bool newRepeat)
  274. {
  275. this->m_repeat = newRepeat;
  276. }
  277. bool CAudioStream::isRepeat ()
  278. {
  279. return this->m_repeat;
  280. }
  281. const void* CAudioStream::getBuffer ()
  282. {
  283. return this->m_buffer;
  284. }
  285. int CAudioStream::getLength ()
  286. {
  287. return this->m_length;
  288. }
  289. int CAudioStream::getPosition ()
  290. {
  291. return this->m_position;
  292. }
  293. void CAudioStream::setPosition (int current)
  294. {
  295. this->m_position = current;
  296. }
  297. void CAudioStream::stop ()
  298. {
  299. if (this->isInitialized () == false)
  300. return;
  301. // pause audio
  302. SDL_PauseAudio (1);
  303. // stop the threads running
  304. this->m_initialized = false;
  305. }
  306. int CAudioStream::resampleAudio (
  307. AVFrame * decoded_audio_frame,
  308. enum AVSampleFormat out_sample_fmt,
  309. int out_channels,
  310. int out_sample_rate,
  311. uint8_t * out_buf
  312. )
  313. {
  314. SwrContext * swr_ctx = NULL;
  315. int ret = 0;
  316. int64_t in_channel_layout = this->getContext ()->channel_layout;
  317. int64_t out_channel_layout = AV_CH_LAYOUT_STEREO;
  318. int out_nb_channels = 0;
  319. int out_linesize = 0;
  320. int in_nb_samples = 0;
  321. int out_nb_samples = 0;
  322. int max_out_nb_samples = 0;
  323. uint8_t ** resampled_data = NULL;
  324. int resampled_data_size = 0;
  325. swr_ctx = swr_alloc();
  326. if (!swr_ctx)
  327. {
  328. printf("swr_alloc error.\n");
  329. return -1;
  330. }
  331. // get input audio channels
  332. in_channel_layout = (this->getContext ()->channels ==
  333. av_get_channel_layout_nb_channels(this->getContext ()->channel_layout)) ? // 2
  334. this->getContext ()->channel_layout :
  335. av_get_default_channel_layout(this->getContext ()->channels);
  336. // check input audio channels correctly retrieved
  337. if (in_channel_layout <= 0)
  338. {
  339. printf("in_channel_layout error.\n");
  340. return -1;
  341. }
  342. // set output audio channels based on the input audio channels
  343. if (out_channels == 1)
  344. {
  345. out_channel_layout = AV_CH_LAYOUT_MONO;
  346. }
  347. else if (out_channels == 2)
  348. {
  349. out_channel_layout = AV_CH_LAYOUT_STEREO;
  350. }
  351. else
  352. {
  353. out_channel_layout = AV_CH_LAYOUT_SURROUND;
  354. }
  355. // retrieve number of audio samples (per channel)
  356. in_nb_samples = decoded_audio_frame->nb_samples;
  357. if (in_nb_samples <= 0)
  358. {
  359. printf("in_nb_samples error.\n");
  360. return -1;
  361. }
  362. // Set SwrContext parameters for resampling
  363. av_opt_set_int( // 3
  364. swr_ctx,
  365. "in_channel_layout",
  366. in_channel_layout,
  367. 0
  368. );
  369. // Set SwrContext parameters for resampling
  370. av_opt_set_int(
  371. swr_ctx,
  372. "in_sample_rate",
  373. this->getContext ()->sample_rate,
  374. 0
  375. );
  376. // Set SwrContext parameters for resampling
  377. av_opt_set_sample_fmt(
  378. swr_ctx,
  379. "in_sample_fmt",
  380. this->getContext ()->sample_fmt,
  381. 0
  382. );
  383. // Set SwrContext parameters for resampling
  384. av_opt_set_int(
  385. swr_ctx,
  386. "out_channel_layout",
  387. out_channel_layout,
  388. 0
  389. );
  390. // Set SwrContext parameters for resampling
  391. av_opt_set_int(
  392. swr_ctx,
  393. "out_sample_rate",
  394. out_sample_rate,
  395. 0
  396. );
  397. // Set SwrContext parameters for resampling
  398. av_opt_set_sample_fmt(
  399. swr_ctx,
  400. "out_sample_fmt",
  401. out_sample_fmt,
  402. 0
  403. );
  404. // Once all values have been set for the SwrContext, it must be initialized
  405. // with swr_init().
  406. ret = swr_init(swr_ctx);;
  407. if (ret < 0)
  408. {
  409. printf("Failed to initialize the resampling context.\n");
  410. return -1;
  411. }
  412. max_out_nb_samples = out_nb_samples = av_rescale_rnd(
  413. in_nb_samples,
  414. out_sample_rate,
  415. this->getContext ()->sample_rate,
  416. AV_ROUND_UP
  417. );
  418. // check rescaling was successful
  419. if (max_out_nb_samples <= 0)
  420. {
  421. printf("av_rescale_rnd error.\n");
  422. return -1;
  423. }
  424. // get number of output audio channels
  425. out_nb_channels = av_get_channel_layout_nb_channels(out_channel_layout);
  426. ret = av_samples_alloc_array_and_samples(
  427. &resampled_data,
  428. &out_linesize,
  429. out_nb_channels,
  430. out_nb_samples,
  431. out_sample_fmt,
  432. 0
  433. );
  434. if (ret < 0)
  435. {
  436. printf("av_samples_alloc_array_and_samples() error: Could not allocate destination samples.\n");
  437. return -1;
  438. }
  439. // retrieve output samples number taking into account the progressive delay
  440. out_nb_samples = av_rescale_rnd(
  441. swr_get_delay(swr_ctx, this->getContext ()->sample_rate) + in_nb_samples,
  442. out_sample_rate,
  443. this->getContext ()->sample_rate,
  444. AV_ROUND_UP
  445. );
  446. // check output samples number was correctly retrieved
  447. if (out_nb_samples <= 0)
  448. {
  449. printf("av_rescale_rnd error\n");
  450. return -1;
  451. }
  452. if (out_nb_samples > max_out_nb_samples)
  453. {
  454. // free memory block and set pointer to NULL
  455. av_free(resampled_data[0]);
  456. // Allocate a samples buffer for out_nb_samples samples
  457. ret = av_samples_alloc(
  458. resampled_data,
  459. &out_linesize,
  460. out_nb_channels,
  461. out_nb_samples,
  462. out_sample_fmt,
  463. 1
  464. );
  465. // check samples buffer correctly allocated
  466. if (ret < 0)
  467. {
  468. printf("av_samples_alloc failed.\n");
  469. return -1;
  470. }
  471. max_out_nb_samples = out_nb_samples;
  472. }
  473. if (swr_ctx)
  474. {
  475. // do the actual audio data resampling
  476. ret = swr_convert(
  477. swr_ctx,
  478. resampled_data,
  479. out_nb_samples,
  480. (const uint8_t **) decoded_audio_frame->data,
  481. decoded_audio_frame->nb_samples
  482. );
  483. // check audio conversion was successful
  484. if (ret < 0)
  485. {
  486. printf("swr_convert_error.\n");
  487. return -1;
  488. }
  489. // Get the required buffer size for the given audio parameters
  490. resampled_data_size = av_samples_get_buffer_size(
  491. &out_linesize,
  492. out_nb_channels,
  493. ret,
  494. out_sample_fmt,
  495. 1
  496. );
  497. // check audio buffer size
  498. if (resampled_data_size < 0)
  499. {
  500. printf("av_samples_get_buffer_size error.\n");
  501. return -1;
  502. }
  503. }
  504. else
  505. {
  506. printf("swr_ctx null error.\n");
  507. return -1;
  508. }
  509. // copy the resampled data to the output buffer
  510. memcpy(out_buf, resampled_data[0], resampled_data_size);
  511. /*
  512. * Memory Cleanup.
  513. */
  514. if (resampled_data)
  515. {
  516. // free memory block and set pointer to NULL
  517. av_freep(&resampled_data[0]);
  518. }
  519. av_freep(&resampled_data);
  520. resampled_data = NULL;
  521. if (swr_ctx)
  522. {
  523. // Free the given SwrContext and set the pointer to NULL
  524. swr_free(&swr_ctx);
  525. }
  526. return resampled_data_size;
  527. }
  528. int CAudioStream::decodeFrame (uint8_t* audioBuffer, int bufferSize)
  529. {
  530. AVPacket *pkt = av_packet_alloc ();
  531. static uint8_t *audio_pkt_data = NULL;
  532. static int audio_pkt_size = 0;
  533. int len1, data_size = 0;
  534. // allocate a new frame, used to decode audio packets
  535. static AVFrame * avFrame = NULL;
  536. avFrame = av_frame_alloc();
  537. if (!avFrame)
  538. {
  539. printf("Could not allocate AVFrame.\n");
  540. return -1;
  541. }
  542. for (; g_KeepRunning;) {
  543. while (audio_pkt_size > 0) {
  544. int got_frame = 0;
  545. int ret = avcodec_receive_frame(this->getContext (), avFrame);
  546. if (ret == 0)
  547. {
  548. got_frame = 1;
  549. }
  550. if (ret == AVERROR(EAGAIN))
  551. {
  552. ret = 0;
  553. }
  554. if (ret == 0)
  555. {
  556. ret = avcodec_send_packet(this->getContext (), pkt);
  557. }
  558. if (ret == AVERROR(EAGAIN))
  559. {
  560. ret = 0;
  561. }
  562. else if (ret < 0)
  563. {
  564. return -1;
  565. }
  566. else
  567. {
  568. len1 = pkt->size;
  569. }
  570. if (len1 < 0)
  571. {
  572. // if error, skip frame
  573. audio_pkt_size = 0;
  574. break;
  575. }
  576. audio_pkt_data += len1;
  577. audio_pkt_size -= len1;
  578. data_size = 0;
  579. if (got_frame) {
  580. // audio resampling
  581. data_size = this->resampleAudio (
  582. avFrame,
  583. AV_SAMPLE_FMT_S16,
  584. this->getContext ()->channels,
  585. this->getContext ()->sample_rate,
  586. audioBuffer
  587. );
  588. assert(data_size <= bufferSize);
  589. }
  590. if (data_size <= 0) {
  591. /* No data yet, get more frames */
  592. continue;
  593. }
  594. /* We have data, return it and come back for more later */
  595. return data_size;
  596. }
  597. if (pkt->data)
  598. av_packet_unref(pkt);
  599. this->dequeuePacket (pkt);
  600. audio_pkt_data = pkt->data;
  601. audio_pkt_size = pkt->size;
  602. }
  603. return 0;
  604. }