Class: Cohere::Transcribe::Audio::FFmpegNative::Library
- Inherits:
-
Object
- Object
- Cohere::Transcribe::Audio::FFmpegNative::Library
- Defined in:
- lib/cohere/transcribe/audio/ffmpeg_native.rb
Constant Summary collapse
- FUNCTIONS =
{ probe: [%i[voidp size_t], :int], decode: [%i[voidp int uint64 voidp voidp voidp size_t], :int], duration: [%i[voidp voidp voidp size_t], :int], cancel: [[], :void], free: [[:voidp], :void] }.freeze
- OPTIONAL_FUNCTIONS =
{ versions: [%i[voidp size_t], :int] }.freeze
- TYPE_MAP =
{ void: Fiddle::TYPE_VOID, voidp: Fiddle::TYPE_VOIDP, int: Fiddle::TYPE_INT, size_t: Fiddle::TYPE_SIZE_T, uint64: Fiddle::TYPE_UINT64_T }.freeze
Instance Attribute Summary collapse
-
#avutil_major ⇒ Object
readonly
Returns the value of attribute avutil_major.
-
#diagnostic ⇒ Object
readonly
Returns the value of attribute diagnostic.
-
#ffmpeg_versions ⇒ Object
readonly
Returns the value of attribute ffmpeg_versions.
-
#path ⇒ Object
readonly
Returns the value of attribute path.
Class Method Summary collapse
Instance Method Summary collapse
- #cancel_all! ⇒ Object
- #decode(path, sample_rate:, max_decoded_bytes:) ⇒ Object
- #duration(path) ⇒ Object
-
#initialize(path) ⇒ Library
constructor
A new instance of Library.
- #probe! ⇒ Object
Constructor Details
#initialize(path) ⇒ Library
Returns a new instance of Library.
101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/cohere/transcribe/audio/ffmpeg_native.rb', line 101 def initialize(path) @path = path @handle = Fiddle::Handle.new(path, Fiddle::RTLD_NOW) functions = FUNCTIONS.to_h do |name, signature| [name, bind_function(name, signature)] end OPTIONAL_FUNCTIONS.each do |name, signature| functions[name] = bind_function(name, signature) rescue Fiddle::DLError nil end @functions = functions.freeze end |
Instance Attribute Details
#avutil_major ⇒ Object (readonly)
Returns the value of attribute avutil_major.
99 100 101 |
# File 'lib/cohere/transcribe/audio/ffmpeg_native.rb', line 99 def avutil_major @avutil_major end |
#diagnostic ⇒ Object (readonly)
Returns the value of attribute diagnostic.
99 100 101 |
# File 'lib/cohere/transcribe/audio/ffmpeg_native.rb', line 99 def diagnostic @diagnostic end |
#ffmpeg_versions ⇒ Object (readonly)
Returns the value of attribute ffmpeg_versions.
99 100 101 |
# File 'lib/cohere/transcribe/audio/ffmpeg_native.rb', line 99 def ffmpeg_versions @ffmpeg_versions end |
#path ⇒ Object (readonly)
Returns the value of attribute path.
99 100 101 |
# File 'lib/cohere/transcribe/audio/ffmpeg_native.rb', line 99 def path @path end |
Class Method Details
.candidate_paths ⇒ Object
58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/cohere/transcribe/audio/ffmpeg_native.rb', line 58 def candidate_paths explicit = ENV.fetch("COHERE_TRANSCRIBE_AUDIO_LIBRARY", nil) return [explicit] if explicit && !explicit.empty? packaged = File.("../native", __dir__) patterns = case RbConfig::CONFIG.fetch("host_os") when /darwin/ then ["libcohere_audio*.dylib"] when /mswin|mingw|cygwin/ then ["cohere_audio*.dll", "libcohere_audio*.dll"] else ["libcohere_audio.so", "libcohere_audio.so.*"] end paths = patterns.flat_map { |pattern| Dir.glob(File.join(packaged, pattern)) }.sort paths.concat(system_library_names) paths.uniq end |
.load ⇒ Object
45 46 47 48 49 50 51 |
# File 'lib/cohere/transcribe/audio/ffmpeg_native.rb', line 45 def load @mutex ||= Mutex.new # A failed load is deliberately retryable. Embedders may set an # adapter override or make a packaged/system library available # after an earlier best-effort audio probe. @mutex.synchronize { @instance ||= load_uncached } end |
.loaded ⇒ Object
53 54 55 56 |
# File 'lib/cohere/transcribe/audio/ffmpeg_native.rb', line 53 def loaded mutex = @mutex mutex&.synchronize { @instance } end |
Instance Method Details
#cancel_all! ⇒ Object
242 243 244 245 |
# File 'lib/cohere/transcribe/audio/ffmpeg_native.rb', line 242 def cancel_all! @functions.fetch(:cancel).call nil end |
#decode(path, sample_rate:, max_decoded_bytes:) ⇒ Object
144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/cohere/transcribe/audio/ffmpeg_native.rb', line 144 def decode(path, sample_rate:, max_decoded_bytes:) Internal::InterruptibleNativeCall.run( cancel: -> { @functions.fetch(:cancel).call }, join_interval: CANCELLATION_JOIN_INTERVAL, missing_outcome: TranscriptionRuntimeError.new( "Native FFmpeg decode worker exited without reporting an outcome" ), thread_name: "cohere-ffmpeg-decode" ) do decode_owned(path, sample_rate: sample_rate, max_decoded_bytes: max_decoded_bytes) end end |
#duration(path) ⇒ Object
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
# File 'lib/cohere/transcribe/audio/ffmpeg_native.rb', line 217 def duration(path) duration_slot = Fiddle::Pointer.malloc(Fiddle::SIZEOF_DOUBLE, Fiddle::RUBY_FREE) duration_slot[0, Fiddle::SIZEOF_DOUBLE] = [-1.0].pack("d") = Fiddle::Pointer.malloc(ERROR_CAPACITY, Fiddle::RUBY_FREE) [0, ERROR_CAPACITY] = "\0" * ERROR_CAPACITY status = @functions.fetch(:duration).call( c_string(path.to_s), duration_slot, , ERROR_CAPACITY ) detail = .to_s.force_encoding(Encoding::UTF_8).scrub unless status.zero? raise Interrupt, "Native FFmpeg duration probe was cancelled for #{path}: #{detail}" if status == CANCELLED_STATUS raise TranscriptionRuntimeError, "Cannot inspect #{path} through native FFmpeg: #{detail}" end seconds = duration_slot[0, Fiddle::SIZEOF_DOUBLE].unpack1("d") return nil unless seconds.finite? && seconds >= 0.0 seconds end |
#probe! ⇒ Object
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/cohere/transcribe/audio/ffmpeg_native.rb', line 115 def probe! = Fiddle::Pointer.malloc(ERROR_CAPACITY, Fiddle::RUBY_FREE) [0, ERROR_CAPACITY] = "\0" * ERROR_CAPACITY status = @functions.fetch(:probe).call(, ERROR_CAPACITY) @diagnostic = .to_s.force_encoding(Encoding::UTF_8).scrub.freeze raise TranscriptionRuntimeError, "Native FFmpeg libraries are unavailable: #{@diagnostic}" unless status.zero? versions = @functions[:versions] return clear_ffmpeg_versions unless versions tuple_bytes = 4 * Fiddle::SIZEOF_INT tuple = Fiddle::Pointer.malloc(tuple_bytes, Fiddle::RUBY_FREE) tuple[0, tuple_bytes] = [0, 0, 0, 0].pack("i!*") version_status = versions.call(tuple, 4) unless version_status.zero? raise TranscriptionRuntimeError, "Native FFmpeg libraries did not report their version tuple: #{@diagnostic}" end @ffmpeg_versions = tuple[0, tuple_bytes].unpack("i!4").freeze unless @ffmpeg_versions.all?(&:positive?) raise TranscriptionRuntimeError, "Native FFmpeg libraries reported an invalid version tuple: #{@ffmpeg_versions.inspect}" end @avutil_major = @ffmpeg_versions.fetch(2) self end |