Jan 31

iPhone Audio Programmierung mit Celestial

Kategorie: Anleitungen / Dokusholeg

Auf dem iPhone gibt es 3 verschiedene Frameworks um Audio wiederzugeben: Core Audio, Celestial und Audio Toolbox. Zusätzlich existiert ein Audio-Daemon mediaserverd, welcher die Audio Ausgabe der verschiedenen Applikationen verwaltet und auf Events wie Telefonklingeln und das Ändern der Lautstärke reagiert. Core Audio ist das am wenigsten abstrahierte Framework (low-level), welches direkten Zugang zur Audio Hardware des iPhones bereitstellt. Es ist daher aber auch am unzugänglichsten von allen 3 Frameworks. Wenn man mit Core Audio versucht Audio Dateien wiederzugeben, dann wird der mediaserverd Prozess gekillt und damit auch die restliche Audio Ausgabe des iPhones. Daher werde ich nicht weiter auf dieses Framework eingehen. Interessierte bekommen mehr Informationen von der offiziellen Apple Developer Site. Audio Toolbox ist die nächst höhere Abstraktion und bietet Funktionen um einen digitalen Datenstrom mit Sound-Daten (zB. PCM) abzuspielen. Da dieses Framework nicht gerade einfach für Anfänger der Audio-Programmierung ist, werde ich darüber ein andermal schreiben. In diesem Beitrag möchte ich zeigen wie man mit Hilfe des Celestial Frameworks auf dem iPhone Audio wiedergeben und aufnehmen kann. Celestial ist am meisten abstrahiert, es ist vergleichbar mit QTKit bei normalen OS X Desktop Applikationen. Um eine Audio Datei abzuspielen benötigt man nur wenige Zeilen Code.

#import <Celestial/AVController.h>
#import <Celestial/AVItem.h> 

...

AVItem *avi;
AVController *avc;
NSError *error;

avc = [[AVController alloc] init];
avi = [[AVItem alloc] initWithPath:@"/Library/Ringtones/Alarm.m4r" error:&error];
if (error != nil) {
	NSLog(@"Es ist ein Fehler aufgetreten: %@", error);
}
[avc setCurrentItem:avi preservingRate:YES];
[avc play:nil];

...

[avc release];
[avi release];

Der AVController ist dazu da AVItems oder AVQueues (siehe weiter unten) abzuspielen. Er verbindet sich mit dem Audio Daemon und steuert den ganzen Sound, welcher über ihn gespielt wird (Wiedergabe, Pause, Lautstärke, EQ, Frequenz ..). Ein AVItem repräsentiert das einzelne Sound-Sample, welches in Form einer Datei vorliegen muss. Ein AVItem kann mit allen möglichen Audioformaten initialisiert werden, egal ob in reiner Form (PCM) oder komprimiert (zB. mp3). Anstelle eines Pfades zu einer Datei im Dateisystem kann man auch eine URL angeben. Wenn ein Programm dies einsetzt, sollte es vorher prüfen ob überhaupt eine Verbindung zum Internet besteht. Wenn man sein AVItem initialisiert hat, dann übergibt man es mit der Funktion setCurrentItem dem AVController, welcher es dann mit der Funktion play abspielt

AVQueues

Mit AVQueues kann man mehrere Audiodateien mit einem Befehl abspielen. Leider nur hintereinander, aber dafür kann man während der Abarbeitung neue Dateien hinzufügen und bestehende verschieben oder löschen. Eine Audioqueue kann man mit einem Array vergleichen, in welches Samples in einer bestimmten Reihenfolge abgelegt werden können um später abgespielt zu werden.

#import <Celestial/AVController.h>
#import <Celestial/AVItem.h> 

...

AVItem *avi1;
AVItem *avi2;
AVQueue *avq
AVController *avc;
NSError *error;

avc = [[AVController alloc] init];
avq = [ [ AVQueue alloc ] init ]; 

avi1 = [[AVItem alloc] initWithPath:@"/Library/Ringtones/Alarm.m4r" error:&error];
if (error != nil) {
	NSLog(@"Es ist ein Fehler aufgetreten: %@", error);
}

avi2 = [[AVItem alloc] initWithPath:@"/Library/Ringtones/Blues.m4r" error:&error];
if (error != nil) {
	NSLog(@"Es ist ein Fehler aufgetreten: %@", error);
}

[avq appendItem: avi1 error: &error ];
if (error != nil) {
	NSLog(@"Es ist ein Fehler aufgetreten: %@", error);
}
[avq appendItem: avi2 error: &error ];
if (error != nil) {
	NSLog(@"Es ist ein Fehler aufgetreten: %@", error);
}
[avc setQueue: avq ];
[avc play:nil ]; 

...

|avc release];
|avq release];
[avi1 release];
[avi2 release];

Im obigen Beispiel wird ein AVController, eine AVQueue-und zwei AVItems erzeugt. Die AVItems werden dann mit der appendItem Methode der AVQueue hinzugefügt. Am Ende wird anstelle eines AVItems mit der Methode setQueue dem AVController die AVQueue übergeben, welche dann mit der play Methode abgespielt wird.

Audio aufnehmen

Celestial ist auch hervorragend geeignet mit Hilfe der AVRecorder Klasse Sound vom eingebauten Mikrofon aufzunehmen.

#import <Celestial/AVRecorder.h>

...

NSURL *url = [[NSURL alloc] initWithString: @"/tmp/myRecord.amr"];
avr = [[AVRecorder alloc] init];
[avr setFilePath: url];

//Aufnahme starten
[avr activate: nil];
[avr start];

...

// Aufnahme beenden:
[avr stop];
[avr deactivate];

In diesem Beispiel wird zuerst ein AVRecorder Objekt erzeugt, welchem mit der Methode setFilePath einen Pfad in Form eines NSURL Objekts zugewiesen wird. In diese Datei wird dann später die Aufnahme gespeichert. Mit der Methode activate wird das Mikrofon aktiviert und mit start wird die Aufnahme gestartet. Um die Aufnahme zu beenden wird zuerst die stop Methode aufgerufen und zuletzt das Mikrofon wieder deaktiviert.

Ich empfehle jedem, sich die Header Dateien AVController.h, AVItem.h, AVQueue.h, und AVRecorder.h genauer anzuschauen. Die Funktionen sind gut benannt, so dass man sich recht gut damit zurechtfindet. Dies kann man entweder direkt tun, indem man die Dateien in einem Editor öffnet oder einfach die Firmware Doku durchstöbert.

20 Kommentare zu “iPhone Audio Programmierung mit Celestial”

  1. Michael sagt:

    Hallo!

    Habe eine Frage zu dem oben angeführten ersten Bsp.
    Welche Header muss ich hier inkludieren?
    , und welche noch?
    Wo finde ich den NSObject-Header?

    Mfg,
    Michael

  2. Michael sagt:

    “”
    hat er beim ersten post ausgeblendet…

  3. Michael sagt:

    ok anscheinend geht das nicht, dass man einen Header hier reinpostet…
    celestial/celestial.h, den wollte ich anführen…

  4. holeg sagt:

    Da bei den Kommentaren HTML erlaubt ist, werden die Header Anweisungen in spitzen Klammern als HTML Tag interpretiert. Da der Browser solche Tags nicht kennt muss man ein < als &lt; schreiben und ein > als &gt;

    Ich sehe gerade, den selben Fehler habe ich im obigen Code Beispiel gemacht. Werde das gleich korrigieren… ;-)

  5. Michael sagt:

    Hallo Holeg!
    Danke für deine Korrektur.
    Habe versucht mit dem oben angeführten BSP. ein PRG zu schreiben, dass eine MP3 abspielt.
    wenn ich es am IPod Touch starte, schließt sich nach wenigen sek. das Fenster wieder!
    Habe mich genau an deine Vorgabe gehalten!
    Was könnte der Fehler sein?

    Ein weiteres Problem ist, dass ich die MusicLibrary/MusicLibrary.h und weitere Header dieses Frameworks nicht miteinbinden kann. Habe es auch schon im Makefile ergänzt, das bringt aber leider nichts.

  6. holeg sagt:

    Hast Du mal versucht das Programm per Terminal (ssh) zu starten? Siehe http://www.iphone-dev.de/index.php/2008/01/28/iphone-programme-debuggen Da sieht man dann eine genauere Fehlermeldung wenn das Programm abbricht.

    Mit Music Library habe ich bisher noch keine Erfahrungen gemacht. Wenn Du das Framework im Makefile bei den LDFLAGS hinzufügst, sollte es eigentlich funktionieren.

  7. holeg sagt:

    Noch ne Idee. Hast Du die Audio Frameworks im Makefile eingetragen?

    Bei der LDFLAGS Zeile musst Du folgendes hinzufügen:

    -framework CoreAudio -framework AudioToolbox -framework Celestial
    
  8. Michael sagt:

    Hallo Holeg!
    Danke für deine Hilfe!
    So gescheit war ich anscheinend nicht, dass ich daran denke, dass die -framework CoreAudio -framework AudioToolbox -framework Celestial, auch alle miteingefügt werden…
    Jetzt funktioniert das!
    Danke nochmal :)

  9. Christian sagt:

    Hallo,

    gibt es denn auch eine Möglichkeit mehrere Audiodateien GLEICHZEITIG abzuspielen?
    Das geht mit AVQueues nicht soweit oben zu lesen ist.

    Grüße
    Christian

  10. holeg sagt:
  11. Christian sagt:

    Hi,

    holeg..wie läuft es ?
    Ist der Artikel schon absehbar? Bin gespannt…

    Grüße

  12. holeg sagt:

    Schätze mal das ich den Artikel am Wochenende fertig bekomme, garantiere aber nicht dafür ;-)

  13. Christian sagt:

    Super,

    bin für jede Hilfe dankbar :-)

  14. iPhone Audio Programmierung mit Audio Toolbox » Beitrag » iPhone-dev.de sagt:

    […] In einem älteren Artikel habe ich darüber geschrieben, wie man mit Celestial Audio auf dem iPhone wiedergeben kann. Mit dieser Methode kann man auf sehr einfache Weise fertige Audio Dateien abspielen. Möchte man jedoch selbst erzeugten Sound oder mehrere Audio-Streams gleichzeitig abspielen, wie es z.B. für Spiele notwendig ist, dann kommt man mit Celestial nicht weiter. Für diesen Fall hat Apple das AudioToolbox Framework erschaffen. Dieses Framework hat eine eigene Audio Queue, welche erschaffen wurde um reine PCM Audio Daten zu verarbeiten. Um die Funktionsweise einer Audio Queue verstehen zu können, sollte man sich im Vorfeld schon mit digitaler Audioverarbeitung auseinander gesetzt haben. Man findet zu dem Thema im Internet genug Infos, daher möchte ich nicht näher darauf eingehen. Zu empfehlen wäre noch das Buch von Bruce und Marty Fries mit dem Titel Digital Audio Essentials. […]

  15. nobreak sagt:

    Hi, was könnte der Grund dafür sein, das ich zwar den Sound abspielen kann (NSError = nil und [avc play:nil] = YES) aber nix höre. Sound allgemein funktioniert (Tastatur-Clicks - iPod - klingen usw). Achso, ich habe dein erstes Beispiel verwendet

  16. holeg sagt:

    Vielleicht ist die Sounddatei schrott?

  17. nobreak sagt:

    Nein, ist es leider nicht - ist halt die alarm.m4r - die als Klingelton auch funktioniert - habe mal auf dem AVController die Lautstärke abgefragt - ist aktuell auf “0″ und läst sich nicht mit [avc setVolume:1] hochsetzen - bleibt immer 0.

  18. holeg sagt:

    Welche firmware benutzt Du?

  19. blacksheep sagt:

    hallo holeg, frage zu audio recording: ich möcht gern nicht übers mikrophon aufnehmen, sondern die töne die ich in einem musikinstrument-app spiele. wie mach ich das? danke blacksheep

  20. holeg sagt:

    Hallo blacksheep,

    das geht leider nicht da auf dem iPhone nur eine App offen sein darf. Das würde nur gehen wenn die Musikinstrument-App eine Aufnahmefunktion besitzt.

    Grüße,
    Holeg

Dein Kommentar