• Audiosink design


    Audiosink的设计,需要满足下列一些需求:

    •  良好的chain_based 支持。绝大多数简单playback pipelines都是将音频数据从decoder直接push给audiosink;

    •  良好 getrange_based支持。大部分专业的应用都是audio sink从pipeline拉取数据。典型的作法是在一个回调函数中pull N Samples,回调函数一般在一个单独的线程或者是硬件设备来调度。

    • 提供准确的时钟。必须能够提供即使samples被丢弃或在流中发现不连续时也能提供采样准确的时钟。

    • 可能的话,提供DMA支持

    Design

    The design is based on a set of base classes and the concept of a ringbuffer of samples.

    +-----------+   - provide preroll, rendering, timing
    + basesink  +   - caps nego
    +-----+-----+
          |
    +-----V----------+     - manages ringbuffer
    + audiobasesink  +   - manages scheduling (push/pull)
    +-----+----------+     - manages clock/query/seek
          |                  - manages scheduling of samples in the ringbuffer
          |                  - manages caps parsing
          |
    +-----V------+   - default ringbuffer implementation with a GThread
    + audiosink  +   - subclasses provide open/read/close methods
    +------------+
    

    The ringbuffer is a contiguous piece of memory divided into segtotal pieces of segments. Each segment has segsize bytes.

          play position 
            v          
    +---+---+---+-------------------------------------+----------+
    + 0 | 1 | 2 | ....                                | segtotal |
    +---+---+---+-------------------------------------+----------+
    <--->
      segsize bytes = N samples * bytes_per_sample.
    
    如上,环形缓冲器有一个play position,以segment表示。play position是设备正在从ringbuffer读取samples的位置。
    ringbuffer可以进入PLAYING或STOPPED状态:
    在STOPPED状态下,没有samples被put到设备,play pointer不前进。
    在PLAYING状态下,samples被写入设备,并且在每个seg被写入设备之后,ringbuffer应该调用可配置的回调,
    play pointer在每个段被写入之后前进。

    对ringbuffer的写入操作将会把新的samples放入ringbuffer中。如果ringbuffer中没有足够的空间,
    写操作将被阻塞。即使buffer为空,ringbuffer的播放也不会停止。当buffer为空时,设备会播放静音。
    ringbuffer通过无锁原子操作实现,特别是在读取端,以便尽可能地降低低延迟。
    每当一个new samples要put进ringbuffer,先获取read pointer,请求的write position和actural position作差值,
          /* get the currently processed segment */
          segdone = g_atomic_int_get (&buf->segdone) - buf->segbase;
    
          /* see how far away it is from the write segment */
          diff = writeseg - segdone;
       
    .....

          /* segment too far ahead, writer too slow, we need to drop, hopefully UNLIKELY */
          if (G_UNLIKELY (diff < 0)) {
            /* we need to drop one segment at a time, pretend we wrote a segment. */
            skip = TRUE;
            break;
          }

          /* write segment is within writable range, we can break the loop and
           * start writing the data. */
          if (diff <= segtotal) {
            skip = FALSE;
            break;
          }

          /* else we need to wait for the segment to become writable. */
          if (!wait_segment (buf))
            goto not_started;
        }
    
    



    如果差值diff<0,则samples来太慢了,丢掉来太慢的数据。如果diff > segtotal,写入部分必须等待播放指针前进。

    也就是需要设备先消耗掉ringbuffer中的数据,才能继续往ringbuffer中写入新的数据。

  • 相关阅读:
    [转]百度地图API详解之地图坐标系统
    [转]MBTiles 离线地图演示
    [shell 编程] if [ $# -eq 0 ]该语句是什么含义?
    [shell编程] sh脚本异常:/bin/sh^M:bad interpreter: No such file or directory
    [Android Studio] Android studio 多渠道打包(超简洁版)
    [Android Pro] Android中全局Application的onCreate多次调用问题
    [Java基础] Java如何实现条件编译
    [Git] 根据commiter过滤该用户的所有提交
    [Android Pro] Notification的使用
    [Git] Git把Tag推送到远程仓库
  • 原文地址:https://www.cnblogs.com/shakin/p/6993177.html
Copyright © 2020-2023  润新知