audio.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. #include "player.h"
  2. #include "packet.h"
  3. #include "frame.h"
  4. static void sdl_audio_callback(void *opaque, Uint8 *stream, int len);
  5. // 从packet_queue中取一个packet,解码生成frame
  6. static int audio_decode_frame(AVCodecContext *p_codec_ctx, packet_queue_t *p_pkt_queue, AVFrame *frame, CMediaHostApi* hostapi)
  7. {
  8. int ret = -1;
  9. while (0 == p_pkt_queue->abort_request)
  10. {
  11. AVPacket pkt = {0};
  12. while (0 == p_pkt_queue->abort_request)
  13. {
  14. //if (d->queue->abort_request)
  15. // return -1;
  16. // 3.2 一个音频packet含一至多个音频frame,每次avcodec_receive_frame()返回一个frame,此函数返回。
  17. // 下次进来此函数,继续获取一个frame,直到avcodec_receive_frame()返回AVERROR(EAGAIN),
  18. // 表示解码器需要填入新的音频packet
  19. ret = avcodec_receive_frame(p_codec_ctx, frame);
  20. if (ret >= 0)
  21. {
  22. // 时基转换,从d->avctx->pkt_timebase时基转换到1/frame->sample_rate时基
  23. AVRational tb{ 1, frame->sample_rate };
  24. if (frame->pts != AV_NOPTS_VALUE)
  25. {
  26. frame->pts = av_rescale_q(frame->pts, p_codec_ctx->pkt_timebase, tb);
  27. }
  28. else
  29. {
  30. hostapi->Debug(MEDIA_LOG_DEBUG, "frame->pts no.");
  31. }
  32. return 1;
  33. }
  34. else if (ret == AVERROR_EOF)
  35. {
  36. //hostapi->Debug("audio avcodec_receive_frame(): the decoder has been flushed.");
  37. avcodec_flush_buffers(p_codec_ctx);
  38. return -1;
  39. }
  40. else if (ret == AVERROR(EAGAIN))
  41. {
  42. //hostapi->Debug("audio avcodec_receive_frame(): input is not accepted in the current state.");
  43. break;
  44. }
  45. else
  46. {
  47. hostapi->Debug(MEDIA_LOG_DEBUG, "audio avcodec_receive_frame(): other errors.");
  48. continue;
  49. }
  50. }
  51. //printf("avcodec_receive_frame ret = %d, begin packet_queue_get\n", ret);
  52. // 1. 取出一个packet。使用pkt对应的serial赋值给d->pkt_serial
  53. if (packet_queue_get(p_pkt_queue, &pkt, true) < 0)
  54. {
  55. hostapi->Debug(MEDIA_LOG_DEBUG, "packet_queue_get return -1 exit audio_decode_frame function.");
  56. return -1;
  57. }
  58. // packet_queue中第一个总是flush_pkt。每次seek操作会插入flush_pkt,更新serial,开启新的播放序列
  59. //hostapi->Debug("packet_queue_get pkt.data == 0x%0x, pkt.size == %d.", pkt.data, pkt.size);
  60. if (NULL == pkt.data || 0 == pkt.size)
  61. {
  62. // 复位解码器内部状态/刷新内部缓冲区。当seek操作或切换流时应调用此函数。
  63. avcodec_flush_buffers(p_codec_ctx);
  64. return -2;
  65. }
  66. else
  67. {
  68. // 2. 将packet发送给解码器
  69. // 发送packet的顺序是按dts递增的顺序,如IPBBPBB
  70. // pkt.pos变量可以标识当前packet在视频文件中的地址偏移
  71. int iresult = avcodec_send_packet(p_codec_ctx, &pkt);
  72. if (AVERROR(EAGAIN) == iresult)
  73. {
  74. hostapi->Debug(MEDIA_LOG_DEBUG, "receive_frame and send_packet both returned EAGAIN, which is an API violation.");
  75. }
  76. if (0 == iresult)
  77. {
  78. av_packet_unref(&pkt);
  79. }
  80. }
  81. }
  82. return ret;
  83. }
  84. // 音频解码线程:从音频packet_queue中取数据,解码后放入音频frame_queue
  85. static int audio_decode_thread(void *arg)
  86. {
  87. player_stat_t *is = (player_stat_t *)arg;
  88. AVFrame *p_frame = av_frame_alloc();
  89. frame_t *af;
  90. int got_frame = 0;
  91. AVRational tb;
  92. int ret = 0;
  93. int inullpacket = 0;
  94. if (p_frame == NULL){
  95. return AVERROR(ENOMEM);
  96. }
  97. while (0 == is->abort_request)
  98. {
  99. //printf("%s:%d is->index = %d, is->p_acodec_ctx[is->index] = 0x%0x\n", __FUNCTION__, __LINE__, is->index, is->p_acodec_ctx[is->index]);
  100. got_frame = audio_decode_frame(is->p_acodec_ctx[is->index], &is->audio_pkt_queue, p_frame, is->rvc_hostapi);
  101. if (got_frame < 0){
  102. if(-2 == got_frame && inullpacket < 2){
  103. inullpacket++;
  104. continue;
  105. }
  106. else {
  107. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, " audio_decode_frame < 0, goto end");
  108. goto the_end;
  109. }
  110. }
  111. else
  112. {
  113. inullpacket = 0;
  114. }
  115. if (got_frame)
  116. {
  117. tb = { 1, p_frame->sample_rate };
  118. //从frame队列找到一个可写的空间,若未停止则一直等待,已停止时返回NULL
  119. if (!(af = frame_queue_peek_writable(&is->audio_frm_queue))) {
  120. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "frame_queue_peek_writable return NULL, goto end.");
  121. goto the_end;
  122. }
  123. af->pts = (p_frame->pts == AV_NOPTS_VALUE) ? NAN : p_frame->pts * av_q2d(tb);
  124. af->pos = p_frame->pkt_pos;
  125. //-af->serial = is->auddec.pkt_serial;
  126. // 当前帧包含的(单个声道)采样数/采样率就是当前帧的播放时长
  127. AVRational tbdata{ p_frame->nb_samples, p_frame->sample_rate };
  128. //af->duration = av_q2d((AVRational) { p_frame->nb_samples, p_frame->sample_rate });
  129. af->duration = av_q2d(tbdata);
  130. // 将frame数据拷入af->frame,af->frame指向音频frame队列尾部
  131. av_frame_move_ref(af->frame, p_frame);
  132. // 更新音频frame队列大小及写指针
  133. frame_queue_push(&is->audio_frm_queue);
  134. }
  135. }
  136. the_end:
  137. av_frame_free(&p_frame);
  138. SDL_Delay(100);
  139. is->abort_request = 1;
  140. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "audio decode thread exit, thread id is %u, and is->abort_request = %d", SDL_ThreadID(), is->abort_request);
  141. return ret;
  142. }
  143. int open_audio_stream(player_stat_t *is)
  144. {
  145. AVCodecContext *p_codec_ctx = NULL;
  146. AVCodecParameters *p_codec_par = NULL;
  147. AVCodec* p_codec = NULL;
  148. int ret = -1;
  149. // 1. 为音频流构建解码器AVCodecContext
  150. for (size_t index = 0; index < is->uFilesCount; index++){
  151. // 1.1 获取解码器参数AVCodecParameters
  152. p_codec_par = is->p_audio_stream[index]->codecpar;
  153. // 1.2 获取解码器
  154. p_codec = avcodec_find_decoder(p_codec_par->codec_id);
  155. if (NULL == p_codec) {
  156. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "Cann't find codec!");
  157. return ret;
  158. }
  159. // 1.3 构建解码器AVCodecContext
  160. // 1.3.1 p_codec_ctx初始化:分配结构体,使用p_codec初始化相应成员为默认值
  161. p_codec_ctx = avcodec_alloc_context3(p_codec);
  162. if (p_codec_ctx == NULL) {
  163. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "avcodec_alloc_context3() failed.");
  164. return ret;
  165. }
  166. // 1.3.2 p_codec_ctx初始化:p_codec_par ==> p_codec_ctx,初始化相应成员
  167. ret = avcodec_parameters_to_context(p_codec_ctx, p_codec_par);
  168. if (ret < 0) {
  169. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "avcodec_parameters_to_context() failed %d.", ret);
  170. return ret;
  171. }
  172. // 1.3.3 p_codec_ctx初始化:使用p_codec初始化p_codec_ctx,初始化完成
  173. ret = avcodec_open2(p_codec_ctx, p_codec, NULL);
  174. if (ret < 0) {
  175. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "avcodec_open2() failed %d.", ret);
  176. return ret;
  177. }
  178. p_codec_ctx->pkt_timebase = is->p_audio_stream[index]->time_base;
  179. is->p_acodec_ctx[index] = p_codec_ctx;
  180. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "%s:%d is->p_acodec_ctx[%d] = 0x%0x", __FUNCTION__, __LINE__, index, p_codec_ctx);
  181. }
  182. // 2. 创建音频解码线程
  183. SDL_Thread* audio_decode = SDL_CreateThread(audio_decode_thread, "audio decode thread", is);
  184. if (NULL == audio_decode) {
  185. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "SDL_Create audio decode thread failed: %s.", SDL_GetError());
  186. return -1;
  187. }
  188. else {
  189. ret = 0;
  190. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "create %s success, and thread id is %u.", SDL_GetThreadName(audio_decode), SDL_GetThreadID(audio_decode));
  191. }
  192. return ret;
  193. }
  194. static int audio_resample(player_stat_t *is, int64_t audio_callback_time)
  195. {
  196. int data_size = 0, resampled_data_size = 0;
  197. int64_t dec_channel_layout = 0;
  198. av_unused double audio_clock0 = 0.0;
  199. int wanted_nb_samples = 0;
  200. frame_t *af = NULL;
  201. #if defined(_WIN32)
  202. while (frame_queue_nb_remaining(&is->audio_frm_queue) == 0)
  203. {
  204. if ((av_gettime_relative() - audio_callback_time) > 1000000LL * is->audio_hw_buf_size / is->audio_param_tgt.bytes_per_sec / 2)
  205. return -1;
  206. av_usleep(1000);
  207. }
  208. #endif
  209. // 若队列头部可读,则由af指向可读帧
  210. if (!(af = frame_queue_peek_readable(&is->audio_frm_queue))) {
  211. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "%s:%d abort_request flag is true, function return", __FUNCTION__, __LINE__);
  212. return -2;
  213. }
  214. frame_queue_next(&is->audio_frm_queue);
  215. // 根据frame中指定的音频参数获取缓冲区的大小
  216. data_size = av_samples_get_buffer_size(NULL, af->frame->channels, // 本行两参数:linesize,声道数
  217. af->frame->nb_samples, // 本行一参数:本帧中包含的单个声道中的样本数
  218. (AVSampleFormat)af->frame->format, 1); // 本行两参数:采样格式,不对齐
  219. // 获取声道布局
  220. dec_channel_layout =
  221. (af->frame->channel_layout && af->frame->channels == av_get_channel_layout_nb_channels(af->frame->channel_layout)) ?
  222. af->frame->channel_layout : av_get_default_channel_layout(af->frame->channels);
  223. wanted_nb_samples = af->frame->nb_samples;
  224. // is->audio_param_tgt是SDL可接受的音频帧数,是audio_open()中取得的参数
  225. // 在audio_open()函数中又有“is->audio_src = is->audio_param_tgt”
  226. // 此处表示:如果frame中的音频参数 == is->audio_src == is->audio_param_tgt,那音频重采样的过程就免了(因此时is->swr_ctr是NULL)
  227. //      否则使用frame(源)和is->audio_param_tgt(目标)中的音频参数来设置is->swr_ctx,并使用frame中的音频参数来赋值is->audio_src
  228. if (af->frame->format != is->audio_param_src.fmt ||
  229. dec_channel_layout != is->audio_param_src.channel_layout ||
  230. af->frame->sample_rate != is->audio_param_src.freq)
  231. {
  232. swr_free(&is->audio_swr_ctx);
  233. // 使用frame(源)和is->audio_param_tgt(目标)中的音频参数来设置is->audio_swr_ctx
  234. is->audio_swr_ctx = swr_alloc_set_opts(NULL,
  235. is->audio_param_tgt.channel_layout, is->audio_param_tgt.fmt, is->audio_param_tgt.freq,
  236. dec_channel_layout, (AVSampleFormat)af->frame->format, af->frame->sample_rate,
  237. 0, NULL);
  238. if (!is->audio_swr_ctx || swr_init(is->audio_swr_ctx) < 0)
  239. {
  240. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!",
  241. af->frame->sample_rate, av_get_sample_fmt_name((AVSampleFormat)af->frame->format), af->frame->channels,
  242. is->audio_param_tgt.freq, av_get_sample_fmt_name(is->audio_param_tgt.fmt), is->audio_param_tgt.channels);
  243. swr_free(&is->audio_swr_ctx);
  244. return -1;
  245. }
  246. // 使用frame中的参数更新is->audio_src,第一次更新后后面基本不用执行此if分支了,因为一个音频流中各frame通用参数一样
  247. is->audio_param_src.channel_layout = dec_channel_layout;
  248. is->audio_param_src.channels = af->frame->channels;
  249. is->audio_param_src.freq = af->frame->sample_rate;
  250. is->audio_param_src.fmt = (AVSampleFormat)af->frame->format;
  251. }
  252. if (is->audio_swr_ctx)
  253. {
  254. // 重采样输入参数1:输入音频样本数是af->frame->nb_samples
  255. // 重采样输入参数2:输入音频缓冲区
  256. const uint8_t **in = (const uint8_t **)af->frame->extended_data;
  257. // 重采样输出参数1:输出音频缓冲区尺寸
  258. // 重采样输出参数2:输出音频缓冲区
  259. uint8_t **out = &is->audio_frm_rwr;
  260. // 重采样输出参数:输出音频样本数(多加了256个样本)
  261. int out_count = (int64_t)wanted_nb_samples * is->audio_param_tgt.freq / af->frame->sample_rate + 256;
  262. // 重采样输出参数:输出音频缓冲区尺寸(以字节为单位)
  263. int out_size = av_samples_get_buffer_size(NULL, is->audio_param_tgt.channels, out_count, is->audio_param_tgt.fmt, 0);
  264. int len2 = 0;
  265. if (out_size < 0){
  266. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "av_samples_get_buffer_size() failed.");
  267. return -1;
  268. }
  269. av_fast_malloc(&is->audio_frm_rwr, &is->audio_frm_rwr_size, out_size);
  270. if (!is->audio_frm_rwr) {
  271. return AVERROR(ENOMEM);
  272. }
  273. // 音频重采样:返回值是重采样后得到的音频数据中单个声道的样本数
  274. len2 = swr_convert(is->audio_swr_ctx, out, out_count, in, af->frame->nb_samples);
  275. if (len2 < 0){
  276. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "swr_convert() failed.");
  277. return -1;
  278. }
  279. if (len2 == out_count){
  280. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "audio buffer is probably too small.");
  281. if (swr_init(is->audio_swr_ctx) < 0)
  282. swr_free(&is->audio_swr_ctx);
  283. }
  284. is->p_audio_frm = is->audio_frm_rwr;
  285. // 重采样返回的一帧音频数据大小(以字节为单位)
  286. resampled_data_size = len2 * is->audio_param_tgt.channels * av_get_bytes_per_sample(is->audio_param_tgt.fmt);
  287. }
  288. else
  289. {
  290. // 未经重采样,则将指针指向frame中的音频数据
  291. is->p_audio_frm = af->frame->data[0];
  292. resampled_data_size = data_size;
  293. }
  294. audio_clock0 = is->audio_clock;
  295. /* update the audio clock with the pts */
  296. if (!isnan(af->pts)){
  297. is->audio_clock = af->pts + (double)af->frame->nb_samples / af->frame->sample_rate;
  298. }
  299. else{
  300. is->audio_clock = NAN;
  301. }
  302. is->audio_clock_serial = af->serial;
  303. #ifdef DEBUG
  304. {
  305. static double last_clock;
  306. //printf("audio: delay=%0.3f clock=%0.3f clock0=%0.3f\n",
  307. // is->audio_clock - last_clock,
  308. // is->audio_clock, audio_clock0);
  309. //is->rvc_log("audio: delay=%0.3f clock=%0.3f clock0=%0.3f\n",
  310. // is->audio_clock - last_clock,
  311. // is->audio_clock, audio_clock0);
  312. last_clock = is->audio_clock;
  313. }
  314. #endif
  315. return resampled_data_size;
  316. }
  317. static int open_audio_playing(void *arg)
  318. {
  319. player_stat_t *is = (player_stat_t *)arg;
  320. SDL_AudioSpec wanted_spec = {0};
  321. SDL_AudioSpec actual_spec = {0};
  322. // 2. 打开音频设备并创建音频处理线程
  323. // 2.1 打开音频设备,获取SDL设备支持的音频参数actual_spec(期望的参数是wanted_spec,实际得到actual_spec)
  324. // 1) SDL提供两种使音频设备取得音频数据方法:
  325. // a. push,SDL以特定的频率调用回调函数,在回调函数中取得音频数据
  326. // b. pull,用户程序以特定的频率调用SDL_QueueAudio(),向音频设备提供数据。此种情况wanted_spec.callback=NULL
  327. // 2) 音频设备打开后播放静音,不启动回调,调用SDL_PauseAudio(0)后启动回调,开始正常播放音频
  328. wanted_spec.freq = is->p_acodec_ctx[is->index]->sample_rate; // 采样率
  329. wanted_spec.format = AUDIO_S16SYS; // S表带符号,16是采样深度,SYS表采用系统字节序
  330. wanted_spec.channels = is->p_acodec_ctx[is->index]->channels; // 声音通道数
  331. wanted_spec.silence = 0; // 静音值
  332. // wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE; // SDL声音缓冲区尺寸,单位是单声道采样点尺寸x通道数
  333. // SDL声音缓冲区尺寸,单位是单声道采样点尺寸x声道数
  334. wanted_spec.samples = FFMAX(SDL_AUDIO_MIN_BUFFER_SIZE, 2 << av_log2(wanted_spec.freq / SDL_AUDIO_MAX_CALLBACKS_PER_SEC));
  335. wanted_spec.callback = sdl_audio_callback; // 回调函数,若为NULL,则应使用SDL_QueueAudio()机制
  336. wanted_spec.userdata = is; // 提供给回调函数的参数
  337. int iaudioapeaker = SDL_GetNumAudioDevices(0);
  338. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "audio output device number is %d.", iaudioapeaker);
  339. for (int i = 0; i < iaudioapeaker; i++){
  340. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "device id %d audio device name is %s.",i, SDL_GetAudioDeviceName(i, 0));
  341. }
  342. if (SDL_OpenAudio(&wanted_spec, &actual_spec) < 0){
  343. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "SDL_OpenAudio() failed: %s.", SDL_GetError());
  344. return -1;
  345. }
  346. else {
  347. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "-----------SDL_OpenAudio() success:");
  348. }
  349. //SDL_AudioDeviceID idev = 0;
  350. //idev = SDL_OpenAudioDevice(NULL, 0, &wanted_spec, &actual_spec, SDL_AUDIO_ALLOW_FORMAT_CHANGE);
  351. //if (0 == idev) {
  352. // is->rvc_hostapi->Debug("SDL Open Audio Device failed: %s.", SDL_GetError());
  353. // return -1;
  354. //}
  355. //else {
  356. // is->rvc_hostapi->Debug("-----------SDL Open Audio Device{id=%d} success.", idev);
  357. //}
  358. // 2.2 根据SDL音频参数构建音频重采样参数
  359. // wanted_spec是期望的参数,actual_spec是实际的参数,wanted_spec和auctual_spec都是SDL中的参数。
  360. // 此处audio_param是FFmpeg中的参数,此参数应保证是SDL播放支持的参数,后面重采样要用到此参数
  361. // 音频帧解码后得到的frame中的音频格式未必被SDL支持,比如frame可能是planar格式,但SDL2.0并不支持planar格式,
  362. // 若将解码后的frame直接送入SDL音频缓冲区,声音将无法正常播放。所以需要先将frame重采样(转换格式)为SDL支持的模式,
  363. // 然后送再写入SDL音频缓冲区
  364. is->audio_param_tgt.fmt = AV_SAMPLE_FMT_S16;
  365. is->audio_param_tgt.freq = actual_spec.freq;
  366. is->audio_param_tgt.channel_layout = av_get_default_channel_layout(actual_spec.channels);
  367. is->audio_param_tgt.channels = actual_spec.channels;
  368. is->audio_param_tgt.frame_size = av_samples_get_buffer_size(NULL, actual_spec.channels, 1, is->audio_param_tgt.fmt, 1);
  369. is->audio_param_tgt.bytes_per_sec = av_samples_get_buffer_size(NULL, actual_spec.channels, actual_spec.freq, is->audio_param_tgt.fmt, 1);
  370. if (is->audio_param_tgt.bytes_per_sec <= 0 || is->audio_param_tgt.frame_size <= 0){
  371. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "av_samples_get_buffer_size failed.");
  372. //SDL_CloseAudioDevice(idev);
  373. SDL_CloseAudio();
  374. return -1;
  375. }
  376. is->audio_param_src = is->audio_param_tgt;
  377. is->audio_hw_buf_size = actual_spec.size; // SDL音频缓冲区大小
  378. is->audio_frm_size = 0;
  379. is->audio_cp_index = 0;
  380. // 3. 暂停/继续音频回调处理。参数1表暂停,0表继续。
  381. // 打开音频设备后默认未启动回调处理,通过调用SDL_PauseAudio(0)来启动回调处理。
  382. // 这样就可以在打开音频设备后先为回调函数安全初始化数据,一切就绪后再启动音频回调。
  383. // 在暂停期间,会将静音值往音频设备写。
  384. SDL_PauseAudio(0);
  385. //SDL_PauseAudioDevice(idev, 0);
  386. while (is->abort_request == 0){
  387. SDL_Delay(1);
  388. }
  389. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "----------%s:%d before SDL Close Audio", __FUNCTION__, __LINE__);
  390. SDL_CloseAudio();
  391. //SDL_CloseAudioDevice(idev);
  392. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "---------%s:%d after SDL Close Audio", __FUNCTION__, __LINE__);
  393. return 0;
  394. }
  395. // 音频处理回调函数。读队列获取音频包,解码,播放
  396. // 此函数被SDL按需调用,此函数不在用户主线程中,因此数据需要保护
  397. // \param[in] opaque 用户在注册回调函数时指定的参数
  398. // \param[out] stream 音频数据缓冲区地址,将解码后的音频数据填入此缓冲区
  399. // \param[out] len 音频数据缓冲区大小,单位字节
  400. // 回调函数返回后,stream指向的音频缓冲区将变为无效
  401. // 双声道采样点的顺序为LRLRLR
  402. static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
  403. {
  404. player_stat_t *is = (player_stat_t *)opaque;
  405. int audio_size = 0, len1 = 0;
  406. if (1 == is->abort_request){
  407. return;
  408. }
  409. int64_t audio_callback_time = av_gettime_relative();
  410. while (len > 0 && 0 == is->abort_request) // 输入参数len等于is->audio_hw_buf_size,是audio_open()中申请到的SDL音频缓冲区大小
  411. {
  412. if (is->audio_cp_index >= (int)is->audio_frm_size){
  413. // 1. 从音频frame队列中取出一个frame,转换为音频设备支持的格式,返回值是重采样音频帧的大小
  414. audio_size = audio_resample(is, audio_callback_time);
  415. if (audio_size < 0){
  416. if (-2 == audio_size) {
  417. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "audio_size is -2 sdl_audio_callback return.");
  418. return;
  419. }
  420. /* if error, just output silence */
  421. is->p_audio_frm = NULL;
  422. is->audio_frm_size = SDL_AUDIO_MIN_BUFFER_SIZE / is->audio_param_tgt.frame_size * is->audio_param_tgt.frame_size;
  423. }
  424. else{
  425. is->audio_frm_size = audio_size;
  426. }
  427. is->audio_cp_index = 0;
  428. }
  429. // 引入is->audio_cp_index的作用:防止一帧音频数据大小超过SDL音频缓冲区大小,这样一帧数据需要经过多次拷贝
  430. // 用is->audio_cp_index标识重采样帧中已拷入SDL音频缓冲区的数据位置索引,len1表示本次拷贝的数据量
  431. len1 = is->audio_frm_size - is->audio_cp_index;
  432. if (len1 > len){
  433. len1 = len;
  434. }
  435. //printf("len1 = %d\n", len1);
  436. // 2. 将转换后的音频数据拷贝到音频缓冲区stream中,之后的播放就是音频设备驱动程序的工作了
  437. if (is->p_audio_frm != NULL){
  438. SDL_memset(stream, 0, len1);
  439. int ivolume = is->uVolume;
  440. if (0 == is->on_audio_volume(&ivolume,is->user_data)){
  441. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "on_audio_volume success.");
  442. }
  443. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "audio uVolume is %d.", ivolume);
  444. SDL_MixAudio(stream, (uint8_t*)is->p_audio_frm + is->audio_cp_index, len1, ivolume);
  445. }
  446. else{
  447. SDL_memset(stream, 0, len1);
  448. }
  449. len -= len1;
  450. stream += len1;
  451. is->audio_cp_index += len1;
  452. }
  453. // is->audio_write_buf_size是本帧中尚未拷入SDL音频缓冲区的数据量
  454. is->audio_write_buf_size = is->audio_frm_size - is->audio_cp_index;
  455. //is->rvc_hostapi->Debug("audio_write_buf_size == %d.", is->audio_write_buf_size);
  456. /* Let's assume the audio driver that is used by SDL has two periods. */
  457. // 3. 更新时钟
  458. if (!isnan(is->audio_clock))
  459. {
  460. // 更新音频时钟,更新时刻:每次往声卡缓冲区拷入数据后
  461. // 前面audio_decode_frame中更新的is->audio_clock是以音频帧为单位,所以此处第二个参数要减去未拷贝数据量占用的时间
  462. set_clock_at(&is->audio_clk,
  463. is->audio_clock - (double)(2 * is->audio_hw_buf_size + is->audio_write_buf_size) / is->audio_param_tgt.bytes_per_sec,
  464. is->audio_clock_serial,
  465. audio_callback_time / 1000000.0);
  466. }
  467. }
  468. int open_audio(player_stat_t *is)
  469. {
  470. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "enter open_audio()");
  471. if (-1 == is->audio_idx[is->index]){
  472. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "not find audio stream");
  473. }
  474. else {
  475. open_audio_stream(is);
  476. open_audio_playing(is);
  477. }
  478. is->rvc_hostapi->Debug(MEDIA_LOG_DEBUG, "exit open_audio()");
  479. return 0;
  480. }