- PVSM.RU - https://www.pvsm.ru -
Добрый день, читатели!
Я хотел бы поделиться решением проблемы проигрывания аудио из приложений iOS. Мы столкнулись с этим в процессе разработки очередного приложения: нам хотелось запускать и останавливать воспроизведение музыки и звуковых эффектов в разных местах, зачастую находящихся в разных классах приложения.

Обычно “болванка” необходимого функционала для этого копируется и адаптируется под конкретный сценарий использования. Мы делали это не раз и решили, что пришло время для более элегантного решения. Таким решением оказалось сделать “синглтон”, который был бы не только доступен из разных мест в приложении, но и сэкономил бы ресурсы системы в случае использования одного и того же аудио несколько раз.
В iOS, воспроизвести звуки можно несколькими способами [1]. Система разделяет звуки на “системные” – короткие звуки, которые проигрываются чтобы проинформировать пользователя о каком-то действии; например “озвучить” нажатие на кнопку или подтвердить отправку электронной почты. Другая категория это “музыка” – продолжительное аудио, такое как песни, мелодии и т.д. В нашем случае — это была мелодия, написанная для приложения замечательным композитором Бахтияром Аманжолом.
Проигрывание коротких звуков обеспечивaется с помощью “System Sound Services [2]”. Воспроизведение более продолжительного аудио обеспечивается целой серией средств, работающих на разных уровнях абстракции; мы приняли решение воспользоваться AVAudioPlayer [3].
Для удобства использования, мы решили дать доступ к функционалу посредством “методов класса” нежели чем “методов объекта”. В результате, проиграть звук можно посредством вот такого кода:
[MCSoundBoard playSoundForKey:@"ding"];
Для того чтобы реализовать такого рода вызов и, одновременно, кэшировать фрагменты аудио, мы использовали шаблон “синглтон”. Синглтоны в Objective-C можно реализовать многими способами. Исследуя эту проблему, мы набрели на очень аккуратный метод, описанный здесь [4]. Вот как выглядит необходимый код:
+ (MCSoundBoard *)sharedInstance
{
__strong static id _sharedObject = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedObject = [[self alloc] init];
});
return _sharedObject;
}
Затем мы определили “публичные” методы (обратите внимание что это – методы класса):
+ (void)addSoundAtPath:(NSString *)filePath forKey:(id)key;
+ (void)playSoundForKey:(id)key;
+ (void)addAudioAtPath:(NSString *)filePath forKey:(id)key;
+ (void)playAudioForKey:(id)key;
+ (void)stopAudioForKey:(id)key;
+ (void)pauseAudioForKey:(id)key;
Эти публичные статичные методы вызывают методы объекта синглтона:
- (void)addSoundAtPath:(NSString *)filePath forKey:(id)key
{
NSURL* fileURL = [NSURL fileURLWithPath:filePath];
SystemSoundID soundId;
AudioServicesCreateSystemSoundID((__bridge CFURLRef)fileURL, &soundId);
[_sounds setObject:[NSNumber numberWithInt:soundId] forKey:key];
}
+ (void)addSoundAtPath:(NSString *)filePath forKey:(id)key
{
[[self sharedInstance] addSoundAtPath:filePath forKey:key];
}
На этом, “музыкальный” функционал приложения был готов. Осталось избавиться от слишком «резких» включений и выключений музыки. Решением стало постепенно добавлять или убавлять уровень звука. AVFoundation такой возможности не давал. К счастью реализовать это с помощью основной библиотеки не так уж сложно:
- (void)fadeOutAndStop:(NSTimer *)timer
{
AVAudioPlayer *player = timer.userInfo;
float volume = player.volume;
volume = volume - 1.0 / MCSOUNDBOARD_AUDIO_FADE_STEPS;
volume = volume < 0.0 ? 0.0 : volume;
player.volume = volume;
if (volume == 0.0) {
[timer invalidate];
[player pause];
}
}
- (void)stopAudioForKey:(id)key fadeOutInterval:(NSTimeInterval)fadeOutInterval
{
AVAudioPlayer *player = [_audio objectForKey:key];
// If fade in inteval interval is not 0, schedule fade in
if (fadeOutInterval > 0) {
NSTimeInterval interval = fadeOutInterval / MCSOUNDBOARD_AUDIO_FADE_STEPS;
[NSTimer scheduledTimerWithTimeInterval:interval
target:self
selector:@selector(fadeOutAndStop:)
userInfo:player
repeats:YES];
} else {
[player stop];
}
}
Вот и все. Надеюсь, материал поможет людям столкнувшейся с аналогичной задачей.
Дополнительно: Страница MCSoundBoard на GitHub [5]
Автор: bgln
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/razrabotka-pod-ios/12464
Ссылки в тексте:
[1] несколькими способами: http://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/MultimediaPG/UsingAudio/UsingAudio.html#//apple_ref/doc/uid/TP40009767-CH2
[2] System Sound Services: http://developer.apple.com/library/ios/#documentation/AudioToolbox/Reference/SystemSoundServicesReference/Reference/reference.html
[3] AVAudioPlayer: http://developer.apple.com/library/ios/#DOCUMENTATION/AVFoundation/Reference/AVAudioPlayerClassReference/Reference/Reference.html
[4] здесь: http://lukeredpath.co.uk/blog/a-note-on-objective-c-singletons.html
[5] Страница MCSoundBoard на GitHub: https://github.com/Baglan/MCSoundBoard
Нажмите здесь для печати.