关于OpenSL ES播放音频数据的一个奇怪的问题

Author:lihaiping1603@aliyun.com

最近用业余时间做了一个android平台的播放器sdk,其中视频用的opengl es,音频用的opensl es 做渲染,其中整个播放器在音视频同步的过程中,使用的视频同步到音频的方式,以音频作为主时钟。

今天在测试的过程中发现一个奇怪的问题,我音频数据的填充,使用了单独的音频线程,这其中的实现,主要参考ijk的实现代码和方式。

整个流程方式:我在音频播放的过程中设置的200ms的播放缓冲区给底层队列,当我把音频数据缓冲区填满以后,就wait_timeout(1s),如果在wait的过程中,底层有回调,就会signal,从而唤醒wait函数,然后再查询缓冲区大小,是否可以填充数据,如果可以填充数据的话,就填充数据进去,同时在填充数据的函数中,通过计算音频的pts和缓冲区的剩余数据大小,来更新当前的音频播放时钟位置。其中问题就是出在更新音频时钟位置的这个地方,我们计算剩余缓冲区的数据大小的时候,通过调用这个函数来获取底层数据的缓冲区延时:

通过计算state.count的计数来获取这个延时时间。

那么现在的问题现象是这样的,在视频正常播放的过程中,我填充了200ms满的缓冲区音频数据去播放,在填充数据线程中wait,然后在大概过了120ms之后,底层回调:

发送信号唤醒wait函数,然后我去拷贝音频数据,拷贝完数据之后,计算时钟,这个时候查询底层缓冲区数据还剩多少,发现state.count=17,也就是说填满的时候20,现在获取还剩17,意思是中间难道只消耗了30ms的音频数据?不太可能啊,正常播放的情况下,120ms应该消耗120ms的音频数据才对啊,为啥这个地方只消耗了30ms的数据呢?

经过进一步的排查和分析,发现了问题,如果经过了120ms的播放时间,底层实际消耗的音频数据是为120ms,而他开始回调,并连续回调12次。但第一次回调的时候,我们就唤醒了wait函数,这个时候我们去拷贝数据,而从唤醒到拷贝数据完成,并重新获取底层缓冲区大小的的这个过程,因为时间很短,短到他12次的连续回调,实际上只完成了3次回调,这个时候我们就去获取了state.count,发现它比之前只少了3次,所以误认为这个时间他只消耗了30ms的数据。因为state.count这个底层计数,他回调一次-1,并不会真正的实时反映实际的数据消耗过程。

那么我的代码和ijk的貌似看上去一致啊,为啥他的不会出现这个问题?后面思考发现问题所在,ijk在播放填充的数据线程中,通过回调给上层,他在上层的实现中实现了音频数据的解码,也就是正是这个解码函数产生的影响,他的这个耗时,完全足以让底层的音频连续回调,回调完毕,所以再去拿数据以后,就是正确的结果。

本人主要是个人对调试的理解和记录,仅供参考。

转载请注明出处:https://www.cnblogs.com/lihaiping/p/11739836.html

(原)关于OpenSL ES播放音频数据的一个奇怪的问题的更多相关文章

  1. Android OpenSL ES 开发:Android OpenSL 录制 PCM 音频数据

    一.实现说明 OpenSL ES的录音要比播放简单一些,在创建好引擎后,再创建好录音接口基本就可以录音了.在这里我们做的是流式录音,所以需要用至少2个buffer来缓存录制好的PCM数据,这里我们可以 ...

  2. Android 音视频深入 十四 FFmpeg与OpenSL ES 播放mp3音乐,能暂停(附源码下载)

    项目地址https://github.com/979451341/FFmpegOpenslES 这次说的是FFmpeg解码mp3,数据给OpenSL ES播放,并且能够暂停. 1.创建引擎 slCre ...

  3. iOS 9音频应用播放音频之第一个ios9音频实例2

    iOS 9音频应用播放音频之第一个ios9音频实例2 ios9音频应用关联 iOS9音频应用中对于在主视图上添加的视图或控件,在使用它们时必须要与插座变量进行关联.ios9插座变量其实就是为主视图中的 ...

  4. iOS 9音频应用播放音频之第一个ios9音频实例

    iOS 9音频应用播放音频之第一个ios9音频实例 第一个ios9音频实例 为了让开发者可以对上面的内容有更加深入的了解,本节将实现播放音频的第一个实例.在此实例中会涉及到项目的创建.界面设计.关联以 ...

  5. Android音视频学习第7章:使用OpenSL ES进行音频解码

    /* * *这里使用了transcode-1.1.7对wav文件进行解码.然后使用opensl es进行播放 * */ //用到的变量和结构体 WAV wav; //wav文件指针 SLObjectI ...

  6. OpenSL ES: 利用OpenSL ES播放一个存在于SDcard上的PCM文件

    native-lib.cpp #include <jni.h> #include <string> #include <SLES/OpenSLES.h> #incl ...

  7. 【Android 多媒体应用】使用MediaCodec解码使用AudioTrack播放音频数据

    1.MainActivity.java import android.app.Activity; import android.os.Bundle; import android.os.Environ ...

  8. 【Android 多媒体应用】使用MediaRecoder录制,MediaPlayer播放音频数据

    1.MainActivity.java import android.annotation.TargetApi; import android.app.Activity; import android ...

  9. Android OpenSL ES 开发:OpenSL ES利用SoundTouch实现PCM音频的变速和变调

    缘由 OpenSL ES 学习到现在已经知道 OpenSL ES 不仅能播放和录制PCM音频数据,还能改变声音大小.设置左声道或右声道播放.还能变速播放,可谓是播放音频的王者.但是变速有一点不好的就是 ...

随机推荐

  1. httprunner学习7-extract提取content返回对象

    前言 提取response返回的对象数据,用extract关键字.前面有关于token的取值,通过content.token取值. 本篇详细讲解如何从返回的json数据提取出想要的各种数据 conte ...

  2. cmds jdbc连接写法

    格式一:  Oracle JDBC Thin using a ServiceName: jdbc:oracle:thin:@//<host>:<port>/<servic ...

  3. pm2日志管理插件

    pm2的日志模块默认是每一个服务进程都分配两个默认的日志文件 普通日志 错误日志 这两个日志文件存放于/root/.pm2/logs中,如果pm2管理5个服务,那么该文件夹下总共有10个日志文件,并且 ...

  4. hive中时间操作(一)

    转:https://blog.csdn.net/u012474716/article/details/78925319/ hive中常用的时间为时间戳和日期格式之间的转换 常用的函数为: to_dat ...

  5. Blink示例程序

    打开Arduino IDE(话说与Processing IDE的UI好像啊 然后将这段代码输入.也可从文件>例子>01.Basics/Blink(File/Examples/01.Basi ...

  6. 使用jenkins exporter 监控jenkins 构建任务

    jenkins 提供了rest api,我们可以基于rest api 暴露prometheus metrics,社区已经有了好多 开源的实现了,使用起来也比较方便,以下集成几个进行简单的测试 环境准备 ...

  7. A@[G!C]%008

    A@[G!C]%008 A Simple Calculator 细节题. B Contiguous Repainting 最后只要有连续\(K\)个鸽子同色就可以构造方案,枚举+前缀和 C Tetro ...

  8. Impala 架构探索-Impala 系统组成与使用调优

    要好好使用 Impala 就得好好梳理一下他得结构以及他存在得一些问题或者需要注意得地方.本系列博客主要想记录一下对 Impala 架构梳理以及使用上的 workaround. Impala 简介 首 ...

  9. GoCN每日新闻(2019-11-11)

    GoCN每日新闻(2019-11-11) GoCN每日新闻(2019-11-11) 1. Go的内存管理与回收 https://medium.com/a-journey-with-go/go-memo ...

  10. SpringBoot上传文件到本服务器 目录与jar包同级问题

    目录 前言 原因 实现 不要忘记 最后的封装 Follow up   前言 看标题好像很简单的样子,但是针对使用jar包发布SpringBoot项目就不一样了.当你使用tomcat发布项目的时候,上传 ...