require "opentok/client" require "opentok/archive" require "opentok/archive_list" module OpenTok # A class for working with OpenTok archives. class Archives # @private def initialize(client) @client = client end # Starts archiving an OpenTok session. # # Clients must be actively connected to the OpenTok session for you to successfully start # recording an archive. # # You can only record one archive at a time for a given session. You can only record archives # of sessions that use the OpenTok Media Router (sessions with the media mode set to routed); # you cannot archive sessions with the media mode set to relayed. # # For more information on archiving, see the # {https://tokbox.com/opentok/tutorials/archiving OpenTok archiving} programming guide. # # @param [String] session_id The session ID of the OpenTok session to archive. # @param [Hash] options A hash with the keys 'name', 'has_audio', 'has_video', # and 'output_mode'. # @option options [String] :name This is the name of the archive. You can use this name # to identify the archive. It is a property of the Archive object, and it is a property # of archive-related events in the OpenTok client SDKs. # @option options [true, false] :has_audio Whether the archive will include an audio track # (true) or not false). The default value is true # (an audio track is included). If you set both has_audio and # has_video to false, the call to the create() # method results in an error. # @option options [true, false] :has_video Whether the archive will include a video track # (true) or not false). The default value is true # (a video track is included). If you set both has_audio and # has_video to false, the call to the create() # method results in an error. # @option options [String] :output_mode Whether all streams in the archive are recorded # to a single file (:composed, the default) or to individual files # (:individual). For more information on archiving and the archive file # formats, see the {https://tokbox.com/opentok/tutorials/archiving OpenTok archiving} # programming guide. # @option options [String] :resolution The resolution of the archive, either "640x480" (SD, the # default) or "1280x720" (HD). This property only applies to composed archives. If you set # this property and set the outputMode property to "individual", the call the method # results in an error. # @option options [Hash] :layout Specify this to assign the initial layout type for # the archive. This applies only to composed archives. This is a hash containing three keys: # :type, :stylesheet and :screenshare_type. # Valid values for :type are "bestFit" (best fit), "custom" (custom), # "horizontalPresentation" (horizontal presentation), # "pip" (picture-in-picture), and "verticalPresentation" (vertical presentation)). # If you specify a "custom" layout type, set the :stylesheet key to the # stylesheet (CSS). (For other layout types, do not set the :stylesheet key.) # Valid values for :screenshare_type are "bestFit", "pip", # "verticalPresentation", "horizontalPresentation". This property is optional. # If it is specified, then the :type property **must** be set to "bestFit". # If you do not specify an initial layout type, the archive uses the best fit # layout type. For more information, see # {https://tokbox.com/developer/guides/archiving/layout-control.html Customizing # the video layout for composed archives}. # # @return [Archive] The Archive object, which includes properties defining the archive, # including the archive ID. # # @raise [OpenTokArchiveError] The archive could not be started. The request was invalid or # the session has no connected clients. # @raise [OpenTokAuthenticationError] Authentication failed while starting an archive. # Invalid API key. # @raise [OpenTokArchiveError] The archive could not be started. The session ID does not exist. # @raise [OpenTokArchiveError] The archive could not be started. The session could be # peer-to-peer or the session is already being recorded. # @raise [OpenTokArchiveError] The archive could not be started. def create(session_id, options = {}) raise ArgumentError, "session_id not provided" if session_id.to_s.empty? raise ArgumentError, "Resolution cannot be supplied for individual output mode" if options.key?(:resolution) and options[:output_mode] == :individual # normalize opts so all keys are symbols and only include valid_opts valid_opts = [ :name, :has_audio, :has_video, :output_mode, :resolution, :layout ] opts = options.inject({}) do |m,(k,v)| if valid_opts.include? k.to_sym m[k.to_sym] = v end m end archive_json = @client.start_archive(session_id, opts) Archive.new self, archive_json end # Gets an Archive object for the given archive ID. # # @param [String] archive_id The archive ID. # # @return [Archive] The Archive object. # @raise [OpenTokArchiveError] The archive could not be retrieved. The archive ID is invalid. # @raise [OpenTokAuthenticationError] Authentication failed while retrieving the archive. # Invalid API key. # @raise [OpenTokArchiveError] The archive could not be retrieved. def find(archive_id) raise ArgumentError, "archive_id not provided" if archive_id.to_s.empty? archive_json = @client.get_archive(archive_id.to_s) Archive.new self, archive_json end # Returns an ArchiveList, which is an array of archives that are completed and in-progress, # for your API key. # # @param [Hash] options A hash with keys defining which range of archives to retrieve. # @option options [integer] :offset Optional. The index offset of the first archive. 0 is offset # of the most recently started archive. 1 is the offset of the archive that started prior to # the most recent archive. If you do not specify an offset, 0 is used. # @option options [integer] :count Optional. The number of archives to be returned. The maximum # number of archives returned is 1000. # @option options [String] :session_id Optional. The session ID that archives belong to. This is # useful when listing multiple archives for an {https://tokbox.com/developer/guides/archiving/#automatic-archives automatically archived session}. # # @return [ArchiveList] An ArchiveList object, which is an array of Archive objects. def all(options = {}) raise ArgumentError, "Limit is invalid" unless options[:count].nil? or (0..1000).include? options[:count] archive_list_json = @client.list_archives(options[:offset], options[:count], options[:sessionId]) ArchiveList.new self, archive_list_json end # Stops an OpenTok archive that is being recorded. # # Archives automatically stop recording after 120 minutes or when all clients have disconnected # from the session being archived. # # @param [String] archive_id The archive ID of the archive you want to stop recording. # # @return [Archive] The Archive object corresponding to the archive being stopped. # # @raise [OpenTokArchiveError] The archive could not be stopped. The request was invalid. # @raise [OpenTokAuthenticationError] Authentication failed while stopping an archive. # @raise [OpenTokArchiveError] The archive could not be stopped. The archive ID does not exist. # @raise [OpenTokArchiveError] The archive could not be stopped. The archive is not currently # recording. # @raise [OpenTokArchiveError] The archive could not be started. def stop_by_id(archive_id) raise ArgumentError, "archive_id not provided" if archive_id.to_s.empty? archive_json = @client.stop_archive(archive_id) Archive.new self, archive_json end # Deletes an OpenTok archive. # # You can only delete an archive which has a status of "available", "uploaded", or "deleted". # Deleting an archive removes its record from the list of archives. For an "available" archive, # it also removes the archive file, making it unavailable for download. For a "deleted" # archive, the archive remains deleted. # # @param [String] archive_id The archive ID of the archive you want to delete. # # @raise [OpenTokAuthenticationError] Authentication failed or an invalid archive ID was given. # @raise [OpenTokArchiveError] The archive could not be deleted. The status must be # 'available', 'deleted', or 'uploaded'. # @raise [OpenTokArchiveError] The archive could not be deleted. def delete_by_id(archive_id) raise ArgumentError, "archive_id not provided" if archive_id.to_s.empty? response = @client.delete_archive(archive_id) (200..300).include? response.code end # Sets the layout type for a composed archive. For a description of layout types, see # {https://tokbox.com/developer/guides/archiving/layout-control.html Customizing # the video layout for composed archives}. # # @param [String] archive_id # The archive ID. # # @option options [String] :type # The layout type. Set this to "bestFit", "pip", "verticalPresentation", # "horizontalPresentation", "focus", or "custom". # # @option options [String] :stylesheet # The stylesheet for a custom layout. Set this parameter # if you set type to "custom". Otherwise, leave it undefined. # # @option options [String] :screenshare_type # The screenshare layout type. Set this to "bestFit", "pip", "verticalPresentation" or # "horizonalPresentation". If this is defined, then the type parameter # must be set to "bestFit". # # @raise [ArgumentError] # The archive_id or options parameter is empty. Or the "custom" # type was specified without a stylesheet option. Or a stylesheet was passed in for a # type other than custom. Or an invalid type was passed in. # # @raise [OpenTokAuthenticationError] # Authentication failed. # # @raise [ArgumentError] # The archive_id or options parameter is empty. # # @raise [ArgumentError] # The "custom" type was specified without a stylesheet option. # # @raise [ArgumentError] # A stylesheet was passed in for a type other than custom. Or an invalid type was passed in. # # @raise [ArgumentError] # An invalid layout type was passed in. # # @raise [OpenTokError] # OpenTok server error. # # @raise [OpenTokArchiveError] # Setting the layout failed. def layout(archive_id, options = {}) raise ArgumentError, "option parameter is empty" if options.empty? raise ArgumentError, "archive_id not provided" if archive_id.to_s.empty? type = options[:type] raise ArgumentError, "custom type must have a stylesheet" if (type.eql? "custom") && (!options.key? :stylesheet) valid_non_custom_layouts = ["bestFit","horizontalPresentation","pip", "verticalPresentation", ""] valid_non_custom_type = valid_non_custom_layouts.include? type raise ArgumentError, "type is not valid" if !valid_non_custom_type && !(type.eql? "custom") raise ArgumentError, "type is not valid or stylesheet not needed" if valid_non_custom_type and options.key? :stylesheet raise ArgumentError, "screenshare_type is not valid" if options[:screenshare_type] && !valid_non_custom_layouts.include?(options[:screenshare_type]) raise ArgumentError, "type must be set to 'bestFit' if screenshare_type is defined" if options[:screenshare_type] && type != 'bestFit' response = @client.layout_archive(archive_id, options) (200..300).include? response.code end end end