从iOS设备连续录制并发送/串流声音

时间:2012-07-27 11:30:23

标签: iphone ios cocoa-touch ipad audio-recording

我正在开发一款iOS应用程序,其上有一个带麦克风的按钮(以及其他功能)。当用户按下麦克风时,它会突出显示,应用程序现在应该开始从设备的麦克风录制声音并发送到服务器(专用于应用程序的服务器,由我知道的人开发,因此我可以影响其设计)。

我正在寻找最简单但最坚固的方法,即我不需要开发复杂的流媒体解决方案或VoIP功能,除非它像其他任何内容一样简单。

主要问题是我们不知道用户录制声音的时间长短,但我们希望确保声音连续发送到服务器,我们不希望等到用户完成录制。如果数据以块的形式到达服务器是可以的,但是我们不希望错过用户可能正在记录的任何信息,因此一个块必须在前一个块结束的地方继续,依此类推。

我们的第一个想法是创建例如10秒的声音剪辑的“块”并将它们连续发送到服务器。是否有任何流媒体解决方案更好/更简单,我错过了?

我的问题是,在iOS上解决此任务的最简单但仍然可靠的方法是什么?

有没有办法从AVAudioRecorder的正在运行的录音中提取声音块而不实际停止录音?

2 个答案:

答案 0 :(得分:20)

实际上,使用固定大小的块可能更容易,而不是固定时间。然后你可以有两个缓冲区,一个目前用示例数据填充的缓冲区。当活动缓冲区已满时,切换到填充另一个缓冲区,同时向发送方线程发送信号,该线程接收第一个缓冲区并将其发送到服务器。

您当然可以使用固定时间,但是您需要确保缓冲区足够大以保留所有样本,或者使用可在需要时增加大小的动态缓冲区。双缓冲和发送线程仍然可以是相同的。

答案 1 :(得分:20)

看看this
在本教程中,录制的声音将保存在soundFileURL中,然后您只需要创建一个包含该内容的nsdata,然后将其发送到您的服务器。
希望这会有所帮助。

编辑:
我刚创建了一个包含3个按钮的版本,REC,SEND和Stop:
REC:将开始录制到文件中 发送:将保存在NSData中记录的文件,并将其发送到服务器,然后重新开始录制 和STOP:将停止录制。
这是代码: 在你的.h文件中:

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

@interface ViewController : UIViewController <AVAudioRecorderDelegate>

@property (nonatomic, retain) AVAudioRecorder *audioRecorder;
@property (nonatomic, retain) IBOutlet UIButton *recordButton;
@property (nonatomic, retain) IBOutlet UIButton *stopButton;
@property (nonatomic, retain) IBOutlet UIButton *sendButton;

@property BOOL stoped;

- (IBAction)startRec:(id)sender;
- (IBAction)sendToServer:(id)sender;
- (IBAction)stop:(id)sender;
@end

并在.m文件中:

#import "ViewController.h"

@implementation ViewController
@synthesize audioRecorder;
@synthesize recordButton,sendButton,stopButton;
@synthesize stoped;

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
sendButton.enabled = NO;
stopButton.enabled = NO;
stoped = YES;

NSArray *dirPaths;
NSString *docsDir;

dirPaths = NSSearchPathForDirectoriesInDomains(
                                               NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
NSString *soundFilePath = [docsDir
                           stringByAppendingPathComponent:@"tempsound.caf"];

NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];

NSDictionary *recordSettings = [NSDictionary 
                                dictionaryWithObjectsAndKeys:
                                [NSNumber numberWithInt:AVAudioQualityMin],
                                AVEncoderAudioQualityKey,
                                [NSNumber numberWithInt:16], 
                                AVEncoderBitRateKey,
                                [NSNumber numberWithInt: 2], 
                                AVNumberOfChannelsKey,
                                [NSNumber numberWithFloat:44100.0], 
                                AVSampleRateKey,
                                nil];

NSError *error = nil;

audioRecorder = [[AVAudioRecorder alloc]
                 initWithURL:soundFileURL
                 settings:recordSettings
                 error:&error];
audioRecorder.delegate = self;
if (error)
{
    NSLog(@"error: %@", [error localizedDescription]);

} else {
    [audioRecorder prepareToRecord];
}
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

- (BOOL) sendAudioToServer :(NSData *)data {
    NSData *d = [NSData dataWithData:data];
    //now you'll just have to send that NSData to your server

    return YES;
}
-(void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag
{
NSLog(@"stoped");
    if (!stoped) {
        NSData *data = [NSData dataWithContentsOfURL:recorder.url];
        [self sendAudioToServer:data];
        [recorder record];
NSLog(@"stoped sent and restarted");
    }
}
- (IBAction)startRec:(id)sender {
if (!audioRecorder.recording)
{
    sendButton.enabled = YES;
    stopButton.enabled = YES;
    [audioRecorder record];
}
}

- (IBAction)sendToServer:(id)sender {
stoped = NO;
[audioRecorder stop];
}

- (IBAction)stop:(id)sender {
stopButton.enabled = NO;
sendButton.enabled = NO;
recordButton.enabled = YES;

stoped = YES;
if (audioRecorder.recording)
{
    [audioRecorder stop];
}
}
@end

祝你好运。