diff --git a/ruby/lib/jam_ruby/models/active_music_session.rb b/ruby/lib/jam_ruby/models/active_music_session.rb index 937f3ad20..cc97f572c 100644 --- a/ruby/lib/jam_ruby/models/active_music_session.rb +++ b/ruby/lib/jam_ruby/models/active_music_session.rb @@ -320,7 +320,7 @@ module JamRuby connection = Connection.where(user_id: current_user.id, client_id: client_id).first! my_locidispid = connection.locidispid - my_audio_latency = connection.last_jam_audio_latency + my_audio_latency = connection.last_jam_audio_latency || 0 # we can't assume that the user has an audio_latency when searching self.connection.execute("select ams_index('#{current_user.id}'::varchar, #{my_locidispid}::bigint, #{my_audio_latency}::integer)"); end @@ -407,6 +407,7 @@ module JamRuby # returns the set of users in a music_sessions and the music_session they are in and their latency. # ams_init must be called first. + # user.audio_latency / 2 , + other_user.audio_latency of them / 2, + network latency /2 def self.ams_users() return User.select('users.*, ams_users_tmp.music_session_id, ams_users_tmp.latency') .joins( diff --git a/ruby/lib/jam_ruby/models/connection.rb b/ruby/lib/jam_ruby/models/connection.rb index fc3d43682..ac40e38ca 100644 --- a/ruby/lib/jam_ruby/models/connection.rb +++ b/ruby/lib/jam_ruby/models/connection.rb @@ -169,10 +169,6 @@ module JamRuby end def associate_tracks(tracks) - # @log.debug "Tracks:" - # @log.debug tracks - - unless tracks.nil? self.tracks.clear() tracks.each do |track| diff --git a/web/app/controllers/api_music_sessions_controller.rb b/web/app/controllers/api_music_sessions_controller.rb index 7f4f7f09e..f633c3c7b 100644 --- a/web/app/controllers/api_music_sessions_controller.rb +++ b/web/app/controllers/api_music_sessions_controller.rb @@ -83,7 +83,14 @@ class ApiMusicSessionsController < ApiController offset: params[:offset], limit: params[:limit]).all - @music_session_users = ActiveMusicSession.ams_users().all + music_session_users = ActiveMusicSession.ams_users.all + + @user_scores = {} + music_session_users.each do |user| + @user_scores[user.id] = {latency: user.latency} + end + + render "api_music_sessions/ams_index" end end diff --git a/web/app/helpers/score_helper.rb b/web/app/helpers/score_helper.rb new file mode 100644 index 000000000..1609e2378 --- /dev/null +++ b/web/app/helpers/score_helper.rb @@ -0,0 +1,9 @@ +module ScoreHelper + + # helper method to make finding a user's score fault-tolerant + def user_score(user_id) + @user_scores ||= {} + user = @user_scores[user_id] + user ? user[:latency] : nil + end +end diff --git a/web/app/views/api_music_sessions/ams_index.rabl b/web/app/views/api_music_sessions/ams_index.rabl new file mode 100644 index 000000000..05e15a27f --- /dev/null +++ b/web/app/views/api_music_sessions/ams_index.rabl @@ -0,0 +1,3 @@ +object @music_sessions + +extends "api_music_sessions/show_history" diff --git a/web/app/views/api_music_sessions/show_history.rabl b/web/app/views/api_music_sessions/show_history.rabl index 444e06a3c..162fbdb32 100644 --- a/web/app/views/api_music_sessions/show_history.rabl +++ b/web/app/views/api_music_sessions/show_history.rabl @@ -74,6 +74,15 @@ else attributes :id, :sender_id, :receiver_id } + child({:approved_rsvps => :approved_rsvps}) { + attributes :id, :photo_url, :first_name, :last_name, :instrument_id + + node do |user| + { latency: user_score(user.id) } + end + + } + child(:active_music_session => :active_music_session) { attributes :claimed_recording_initiator_id, :track_changes_counter @@ -99,7 +108,7 @@ else attributes :ip_address, :client_id, :joined_session_at node :user do |connection| - { :id => connection.user.id, :photo_url => connection.user.photo_url, :name => connection.user.name, :is_friend => connection.user.friends?(current_user), :connection_state => connection.aasm_state } + { :id => connection.user.id, :photo_url => connection.user.photo_url, :name => connection.user.name, :is_friend => connection.user.friends?(current_user), :connection_state => connection.aasm_state, latency: user_score(connection.user.id) } end child(:tracks => :tracks) { @@ -107,8 +116,6 @@ else } } - - # only show join_requests if the current_user is in the session node(:join_requests, :if => lambda { |music_session| music_session.users.exists?(current_user) } ) do |music_session| child(:join_requests => :join_requests) { diff --git a/web/config/routes.rb b/web/config/routes.rb index e3012cfcd..9107f09d2 100644 --- a/web/config/routes.rb +++ b/web/config/routes.rb @@ -153,6 +153,7 @@ SampleApp::Application.routes.draw do match '/participants/:id' => 'api_music_sessions#participant_delete', :via => :delete match '/sessions/scheduled' => 'api_music_sessions#scheduled', :via => :get match '/sessions/legacy' => 'api_music_sessions#create_legacy', :via => :post + match '/sessions/active' => 'api_music_sessions#ams_index', :via => :get match '/sessions/:id' => 'api_music_sessions#show', :via => :get, :as => 'api_session_detail' match '/sessions/:id' => 'api_music_sessions#update', :via => :put match '/sessions/:id' => 'api_music_sessions#session_update', :via => :post @@ -166,7 +167,7 @@ SampleApp::Application.routes.draw do match '/sessions/:id/history' => 'api_music_sessions#show_history', :via => :get, :as => 'api_session_history_detail' match '/sessions/:id/details/comments' => 'api_music_sessions#add_session_info_comment', :via => :post - + # music session tracks match '/sessions/:id/tracks' => 'api_music_sessions#track_create', :via => :post match '/sessions/:id/tracks' => 'api_music_sessions#track_sync', :via => :put diff --git a/web/spec/controllers/api_music_sessions_controller_spec.rb b/web/spec/controllers/api_music_sessions_controller_spec.rb new file mode 100644 index 000000000..31a948bd8 --- /dev/null +++ b/web/spec/controllers/api_music_sessions_controller_spec.rb @@ -0,0 +1,87 @@ +require 'spec_helper' + +describe ApiMusicSessionsController do + render_views + + let(:tracks) { [{'sound' => 'mono', 'client_track_id' => 'abc', 'instrument_id' => 'piano'}] } + let(:user) { FactoryGirl.create(:user) } + let (:conn) { FactoryGirl.create(:connection, :user => user) } + + let(:other) { FactoryGirl.create(:user) } + let (:other_conn) { FactoryGirl.create(:connection, user: other, ip_address: '2.2.2.2') } + + let(:third_user) { FactoryGirl.create(:user) } + + before(:each) do + controller.current_user = user + + ActiveMusicSession.delete_all + MusicSession.delete_all + end + + describe "ams_index" do + + it "no results" do + get :ams_index, {client_id: conn.client_id} + response.should be_success + json = JSON.parse(response.body, :symbolize_names => true) + json.length.should == 0 + end + + it "just self" do + # create a session with self in it + ams = FactoryGirl.create(:active_music_session, creator: user) + conn.join_the_session(ams.music_session, true, tracks, user, 10) + conn.errors.any?.should be_false + + get :ams_index, {client_id: conn.client_id} + json = JSON.parse(response.body, :symbolize_names => true) + json.length.should == 1 + json[0][:active_music_session][:participants][0][:user][:latency].should be_nil + end + + it "someone else with no score with self" do + # create a session with someone else in it, but no score + ams = FactoryGirl.create(:active_music_session, creator: other) + other_conn.join_the_session(ams.music_session, true, tracks, user, 10) + other_conn.errors.any?.should be_false + + get :ams_index, {client_id: conn.client_id} + json = JSON.parse(response.body, :symbolize_names => true) + json.length.should == 1 + json[0][:active_music_session][:participants][0][:user][:latency].should be_nil + end + + it "someone else with a score with a self" do + # create a session with someone else in it, but no score + ams = FactoryGirl.create(:active_music_session, creator: other) + other_conn.join_the_session(ams.music_session, true, tracks, other, 10) + other_conn.errors.any?.should be_false + Score.createx(conn.locidispid, conn.client_id, conn.addr, other_conn.locidispid, other_conn.client_id, other_conn.addr, 20, nil) + + get :ams_index, {client_id: conn.client_id} + json = JSON.parse(response.body, :symbolize_names => true) + json.length.should == 1 + json[0][:active_music_session][:participants][0][:user][:latency].should == 17.5 + end + + it "someone else with a score with a self, and another with an approved RSVP" do + # create a session with someone else in it, but no score + ams = FactoryGirl.create(:active_music_session, creator: other) + other_conn.join_the_session(ams.music_session, true, tracks, other, 10) + other_conn.errors.any?.should be_false + Score.createx(conn.locidispid, conn.client_id, conn.addr, other_conn.locidispid, other_conn.client_id, other_conn.addr, 20, nil) + + rsvp_slot = FactoryGirl.create(:rsvp_slot, music_session: ams.music_session, instrument: Instrument.find('piano')) + rsvp_request = FactoryGirl.create(:rsvp_request, user: third_user) + rsvp_request_rsvp_slot = FactoryGirl.create(:rsvp_request_rsvp_slot, chosen:true, rsvp_request: rsvp_request, rsvp_slot:rsvp_slot) + + get :ams_index, {client_id: conn.client_id} + json = JSON.parse(response.body, :symbolize_names => true) + json.length.should == 1 + json[0][:active_music_session][:participants][0][:user][:latency].should_not be_nil + json[0][:approved_rsvps][0][:id].should == third_user.id + json[0][:approved_rsvps][0][:latency].should == 17.5 + end + end +end diff --git a/web/spec/factories.rb b/web/spec/factories.rb index 1691838c8..0c8cd23f8 100644 --- a/web/spec/factories.rb +++ b/web/spec/factories.rb @@ -15,6 +15,7 @@ FactoryGirl.define do country "US" terms_of_service true subscribe_email true + last_jam_audio_latency 5 factory :fan do musician false @@ -132,7 +133,7 @@ FactoryGirl.define do sequence(:client_id) { |n| "client_id#{n}"} ip_address "1.1.1.1" as_musician true - addr 0 + addr {JamIsp.ip_to_num(ip_address)} locidispid 0 client_type 'client' end @@ -483,6 +484,10 @@ FactoryGirl.define do cancel_all false end + factory :rsvp_request_rsvp_slot, class: JamRuby::RsvpRequestRsvpSlot do + chosen false + end + factory :diagnostic, :class => JamRuby::Diagnostic do type JamRuby::Diagnostic::NO_HEARTBEAT_ACK creator JamRuby::Diagnostic::CLIENT