=begin Summary of icecast implementation: mount lock locations: * IcecastMount.listener_add * IcecastMount.listener_remove * IcecastMount.source_up * IcecastMount.source_down * IcecastSourceCheck on each stale IcecastMount sourced_needs_changing_at behavior: * set to Time.now if first listener comes in (current listeners==0 as they join) * set to Time.now if last listener leaves (current listeners == 1 as they leave) * set to nil if source begins * set to nil if source ends * a session's clients gets requested to start a source if one of: ** an IcecastMount is saved and listeners go above 0 and not currently sourced ** an IcecastSourceCheck finds a IcecastMount with a stale sourced_needs_changing_at and mount.listeners > 0 && !mount.sourced * a session's clients get requested to stop a source if ** an IcecastSourceCheck finds a IcecastMount with a stale sourced_needs_changing_at and mount.listeners == 0 && mount.sourced =end class ApiIcecastController < ApiController before_filter :local_only, :only => [:test] before_filter :parse_mount, :only => [:mount_add, :mount_remove, :listener_add, :listener_remove] before_filter :api_signed_in_user, :only => [ :create_source_change ] # each request will have this in it, if it's icecast. #user-agent = Icecast 2.3.3 respond_to :json def test puts "========= GOT IT=======" render text: 'GOT IT', :status => :ok end def mount_add mount = IcecastMount.find_by_name!(@mount_id) mount.source_up render text: '', :status => :ok end def mount_remove mount = IcecastMount.find_by_name!(@mount_id) mount.source_down render text: '', :status => :ok end def listener_add client = params[:client] # icecast internal id, e.g. 149 user = params[:user] # basic auth in the request sent to icecast pass = params[:pass] # basic auth in the request sent to icecast remote_ip = params[:ip] remote_user_agent = params[:agent] mount = IcecastMount.find_by_name(@mount_id) mount.listener_add if mount render text: '', :status => :ok end def listener_remove client = params[:client] # you can use this to correlate the listener_add... user = params[:user] # or user/pass (icecast is storing these as well and reflects them back) pass = params[:pass] duration = params[:duration] # seconds connected to the listen stream mount = IcecastMount.find_by_name(@mount_id) mount.listener_remove if mount render text: '', :status => :ok end # info reported by the client to the server letting us track what's going on at a deeper level def create_source_change mount = IcecastMount.find(params[:id]) @source_change = IcecastSourceChange.new @source_change.source_direction = params[:source_direction] @source_change.user = current_user @source_change.client_id = params[:client_id] @source_change.success = params[:success] @source_change.reason = params[:reason] @source_change.detail = params[:detail] @source_change.mount = mount @source_change.change_type = IcecastSourceChange::CHANGE_TYPE_CLIENT @source_change.save if @source_change.errors.any? response.status = :unprocessable_entity respond_with @source_change else source_change_json = Rabl::Renderer.json(@source_change, 'api_icecast/source_change_notification') SubscriptionMessage.mount_source_change(mount, source_change_json) render :json => {}, :status => 200 end end def show @mount = IcecastMount.find(params[:id]) respond_with @mount, responder: ApiResponder end protected def local_only request.local? end def parse_mount() mount = params[:mount] # Example A # browser: http://icecast/a # mount: /a # # Example B # browser: http://icecast/a?dog=legs&mump # mount: /a?dog=legs&mump # browser: http://icecast/a#bleh # mount: /a uri = URI(mount) @mount_id = uri.path @mount_params = Rack::Utils.parse_query(uri.query) end end