【问题标题】:How to capture audio output in iOS?如何在 iOS 中捕获音频输出?
【发布时间】:2015-05-20 10:46:26
【问题描述】:

我正在我的应用中播放来自互联网的音频流,我想显示一个图形均衡器。我用于流式传输的库是FreeStreamer。为了绘制图形均衡器,我使用ZLHistogramAudioPlot。这两个库是唯一符合我需求的库。问题是我无法让他们一起工作。

ZLHistogramAudioPlot 需要一个缓冲区和 bufferSize 才能更新它的视图。这是它的更新方法:

- (void)updateBuffer:(float *)buffer withBufferSize:(UInt32)bufferSize {
    [self setSampleData:buffer length:bufferSize];
}

不幸的是,FreeStreamer 库没有提供读取音频输出的方法,因为它向声卡输出。所以,我需要的是一种读取即将通过扬声器播放的音频输出流的方法(而不是来自互联网的字节流,因为它是以块的形式接收的,然后被缓冲,这意味着直方图不会在实时)。

我发现可以使用 Apple 的 CoreAudio 框架中的 AURemoteIO 来执行此操作,但 Apple 的示例项目复杂到无法理解,网上关于使用 AURemoteIO 的示例很少甚至没有。

这是实现这一目标的最佳方式吗?如果是,任何有用的信息/链接将不胜感激。

【问题讨论】:

  • 你是如何播放互联网音频流的?
  • 我使用FreeStreamer通过url播放流。
  • 你能了解 freestreamers 的内部信息吗?还是用 AVPlayer 替换它?
  • 我可以了解它的内部结构,但它们非常复杂,我看不出我需要更改哪些内容才能使其正常工作。我可以改用 AVPlayer,但我选择了 FreeStreamer,因为它非常优化并且只使用 1% 的 CPU 来运行。
  • 您能指出我将如何使用 AVPlayer 查看输出流吗?

标签: ios audio streaming core-audio equalizer


【解决方案1】:

这是查看 FreeStreamer 标头的可能答案

#define minForSpectrum 1024

@implementation MyClass {
    TPCircularBuffer SpectrumAnalyzerBuffer;
}

- (void)dealloc {
    TPCircularBufferCleanup(&SpectrumAnalyzerBuffer);
}

-(instancetype) init {
   self = [super init];
   if (self) {
      TPCircularBufferInit(&SpectrumAnalyzerBuffer, 16384);
      self.audioController.activeStream.delegate = self;
   }
   return self;
}

- (void)audioStream:(FSAudioStream *)audioStream samplesAvailable:(const int16_t *)samples count:(NSUInteger)count {
    // incoming data is integer

    SInt16 *buffer = samples;
    Float32 *floatBuffer = malloc(sizeof(Float32)*count);
    // convert to float
    vDSP_vflt16(buffer, 1, floatBuffer, 1, count);

    // scale
    static float scale = 1.f / (INT16_MAX/2);
    static float zero = 0.f;

    vDSP_vsmsa(floatBuffer, 1, &scale, &zero, floatBuffer, 1, count);

    TPCircularBufferProduceBytes(&SpectrumAnalyzerBuffer, floatBuffer, count*sizeof(Float32));

    free(floatBuffer);   
}

- (void) timerCallback: (NSTimer*) timer {

    Float32 *spectrumBufferData = TPCircularBufferTail(&SpectrumAnalyzerBuffer, &availableSpectrum);

    if (availableSpectrum >= minForSpectrum) {
        // note visualiser may want chunks of a fixed size if its doing fft
        [histogram updateBuffer: spectrumBufferData length: minForSpectrum];
        TPCircularBufferConsume(&SpectrumAnalyzerBuffer, minForSpectrum);
    }


}

【讨论】:

  • 不,这些是从流中接收到的样本,它们以块的形式出现,每隔一百毫秒左右,而不是连续的,所以直方图会抽搐,它不会真正更新时间。
  • 总共要有足够的样本来制作音频,使用TPCircularBuffer将样本放入,然后再取出。 (假设您的图形期望相同的采样率)。 FreeStreamer 文档说您实际上不应该阻塞,所以缓冲区确实是强制性的。
  • 将缓冲区的代码添加到答案中。还想到,如果您的可视化器就像我使用的那样,那么它会需要其配置大小的固定块数据,您不能每次都将所有数据都扔给它。
  • 是的,但它想要的是这些块的连续流。 samplesAvailable 方法每隔几毫秒调用一次,因此它不提供连续的块流。我将尝试使用缓冲区。只是古玩,你为什么放弃 AVPlayer 方法?我认为这会更容易。
  • 带有 AudioProcessingTap 的 AVPlayer 会更容易,它是我在我的一个应用程序中使用的,但是对于 m3u 链接,音频水龙头显然不起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-07
  • 1970-01-01
  • 2014-10-07
  • 1970-01-01
  • 2015-09-06
相关资源
最近更新 更多