jam-cloud/ruby/lib/jam_ruby/models/active_music_session.rb

991 lines
34 KiB
Ruby
Raw Permalink Normal View History

2014-05-06 13:34:38 +00:00
module JamRuby
class ActiveMusicSession < ActiveRecord::Base
@@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'
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"
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"
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'
belongs_to :creator, :class_name => 'JamRuby::User', :foreign_key => :user_id
2014-05-06 13:34:38 +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"
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
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
# 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
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
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
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
if backing_track_path_was.present?
2015-01-11 20:15:47 +00:00
errors.add(error_key, ValidationMessages::BACKING_TRACK_ALREADY_OPEN)
end
# validate that there is no jam track already open in this session
if jam_track_id_was.present?
2015-01-11 20:15:47 +00:00
errors.add(error_key, ValidationMessages::JAM_TRACK_ALREADY_OPEN)
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)
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]
query = ActiveMusicSession
.joins(
%Q{
INNER JOIN
2014-05-06 22:50:41 +00:00
music_sessions
ON
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
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
}
)
query = Search.scope_schools_together_sessions(query, current_user)
2020-10-14 02:05:08 +00:00
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')
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
2020-04-29 20:51:50 +00:00
# all sessions that are private and active, yet I can see
def self.friend_active_index(user, options)
session_id = options[:session_id]
genre = options[:genre]
lang = options[:lang]
keyword = options[:keyword]
offset = options[:offset]
limit = options[:limit]
query = MusicSession.select('music_sessions.*')
query = query.joins("INNER JOIN active_music_sessions ON music_sessions.id = active_music_sessions.id")
# one flaw in the join below is that we only consider if the creator of the session has asked you to be your friend, but you have not accepted. While this means you may always see a session by someone you haven't friended, the goal is to match up new users more quickly
query = query.joins(
%Q{
LEFT OUTER JOIN
rsvp_requests
2020-05-06 19:42:52 +00:00
ON rsvp_requests.music_session_id = active_music_sessions.id and rsvp_requests.user_id = '#{user.id}' AND rsvp_requests.chosen = true
2020-04-29 20:51:50 +00:00
LEFT OUTER JOIN
invitations
ON
active_music_sessions.id = invitations.music_session_id AND invitations.receiver_id = '#{user.id}'
LEFT OUTER JOIN
friendships
ON
active_music_sessions.user_id = friendships.user_id AND friendships.friend_id = '#{user.id}'
LEFT OUTER JOIN
friendships as friendships_2
ON
active_music_sessions.user_id = friendships_2.friend_id AND friendships_2.user_id = '#{user.id}'
}
)
# keep only rsvp/invitation/friend results. Nice tailored active list now!
query = query.where("rsvp_requests.id IS NOT NULL OR invitations.id IS NOT NULL or active_music_sessions.user_id = '#{user.id}' OR (friendships.id IS NOT NULL AND friendships_2.id IS NOT NULL)")
# 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?
query = query.where('music_sessions.id = ?', session_id) unless session_id.blank?
query = query.where("(description_tsv @@ to_tsquery('jamenglish', ?))", ActiveRecord::Base.connection.quote(keyword) + ':*') unless keyword.blank?
2020-05-06 19:42:52 +00:00
query = query.group("music_sessions.id, active_music_sessions.created_at")
query = query.order("active_music_sessions.created_at DESC")
2020-04-29 20:51:50 +00:00
query
end
# all sessions that are private and active, yet I can see
2020-10-14 02:05:08 +00:00
def self.public_index(user, options)
2020-04-29 20:51:50 +00:00
session_id = options[:session_id]
genre = options[:genre]
lang = options[:lang]
keyword = options[:keyword]
offset = options[:offset]
limit = options[:limit]
query = MusicSession.select('music_sessions.*')
query = query.joins("INNER JOIN active_music_sessions ON music_sessions.id = active_music_sessions.id")
query = query.where("musician_access = TRUE")
2020-10-14 02:05:08 +00:00
query = Search.scope_schools_together_sessions(query, user)
2020-04-29 20:51:50 +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?
query = query.where('music_sessions.id = ?', session_id) unless session_id.blank?
query = query.where("(description_tsv @@ to_tsquery('jamenglish', ?))", ActiveRecord::Base.connection.quote(keyword) + ':*') unless keyword.blank?
2020-05-06 19:42:52 +00:00
query = query.group("music_sessions.id, active_music_sessions.created_at")
query = query.order("active_music_sessions.created_at DESC")
2020-04-29 20:51:50 +00:00
query
end
2014-05-06 13:34:38 +00:00
# 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
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
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
}
)
query = Search.scope_schools_together_sessions(query, current_user)
2020-10-14 02:05:08 +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')
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
# initialize the two temporary tables we use to drive ams_index and ams_users
def self.ams_init(current_user, options = {})
2014-08-18 15:37:55 +00:00
my_locidispid = current_user.last_jam_locidispid
# 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
locidispid_expr = my_locidispid ? "#{my_locidispid}::bigint" : '0::bigint'
self.connection.execute("select ams_index('#{current_user.id}'::varchar, #{locidispid_expr}, #{my_audio_latency}::integer)").check
end
# Generate a list of music sessions (that are active) filtered by genre, language, keyword, and sorted
# (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.
def self.ams_query(current_user, options = {})
session_id = options[:session_id]
client_id = options[:client_id]
genre = options[:genre]
lang = options[:lang]
keyword = options[:keyword]
offset = options[:offset]
limit = options[:limit]
day = options[:day]
timezone_offset = options[:timezone_offset]
query = MusicSession
.select('music_sessions.*')
# this is not really needed when ams_music_session_tmp is joined
# unless there is something specific we need out of active_music_sessions
# query = query.joins(
# %Q{
# INNER JOIN
# active_music_sessions
# ON
# active_music_sessions.id = music_sessions.id
# }
# )
# .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')
query = query.order(
%Q{
tag, latency, music_sessions.id
}
)
.group(
%Q{
tag, latency, music_sessions.id
}
)
# 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?
query = query.where('music_sessions.id = ?', session_id) unless session_id.blank?
query = query.where("(description_tsv @@ to_tsquery('jamenglish', ?))", ActiveRecord::Base.connection.quote(keyword) + ':*') unless keyword.blank?
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
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}")
end
end
return query
end
# 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
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')
.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
# NOTE: unused anymore!
#
# 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)
music_sessions = ActiveMusicSession.ams_query(current_user, params).all
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}
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)
# 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
2020-11-03 19:24:00 +00:00
Notification.send_tracks_changed(active_music_session)
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?
Notification.send_musician_session_join(music_session, user)
2014-05-20 13:26:32 +00:00
end
end
end
connection
# 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
music_session.running_recordings.each do |recording|
recording.stop
end
2014-05-20 13:26:32 +00:00
# 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
2020-10-14 02:05:08 +00:00
active_music_session.school_id = user.school_id
active_music_session.is_platform_instructor = user.is_platform_instructor
2014-05-20 13:26:32 +00:00
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)
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?
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
def is_jam_track_open?
!self.jam_track.nil?
end
2015-01-11 20:15:47 +00:00
def is_backing_track_open?
self.backing_track_path.present?
2015-01-11 20:15:47 +00:00
end
def is_metronome_open?
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
self.opening_recording = true
2014-05-06 13:34:38 +00:00
self.save
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
2020-05-06 19:42:52 +00:00
def friends_can_join
music_session.friends_can_join
end
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 is_lesson_member?(user)
music_session.is_lesson_member?(user)
end
2014-05-06 13:34:38 +00:00
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
def band
music_session.band
2014-05-06 13:34:38 +00:00
end
def approval_required
music_session.approval_required
2014-05-06 13:34:38 +00:00
end
def music_notations
music_session.music_notations
end
2020-05-08 04:40:57 +00:00
def music_session_id_int
music_session.music_session_id_int
end
# 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
2021-08-24 13:54:16 +00:00
def use_video_conferencing_server
music_session.use_video_conferencing_server
end
2014-05-06 13:34:38 +00:00
def tick_track_changes
self.track_changes_counter += 1
self.save!(:validate => false)
end
def in_session?(user)
self.users.exists?(user.id)
end
2014-05-06 13:34:38 +00:00
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
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
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
session.save!
feed = Feed.find_by_music_session_id(self.id)
# this should never be hit since the feed entry is created when the music_session record is created
if feed.nil?
feed = Feed.new
feed.music_session_id = self.id
end
2020-10-14 02:05:08 +00:00
feed.school_id = self.school_id
feed.is_platform_instructor = self.is_platform_instructor
feed.active = true
feed.save
#GoogleAnalyticsEvent.track_session_duration(self)
#GoogleAnalyticsEvent.track_band_real_session(self)
2014-05-06 13:34:38 +00:00
end
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
#self.tick_track_changes
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
# @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
2020-11-21 22:14:37 +00:00
def play_time_remaining(user)
rules = SubscriptionDefinitions.rules(user.subscription_plan_code)
play_time_per_session = rules[:play_time_per_session]
if play_time_per_session.nil?
nil
else
(play_time_per_session * 3600) - MusicSessionUserHistory.where(music_session_id: self.id).where(user_id: user.id).sum("extract('epoch' from (COALESCE(session_removed_at, NOW()) - created_at))")
end
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 = {}
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
2021-08-24 13:54:16 +00:00
end