Mobil Programlama

iOS

iOS Uygulamalarında Ses Kaydetmek

Lisans: Creative Commons 26.11.2020 tarihinde güncellendi
Bakabileceğiniz Etiketler: Eğitmen: Geleceği Yazanlar Ekibi

Bu bölümde iOS uygulamanızda mikrofon kullanarak nasıl ses kayıt yapabileceğinizi anlatacağız. Öncelikle uygulamamıza AVFoundation Framework ekleyelim. AVFoundation bir ses dosyası oynatılması ve mikrofondan yapılan kaydın bir ses dosyası formatında kayıt edilmesi ile ilgili kütüphaneleri içermektedir. Projeye AVFoundation’ı dâhil etmek için proje özellikleri menüsünden General seçeneğini seçerek Linked Frameworks and Libraries altında AVFoundation kütüphanesini ekleyelim:

Bu aşamadan sonra projemizde ilk ekranımızı oluşturalım ve iki adet düğme ekleyelim. Düğmelerden biri ses kayıt işlemini başlatmak için kullanılırken diğeri ise kayıt bittikten sonra oluşturulan dosyayı dinlemek için kullanılacaktır. Biz burada ekranı oluştururken Interface Builder kullanmayı tercih ettik:

Ekrana düğmeleri sürükledikten sonra iki adet IBAction tipinde fonksiyon tanımlayarak düğmelere basıldığında işleme sokulacak kodları hazırlayalım.

recordAction: metodu ses kayıt işlemi başladığında yapılacak işlemleri anlatırken, playAction: metodu dosyayı oynatma amacıyla kullanılacaktır.

Header dosyamızda AVFoundation kütüphanesini kullanmak için bir import işlemi gerçekleştirmemiz gerekir. Bununla beraber ses kayıt amacıyla kullanacağımız AVAudioRecorder tipindeki değişkeni ve ses dosyası oynatmak için kullanacağımız AVAudioPlayer tipindeki değişkeni de burada tanımlayalım. soundFilePath değişkeni ise dosyanın kayıt edileceği yeri işaret edecektir.

 

// MainViewController.h

// SesKayitUygulamasi

 

#import <UIKit/UIKit.h>

#import <AVFoundation/AVFoundation.h>


@interface MainViewController : UIViewController <AVAudioPlayerDelegate,AVAudioRecorderDelegate> {

AVAudioRecorder *recorder;

AVAudioPlayer *player;

NSString *soundFilePath;

}

- (IBAction) recordAction:(id)sender;

- (IBAction) playAction:(id)sender;

@end

 


AVAudioPlayerDelegate temsilcisi ses oynatma işlemi başarılı bir şekilde bittiğinde audioPlayerDidFinishPlaying:successfully: metodunu uyarır ve bizim için gerekli aksiyonları almamızı sağlar. Bir hata olduğunda ise audioPlayerDecodeErrorDidOccur:error: metodu uyarılacaktır. Bu şekilde bir ses dosyasını yürütürken oluşabilecek hataları yakalayabilir ve bununla ilgili kullanıcıya gerekli uyarıları yapabiliriz (bozuk dosya, uygunsuz dosya formatı vb.). AVAudioRecorderDelegate temsilcisi ise kayıt işlemini takip etmemizi sağlar.

audioPlayerDidFinishRecording:successfully: kayıt işleminin başarıyla gerçekleştiğini söylerken audioPlayerEncodeErrorDidOccur:error: ise kayıt işlemi sırasında oluşan hataları bize bildirir.

Ses işlemlerine başlamadan önce uygulamamız açıldığında bir ses oturumu başlatmamız gerekir. Bu şekilde uygulamanın ses oynatma ve ses kayıt özelliklerini kullanabileceğini belirtiriz.

 

- (void)viewDidLoad

{

[super viewDidLoad];

// Do any additional setup after loading the view from its nib.

AVAudioSession *audioSession = [AVAudioSession sharedInstance];

[audioSession setActive: YES error: nil];

}

 

AVAudioSession başlatıldığında artık ses oynatma ve ses kayıt işlemleri için hazırız.

Uyarı : Eğer bir oturum açma sırasında başka bir uygulama hoparlörü ya da mikrofonu kullanıyorsa (örneğin bu uygulamayı geliştirirken arkada QuickTime ile müzik dinliyorsanız) uygulamamıza ses oturumu açma izni verilmeyebilir. Bu durum daha çok işletim sisteminin hiyerarşisiyle ilgilidir ve böyle bir durum da bize error değişkeni ile bildirilecektir.


Şimdi recordAction: metodumuzu yazalım ve kayıt işlemi için yapmamız gerekenleri görelim;

 

- (IBAction) recordAction:(id)sender {

    UIButton *button = (UIButton *) sender;

    if([button.titleLabel.text isEqualToString:@"Kayıt"]) {

// kayit basladi buton ismini degistir

        [button setTitle:@"Durdur" forState:UIControlStateNormal];

// kayita hazirlan

        [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryRecord error: nil];

// kayit ses kalitesi

        NSDictionary *recordSettings =

        [[NSDictionary alloc] initWithObjectsAndKeys:

            [NSNumber numberWithFloat: 44100.0], AVSampleRateKey,

            [NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,

            [NSNumber numberWithInt: 1], AVNumberOfChannelsKey,

            [NSNumber numberWithInt: AVAudioQualityMax], AVEncoderAudioQualityKey,

            nil];

        NSString *tempDir = NSTemporaryDirectory();

        soundFilePath = [NSString stringWithFormat:@"%@sound%d.caf",tempDir,arc4random() % 100000];

        NSLog(@"Dosya : %@",soundFilePath);

        AVAudioRecorder *newRecorder = [[AVAudioRecorder alloc] initWithURL: [[NSURL alloc] initFileURLWithPath: soundFilePath] settings: recordSettings error: nil];

        recorder = newRecorder;

        recorder.delegate = self;

        [recorder prepareToRecord];

        if([recorder record])
        {
            NSLog(@"Recording...");
        }

    } else {

        [button setTitle:@"Kayıt" forState:UIControlStateNormal];

        [recorder stop];

        recorder = nil;
    }
}

 


İlk olarak ses oturumunu ses kayıt için ayarlamamız gerekmektedir. AVAudioSession içerisinde yer alan setCategory metodu oturumu kayıt ya da oynatma amacıyla kullanacağımızı belirler. Biz kayıt yapacağımızdan AVAudioSessionCategoryRecord değeri ile kayıt işlemine hazırlık yapıyoruz. Bir sonraki adımda ise yapılacak kayıtla ilgili ses kalitesi değerlerini vermemiz gerekiyor. Aşağıdaki değerler tek kanal, kayıpsız ve 44kHz’lik bir kayıt yapmaya yarar. Burada unutmamanız gereken nokta, kayıt ne kadar kaliteli olursa o kadar büyük bir dosya oluşacağı gerçeğidir.

 

// kayit ses kalitesi

NSDictionary *recordSettings =

[[NSDictionary alloc] initWithObjectsAndKeys:

[NSNumber numberWithFloat: 44100.0], AVSampleRateKey,

[NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,

[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,

[NSNumber numberWithInt: AVAudioQualityMax], AVEncoderAudioQualityKey,

nil];

 


Oluşturulan dosyanın diskte kayıt edileceği yeri belirlememiz gerekir. Biz burada sound%d.caf ile rastgele numaralar vererek geçici klasörde çeşitli dosyalar oluşturma yoluna gittik. Dosya adını verdikten sonra AVAudioRecorder oluşturarak mikrofondan alınan sesin dosyaya yazılmasını record metodu ile başlatabiliriz. record metodu eğer kayıt başlarsa YES değeri döndürecektir.

 

AVAudioRecorder *newRecorder = [[AVAudioRecorder alloc] initWithURL: [[NSURL alloc] initFileURLWithPath: soundFilePath] settings: recordSettings error: nil];

recorder = newRecorder;

recorder.delegate = self;

[recorder prepareToRecord];

if([recorder record])
{
    NSLog(@"Recording...");
}

 


Yapılan delegate ataması ise kayıt başarılı bittiğinde ya da kayıt sırasında bir hata olduğunda aşağıdaki metodları uyarır;

 

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

UIButton *button = (UIButton *)[self.view viewWithTag:kRecordButtonTag];

[button setTitle:@"Kayıt" forState:UIControlStateNormal];

}

- (void) audioRecorderEncodeErrorDidOccur:(AVAudioRecorder *)recorder error:(NSError *)error {

UIButton *button = (UIButton *)[self.view viewWithTag:kRecordButtonTag];

[button setTitle:@"Kayıt" forState:UIControlStateNormal];

NSLog(@"%@",[error description]);

}

 


Biz burada bir hata oluştuğunda düğmenin adını Kayıt şekline döndürüyoruz ve hatayı konsola yazdırıyoruz. Dilerseniz siz de hataya göre bir aksiyon alabilir ya da bunu bir UIAlertView ile kullanıcının dikkatine sunabilirsiniz.

Kayıt sorunsuz başladığında düğmenin metin değeri Durdur olarak değişecektir. Bu durumda düğmeye tekrar basıldığında kayıt işlemini durdurmak için aşağıdaki kod çağırılır;

 

[button setTitle:@"Kayıt" forState:UIControlStateNormal];

[recorder stop];

recorder = nil;

 

Kayıt işlemi bittikten sonra oluşturulan dosyanın yeri soundFilePath değişkeni içerisinde tutulmaktadır. Oynat düğmesine basıldığında playAction: metodu harekete geçer ve aşağıdaki işlemleri gerçekleştirir;

 

- (IBAction) playAction:(id)sender {

    UIButton *button = (UIButton *) sender;

    if([button.titleLabel.text isEqualToString:@"Oynat"]) {

        [button setTitle:@"Durdur" forState:UIControlStateNormal];

        NSLog(@"Dosya : %@",soundFilePath);

        [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: nil];

        AVAudioPlayer *newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: [[NSURL alloc] initFileURLWithPath: soundFilePath] error: nil];

        player = newPlayer;

        [player prepareToPlay];

        [player setDelegate: self];

        [player setVolume:1.0];

        if([player play])
        {
            NSLog(@"Playing...");
        }

    } else {

        [button setTitle:@"Oynat" forState:UIControlStateNormal];

        [player stop];

        player = nil;
    }
}

 


Kayıt işlemine benzer şekilde oynatma işlemini gerçekleştirmek için öncelikle ses oturumunu AVAudioSessionCateoryPlayback değeriyle dosya oynatmaya hazır hale getiririz. Ardından AVAudioPlayer sınıfı ile dosya yerini NSURL tipinde vererek hangi dosyanın oynatılacağını belirtiriz. prepareToPlay metodu AVAudioPlayer’ı dosyayı oynatmaya hazır hale getirir. setVolume: ise cihazın hoparlörünün sesini açar ve 0 - 1 arasında bir değer alır. play metodu oynatma işlemini başlatacaktır. Eğer dosya başarıyla çalmaya başlarsa bu metot YES döner.

Temsilci metodlar ise aşağıdaki gibi verilmiştir;

 

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {

    UIButton *button = (UIButton *)[self.view viewWithTag:kPlayButtonTag];

    [button setTitle:@"Oynat" forState:UIControlStateNormal];
}

- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error {

    UIButton *button = (UIButton *)[self.view viewWithTag:kPlayButtonTag];

    [button setTitle:@"Oynat" forState:UIControlStateNormal];

    NSLog(@"%@",[error description]);
}

 


Yeni kayıt işleminde olduğu gibi oynatma işlemi de başladığında düğmemiz Durdur değerini alacaktır. Bu durumda oynatma işlemini durdurmak için aşağıdaki kod parçası kullanılır;

 

[button setTitle:@"Oynat" forState:UIControlStateNormal];

[player stop];

player = nil;

 

ViewController.m dosyasınında tamamı aşağıdaki gibidir;

 

//  MainViewController.m

//  SesKayitUygulamasi

#import "MainViewController.h"

#define kRecordButtonTag 101
#define kPlayButtonTag 201

@interface MainViewController ()

@end

@implementation MainViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (IBAction) recordAction:(id)sender {
    UIButton *button = (UIButton *) sender;

    if([button.titleLabel.text isEqualToString:@"Kayıt"])
    {
        // kayit basladi buton ismini degistir
        [button setTitle:@"Durdur" forState:UIControlStateNormal];
        // kayita hazirlan
        [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryRecord error: nil];
        // kayit ses kalitesi
        NSDictionary *recordSettings =
        [[NSDictionary alloc] initWithObjectsAndKeys:
            [NSNumber numberWithFloat: 44100.0], AVSampleRateKey,
            [NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,
            [NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
            [NSNumber numberWithInt: AVAudioQualityMax], AVEncoderAudioQualityKey,
            nil];
        NSString *tempDir = NSTemporaryDirectory();
        soundFilePath = [NSString stringWithFormat:@"%@sound%d.caf",tempDir,arc4random() % 100000];
        NSLog(@"Dosya : %@",soundFilePath);
        AVAudioRecorder *newRecorder = [[AVAudioRecorder alloc] initWithURL: [[NSURL alloc] initFileURLWithPath: soundFilePath] settings: recordSettings error: nil];
        recorder = newRecorder;
        recorder.delegate = self;
        [recorder prepareToRecord];
        
        if([recorder record])
        {
            NSLog(@"Recording...");
        }

    } else {
        [button setTitle:@"Kayıt" forState:UIControlStateNormal];
        [recorder stop];
        recorder = nil;
    }
}

- (IBAction) playAction:(id)sender {
    UIButton *button = (UIButton *) sender;
    
    if([button.titleLabel.text isEqualToString:@"Oynat"])
    {
        [button setTitle:@"Durdur" forState:UIControlStateNormal];
        NSLog(@"Dosya : %@",soundFilePath);
        [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: nil];
        AVAudioPlayer *newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: [[NSURL alloc] initFileURLWithPath: soundFilePath] error: nil];
        player = newPlayer;
        [player prepareToPlay];
        [player setDelegate: self];
        [player setVolume:1.0];
        
        if([player play])
        {
            NSLog(@"Playing...");
        }

    } else {
        [button setTitle:@"Oynat" forState:UIControlStateNormal];
        [player stop];
        player = nil;
    }
}

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
    UIButton *button = (UIButton *)[self.view viewWithTag:kPlayButtonTag];
    [button setTitle:@"Oynat" forState:UIControlStateNormal];
}

- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error {
    UIButton *button = (UIButton *)[self.view viewWithTag:kPlayButtonTag];
    [button setTitle:@"Oynat" forState:UIControlStateNormal];
    NSLog(@"%@",[error description]);
}

- (void) audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag {
    UIButton *button = (UIButton *)[self.view viewWithTag:kRecordButtonTag];
    [button setTitle:@"Kayıt" forState:UIControlStateNormal];
}

- (void) audioRecorderEncodeErrorDidOccur:(AVAudioRecorder *)recorder error:(NSError *)error {
    UIButton *button = (UIButton *)[self.view viewWithTag:kRecordButtonTag];
    [button setTitle:@"Kayıt" forState:UIControlStateNormal];
    NSLog(@"%@",[error description]);
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.

    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    [audioSession setActive: YES error: nil];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end