148 votes

Comment enregistrer de l'audio sur un iPhone avec AVAudioRecorder ?

Maintenant que le SDK de l'iPhone 3.0 est public, je pense pouvoir poser cette question à ceux d'entre vous qui ont déjà joué avec le SDK 3.0. Je souhaite enregistrer de l'audio dans mon application, mais je veux utiliser AVAudioRecorder et non l'ancienne façon d'enregistrer comme l'exemple SpeakHere spectacles. Il n'y a pas d'exemples de la meilleure façon de procéder dans l'iPhone Dev Center et seulement des références aux classes. Je suis un débutant dans le développement de l'iPhone et je cherche donc un exemple simple pour me lancer.

207voto

Massimo Cafaro Points 18759

En fait, il n'y a pas d'exemples du tout. Voici mon code de travail. L'enregistrement est déclenché par l'utilisateur qui appuie sur un bouton de la navBar. L'enregistrement utilise la qualité cd (44100 échantillons), stéréo (2 canaux) linéaire pcm. Attention : si vous voulez utiliser un format différent, en particulier un format encodé, assurez-vous de bien comprendre comment définir les paramètres de l'AVAudioRecorder (lisez attentivement la documentation sur les types d'audio), sinon vous ne serez jamais capable de l'initialiser correctement. Une dernière chose. Dans le code, je ne montre pas comment gérer les données de comptage, mais vous pouvez le découvrir facilement. Enfin, notez que la méthode deleteRecording de l'AVAudioRecorder, telle qu'elle a été écrite, fait planter votre application. C'est pourquoi je supprime le fichier enregistré par le biais du gestionnaire de fichiers. Lorsque l'enregistrement est terminé, je sauvegarde l'audio enregistré en tant que NSData dans l'objet en cours d'édition en utilisant KVC.

#define DOCUMENTS_FOLDER [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]

- (void) startRecording{

UIBarButtonItem *stopButton = [[UIBarButtonItem alloc] initWithTitle:@"Stop" style:UIBarButtonItemStyleBordered  target:self action:@selector(stopRecording)];
self.navigationItem.rightBarButtonItem = stopButton;
[stopButton release];

AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *err = nil;
[audioSession setCategory :AVAudioSessionCategoryPlayAndRecord error:&err];
if(err){
    NSLog(@"audioSession: %@ %d %@", [err domain], [err code], [[err userInfo] description]);
    return;
}
[audioSession setActive:YES error:&err];
err = nil;
if(err){
    NSLog(@"audioSession: %@ %d %@", [err domain], [err code], [[err userInfo] description]);
    return;
}

recordSetting = [[NSMutableDictionary alloc] init];

[recordSetting setValue :[NSNumber numberWithInt:kAudioFormatLinearPCM] forKey:AVFormatIDKey];
[recordSetting setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey]; 
[recordSetting setValue:[NSNumber numberWithInt: 2] forKey:AVNumberOfChannelsKey];

[recordSetting setValue :[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
[recordSetting setValue :[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsBigEndianKey];
[recordSetting setValue :[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsFloatKey];

// Create a new dated file
NSDate *now = [NSDate dateWithTimeIntervalSinceNow:0];
NSString *caldate = [now description];
recorderFilePath = [[NSString stringWithFormat:@"%@/%@.caf", DOCUMENTS_FOLDER, caldate] retain];

NSURL *url = [NSURL fileURLWithPath:recorderFilePath];
err = nil;
recorder = [[ AVAudioRecorder alloc] initWithURL:url settings:recordSetting error:&err];
if(!recorder){
    NSLog(@"recorder: %@ %d %@", [err domain], [err code], [[err userInfo] description]);
    UIAlertView *alert =
    [[UIAlertView alloc] initWithTitle: @"Warning"
                               message: [err localizedDescription]
                              delegate: nil
                     cancelButtonTitle:@"OK"
                     otherButtonTitles:nil];
    [alert show];
    [alert release];
    return;
}

//prepare to record
[recorder setDelegate:self];
[recorder prepareToRecord];
recorder.meteringEnabled = YES;

BOOL audioHWAvailable = audioSession.inputIsAvailable;
if (! audioHWAvailable) {
    UIAlertView *cantRecordAlert =
    [[UIAlertView alloc] initWithTitle: @"Warning"
                               message: @"Audio input hardware not available"
                              delegate: nil
                     cancelButtonTitle:@"OK"
                     otherButtonTitles:nil];
    [cantRecordAlert show];
    [cantRecordAlert release]; 
    return;
}

// start recording
[recorder recordForDuration:(NSTimeInterval) 10];

}

- (void) stopRecording{

[recorder stop];

NSURL *url = [NSURL fileURLWithPath: recorderFilePath];
NSError *err = nil;
NSData *audioData = [NSData dataWithContentsOfFile:[url path] options: 0 error:&err];
if(!audioData)
    NSLog(@"audio data: %@ %d %@", [err domain], [err code], [[err userInfo] description]);
[editedObject setValue:[NSData dataWithContentsOfURL:url] forKey:editedFieldKey];   

//[recorder deleteRecording];

NSFileManager *fm = [NSFileManager defaultManager];

err = nil;
[fm removeItemAtPath:[url path] error:&err];
if(err)
    NSLog(@"File Manager: %@ %d %@", [err domain], [err code], [[err userInfo] description]);

UIBarButtonItem *startButton = [[UIBarButtonItem alloc] initWithTitle:@"Record" style:UIBarButtonItemStyleBordered  target:self action:@selector(startRecording)];
self.navigationItem.rightBarButtonItem = startButton;
[startButton release];

}

- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *) aRecorder successfully:(BOOL)flag
{

NSLog (@"audioRecorderDidFinishRecording:successfully:");
// your actions here

}

0 votes

Je pense que j'ai presque réussi à faire fonctionner votre code, mais j'ai du mal avec le truc des délégués. Je suis assez nouveau dans l'Objective C et je n'ai toujours pas compris la manière correcte de faire le délégué pour quelque chose comme ça. Mon délégué essaie d'implémenter NSObject <AVAudioRecorder>, mais je ne pense pas le faire correctement. Serait-il trop difficile de poster le code du délégué également ? Merci.

0 votes

Je l'ai finalement fait fonctionner en ajoutant ceci à ma classe déléguée @protocol AVAudioRecorder @optional - (void)audioRecorderBeginInterruption :(AVAudioRecorder *)recorder ; - (void)audioRecorderDidFinishRecording :(AVAudioRecorder *)recorder successfully : (BOOL)flag ; - (void)audioRecorderEncodeErrorDidOccur :(AVAudioRecorder *)recorder error :(NSError *)error ; - (void)audioRecorderEndInterruption :(AVAudioRecorder *)recorder ; Cela semble fonctionner, mais je ne sais pas si c'est la meilleure pratique ou non. Maintenant, j'ai besoin de le faire persister dans un magasin de données local et de le lire, entre autres choses.

0 votes

Ce n'est pas vrai, Jim. Dans l'en-tête de votre contrôleur d'enregistreur, vous feriez quelque chose comme.... #import <AVFoundation/AVFoundation.h> @interface RecorderViewController : UIViewController <AVAudioRecorderDelegate> {

85voto

Shaybc Points 830

Bien qu'il s'agisse d'une question à laquelle on a déjà répondu (et qui date un peu), j'ai décidé de poster mon code complet pour les autres qui ont eu du mal à trouver un bon exemple de lecture et d'enregistrement (prêt à l'emploi) - y compris l'encodage, le pcm, la lecture via le haut-parleur, l'écriture dans un fichier - le voici :

AudioPlayerViewController.h :

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

@interface AudioPlayerViewController : UIViewController {
AVAudioPlayer *audioPlayer;
AVAudioRecorder *audioRecorder;
int recordEncoding;
enum
{
    ENC_AAC = 1,
    ENC_ALAC = 2,
    ENC_IMA4 = 3,
    ENC_ILBC = 4,
    ENC_ULAW = 5,
    ENC_PCM = 6,
} encodingTypes;
}

-(IBAction) startRecording;
-(IBAction) stopRecording;
-(IBAction) playRecording;
-(IBAction) stopPlaying;

@end

AudioPlayerViewController.m :

#import "AudioPlayerViewController.h"

@implementation AudioPlayerViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    recordEncoding = ENC_AAC;
}

-(IBAction) startRecording
{
NSLog(@"startRecording");
[audioRecorder release];
audioRecorder = nil;

// Init audio with record capability
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryRecord error:nil];

NSMutableDictionary *recordSettings = [[NSMutableDictionary alloc] initWithCapacity:10];
if(recordEncoding == ENC_PCM)
{
    [recordSettings setObject:[NSNumber numberWithInt: kAudioFormatLinearPCM] forKey: AVFormatIDKey];
    [recordSettings setObject:[NSNumber numberWithFloat:44100.0] forKey: AVSampleRateKey];
    [recordSettings setObject:[NSNumber numberWithInt:2] forKey:AVNumberOfChannelsKey];
    [recordSettings setObject:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
    [recordSettings setObject:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsBigEndianKey];
    [recordSettings setObject:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsFloatKey];   
}
else
{
    NSNumber *formatObject;

    switch (recordEncoding) {
        case (ENC_AAC): 
            formatObject = [NSNumber numberWithInt: kAudioFormatMPEG4AAC];
            break;
        case (ENC_ALAC):
            formatObject = [NSNumber numberWithInt: kAudioFormatAppleLossless];
            break;
        case (ENC_IMA4):
            formatObject = [NSNumber numberWithInt: kAudioFormatAppleIMA4];
            break;
        case (ENC_ILBC):
            formatObject = [NSNumber numberWithInt: kAudioFormatiLBC];
            break;
        case (ENC_ULAW):
            formatObject = [NSNumber numberWithInt: kAudioFormatULaw];
            break;
        default:
            formatObject = [NSNumber numberWithInt: kAudioFormatAppleIMA4];
    }

    [recordSettings setObject:formatObject forKey: AVFormatIDKey];
    [recordSettings setObject:[NSNumber numberWithFloat:44100.0] forKey: AVSampleRateKey];
    [recordSettings setObject:[NSNumber numberWithInt:2] forKey:AVNumberOfChannelsKey];
    [recordSettings setObject:[NSNumber numberWithInt:12800] forKey:AVEncoderBitRateKey];
    [recordSettings setObject:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
    [recordSettings setObject:[NSNumber numberWithInt: AVAudioQualityHigh] forKey: AVEncoderAudioQualityKey];
}

NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/recordTest.caf", [[NSBundle mainBundle] resourcePath]]];

NSError *error = nil;
audioRecorder = [[ AVAudioRecorder alloc] initWithURL:url settings:recordSettings error:&error];

if ([audioRecorder prepareToRecord] == YES){
    [audioRecorder record];
}else {
    int errorCode = CFSwapInt32HostToBig ([error code]); 
    NSLog(@"Error: %@ [%4.4s])" , [error localizedDescription], (char*)&errorCode); 

}
NSLog(@"recording");
}

-(IBAction) stopRecording
{
NSLog(@"stopRecording");
[audioRecorder stop];
NSLog(@"stopped");
}

-(IBAction) playRecording
{
NSLog(@"playRecording");
// Init audio with playback capability
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];

NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/recordTest.caf", [[NSBundle mainBundle] resourcePath]]];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
audioPlayer.numberOfLoops = 0;
[audioPlayer play];
NSLog(@"playing");
}

-(IBAction) stopPlaying
{
NSLog(@"stopPlaying");
[audioPlayer stop];
NSLog(@"stopped");
}

- (void)dealloc
{
[audioPlayer release];
[audioRecorder release];
[super dealloc];
}

@end

J'espère que cela aidera certains d'entre vous.

0 votes

Bonjour, Lorsque je construis et exécute le second code fourni par ShayBC sur le simulateur d'iphone, je n'obtiens aucun résultat mais dans la console il montre que cela fonctionne. Est-ce que le simulateur Iphone utilise le haut-parleur et le microphone de mon ordinateur portable ou est-ce qu'il est muet et je dois construire l'application sur le dispositif ?

1 votes

@Bataly le simulateur iphone jouera vos fichiers son (mp3 / caf.... ) et peut enregistrer à travers votre micro portable essayez de regarder dans les préférences système de Léopard s'il y a des problèmes, mais la meilleure façon de tester votre application est de l'exécuter sur un vrai iDevice, et c'est une bonne idée pour tout le code que vous écrivez car il y a beaucoup d'applications qui sont rejetées de l'app-store en raison d'un crash car elles n'ont jamais été testées sur un vrai iDevice, il y a plus de fonctionnalités qui ne sont pas supportées par le simulateur (bluetooth, appareil photo, multitouch correct, accéléromètre, IAP, GPS, il aura une meilleure performance que le plus iDevice. ..)

0 votes

[recordSettings setObject:formatObject forKey : AVFormatIDKey] ; Cette ligne ne me permet pas d'utiliser AVFormatIDKey comme clé. Que se passe-t-il ? Si je lui attribue une autre valeur, cela fonctionne...

14voto

Avinash Points 321

J'ai téléchargé un exemple de projet. Vous pouvez y jeter un coup d'œil.

Enregistreur de voix

0 votes

Juste au cas où vous ne trouveriez pas le téléchargement : Allez dans "Téléchargements" dans le coin supérieur droit et ensuite dans "PACKAGES DE TELECHARGEMENT".

0 votes

@Phlibbo : Vous n'y trouvez plus rien maintenant ?

0 votes

@user523234 : voici l'url de téléchargement - github.com/AvinashP/VoiceRecorder/downloads#download_128004

11voto

Avinash Points 321

C'est vraiment utile. Le seul problème que j'ai rencontré était la taille du fichier son créé après l'enregistrement. J'avais besoin de réduire la taille du fichier et j'ai donc effectué quelques changements dans les paramètres.

NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc] init];
[recordSetting setValue :[NSNumber numberWithInt:kAudioFormatAppleIMA4] forKey:AVFormatIDKey];
[recordSetting setValue:[NSNumber numberWithFloat:16000.0] forKey:AVSampleRateKey];
[recordSetting setValue:[NSNumber numberWithInt: 1] forKey:AVNumberOfChannelsKey];

La taille du fichier est passée de 360 kb à seulement 25 kb (enregistrement de 2 secondes).

0 votes

Pouvez-vous poster le reste de votre code également ? car je pense qu'il me manque quelque chose. J'ai essayé de modifier de nombreux paramètres mais je ne parviens pas à réduire la taille du fichier

1 votes

J'ai téléchargé un exemple de projet. Vous pouvez y jeter un coup d'œil. github.com/AvinashP/VoiceRecorder

8voto

scourtaud Points 61

J'ai essayé de faire fonctionner ce code pendant les deux dernières heures et bien qu'il n'y ait pas eu d'erreur sur le simulateur, il y en avait une sur l'appareil.

Il s'avère, du moins dans mon cas, que l'erreur provient du répertoire utilisé (bundle) :

NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/recordTest.caf", [[NSBundle mainBundle] resourcePath]]];

Il n'était pas inscriptible ou quelque chose comme ça... Il n'y a pas d'erreur sauf le fait que prepareToRecord a échoué...

Je l'ai donc remplacé par :

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *recDir = [paths objectAtIndex:0];
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/recordTest.caf", recDir]]

Il fonctionne maintenant comme un charme.

J'espère que cela aidera d'autres personnes.

1 votes

Vous n'avez pas le droit d'écrire dans le dossier des ressources.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X