Подтвердить что ты не робот

Запись и передача/поток звука с устройства iOS на сервер непрерывно

Я разрабатываю приложение iOS, на котором есть кнопка с микрофоном (наряду с другими функциями). Когда пользователь нажимает на микрофон, он подсвечивается, и приложение должно теперь начинать запись звука с микрофона устройства и отправлять на сервер (сервер, посвященный приложению, разработанный людьми, которых я знаю, поэтому я могу повлиять на его дизайн).

Я ищу простейший, но самый надежный способ сделать это, т.е. мне не нужно разрабатывать сложные потоковые решения или функции VoIP, если это не так просто сделать, как что-либо еще.

Основная проблема заключается в том, что мы не знаем, как долго пользователь будет записывать звук, но мы хотим, чтобы звуки были отправлены на сервер непрерывно, мы не хотим ждать, пока пользователь закончит запись. Это нормально, если данные поступают на сервер в кусках, однако мы не хотим пропускать какую-либо информацию, которую пользователь может записывать, поэтому один фрагмент должен быть продолжен там, где закончился предыдущий, и т.д.

Наша первая мысль заключалась в том, чтобы создать "куски" звуковых клипов, например, 10 секунд и отправить их на сервер. Есть ли потоковое решение, которое лучше/проще, чем я пропускаю?

Мой вопрос: какой бы простой, но все же надежный подход к решению этой задачи на iOS?

Есть ли способ извлечь фрагменты звука из текущей записи с помощью AVAudioRecorder без фактической остановки записи?

4b9b3361

Ответ 1

посмотрите this
в этом уроке записанный звук будет сохранен в soundFileURL, тогда вам просто нужно будет создать nsdata с этим контентом, а затем отправить его на свой сервер.
надеюсь, что это помогло.

ИЗМЕНИТЬ:
Я только что создал версию, содержащую 3 кнопки, REC, SEND и Stop:
REC: начнет запись в файл.
SEND: сохранит то, что было записано в этом файле в 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

Удачи.

Ответ 2

На самом деле может быть проще иметь блоки фиксированного размера вместо фиксированного времени. Затем вы можете иметь два буфера, один из которых в настоящий момент заполняется образцами данных. Когда активный буфер заполнен, затем переключитесь на заполнение другого буфера, отправив сигнал в поток-отправитель, который берет первый буфер и отправляет его на сервер.

Вместо этого вы можете использовать фиксированное время, но тогда вам нужно убедиться, что буфер достаточно велик, чтобы хранить все сэмплы или использовать динамический буфер, который может увеличиваться по мере необходимости. Тем не менее, поток двойной буферизации и отправки может быть тем же.