Class: OpenAI::LocalAudio::MediaProcess Private
- Inherits:
-
Object
- Object
- OpenAI::LocalAudio::MediaProcess
- Defined in:
- lib/openai/helpers/local_audio/process.rb,
sig/openai/helpers/local_audio/interface.rbs
This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.
Class Method Summary collapse
- .clock ⇒ Float private
- .duration(value, name:) ⇒ Float private
- .environment ⇒ Hash[String, String] private
Instance Method Summary collapse
- #check_deadline ⇒ void private
- #close ⇒ void private
-
#errors? ⇒ Boolean
private
Drain at most one chunk per polling step, retaining no diagnostic content.
-
#initialize(argv, input:, output:, timeout:, capture_errors: false) ⇒ MediaProcess
constructor
private
A new instance of MediaProcess.
- #read(io, stop_on_exit: false) ⇒ String? private
- #wait ⇒ Process::Status private
- #write(io, bytes) ⇒ void private
Constructor Details
#initialize(argv, input:, output:, timeout:, capture_errors: false) ⇒ MediaProcess
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns a new instance of MediaProcess.
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/openai/helpers/local_audio/process.rb', line 41 def initialize(argv, input:, output:, timeout:, capture_errors: false) @deadline = self.class.clock + self.class.duration(timeout, name: :timeout) unless timeout.nil? @error_reader, error_writer = IO.pipe(binmode: true) if capture_errors @pid = Process.spawn( self.class.environment, *argv, in: input, out: output, err: error_writer || File::NULL, close_others: true, unsetenv_others: true ) rescue Errno::ENOENT @error_reader&.close raise DependencyError.new("Install the required FFmpeg/FFplay executable on PATH."), cause: nil rescue SystemCallError @error_reader&.close raise DeviceError.new("Cannot start the local audio executable."), cause: nil ensure error_writer&.close end |
Class Method Details
.clock ⇒ Float
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
29 |
# File 'lib/openai/helpers/local_audio/process.rb', line 29 def self.clock = Process.clock_gettime(Process::CLOCK_MONOTONIC) |
.duration(value, name:) ⇒ Float
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
31 32 33 34 35 36 37 38 39 |
# File 'lib/openai/helpers/local_audio/process.rb', line 31 def self.duration(value, name:) unless value.is_a?(Numeric) && value.real? && value.finite? && value.positive? raise ArgumentError, "#{name} must be a positive finite number of seconds" end result = value.to_f raise ArgumentError, "#{name} is not representable" unless result.finite? result end |
.environment ⇒ Hash[String, String]
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
28 |
# File 'lib/openai/helpers/local_audio/process.rb', line 28 def self.environment = ENV.to_h.slice(*ENVIRONMENT_KEYS) |
Instance Method Details
#check_deadline ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
63 64 65 66 |
# File 'lib/openai/helpers/local_audio/process.rb', line 63 def check_deadline raise TimeoutError, "Local audio operation timed out." if @deadline && self.class.clock >= @deadline errors? end |
#close ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/openai/helpers/local_audio/process.rb', line 119 def close return unless @pid reap unless @status signal("TERM") deadline = self.class.clock + 0.25 until @status || self.class.clock >= deadline reap sleep(0.01) unless @status end unless @status signal("KILL") _, @status = Process.waitpid2(@pid) end end ensure @pid = nil @error_reader&.close unless @error_reader&.closed? end |
#errors? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Drain at most one chunk per polling step, retaining no diagnostic content.
69 70 71 72 73 74 75 76 |
# File 'lib/openai/helpers/local_audio/process.rb', line 69 def errors? if @error_reader && !@error_reader.closed? chunk = @error_reader.read_nonblock(65_536, exception: false) @errors = true if chunk.is_a?(String) && !chunk.empty? end !!@errors end |
#read(io, stop_on_exit: false) ⇒ String?
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/openai/helpers/local_audio/process.rb', line 78 def read(io, stop_on_exit: false) loop do check_deadline return io.read(65_536) if io.is_a?(StringIO) result = io.read_nonblock(65_536, exception: false) return result unless result == :wait_readable if stop_on_exit reap raise PlaybackError, "Audio player exited before the input ended." if @status end io.wait_readable(0.05) end end |
#wait ⇒ Process::Status
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
109 110 111 112 113 114 115 116 117 |
# File 'lib/openai/helpers/local_audio/process.rb', line 109 def wait until @status check_deadline reap sleep(0.01) unless @status end @status end |
#write(io, bytes) ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/openai/helpers/local_audio/process.rb', line 93 def write(io, bytes) offset = 0 while offset < bytes.bytesize check_deadline result = io.write_nonblock(bytes.byteslice(offset, 65_536), exception: false) if result == :wait_writable io.wait_writable(0.05) else offset += result end end rescue Errno::EPIPE raise PlaybackError.new("Audio player closed before receiving the input."), cause: nil end |