ios - 使用 AVAudioPLayer 播放音频片段时出现故障

标签 ios xcode audio stream avaudioplayer

我正在尝试播放来自 IP 摄像机的音频流,它是 API http://...<ip-camera..>/audio.cgi

目前我可以通过调整 MJPEG 客户端来播放流音频,获取音频 block 并将它们放入连续声音包的缓冲区 (NSMutableArray)。这里有一些接收数据的代码:

-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    NSLog(@"Data recv.");

     NSLog(@"Data lenght:%i",[data length]);

    if ([data length]>AUDIO_STREAM_HEADER_SIZE){
        [recvData appendData:data]; //audio stream data - always 1024 bytes
        NSLog(@"Data Append lenght:%i",[recvData length]);

    }
    else {
        [_encabezado appendData:data]; //audio stream header - always 44 bytes
        NSLog(@"Crea encabezado:%@",_encabezado);
        NSLog(@"Largo encabezado:%i",[_encabezado length]);

    }


    if ([recvData length] >= PACKET_SIZE_BUFFER_SONIDO) //PACKET_SIZE_BUFFER_SONIDO = 81920
    {

        NSMutableData *soundData = [[NSMutableData alloc] initWithCapacity:([recvData length])];

        NSMutableData *soundCut = [[NSMutableData alloc] initWithData:recvData];

        [soundData appendData:_encabezado]; //audio stream header
        [soundData appendData:soundCut];  //audio stream data

        [_arrSonidos addObject:soundData];

        if ([_arrSonidos count]>(BUFFER_SIZE_FOR_PLAY-1)) {
            if (playerBuffer.isPlaying) {
                [playerBuffer AgregaDataSound:soundData]; //addDataSound in Buffer
            } else {
                playerBuffer = [[SoundDataPLayer alloc]initWithFileNameQueue:_arrSonidos];
            }
        }

        [recvData setLength:0];

        [soundData release];
    }

}

每次调用函数时(函数显示),每次调用都会获取数据字段的 header (44 字节),然后是数据字节位(1024 字节)。我所做的是让 head 在 NSData 中接收数据然后接收数据直到定义的数据包大小,将数据包与各自的 header 数据一起保存在缓冲区中。因此,我反复将包添加到缓冲区。

另一方面,我创建了一个由上述代码调用的“playerBuffer”(灵感来自网络上的示例),它还负责控制缓冲区并播放缓冲区的每个数据包。此对象基于 AVAudioPlayer :

声音数据播放器.h

#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>

@interface SoundDataPLayer : NSObject <AVAudioPlayerDelegate> {
    AVAudioPlayer* myplayer;
    NSMutableArray* dataSound;
    int index;
}

@property (nonatomic, retain) AVAudioPlayer* myplayer;
@property (nonatomic, retain) NSMutableArray* dataSound;

- (id)initWithFileNameQueue:(NSArray*)datas;
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag;
- (void)playX:(int)i;
- (void)stop;
- (BOOL)isPlaying;
- (void)AgregaDataSound:(NSData *)data;

@end

声音数据播放器.m

#import "SoundDataPLayer.h"
#import "ExtAudioFileConvertUtil.h"

@implementation SoundDataPLayer

@synthesize myplayer;
@synthesize dataSound;

- (id)initWithFileNameQueue:(NSArray*)datas {
    if ((self = [super init])) {
        self.dataSound = [[NSMutableArray alloc]initWithArray:datas];
        index = 0;
        [self playX:index];
    }
    return self;
}

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
    if (index < dataSound.count) {
        [self playX:index];
    } else {
        //reached end of queue
    }
}

- (void)playX:(int)i {

    self.myplayer = [[AVAudioPlayer alloc] initWithData:[dataSound objectAtIndex:i]  error:nil];
    myplayer.delegate = self;
    [myplayer prepareToPlay];
    [myplayer play];

    index++;
}

- (void)stop {
    if (self.myplayer.playing) [myplayer stop];
}

- (BOOL)isPlaying{
    return self.myplayer.playing;
}

- (void)AgregaDataSound:(NSData *)data {
    [dataSound addObject:data]; //Add Sound Data to the buffer
}

@end

那是工作和播放循环播放音频,但在每次循环时 AVAudioPlayer返回播放缓冲区的新数据包 (NSData),它听到每个数据包之间的烦人故障。

我试过 SystemSound并录制声音打包buffer到数据文件中,看数据中是否包含毛刺,但显然毛刺是在数据的末尾。

我在论坛中发现一篇文章似乎解释了发生的事情:here但在我的案例中显然没有完全解释,因为是 x-wav 音频和 PCM 编解码器,所以我认为和理解是未压缩的。虽然我不知道你是如何解压 NSData 的音频的数据包。

来自网络摄像机的流式音频的附加信息:

datas del audio en el header:

"Cache-Control" = "no-cache"; "Content-Type" = "audio/x-wav"; Date = "Tue Jan 5 01:17:04 2010"; Pragma = "no-cache"; Server = "GoAhead-Webs";

Datos adicionales del audio Codec: PCM SampleRate: 16 kHz

如果有人能告诉我如何解决这个问题,我将不胜感激...我尝试解决它很多很多小时...快把我逼疯了!!

提前致谢,抱歉我的英语不好。

最佳答案

您听到的“故障”是您接收“完成播放”事件、处理它、为下一个数据包初始化 AVAudioPlayer 并将数据发送到声卡所花费的时间的组合.

这类似于在开始下一个 CD 播放器之前等待一个 CD 播放器完成播放 — 不可能做出足够快的 react 以实现无故障播放。

您可能想要使用音频队列服务,并且您还需要一些方法来补偿相机和手机之间的音频时钟偏差。

关于ios - 使用 AVAudioPLayer 播放音频片段时出现故障,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15608456/

相关文章:

ios - 如何获取命令行工具的包 ID

ios - UIScrollview 触摸

ios - CoreData实体使用合并策略作为NSMergeByPropertyObjectTrumpMergePolicy保存/更新,从而在Xcode中抛出编译器错误?

xcode - 当缩进级别大于三时,为什么 Xcode 会停止绘制选项卡?

iphone - 检测 2 个 subview 的触摸

ios - 有没有办法在 IOS 上使用 SVG 中的 anchor 链接?

ios - UIToolBar 栏按钮项目不使用 Swift 显示

ios - 在连接的 iOS Safari 中记录 HLS 流段的请求

linux - 使用 Linux 命令行从 WAV/RIFF 获取频谱

jquery - HTML5 音频播放器 : Pause not working