Skip to content

Commit

Permalink
Update video functionality (#307)
Browse files Browse the repository at this point in the history
Updating Video API functionality
  • Loading branch information
superchilled authored Apr 22, 2024
1 parent 2344a79 commit 5b6171d
Show file tree
Hide file tree
Showing 13 changed files with 630 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 7.24.0

* Updating Video API functionality with methods for Live Captions, Audio Connector, Experience Composer, and a `publisheronly` cleint token role. [#307](https://github.com/Vonage/vonage-ruby-sdk/pull/307)

# 7.23.0

* Minor updates to Verify v2. [#306](https://github.com/Vonage/vonage-ruby-sdk/pull/306)
Expand Down
7 changes: 6 additions & 1 deletion lib/vonage/keys.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ def camelcase(hash)
'screenshare_type',
'session_id',
'stream_mode',
'archive_mode'
'archive_mode',
'language_code',
'max_duration',
'partial_captions',
'status_callback_url',
'audio_rate'
]
hash.transform_keys do |k|
if exceptions.include?(k.to_s)
Expand Down
2 changes: 1 addition & 1 deletion lib/vonage/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# typed: strong

module Vonage
VERSION = '7.23.0'
VERSION = '7.24.0'
end
19 changes: 19 additions & 0 deletions lib/vonage/video.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ def create_session(**params)
end

def generate_client_token(session_id:, scope: 'session.connect', role: 'publisher', **params)
valid_roles = %w[publisher subscriber moderator publisheronly]
raise ArgumentError, "Invalid role: #{role}" unless valid_roles.include?(role)

claims = {
application_id: @config.application_id,
scope: scope,
Expand Down Expand Up @@ -104,6 +107,22 @@ def streams
@streams ||= Streams.new(@config)
end

# @return [Captions]
#
def captions
@captions ||= Captions.new(@config)
end

# @return [Renders]
#
def renders
@renders ||= Renders.new(@config)
end

# @return [WebSocket]
#
def web_socket
@web_socket ||= WebSocket.new(@config)
end
end
end
67 changes: 67 additions & 0 deletions lib/vonage/video/captions.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# typed: true
# frozen_string_literal: true

module Vonage
class Video::Captions < Namespace
include Keys

self.authentication = BearerToken

self.request_body = JSON

self.host = :video_host

# Start Live Captions for a Vonage Video stream
#
# @example
# response = client.video.captions.start(
# session_id: "12312312-3811-4726-b508-e41a0f96c68f",
# token: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJp...",
# language_code: 'en-US',
# max_duration: 300,
# partial_captions: false,
# status_callback_url: 'https://example.com/captions/status'
# )
#
# @params [required, String] :session_id The id of the session to start captions for
#
# @param [required, String] :token A valid Vonage Video token with role set to 'moderator'
#
# @params [optional, String] :language_code The BCP-47 code for a spoken language used on this call. The default value is "en-US"
# - Must be one of: 'en-US', 'en-AU', 'en-GB', 'zh-CN', 'fr-FR', 'fr-CA', 'de-DE', 'hi-IN', 'it-IT', 'ja-JP', 'ko-KR', 'pt-BR', 'th-TH'
#
# @param [optional, Integer] :max_duration The maximum duration for the audio captioning, in seconds.
# - The default value is 14,400 seconds (4 hours), the maximum duration allowed.
# - The minimum value for maxDuration is 300 (300 seconds, or 5 minutes).
#
# @param [optional, Boolean] :partial_captions Whether to enable this to faster captioning (true, the default) at the cost of some degree of inaccuracies.
#
# @param [optional, String] :status_callback_url The URL to send the status of the captions to.
#
# @return [Response]
#
# @see TODO: Add document link here
#
def start(session_id:, token:, **params)
request(
'/v2/project/' + @config.application_id + '/captions',
params: camelcase(params.merge({sessionId: session_id, token: token})),
type: Post)
end

# Stop live captions for a session
#
# @example
# response = client.video.captions.stop(captions_id: "7c0580fc-6274-4de5-a66f-d0648e8d3ac3")
#
# @params [required, String] :captions_id ID of the connection used for captions
#
# @return [Response]
#
# @see TODO: Add document link here
#
def stop(captions_id:)
request('/v2/project/' + @config.application_id + '/captions/' + captions_id + '/stop', type: Post)
end
end
end
107 changes: 107 additions & 0 deletions lib/vonage/video/renders.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# typed: true
# frozen_string_literal: true

module Vonage
class Video::Renders < Namespace
include Keys

self.authentication = BearerToken

self.request_body = JSON

self.host = :video_host

# Start an Experience Composer Render
#
# @example
# response = client.video.renders.start(
# session_id: "12312312-3811-4726-b508-e41a0f96c68f",
# token: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJp...",
# url: 'https://example.com/',
# max_duration: 1800,
# resolution: '1280x720',
# properties: {
# name: 'foo'
# }
# )
#
# @params [required, String] :session_id The session ID of the Vonage Video session you are working with.
#
# @param [required, String] :token A valid OpenTok JWT token with a Publisher role and (optionally) connection data to be associated with the output stream.
#
# @params [required, String] :url A publicly reachable URL controlled by the customer and capable of generating the content to be rendered without user intervention.
#
# @params [optional, Integer] :max_duration The maximum duration of the rendered video in seconds.
# - After this time, it is stopped automatically, if it is still running.
# - Min: 60
# - Max: 3600
# - Default: 3600
#
# @params [optional, String] :resolution The resolution of the Experience Composer render.
# - Must be one of: '640x480', '480x640', '1280x720', '720x1280', '1080x1920', '1920x1080'
#
# @params [optional, Hash] :properties The initial configuration of Publisher properties for the composed output stream.
# @option properties [required, String] :name The name of the composed output stream which is published to the session.
#
# @return [Response]
#
# @see TODO: Add document link here
#
def start(session_id:, token:, url:, **params)
request(
'/v2/project/' + @config.application_id + '/render',
params: camelcase(params.merge({sessionId: session_id, token: token, url: url})),
type: Post)
end

# Stop an Experience Composer render
#
# @example
# response = client.video.renders.stop(experience_composer_id: "1248e7070b81464c9789f46ad10e7764")
#
# @params [required, String] :experience_composer_id ID of the Experience Composer instance that you want to stop.
#
# @return [Response]
#
# @see TODO: Add document link here
#
def stop(experience_composer_id:)
request('/v2/project/' + @config.application_id + '/render/' + experience_composer_id, type: Delete)
end

# Get information about an Experience Composer session
#
# @example
# response = client.video.renders.info(experience_composer_id: "1248e7070b81464c9789f46ad10e7764")
#
# @params [required, String] :experience_composer_id ID of the Experience Composer instance for which you are requesitng information.
#
# @return [Response]
#
# @see TODO: Add document link here
#
def info(experience_composer_id:)
request('/v2/project/' + @config.application_id + '/render/' + experience_composer_id)
end

# List all Experience Composer renders in an application
#
# @example
# response = client.video.renders.list
#
# @params [optional, Integer] :offset Specify the index offset of the first experience composer. 0 is offset of the most recently started render.
#
# @params [optional, Integer] :count Limit the number of experience composers to be returned.
#
# @return [Video::Renders::ListResponse]
#
# @see TODO: Add document link here
#
def list(**params)
path = '/v2/project/' + @config.application_id + '/render'
path += "?#{Params.encode(camelcase(params))}" unless params.empty?

request(path, response_class: ListResponse)
end
end
end
11 changes: 11 additions & 0 deletions lib/vonage/video/renders/list_response.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# typed: true

class Vonage::Video::Renders::ListResponse < Vonage::Response
include Enumerable

def each
return enum_for(:each) unless block_given?

@entity.items.each { |item| yield item }
end
end
61 changes: 61 additions & 0 deletions lib/vonage/video/web_socket.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# typed: true
# frozen_string_literal: true

module Vonage
class Video::WebSocket < Namespace
include Keys

self.authentication = BearerToken

self.request_body = JSON

self.host = :video_host

# Start an audio connector websocket connection
#
# @example
# response = client.video.web_socket.connect(
# session_id: "12312312-3811-4726-b508-e41a0f96c68f",
# token: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJp...",
# websocket: {
# uri: 'wss://example.com/ws-endpoint',
# streams: ["8b732909-0a06-46a2-8ea8-074e64d43422"],
# headers: { property1: 'foo', property2: 'bar' },
# audio_rate: 16000
# }
# )
#
# @params [required, String] :session_id The Vonage Video session ID that includes the Vonage Video streams you want to include in the WebSocket stream.
# - The Audio Connector feature is only supported in routed sessions
#
# @param [required, String] :token A valid Vonage Video token for the Audio Connector connection to the Vonage Video Session.
# - You can add additional data to the JWT to identify that the connection is the Audio Connector endpoint or for any other identifying data.
#
# @params [required, Hash] :websocket The WebSocket configuration for the Audio Connector connection.
# @option websocket [required, String] :uri A publicly reachable WebSocket URI to be used for the destination of the audio stream
# @option websocket [optional, String] :streams An array of stream IDs for the Vonage Video streams you want to include in the WebSocket audio.
# - If you omit this property, all streams in the session will be included.
# @option websocket [optional, Hash] :headers An object of key-value pairs of headers to be sent to your WebSocket server with each message, with a maximum length of 512 bytes.
# @option websocket [optional, Integer] :audio_rate A number representing the audio sampling rate in Hz
# - Must be one of: 8000, 16000
#
# @return [Response]
#
# @see TODO: Add document link here
#
def connect(session_id:, token:, websocket:)
raise ArgumentError, 'websocket must be a Hash' unless websocket.is_a?(Hash)
raise ArgumentError, 'websocket must contain a uri' unless websocket.key?(:uri)

request(
'/v2/project/' + @config.application_id + '/connect',
params: {
sessionId: session_id,
token: token,
websocket: camelcase(websocket)
},
type: Post
)
end
end
end
4 changes: 4 additions & 0 deletions test/vonage/test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ def sample_webhook_token
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1ODc0OTQ5NjIsImp0aSI6ImM1YmE4ZjI0LTFhMTQtNGMxMC1iZmRmLTNmYmU4Y2U1MTFiNSIsImlzcyI6IlZvbmFnZSIsInBheWxvYWRfaGFzaCI6ImQ2YzBlNzRiNTg1N2RmMjBlM2I3ZTUxYjMwYzBjMmE0MGVjNzNhNzc4NzliNmYwNzRkZGM3YTIzMTdkZDAzMWIiLCJhcGlfa2V5IjoiYTFiMmMzZCIsImFwcGxpY2F0aW9uX2lkIjoiYWFhYWFhYWEtYmJiYi1jY2NjLWRkZGQtMDEyMzQ1Njc4OWFiIn0.JQRKi1d0SQitmjPINfTWMpt3XZkGsLbD7EjCdXoNSbk"
end

def sample_video_token
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE3MTMxNzc4NTAsImp0aSI6IjYzMmI5NmMwLTM0MzEtNGI5NS1iNmNiLWNjNGFjNDEzNDhkNSIsImV4cCI6MTcxMzE3ODc1MCwiYXBwbGljYXRpb25faWQiOiJlMzM2ZmUxOS01MWNhLTRiNTktYTczOS1jNzA3MWIzZjY5Y2MiLCJzY29wZSI6InNlc3Npb24uY29ubmVjdCIsInNlc3Npb25faWQiOiIxX01YNWxNek0yWm1VeE9TMDFNV05oTFRSaU5Ua3RZVGN6T1Mxak56QTNNV0l6WmpZNVkyTi1makUzTURJME9ETTVNakV6TVRaLVNVeFdLMnh4ZFUxR1VESTJlbFZWVkcxUE9FTnlUVzVSZm41LSIsInJvbGUiOiJtb2RlcmF0b3IiLCJpbml0aWFsX2xheW91dF9jbGFzc19saXN0IjoiIiwic3ViIjoidmlkZW8iLCJhY2wiOnsicGF0aHMiOnsiL3Nlc3Npb24vKioiOnt9fX19.kHj4lHKxWKurScu6LWm7z0G69WuLHyx-Vgf3CDlCYdRRAqJ--SRXPukAAGuA52wvou4wVStd6BWCiSUDxjNb6wG5li3Op6RDdpIiooJ6C1kVdUmbEgBLww76Vy34If0d99XbEZX13KW0XmN6oyrNSih3paanqYzjJcG9elKxnMXLhnTB8Mq6OQXVAiB4Qr6LCqdB57a1eU52Ak2-1F41p3LnzDaElFOepbCdFtIXiFxjd3r62JXiYMNxQCseT2RyPqcKQsFUSBV6k3GvY8ONece-ClSED_prXkChW1o3_7sRsfFqBaQiCGjw4vtIIE17S4atv4Z5rzBPLvUsqpUfog"
end

def sample_valid_signature_secret
"ZYtdTtGV3BCFN7tWmOWr1md66XsquMggr4W2cTtXtcPgfnI0Xw"
end
Expand Down
62 changes: 62 additions & 0 deletions test/vonage/video/captions_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# typed: false
require_relative '../test'

class Vonage::Video::CaptionsTest < Vonage::Test
def captions
Vonage::Video::Captions.new(config)
end

def uri
'https://video.api.vonage.com/v2/project/' + application_id + '/captions'
end

def test_start_method
request_params = {sessionId: video_session_id, token: sample_video_token}
stub_request(:post, uri).with(body: request_params).to_return(response)

assert_kind_of Vonage::Response, captions.start(session_id: video_session_id, token: sample_video_token)
end

def test_start_method_with_optional_params
request_params = {
sessionId: video_session_id,
token: sample_video_token,
languageCode: 'en-US',
maxDuration: 300,
partialCaptions: false,
statusCallbackUrl: 'https://send-status-to.me'
}

stub_request(:post, uri).with(body: request_params).to_return(response)

response = captions.start(
session_id: video_session_id,
token: sample_video_token,
language_code: 'en-US',
max_duration: 300,
partial_captions: false,
status_callback_url: 'https://send-status-to.me'
)

assert_kind_of Vonage::Response, response
end

def test_start_method_without_session_id
assert_raises(ArgumentError) { captions.start(token: sample_video_token) }
end

def test_start_method_without_token
assert_raises(ArgumentError) { captions.start(session_id: video_session_id) }
end

def test_stop_method
captions_id = "7c0680fc-6274-4de5-a66f-d0648e8d3ac2"
stub_request(:post, uri + "/#{captions_id}/stop").to_return(response)

assert_kind_of Vonage::Response, captions.stop(captions_id: captions_id)
end

def test_stop_method_without_captions_id
assert_raises(ArgumentError) { captions.stop }
end
end
Loading

0 comments on commit 5b6171d

Please sign in to comment.