From fe299cbb1a2df7b52155e69bb0f2dc82c929cfeb Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Tue, 17 Mar 2015 01:37:15 +0100 Subject: [PATCH] core/audio: new pure-python/pyobjus AVFoundation audio player This extend our audio provider with a native provider, and supports far more format than the current sdl2 (mp3, ogg, wav). The full list is available at https://developer.apple.com/library/ios/documentation/MusicAudio/Concept ual/CoreAudioOverview/SupportedAudioFormatsMacOSX/SupportedAudioFormatsM acOSX.html --- kivy/__init__.py | 4 +- kivy/core/audio/__init__.py | 4 +- kivy/core/audio/audio_avplayer.py | 71 +++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 kivy/core/audio/audio_avplayer.py diff --git a/kivy/__init__.py b/kivy/__init__.py index 1ae994fc9..f1f086524 100644 --- a/kivy/__init__.py +++ b/kivy/__init__.py @@ -186,7 +186,9 @@ kivy_options = { 'video': ( 'gstplayer', 'ffmpeg', 'ffpyplayer', 'gi', 'pygst', 'pyglet', 'null'), - 'audio': ('gstplayer', 'pygame', 'gi', 'pygst', 'ffpyplayer', 'sdl2'), + 'audio': ( + 'gstplayer', 'pygame', 'gi', 'pygst', 'ffpyplayer', 'sdl2', + 'avplayer'), 'image': ('tex', 'imageio', 'dds', 'gif', 'sdl2', 'pygame', 'pil', 'ffpy'), 'camera': ('opencv', 'gi', 'pygst', 'videocapture', 'avfoundation'), 'spelling': ('enchant', 'osxappkit', ), diff --git a/kivy/core/audio/__init__.py b/kivy/core/audio/__init__.py index 84ffa3dc0..538cc4503 100644 --- a/kivy/core/audio/__init__.py +++ b/kivy/core/audio/__init__.py @@ -40,6 +40,7 @@ from kivy.compat import PY2 from kivy.resources import resource_find from kivy.properties import StringProperty, NumericProperty, OptionProperty, \ AliasProperty, BooleanProperty +from kivy.utils import platform from kivy.setupconfig import USE_SDL2 @@ -193,7 +194,8 @@ class Sound(EventDispatcher): # Little trick here, don't activate gstreamer on window # seem to have lot of crackle or something... audio_libs = [] - +if platform in ('macosx', 'ios'): + audio_libs += [('avplayer', 'audio_avplayer')] # from now on, prefer our gstplayer instead of gi/pygst. try: from kivy.lib.gstplayer import GstPlayer # NOQA diff --git a/kivy/core/audio/audio_avplayer.py b/kivy/core/audio/audio_avplayer.py new file mode 100644 index 000000000..09454e19a --- /dev/null +++ b/kivy/core/audio/audio_avplayer.py @@ -0,0 +1,71 @@ +''' +AudioAvplayer: implementation of Sound using pyobjus / AVFoundation. +Works on iOS / OSX. +''' + +__all__ = ('SoundAvplayer', ) + +from kivy.core.audio import Sound, SoundLoader +from pyobjus import autoclass +from pyobjus.dylib_manager import load_framework, INCLUDE +import sys + +load_framework(INCLUDE.AVFoundation) +AVAudioPlayer = autoclass("AVAudioPlayer") +NSURL = autoclass("NSURL") +NSString = autoclass("NSString") + + +class SoundAvplayer(Sound): + @staticmethod + def extensions(): + # taken from https://developer.apple.com/library/ios/documentation/MusicAudio/Conceptual/CoreAudioOverview/SupportedAudioFormatsMacOSX/SupportedAudioFormatsMacOSX.html + return ("aac", "adts", "aif", "aiff", "aifc", "caf", "mp3", "mp4", + "m4a", "snd", "au", "sd2", "wav") + + def __init__(self, **kwargs): + self._avplayer = None + super(SoundAvplayer, self).__init__(**kwargs) + + def load(self): + self.unload() + fn = NSString.alloc().initWithUTF8String_(self.filename) + url = NSURL.alloc().initFileURLWithPath_(fn) + self._avplayer = AVAudioPlayer.alloc().initWithContentsOfURL_error_(url, None) + + def unload(self): + self.stop() + self._avplayer = None + + def play(self): + if not self._avplayer: + return + self._avplayer.play() + super(SoundAvplayer, self).play() + + def stop(self): + if not self._avplayer: + return + self._avplayer.stop() + super(SoundAvplayer, self).stop() + + def seek(self, position): + if not self._avplayer: + return + self._avplayer.playAtTime_(float(position)) + + def get_pos(self): + if self._avplayer: + return self._avplayer.currentTime + return super(SoundAvplayer, self).get_pos() + + def on_volume(self, instance, volume): + if self._avplayer: + self._avplayer.volume = float(volume) + + def _get_length(self): + if self._avplayer: + return self._avplayer.duration + return super(SoundAvplayer, self)._get_length() + +SoundLoader.register(SoundAvplayer)