我正在开发一款iOS应用程序,其上有一个带麦克风的按钮(以及其他功能)。当用户按下麦克风时,它会突出显示,应用程序现在应该开始从设备的麦克风录制声音并发送到服务器(专用于应用程序的服务器,由我知道的人开发,因此我可以影响其设计)。
我正在寻找最简单但最坚固的方法,即我不需要开发复杂的流媒体解决方案或VoIP功能,除非它像其他任何内容一样简单。
主要问题是我们不知道用户录制声音的时间长短,但我们希望确保声音连续发送到服务器,我们不希望等到用户完成录制。如果数据以块的形式到达服务器是可以的,但是我们不希望错过用户可能正在记录的任何信息,因此一个块必须在前一个块结束的地方继续,依此类推。
我们的第一个想法是创建例如10秒的声音剪辑的“块”并将它们连续发送到服务器。是否有任何流媒体解决方案更好/更简单,我错过了?
我的问题是,在iOS上解决此任务的最简单但仍然可靠的方法是什么?
有没有办法从AVAudioRecorder的正在运行的录音中提取声音块而不实际停止录音?
答案 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
祝你好运。