2014-05-06 13:34:38 +00:00
module JamRuby
class ActiveMusicSession < ActiveRecord :: Base
2014-06-17 22:16:49 +00:00
@@log = Logging . logger [ ActiveMusicSession ]
2014-05-06 13:34:38 +00:00
self . primary_key = 'id'
2014-05-06 22:50:41 +00:00
self . table_name = 'active_music_sessions'
2014-05-06 21:17:26 +00:00
2015-04-15 23:22:55 +00:00
attr_accessor :legal_terms , :max_score , :opening_jam_track , :opening_recording , :opening_backing_track , :opening_metronome , :jam_track_id
2014-05-06 13:34:38 +00:00
belongs_to :claimed_recording , :class_name = > " JamRuby::ClaimedRecording " , :foreign_key = > " claimed_recording_id " , :inverse_of = > :playing_sessions
belongs_to :claimed_recording_initiator , :class_name = > " JamRuby::User " , :inverse_of = > :playing_claimed_recordings , :foreign_key = > " claimed_recording_initiator_id "
2015-01-07 23:44:56 +00:00
belongs_to :jam_track , :class_name = > " JamRuby::JamTrack " , :foreign_key = > " jam_track_id " , :inverse_of = > :playing_sessions
belongs_to :jam_track_initiator , :class_name = > " JamRuby::User " , :inverse_of = > :playing_jam_tracks , :foreign_key = > " jam_track_initiator_id "
2015-01-11 20:15:47 +00:00
belongs_to :backing_track_initiator , :class_name = > " JamRuby::User " , :inverse_of = > :playing_jam_tracks , :foreign_key = > " backing_track_initiator_id "
belongs_to :metronome_initiator , :class_name = > " JamRuby::User " , :inverse_of = > :playing_jam_tracks , :foreign_key = > " metronome_initiator_id "
2014-05-06 21:17:26 +00:00
has_one :music_session , :class_name = > " JamRuby::MusicSession " , :foreign_key = > 'music_session_id'
2014-05-06 13:34:38 +00:00
has_one :mount , :class_name = > " JamRuby::IcecastMount " , :inverse_of = > :music_session , :foreign_key = > 'music_session_id'
2014-05-06 21:17:26 +00:00
belongs_to :creator , :class_name = > 'JamRuby::User' , :foreign_key = > :user_id
2014-05-06 13:34:38 +00:00
2014-05-06 21:17:26 +00:00
has_many :connections , :class_name = > " JamRuby::Connection " , foreign_key : :music_session_id
2014-05-06 13:34:38 +00:00
has_many :users , :through = > :connections , :class_name = > " JamRuby::User "
2014-05-06 21:17:26 +00:00
has_many :recordings , :class_name = > " JamRuby::Recording " , :inverse_of = > :music_session , foreign_key : :music_session_id
2014-05-06 13:34:38 +00:00
has_many :chats , :class_name = > " JamRuby::ChatMessages " , :foreign_key = > " session_id "
validates :creator , :presence = > true
validate :creator_is_musician
2015-01-07 23:44:56 +00:00
validate :validate_opening_recording , :if = > :opening_recording
validate :validate_opening_jam_track , :if = > :opening_jam_track
2015-01-11 20:15:47 +00:00
validate :validate_opening_backing_track , :if = > :opening_backing_track
2015-03-04 01:06:55 +00:00
# not sure if this is helpful since if one opens, it always stays open
2015-01-11 20:15:47 +00:00
validate :validate_opening_metronome , :if = > :opening_metronome
2014-05-06 13:34:38 +00:00
after_create :started_session
after_destroy do | obj |
JamRuby :: MusicSession . removed_music_session ( obj . id )
end
#default_scope :select => "*, 0 as score"
def attributes
super . merge ( 'max_score' = > self . max_score )
end
def max_score
nil unless has_attribute? ( :max_score )
read_attribute ( :max_score ) . to_i
end
before_create :create_uuid
def create_uuid
#self.id = SecureRandom.uuid
end
def before_destroy
2014-10-07 01:03:19 +00:00
feed = Feed . find_by_music_session_id ( self . id )
unless feed . nil?
feed . active = false
feed . save
end
2014-05-06 13:34:38 +00:00
self . mount . destroy if self . mount
end
def creator_is_musician
unless creator . musician?
errors . add ( :creator , ValidationMessages :: MUST_BE_A_MUSICIAN )
end
end
2015-01-07 23:44:56 +00:00
def validate_opening_recording
unless claimed_recording_id_was . nil?
errors . add ( :claimed_recording , ValidationMessages :: CLAIMED_RECORDING_ALREADY_IN_PROGRESS )
end
if is_jam_track_open?
errors . add ( :claimed_recording , ValidationMessages :: JAM_TRACK_ALREADY_OPEN )
end
2015-01-11 20:15:47 +00:00
if is_backing_track_open?
errors . add ( :claimed_recording , ValidationMessages :: BACKING_TRACK_ALREADY_OPEN )
end
if is_metronome_open?
errors . add ( :claimed_recording , ValidationMessages :: METRONOME_ALREADY_OPEN )
end
2015-01-07 23:44:56 +00:00
end
def validate_opening_jam_track
2015-01-11 20:15:47 +00:00
validate_other_audio ( :jam_track )
end
def validate_opening_backing_track
validate_other_audio ( :backing_track )
end
def validate_opening_metronome
validate_other_audio ( :metronome )
end
def validate_other_audio ( error_key )
# validate that there is no backing track already open in this session
2015-01-12 23:44:20 +00:00
if backing_track_path_was . present?
2015-01-11 20:15:47 +00:00
errors . add ( error_key , ValidationMessages :: BACKING_TRACK_ALREADY_OPEN )
end
2015-01-07 23:44:56 +00:00
# validate that there is no jam track already open in this session
2015-01-12 23:44:20 +00:00
if jam_track_id_was . present?
2015-01-11 20:15:47 +00:00
errors . add ( error_key , ValidationMessages :: JAM_TRACK_ALREADY_OPEN )
2015-01-07 23:44:56 +00:00
end
# validate that there is no recording being made
if is_recording?
2015-01-11 20:15:47 +00:00
errors . add ( error_key , ValidationMessages :: RECORDING_ALREADY_IN_PROGRESS )
2015-01-07 23:44:56 +00:00
end
# validate that there is no recording being played back to the session
if is_playing_recording?
2015-01-11 20:15:47 +00:00
errors . add ( error_key , ValidationMessages :: CLAIMED_RECORDING_ALREADY_IN_PROGRESS )
2014-05-06 13:34:38 +00:00
end
end
# returns an array of client_id's that are in this session
# if as_musician is nil, all connections in the session ,regardless if it's a musician or not or not
# you can also exclude a client_id from the returned set by setting exclude_client_id
def get_connection_ids ( options = { } )
as_musician = options [ :as_musician ]
exclude_client_id = options [ :exclude_client_id ]
where = { :music_session_id = > self . id }
where [ :as_musician ] = as_musician unless as_musician . nil?
exclude = " client_id != ' #{ exclude_client_id } ' " unless exclude_client_id . nil?
Connection . select ( :client_id ) . where ( where ) . where ( exclude ) . map ( & :client_id )
end
# This is a little confusing. You can specify *BOTH* friends_only and my_bands_only to be true
# If so, then it's an OR condition. If both are false, you can get sessions with anyone.
def self . index ( current_user , options = { } )
participants = options [ :participants ]
genres = options [ :genres ]
keyword = options [ :keyword ]
friends_only = options [ :friends_only ] . nil? ? false : options [ :friends_only ]
my_bands_only = options [ :my_bands_only ] . nil? ? false : options [ :my_bands_only ]
as_musician = options [ :as_musician ] . nil? ? true : options [ :as_musician ]
2014-05-06 21:17:26 +00:00
query = ActiveMusicSession
. joins (
%Q{
INNER JOIN
2014-05-06 22:50:41 +00:00
music_sessions
2014-05-06 21:17:26 +00:00
ON
2014-05-07 19:16:35 +00:00
active_music_sessions . id = music_sessions . id
2014-05-06 21:17:26 +00:00
}
)
2014-05-06 13:34:38 +00:00
. joins (
%Q{
INNER JOIN
connections
ON
2014-05-06 22:50:41 +00:00
active_music_sessions . id = connections . music_session_id
2014-05-06 13:34:38 +00:00
}
)
. joins (
%Q{
LEFT OUTER JOIN
friendships
ON
connections . user_id = friendships . user_id
AND
friendships . friend_id = '#{current_user.id}'
}
)
. joins (
%Q{
LEFT OUTER JOIN
invitations
ON
2014-05-06 22:50:41 +00:00
invitations . music_session_id = active_music_sessions . id
2014-05-06 13:34:38 +00:00
AND
invitations . receiver_id = '#{current_user.id}'
}
)
. group (
%Q{
2014-05-06 22:50:41 +00:00
active_music_sessions . id
2014-05-06 13:34:38 +00:00
}
)
. order (
%Q{
SUM ( CASE WHEN invitations . id IS NULL THEN 0 ELSE 1 END ) DESC ,
SUM ( CASE WHEN friendships . user_id IS NULL THEN 0 ELSE 1 END ) DESC ,
2014-05-06 22:50:41 +00:00
active_music_sessions . created_at DESC
2014-05-06 13:34:38 +00:00
}
)
if as_musician
query = query . where (
%Q{
musician_access = true
OR
invitations . id IS NOT NULL
}
)
else
# if you are trying to join the session as a fan/listener,
# we have to have a mount, fan_access has to be true, and we have to allow for the reload of icecast to have taken effect
2014-05-06 22:50:41 +00:00
query = query . joins ( 'INNER JOIN icecast_mounts ON icecast_mounts.music_session_id = active_music_sessions.id INNER JOIN icecast_servers ON icecast_mounts.icecast_server_id = icecast_servers.id' )
2014-05-07 15:53:39 +00:00
query = query . where ( 'music_sessions.fan_access = true' )
2014-05-06 22:50:41 +00:00
query = query . where ( " (active_music_sessions.created_at < icecast_servers.config_updated_at) " )
2014-05-06 13:34:38 +00:00
end
2014-05-06 22:50:41 +00:00
query = query . where ( " music_sessions.description like '% #{ keyword } %' " ) unless keyword . nil?
2014-05-06 13:34:38 +00:00
query = query . where ( " connections.user_id " = > participants . split ( ',' ) ) unless participants . nil?
2014-05-06 22:50:41 +00:00
query = query . where ( " music_sessions.genre_id in (?) " , genres ) unless genres . nil?
2014-05-06 13:34:38 +00:00
if my_bands_only
query = query . joins (
%Q{
LEFT OUTER JOIN
bands_musicians
ON
bands_musicians . user_id = '#{current_user.id}'
}
)
end
if my_bands_only || friends_only
query = query . where (
%Q{
#{friends_only ? "friendships.user_id IS NOT NULL" : "false"}
OR
#{my_bands_only ? "bands_musicians.band_id = music_sessions.band_id" : "false"}
}
)
end
return query
end
# This is a little confusing. You can specify *BOTH* friends_only and my_bands_only to be true
# If so, then it's an OR condition. If both are false, you can get sessions with anyone.
# note, this is mostly the same as above but includes paging through the result and and scores.
# thus it needs the client_id...
def self . nindex ( current_user , options = { } )
client_id = options [ :client_id ]
participants = options [ :participants ]
genres = options [ :genres ]
keyword = options [ :keyword ]
friends_only = options [ :friends_only ] . nil? ? false : options [ :friends_only ]
my_bands_only = options [ :my_bands_only ] . nil? ? false : options [ :my_bands_only ]
as_musician = options [ :as_musician ] . nil? ? true : options [ :as_musician ]
offset = options [ :offset ]
limit = options [ :limit ]
connection = Connection . where ( client_id : client_id ) . first!
locidispid = connection . locidispid
2014-05-06 21:17:26 +00:00
query = ActiveMusicSession
2014-05-06 22:50:41 +00:00
. select ( " active_music_sessions.*, max(coalesce(current_scores.score, 1000)) as max_score " ) # 1000 is higher than the allowed max of 999
2014-05-06 13:34:38 +00:00
. joins (
%Q{
INNER JOIN
2014-05-06 22:50:41 +00:00
music_sessions
2014-05-06 13:34:38 +00:00
ON
2014-05-07 19:16:35 +00:00
active_music_sessions . id = music_sessions . id
2014-05-06 13:34:38 +00:00
}
)
. joins (
%Q{
INNER JOIN
connections
ON
2014-05-06 22:50:41 +00:00
active_music_sessions . id = connections . music_session_id
2014-05-06 13:34:38 +00:00
}
)
. joins (
%Q{
LEFT OUTER JOIN
current_scores
ON
current_scores . alocidispid = connections . locidispid
AND
current_scores . blocidispid = #{locidispid}
}
)
. joins (
%Q{
LEFT OUTER JOIN
friendships
ON
connections . user_id = friendships . user_id
AND
friendships . friend_id = '#{current_user.id}'
}
)
. joins (
%Q{
LEFT OUTER JOIN
invitations
ON
2014-05-06 22:50:41 +00:00
invitations . music_session_id = active_music_sessions . id
2014-05-06 13:34:38 +00:00
AND
invitations . receiver_id = '#{current_user.id}'
}
)
. group (
%Q{
2014-05-06 22:50:41 +00:00
active_music_sessions . id
2014-05-06 13:34:38 +00:00
}
)
. order (
%Q{
SUM ( CASE WHEN invitations . id IS NULL THEN 0 ELSE 1 END ) DESC ,
SUM ( CASE WHEN friendships . user_id IS NULL THEN 0 ELSE 1 END ) DESC ,
2014-05-06 22:50:41 +00:00
active_music_sessions . created_at DESC
2014-05-06 13:34:38 +00:00
}
)
2015-01-12 06:20:19 +00:00
query = query . offset ( offset ) if offset
query = query . limit ( limit ) if limit
2014-05-06 13:34:38 +00:00
if as_musician
query = query . where (
%Q{
musician_access = true
OR
2014-05-06 22:50:41 +00:00
music_sessions . user_id = '#{current_user.id}'
2014-05-06 13:34:38 +00:00
OR
invitations . id IS NOT NULL
}
)
else
# if you are trying to join the session as a fan/listener,
# we have to have a mount, fan_access has to be true, and we have to allow for the reload of icecast to have taken effect
2014-05-06 22:50:41 +00:00
query = query . joins ( 'INNER JOIN icecast_mounts ON icecast_mounts.music_session_id = active_music_sessions.id INNER JOIN icecast_servers ON icecast_mounts.icecast_server_id = icecast_servers.id' )
2014-05-07 19:16:35 +00:00
query = query . where ( 'music_sessions.fan_access = true' )
2014-05-06 22:50:41 +00:00
query = query . where ( " (active_music_sessions.created_at < icecast_servers.config_updated_at) " )
2014-05-06 13:34:38 +00:00
end
2014-05-06 22:50:41 +00:00
query = query . where ( " music_sessions.description like '% #{ keyword } %' " ) unless keyword . nil?
2014-05-06 13:34:38 +00:00
query = query . where ( " connections.user_id " = > participants . split ( ',' ) ) unless participants . nil?
2014-05-06 22:50:41 +00:00
query = query . where ( " music_sessions.genre_id in (?) " , genres ) unless genres . nil?
2014-05-06 13:34:38 +00:00
if my_bands_only
query = query . joins (
%Q{
LEFT OUTER JOIN
bands_musicians
ON
bands_musicians . user_id = '#{current_user.id}'
}
)
end
if my_bands_only || friends_only
query = query . where (
%Q{
#{friends_only ? "friendships.user_id IS NOT NULL" : "false"}
OR
#{my_bands_only ? "bands_musicians.band_id = music_sessions.band_id" : "false"}
}
)
end
return query
end
2014-06-15 15:35:15 +00:00
# initialize the two temporary tables we use to drive ams_index and ams_users
2014-06-15 02:27:34 +00:00
def self . ams_init ( current_user , options = { } )
2014-08-18 15:37:55 +00:00
my_locidispid = current_user . last_jam_locidispid
2014-06-17 19:10:24 +00:00
# 13 is an average audio gear value we use if they have not qualified any gear
2014-08-18 15:37:55 +00:00
my_audio_latency = current_user . last_jam_audio_latency || 13
2014-07-23 20:11:02 +00:00
locidispid_expr = my_locidispid ? " #{ my_locidispid } ::bigint " : '0::bigint'
2014-06-15 02:27:34 +00:00
2014-07-23 20:11:02 +00:00
self . connection . execute ( " select ams_index(' #{ current_user . id } '::varchar, #{ locidispid_expr } , #{ my_audio_latency } ::integer) " ) . check
2014-06-15 02:27:34 +00:00
end
2014-06-14 00:47:34 +00:00
# Generate a list of music sessions (that are active) filtered by genre, language, keyword, and sorted
2014-06-15 15:35:15 +00:00
# (and tagged) by rsvp'd (1st), invited (2nd), and musician can join (3rd). within a group tagged the
# same, sorted by score. date seems irrelevant as these are active sessions. ams_init must be called
# first.
2014-06-17 19:10:24 +00:00
def self . ams_query ( current_user , options = { } )
2014-06-28 17:06:32 +00:00
session_id = options [ :session_id ]
2014-06-13 17:38:36 +00:00
client_id = options [ :client_id ]
genre = options [ :genre ]
lang = options [ :lang ]
keyword = options [ :keyword ]
offset = options [ :offset ]
limit = options [ :limit ]
2014-06-17 22:16:49 +00:00
day = options [ :day ]
timezone_offset = options [ :timezone_offset ]
2014-06-13 17:38:36 +00:00
2014-06-14 00:47:34 +00:00
query = MusicSession
2014-06-14 04:51:54 +00:00
. select ( 'music_sessions.*' )
2014-06-14 00:47:34 +00:00
2014-06-15 02:27:34 +00:00
# this is not really needed when ams_music_session_tmp is joined
2014-06-14 00:47:34 +00:00
# unless there is something specific we need out of active_music_sessions
2014-06-13 17:38:36 +00:00
# query = query.joins(
# %Q{
# INNER JOIN
2014-06-15 02:27:34 +00:00
# active_music_sessions
2014-06-13 17:38:36 +00:00
# ON
2014-06-15 02:27:34 +00:00
# active_music_sessions.id = music_sessions.id
2014-06-13 17:38:36 +00:00
# }
# )
2014-06-15 02:27:34 +00:00
# .select('1::integer as tag, 15::integer as latency')
# integrate ams_music_session_tmp into the processing
# then we can join ams_music_session_tmp and not join active_music_sessions
query = query . joins (
%Q{
INNER JOIN
ams_music_session_tmp
ON
ams_music_session_tmp . music_session_id = music_sessions . id
}
)
. select ( 'ams_music_session_tmp.tag, ams_music_session_tmp.latency' )
2014-06-13 17:38:36 +00:00
query = query . order (
%Q{
2014-06-14 04:51:54 +00:00
tag , latency , music_sessions . id
}
)
. group (
%Q{
tag , latency , music_sessions . id
2014-06-13 17:38:36 +00:00
}
)
2014-06-17 22:16:49 +00:00
# if not specified, default offset to 0
offset || = 0
offset = offset . to_i
# if not specified, default limit to 20
limit || = 20
limit = limit . to_i
query = query . offset ( offset )
query = query . limit ( limit )
query = query . where ( " music_sessions.genre_id = ? " , genre ) unless genre . blank?
query = query . where ( 'music_sessions.language = ?' , lang ) unless lang . blank?
2014-06-28 17:06:32 +00:00
query = query . where ( 'music_sessions.id = ?' , session_id ) unless session_id . blank?
2014-08-15 02:28:30 +00:00
query = query . where ( " (description_tsv @@ to_tsquery('jamenglish', ?)) " , ActiveRecord :: Base . connection . quote ( keyword ) + ':*' ) unless keyword . blank?
2014-06-17 22:16:49 +00:00
if ! day . blank? && ! timezone_offset . blank?
begin
day = Date . parse ( day )
next_day = day + 1
timezone_offset = timezone_offset . to_i
2014-06-26 02:50:20 +00:00
if timezone_offset > 0
timezone_offset = " + #{ timezone_offset } "
end
2014-06-17 22:16:49 +00:00
query = query . where ( " scheduled_start BETWEEN TIMESTAMP WITH TIME ZONE ' #{ day } 00:00:00 #{ timezone_offset } '
AND TIMESTAMP WITH TIME ZONE '#{next_day} 00:00:00#{timezone_offset}' " )
rescue Exception = > e
# do nothing. bad date probably
@@log . warn ( " unable to parse day= #{ day } , timezone_offset= #{ timezone_offset } , e= #{ e } " )
2014-06-13 17:38:36 +00:00
end
end
return query
end
2014-06-15 15:35:15 +00:00
# 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.
2014-06-16 20:41:37 +00:00
# user.audio_latency / 2 , + other_user.audio_latency of them / 2, + network latency /2
2014-06-16 20:58:44 +00:00
def self . ams_users
2014-08-18 15:37:55 +00:00
return User . select ( 'users.*, ams_users_tmp.music_session_id, ams_users_tmp.full_score, ams_users_tmp.audio_latency, ams_users_tmp.internet_score' )
2014-06-15 15:35:15 +00:00
. joins (
%Q{
INNER JOIN
ams_users_tmp
ON
ams_users_tmp . user_id = users . id
}
)
. order ( 'ams_users_tmp.music_session_id, ams_users_tmp.user_id' )
end
2014-06-17 19:10:24 +00:00
# wrap me in a transaction!
# note that these queries must be actualized before the end of the transaction
# else the temporary tables created by sms_init will be gone.
def self . ams_index ( current_user , params )
ActiveMusicSession . ams_init ( current_user , params )
2014-06-17 22:16:49 +00:00
music_sessions = ActiveMusicSession . ams_query ( current_user , params ) . all
2014-06-17 19:10:24 +00:00
music_session_users = ActiveMusicSession . ams_users . all
user_scores = { }
music_session_users . each do | user |
2014-08-18 15:37:55 +00:00
user_scores [ user . id ] = { full_score : user . full_score , audio_latency : user . audio_latency , internet_score : user . internet_score }
2014-06-17 19:10:24 +00:00
end
[ music_sessions , user_scores ]
end
2016-10-27 23:24:54 +00:00
def self . participant_create ( user , music_session_id , client_id , as_musician , tracks , audio_latency , client_role = nil , parent_client_id = nil , video_sources = nil )
2014-05-20 13:26:32 +00:00
music_session = MusicSession . find ( music_session_id )
2014-10-13 12:40:10 +00:00
# USERS ARE ALREADY IN SESSION
2014-05-20 13:26:32 +00:00
if music_session . active_music_session
connection = nil
2014-09-14 19:12:25 +00:00
active_music_session = music_session . active_music_session
2014-05-20 13:26:32 +00:00
ActiveRecord :: Base . transaction do
active_music_session . with_lock do # VRFS-1297
active_music_session . tick_track_changes
2016-03-22 16:14:32 +00:00
# VRFS-3986
2016-10-27 23:24:54 +00:00
connection = ConnectionManager . new . join_music_session ( user , client_id , active_music_session , as_musician , tracks , audio_latency , client_role , parent_client_id , video_sources )
2014-05-20 13:26:32 +00:00
if connection . errors . any?
# rollback the transaction to make sure nothing is disturbed in the database
raise ActiveRecord :: Rollback
end
end
end
unless connection . errors . any?
user . update_progression_field ( :first_music_session_at )
MusicSessionUserHistory . save ( music_session_id , user . id , client_id , tracks )
if as_musician
# send to session participants
2014-09-14 19:12:25 +00:00
Notification . send_session_join ( active_music_session , connection , user )
2014-05-20 13:26:32 +00:00
# send "musician joined session" notification only if it's not a band session since there will be a "band joined session" notification
if music_session . band . nil?
2014-09-13 02:57:03 +00:00
Notification . send_musician_session_join ( music_session , user )
2014-05-20 13:26:32 +00:00
end
end
end
connection
2014-10-13 12:40:10 +00:00
# FIRST USER TO JOIN SESSION
2014-05-20 13:26:32 +00:00
else
return_value = nil
time = Benchmark . realtime do
ActiveRecord :: Base . transaction do
# we need to lock the icecast server in this transaction for writing, to make sure thath IcecastConfigWriter
# doesn't dumpXML as we are changing the server's configuraion
icecast_server = IcecastServer . find_best_server_for_user ( user ) if music_session . fan_access
icecast_server . lock! if icecast_server
# check if we are connected to rabbitmq
active_music_session = ActiveMusicSession . new
active_music_session . id = music_session . id # copy the .id from music_session to active_music_session
active_music_session . creator = user
if music_session . fan_access
# create an icecast mount since regular users can listen in to the broadcast
active_music_session . mount = IcecastMount . build_session_mount ( music_session , active_music_session , icecast_server )
end
active_music_session . save
unless active_music_session . errors . any?
2014-05-22 08:02:48 +00:00
music_session . started_at = active_music_session . created_at
music_session . save ( :validate = > false )
2014-05-20 13:26:32 +00:00
# save session parameters for next session
User . save_session_settings ( user , music_session )
# auto-join this user into the newly created session
as_musician = true
2016-10-27 23:24:54 +00:00
connection = ConnectionManager . new . join_music_session ( user , client_id , active_music_session , as_musician , tracks , audio_latency , client_role , parent_client_id , video_sources )
2014-05-20 13:26:32 +00:00
unless connection . errors . any?
user . update_progression_field ( :first_music_session_at )
MusicSessionUserHistory . save ( active_music_session . id , user . id , client_id , tracks )
2016-03-03 22:08:01 +00:00
Notification . send_session_join ( active_music_session , connection , user )
2014-05-20 13:26:32 +00:00
# only send this notification if it's a band session
unless music_session . band . nil?
2014-09-13 02:57:03 +00:00
Notification . send_band_session_join ( music_session , music_session . band )
else
Notification . send_musician_session_join ( music_session , user )
2014-05-20 13:26:32 +00:00
end
2014-05-21 16:24:40 +00:00
return_value = connection
2014-05-20 13:26:32 +00:00
else
return_value = connection
# rollback the transaction to make sure nothing is disturbed in the database
raise ActiveRecord :: Rollback
end
else
return_value = active_music_session
# rollback the transaction to make sure nothing is disturbed in the database
raise ActiveRecord :: Rollback
end
end
end
if time > 2
Logging . logger [ self ] . warn " creating a music session took #{ time * 1000 } milliseconds "
end
return_value
end
end
2014-05-06 13:34:38 +00:00
# Verifies that the specified user can delete this music session
def can_delete? user
# the creator can delete
self . creator == user
end
def access? user
music_session . part_of_session? user
end
def most_recent_recording
recordings . where ( :music_session_id = > self . id ) . order ( 'created_at desc' ) . limit ( 1 ) . first
end
2015-01-07 23:44:56 +00:00
def is_jam_track_open?
! self . jam_track . nil?
end
2015-01-11 20:15:47 +00:00
def is_backing_track_open?
2015-01-12 23:44:20 +00:00
self . backing_track_path . present?
2015-01-11 20:15:47 +00:00
end
def is_metronome_open?
2015-01-12 23:44:20 +00:00
self . metronome_active . present?
2015-01-11 20:15:47 +00:00
end
2014-05-06 13:34:38 +00:00
# is this music session currently recording?
def is_recording?
recordings . where ( :duration = > nil ) . count > 0
end
def is_playing_recording?
! self . claimed_recording . nil?
end
def recording
recordings . where ( :duration = > nil ) . first
end
# stops any active recording
def stop_recording
current_recording = self . recording
current_recording . stop unless current_recording . nil?
end
def claimed_recording_start ( owner , claimed_recording )
self . claimed_recording = claimed_recording
self . claimed_recording_initiator = owner
2015-01-07 23:44:56 +00:00
self . opening_recording = true
2014-05-06 13:34:38 +00:00
self . save
2015-01-07 23:44:56 +00:00
self . opening_recording = false
2014-05-06 13:34:38 +00:00
end
def claimed_recording_stop
self . claimed_recording = nil
self . claimed_recording_initiator = nil
self . save
end
2014-05-06 21:17:26 +00:00
def invitations
music_session . invitations
end
2014-05-06 13:34:38 +00:00
def invited_musicians
music_session . invited_musicians
end
def join_requests
music_session . join_requests
end
def fan_invitations
music_session . fan_invitations
end
def to_s
description
end
def musician_access
music_session . musician_access
end
def fan_access
music_session . fan_access
end
def description
music_session . description
end
2014-06-18 14:54:08 +00:00
def name
music_session . name
end
2014-05-06 13:34:38 +00:00
def genre
music_session . genre
end
def fan_chat
music_session . fan_chat
end
2014-05-06 21:17:26 +00:00
def band
music_session . band
2014-05-06 13:34:38 +00:00
end
2014-05-06 21:17:26 +00:00
def approval_required
music_session . approval_required
2014-05-06 13:34:38 +00:00
end
2014-06-27 03:07:48 +00:00
def music_notations
music_session . music_notations
end
2014-09-08 21:51:28 +00:00
# Verifies that the specified user can join this music session
def can_join? user , as_musician
music_session . can_join? user , as_musician
end
# Verifies that the specified user can see this music session
def can_see? user
music_session . can_see? user
end
2014-05-06 13:34:38 +00:00
def tick_track_changes
self . track_changes_counter += 1
self . save! ( :validate = > false )
end
def connected_participant_count
Connection . where ( :music_session_id = > self . id ,
:aasm_state = > Connection :: CONNECT_STATE . to_s ,
:as_musician = > true )
. count
end
def started_session
2014-05-06 21:17:26 +00:00
raise " active_music_sessions.id must be set by caller " unless self . id
# associate this active_music_session with the music_session formally
session = MusicSession . find ( self . id )
session . active_music_session = self
2014-07-14 21:43:46 +00:00
self . music_session = session # needed because of the Google Analytics below in some test cases
session . scheduled_start = self . created_at unless session . scheduled_start
2014-05-06 21:17:26 +00:00
session . save!
2014-10-11 12:53:26 +00:00
feed = Feed . find_by_music_session_id ( self . id )
2014-10-11 17:57:05 +00:00
# this should never be hit since the feed entry is created when the music_session record is created
2014-10-11 12:53:26 +00:00
if feed . nil?
feed = Feed . new
feed . music_session_id = self . id
end
2014-10-11 17:57:05 +00:00
2014-10-11 12:53:26 +00:00
feed . active = true
feed . save
2016-05-28 02:33:26 +00:00
#GoogleAnalyticsEvent.track_session_duration(self)
#GoogleAnalyticsEvent.track_band_real_session(self)
2014-05-06 13:34:38 +00:00
end
2015-01-07 23:44:56 +00:00
def open_jam_track ( user , jam_track )
self . jam_track = jam_track
self . jam_track_initiator = user
self . opening_jam_track = true
self . save
self . opening_jam_track = false
2016-01-04 03:38:30 +00:00
JamTrackSession . create_session ( jam_track , user , self . music_session ) if jam_track && user
2015-05-15 17:34:35 +00:00
#self.tick_track_changes
2015-01-07 23:44:56 +00:00
end
def close_jam_track
self . jam_track = nil
self . jam_track_initiator = nil
self . save
end
2014-05-06 13:34:38 +00:00
2015-01-12 23:44:20 +00:00
# @param backing_track_path is a relative path:
def open_backing_track ( user , backing_track_path )
self . backing_track_path = backing_track_path
self . backing_track_initiator = user
self . opening_backing_track = true
self . save
self . opening_backing_track = false
end
def close_backing_track
self . backing_track_path = nil
self . backing_track_initiator = nil
self . save
end
def open_metronome ( user )
self . metronome_active = true
self . metronome_initiator = user
self . opening_metronome = true
self . save
self . opening_metronome = false
end
def close_metronome
self . metronome_active = false
self . metronome_initiator = nil
self . save
end
2014-05-06 13:34:38 +00:00
def self . sync ( session_history )
music_session = MusicSession . find_by_id ( session_history . id )
if music_session . nil?
music_session = MusicSession . new
music_session . id = session_history . id
end
music_session . user_id = session_history . creator . id
music_session . band_id = session_history . band . id unless session_history . band . nil?
session_history . save!
end
2015-05-04 19:37:49 +00:00
def self . stats
stats = { }
2016-07-17 15:16:27 +00:00
result = ActiveMusicSession . select ( 'count(distinct(id)) AS total, count(distinct(jam_track_initiator_id)) as jam_track_count, count(distinct(backing_track_initiator_id)) as backing_track_count, count(distinct(metronome_initiator_id)) as metronome_count, count(distinct(claimed_recording_initiator_id)) as recording_count' ) [ 0 ]
2015-05-04 19:37:49 +00:00
stats [ 'count' ] = result [ 'total' ] . to_i
stats [ 'jam_track_count' ] = result [ 'jam_track_count' ] . to_i
stats [ 'backing_track_count' ] = result [ 'backing_track_count' ] . to_i
stats [ 'metronome_count' ] = result [ 'metronome_count' ] . to_i
stats [ 'recording_count' ] = result [ 'recording_count' ] . to_i
stats
end
2016-05-07 18:45:02 +00:00
def lesson_session
music_session . lesson_session
end
2014-05-06 13:34:38 +00:00
end
end