internal bool FlushPacket(out OggPacket packet) => SafeNativeMethods.VorbisBitrateFlushPacket(DspState, out packet) == 1;
public unsafe AudioMetadata ReadMetadata(Stream stream) { OggStream? oggStream = null; SafeNativeMethods.VorbisCommentInit(out var vorbisComment); #if NETSTANDARD2_0 var buffer = ArrayPool<byte>.Shared.Rent(4096); #else Span<byte> buffer = stackalloc byte[4096]; #endif try { using (var sync = new OggSync()) using (var decoder = new VorbisDecoder()) { OggPage page; do { // Read from the buffer into a page while (!sync.PageOut(out page)) { #if NETSTANDARD2_0 var bytesRead = stream.Read(buffer, 0, buffer.Length); #else var bytesRead = stream.Read(buffer); #endif if (bytesRead == 0) throw new AudioInvalidException("No Ogg stream was found."); var nativeBuffer = new Span<byte>(sync.Buffer(bytesRead).ToPointer(), bytesRead); #if NETSTANDARD2_0 buffer.AsSpan().Slice(0, bytesRead).CopyTo(nativeBuffer); #else buffer.Slice(0, bytesRead).CopyTo(nativeBuffer); #endif sync.Wrote(bytesRead); } oggStream ??= new(SafeNativeMethods.OggPageSerialNo(page)); oggStream.PageIn(page); while (oggStream.PacketOut(out var packet)) { decoder.HeaderIn(vorbisComment, packet); if (packet.PacketNumber == 1) return new VorbisCommentToMetadataAdapter(vorbisComment); } } while (!SafeNativeMethods.OggPageEos(page)); throw new AudioInvalidException("The end of the Ogg stream was reached without finding a header."); } } finally { #if NETSTANDARD2_0 ArrayPool<byte>.Shared.Return(buffer); #endif SafeNativeMethods.VorbisCommentClear(ref vorbisComment); oggStream?.Dispose(); } }
internal void Analysis(IntPtr packet) => SafeNativeMethods.VorbisAnalysis(_block, packet);
internal void AddBlock() => SafeNativeMethods.VorbisBitrateAddBlock(_block);
internal void Wrote(int samples) => SafeNativeMethods.VorbisAnalysisWrote(DspState, samples);
internal bool BlockOut() => SafeNativeMethods.VorbisAnalysisBlockOut(DspState, _block) == 1;
public unsafe void WriteMetadata(Stream stream, AudioMetadata metadata, SettingDictionary settings) { using (var tempStream = new TempFileStream()) { OggStream inputOggStream = null; OggStream outputOggStream = null; #if NETSTANDARD2_0 var buffer = ArrayPool <byte> .Shared.Rent(4096); #else Span <byte> buffer = stackalloc byte[4096]; #endif try { using (var sync = new OggSync()) { var headerWritten = false; OggPage page; var pagesWritten = 0u; do { // Read from the buffer into a page while (!sync.PageOut(out page)) { #if NETSTANDARD2_0 var bytesRead = stream.Read(buffer, 0, buffer.Length); #else var bytesRead = stream.Read(buffer); #endif if (bytesRead == 0) { throw new AudioInvalidException("No Ogg stream was found."); } var nativeBuffer = new Span <byte>(sync.Buffer(bytesRead).ToPointer(), bytesRead); #if NETSTANDARD2_0 buffer.AsSpan().Slice(0, bytesRead).CopyTo(nativeBuffer); #else buffer.Slice(0, bytesRead).CopyTo(nativeBuffer); #endif sync.Wrote(bytesRead); } if (inputOggStream == null) { inputOggStream = new OggStream(SafeNativeMethods.OggPageSerialNo(page)); } if (outputOggStream == null) { outputOggStream = new OggStream(inputOggStream.SerialNumber); } // Write new header page(s) using a modified comment packet if (!headerWritten) { inputOggStream.PageIn(page); while (inputOggStream.PacketOut(out var packet)) { switch (packet.PacketNumber) { case 0: outputOggStream.PacketIn(packet); break; // Substitute the new comment packet case 1: using (var adapter = new MetadataToVorbisCommentAdapter(metadata)) { adapter.HeaderOut(out var commentPacket); outputOggStream.PacketIn(commentPacket); } break; // Flush at the end of the header case 2: outputOggStream.PacketIn(packet); while (outputOggStream.Flush(out var outPage)) { WritePage(outPage, tempStream); pagesWritten++; } headerWritten = true; break; default: throw new AudioInvalidException("Missing header packet."); } } } else { // Copy the existing data pages verbatim, with updated sequence numbers UpdateSequenceNumber(ref page, pagesWritten); WritePage(page, tempStream); pagesWritten++; } } while (!SafeNativeMethods.OggPageEos(page)); // Once the end of the input is reached, overwrite the original file and return stream.Position = 0; stream.SetLength(tempStream.Length); tempStream.Position = 0; tempStream.CopyTo(stream); } } finally { #if NETSTANDARD2_0 ArrayPool <byte> .Shared.Return(buffer); #endif inputOggStream?.Dispose(); outputOggStream?.Dispose(); } } }
internal IntPtr GetBuffer(int samples) => SafeNativeMethods.VorbisAnalysisBuffer(DspState, samples);
void FreeUnmanaged() { SafeNativeMethods.OggStreamClear(_state); Marshal.FreeHGlobal(_state); }
internal VorbisDecoder() { SafeNativeMethods.VorbisInfoInit(_info); }
internal bool Flush(out OggPage page) => SafeNativeMethods.OggStreamFlush(_state, out page) != 0;
internal bool PacketOut(out OggPacket packet) => SafeNativeMethods.OggStreamPacketOut(_state, out packet) == 1;
internal bool PageOut(out OggPage page) => SafeNativeMethods.OggStreamPageOut(_state, out page) != 0;
internal OggStream(long serialNumber) #endif { _state = Marshal.AllocHGlobal(Marshal.SizeOf <OggStreamState>()); SafeNativeMethods.OggStreamInit(_state, serialNumber); }
public bool Handle() { var logger = LoggerManager.LoggerFactory.CreateLogger <VorbisLibHandler>(); #if WINDOWS var libPath = Path.Combine( // ReSharper disable once AssignNullToNotNullAttribute Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath), Environment.Is64BitProcess ? "win-x64" : "win-x86"); #if NETSTANDARD2_0 // On Full Framework, AssemblyLoadContext isn't available, so we add the directory to PATH if (RuntimeInformation.FrameworkDescription.StartsWith(".NET Framework", StringComparison.Ordinal)) { Environment.SetEnvironmentVariable("PATH", $"{libPath}{Path.PathSeparator}{Environment.GetEnvironmentVariable("PATH")}"); } else { AddUnmanagedLibraryPath(libPath); } #else AddUnmanagedLibraryPath(libPath); #endif #elif OSX var osVersion = GetOSVersion(); AddUnmanagedLibraryPath(Path.Combine( // ReSharper disable once AssignNullToNotNullAttribute Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath), osVersion.StartsWith("10.12", StringComparison.Ordinal) ? "osx.10.12-x64" : osVersion.StartsWith("10.13", StringComparison.Ordinal) ? "osx.10.13-x64" : "osx.10.14-x64")); #else // LINUX var release = GetRelease(); if (release.StartsWith("Ubuntu 16.04", StringComparison.OrdinalIgnoreCase)) { AddUnmanagedLibraryPath(Path.Combine( // ReSharper disable once AssignNullToNotNullAttribute Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath), release.StartsWith("Ubuntu 16.04", StringComparison.OrdinalIgnoreCase) ? "ubuntu.16.04-x64" : "ubuntu.18.04-x64")); } if (!VerifyLibrary("libogg.so.0")) { logger.LogWarning( release.StartsWith("Ubuntu", StringComparison.OrdinalIgnoreCase) ? "Missing libogg.so.0. Run 'sudo apt-get install -y libogg0 && sudo updatedb' then restart AudioWorks." : "Missing libogg.so.0."); return(false); } #endif logger.LogInformation("Using libvorbis version {0}.", Marshal.PtrToStringAnsi(SafeNativeMethods.VorbisVersion())); return(true); }