Skip to content
Browse files

Add `BubbleWrap::Media` and 'bubble-wrap/media'

Consists of a `Media::Player` class right now,
which is a wrapper over MPMoviePlayerController.
  • Loading branch information...
1 parent 440161c commit 2faf6c37b6f3b497819c3fec86029d2d2953325b @clayallsopp clayallsopp committed
View
22 README.md
@@ -65,6 +65,12 @@ If you wish to only include the `Location` wrapper:
require 'bubble-wrap/location'
```
+If you wish to only include the `Media` wrapper:
+
+```ruby
+require 'bubble-wrap/media'
+```
+
If you want to include everything (ie kitchen sink mode) you can save time and do:
```ruby
@@ -341,6 +347,22 @@ end
Also available is `BW::Location.get_significant`, for monitoring significant location changes.
+## Media
+
+Added wrapper for playing remote and local media. Available are `modal` and custom presentation styles:
+
+```ruby
+# Plays in your custom frame
+local_file = File.join(App.resources_path, 'test.mp3')
+BW::Media.play(NSURL.fileURLWithPath(local_file)) do |media_player|
+ media_player.view.frame = [[10, 100], [100, 100]]
+ self.view.addSubview media_player.view
+end
+
+# Plays in an independent modal controller
+BW::Media.play_modal("http://www.hrupin.com/wp-content/uploads/mp3/testsong_20_sec.mp3")
+```
+
## UI
### Gestures
View
2 lib/bubble-wrap/all.rb
@@ -1,4 +1,4 @@
require File.expand_path('../loader', __FILE__)
-['core', 'http', 'reactor', 'rss_parser', 'ui', 'location'].each { |sub|
+['core', 'http', 'reactor', 'rss_parser', 'ui', 'location', 'media'].each { |sub|
require File.expand_path("../#{sub}", __FILE__)
}
View
7 lib/bubble-wrap/media.rb
@@ -0,0 +1,7 @@
+require 'bubble-wrap/loader'
+BubbleWrap.require('motion/core/string.rb')
+BubbleWrap.require('motion/media/**/*.rb') do
+ file('motion/media/media.rb').depends_on('motion/media/player.rb')
+ file('motion/media/player.rb').depends_on 'motion/core/string.rb'
+ file('motion/media/player.rb').uses_framework('MediaPlayer')
+end
View
15 motion/media/media.rb
@@ -0,0 +1,15 @@
+module BubbleWrap
+ module Media
+ module_function
+
+ def play_modal(*args, &block)
+ Media::Player.new.retain.send(:play_modal, *args, &block)
+ end
+
+ def play(*args, &block)
+ Media::Player.new.retain.send(:play, *args, &block)
+ end
+ end
+end
+
+::Media = BubbleWrap::Media
View
122 motion/media/player.rb
@@ -0,0 +1,122 @@
+module BubbleWrap
+ module Media
+ module Error
+ class InvalidPlayerType < StandardError; end
+ class NilPlayerCallback < StandardError; end
+ end
+
+ class Player
+ attr_reader :media_player
+ ############
+ # Playing Media
+
+ # Plays media in the system-default modal controller
+ # Takes same parameters as #play
+ # NOTE: If you don't supply a :controller option,
+ # the rootViewController will be used.
+ def play_modal(content_url, options = {})
+ play(content_url, options.merge(modal: true))
+ end
+
+ # @param [String, NSURL] content_url is either a local or remote string
+ # for the location of the media you're playing.
+ # NOTE: if you're playing a remote file, your server needs to support
+ # range requests for that URL.
+ #
+ # @param [Hash] options to open the MPMoviePlayerController with
+ # the form {
+ # ### These are properties of MPMoviePlayerController
+ # allow_air_play: true/false; default false,
+ # control_style: [MPMovieControlStyle]; default MPMovieControlStyleDefault,
+ # end_playback_time: [Integer] end time (in seconds) for media; default is -1,
+ # initial_playback_time: [Integer] start time (in seconds) for media; default is -1,
+ # movie_source_type: [MPMovieSourceType] a "hint" so the player knows how to load the data type;
+ # either MPMovieSourceTypeFile or MPMovieSourceTypeStreaming; default is MPMovieSourceTypeUnknown
+ # which may delay playback,
+ # repeat_mode: [MPMovieRepeatMode] how the player repeats at the end of playback; defautl is
+ # MPMovieRepeatModeNone
+ # scaling_mode: [MPMovieScalingMode] scaling mode for movies; default is MPMovieScalingModeAspectFit
+ # should_autoplay: true/false; default true,
+ # use_application_audio_session: true/false; default true.
+ #
+ # ### These are properties of just the ::Player
+ # delay_play: true/false, default false. If false then you have to manually call
+ # @media_player.play in your code
+ # modal: true/false; default false,
+ # controller: [UIViewController] used to present the player modally;
+ # default uses root view controller of window
+ # }
+ #
+ # @block for when setup is done; use this block to present
+ # @media_player.view if options[:modal] == false
+ #
+ # EX
+ # From a local URL:
+ # file = File.join(App.resources_path, 'test.mp3')
+ # BW::Media::Player.play(NSURL.fileURLWithPath(file)) do |media_player|
+ # media_player.view.frame = some_view.bounds
+ # self.view.addSubview media_player.view
+ # end
+ #
+ # From a remote URL:
+ # BW::Media::Player.play("http://www.hrupin.com/wp-content/uploads/mp3/testsong_20_sec.mp3") do |media_player|
+ # media_player.view.frame = some_view.bounds
+ # self.view.addSubview media_player.view
+ # end
+ def play(content_url, options = {}, &block)
+ display_modal = !!options[:modal]
+
+ klass = display_modal ? MPMoviePlayerViewController : MPMoviePlayerController
+
+ content_url = content_url.is_a?(NSURL) ? content_url : NSURL.URLWithString(content_url)
+ @media_player = klass.alloc.initWithContentURL(content_url)
+
+ @media_player.prepareToPlay if not display_modal
+
+ options[:delay_play] = false if not options.has_key? :delay_play
+ options.each { |key, value|
+ setter = "#{key.to_s.camelize}="
+ if @media_player.respond_to? setter
+ @media_player.send(setter, value)
+ end
+ }
+
+ App.notification_center.observe MPMoviePlayerPlaybackDidFinishNotification do |notification|
+ h = notification.userInfo
+ error = h["error"]
+ if error
+ p "BW::Media::Player error: #{error.userInfo.inspect}"
+ p "Code: #{error.code}, Domain: #{error.domain}"
+ end
+ end
+
+ if display_modal
+ @presenting_controller = options[:controller]
+ @presenting_controller ||= UIApplication.sharedApplication.keyWindow.rootViewController
+ @presenting_controller.presentMoviePlayerViewControllerAnimated(@media_player)
+ else
+ if block.nil?
+ raise Error::NilPlayerCallback, "no block callback given in #play; you need\
+ to supply one if options[:modal] == false"
+ end
+ block.call(@media_player)
+ end
+
+ if not display_modal and not options[:delay_play]
+ @media_player.play
+ end
+ end
+
+ # Stops playback for a Media::Player
+ def stop
+ if @media_player.is_a? MPMoviePlayerViewController
+ @presenting_controller.dismissMoviePlayerViewControllerAnimated
+ @presenting_controller = nil
+ else
+ @media_player.stop
+ end
+ @media_player = nil
+ end
+ end
+ end
+end
View
BIN resources/test.mp3
Binary file not shown.
View
70 spec/motion/media/player_spec.rb
@@ -0,0 +1,70 @@
+describe BubbleWrap::Media::Player do
+ describe ".play" do
+ before do
+ @player = BW::Media::Player.new
+ @local_file = NSURL.fileURLWithPath(File.join(App.resources_path, 'test.mp3'))
+ end
+
+ it "should raise error if not modal and no callback given" do
+ should.raise(BW::Media::Error::NilPlayerCallback) do
+ @player.play(@local_file)
+ end
+ end
+
+ it "should yield to a block if not modal" do
+ @did_yield = false
+ @player.play(@local_file) do |_player|
+ @did_yield = true
+ end
+
+ @did_yield.should == true
+ @player.stop
+ end
+ end
+
+ describe ".play_modal" do
+ before do
+ @player = BW::Media::Player.new
+ @local_file = NSURL.fileURLWithPath(File.join(App.resources_path, 'test.mp3'))
+ end
+
+ it "should present a modalViewController on root if no controller given" do
+ @controller = UIApplication.sharedApplication.keyWindow.rootViewController
+
+ @player.play_modal(@local_file)
+
+ wait 1 do
+ @controller.modalViewController.should.not == nil
+
+ @player.stop
+ wait 1 do
+ @controller.modalViewController.should == nil
+ @controller = nil
+ @player = nil
+ end
+ end
+ end
+
+ it "should present a modalViewController if controller given" do
+ @controller = UIViewController.alloc.initWithNibName(nil, bundle:nil)
+
+ # .presentMoviePlayerViewControllerAnimated detects whether or not
+ # @controller.view is part of a hierarchy, I guess. if you remove this
+ # then the test fails.
+ UIApplication.sharedApplication.keyWindow.rootViewController.view.addSubview(@controller.view)
+
+ @player.play_modal(@local_file, controller: @controller)
+
+ wait 1 do
+ @controller.modalViewController.should.not == nil
+
+ @player.stop
+ wait 1 do
+ @controller.modalViewController.should == nil
+ @controller = nil
+ @player = nil
+ end
+ end
+ end
+ end
+end

0 comments on commit 2faf6c3

Please sign in to comment.
Something went wrong with that request. Please try again.