2014-12-18 21:13:55 +00:00
|
|
|
=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
|
|
|
|
|
|
2014-01-19 02:20:44 +00:00
|
|
|
class ApiIcecastController < ApiController
|
2014-03-08 02:52:00 +00:00
|
|
|
before_filter :local_only, :only => [:test]
|
2014-12-18 21:13:55 +00:00
|
|
|
before_filter :parse_mount, :only => [:mount_add, :mount_remove, :listener_add, :listener_remove]
|
|
|
|
|
before_filter :api_signed_in_user, :only => [ :create_source_change ]
|
2014-01-19 02:20:44 +00:00
|
|
|
|
|
|
|
|
# each request will have this in it, if it's icecast.
|
|
|
|
|
#user-agent = Icecast 2.3.3
|
|
|
|
|
|
|
|
|
|
|
2014-12-18 21:13:55 +00:00
|
|
|
respond_to :json
|
|
|
|
|
|
2014-03-08 02:52:00 +00:00
|
|
|
def test
|
|
|
|
|
puts "========= GOT IT======="
|
|
|
|
|
render text: 'GOT IT', :status => :ok
|
|
|
|
|
end
|
|
|
|
|
|
2014-01-19 02:20:44 +00:00
|
|
|
def mount_add
|
2014-01-21 14:51:03 +00:00
|
|
|
mount = IcecastMount.find_by_name!(@mount_id)
|
2014-01-19 02:20:44 +00:00
|
|
|
mount.source_up
|
|
|
|
|
|
|
|
|
|
render text: '', :status => :ok
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def mount_remove
|
2014-01-21 14:51:03 +00:00
|
|
|
mount = IcecastMount.find_by_name!(@mount_id)
|
2014-01-19 02:20:44 +00:00
|
|
|
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]
|
|
|
|
|
|
2014-03-04 17:56:42 +00:00
|
|
|
mount = IcecastMount.find_by_name(@mount_id)
|
|
|
|
|
|
|
|
|
|
mount.listener_add if mount
|
2014-01-19 02:20:44 +00:00
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
2014-03-04 17:56:42 +00:00
|
|
|
mount = IcecastMount.find_by_name(@mount_id)
|
|
|
|
|
mount.listener_remove if mount
|
2014-01-19 02:20:44 +00:00
|
|
|
|
|
|
|
|
render text: '', :status => :ok
|
|
|
|
|
end
|
|
|
|
|
|
2014-12-18 21:13:55 +00:00
|
|
|
# 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
|
|
|
|
|
|
2014-01-19 02:20:44 +00:00
|
|
|
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
|