Skip to content

Commit c3e0bb9

Browse files
committed
- low quality audio convertor for VK audiomessages
1 parent a6f4678 commit c3e0bb9

File tree

7 files changed

+66
-17
lines changed

7 files changed

+66
-17
lines changed

Botticelli.Audio.Tests/UniversalConvertorTests.cs renamed to Botticelli.Audio.Tests/UniversalLowQualityConvertorTests.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
namespace Botticelli.Audio.Tests
44
{
55
[TestFixture()]
6-
public class UniversalConvertorTests
6+
public class UniversalLowQualityConvertorTests
77
{
88
private readonly IConvertor _convertor;
99
private readonly IAnalyzer _analyzer;
1010

11-
public UniversalConvertorTests()
11+
public UniversalLowQualityConvertorTests()
1212
{
1313
_analyzer = new InputAnalyzer();
14-
_convertor = new UniversalConvertor(_analyzer);
14+
_convertor = new UniversalLowQualityConvertor(_analyzer);
1515
}
1616

1717
[Test()]
@@ -33,14 +33,14 @@ public void ConvertMp3ToOpusTest()
3333
}
3434

3535
[Test()]
36-
public void ConvertMp3ToWavTest()
36+
public void ConvertMp3ToOggTest()
3737
{
3838
if (!File.Exists("voice.mp3"))
3939
Assert.Fail("no voice.mp3!");
4040
using var stream = File.OpenRead("voice.mp3");
4141
var outcome = _convertor.Convert(stream, new AudioInfo()
4242
{
43-
AudioFormat = AudioFormat.Aac,
43+
AudioFormat = AudioFormat.Ogg,
4444
Channels = 2,
4545
SampleRate = 8000,
4646
BitsPerSample = 8
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace Botticelli.Audio.Exceptions
8+
{
9+
public class AudioConvertorException : Exception
10+
{
11+
public AudioConvertorException(string message, Exception ex) : base(message, ex) { }
12+
}
13+
}

Botticelli.Audio/IConvertor.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
public interface IConvertor
44
{
55
public byte[] Convert(Stream input, AudioInfo targetParams);
6+
public byte[] Convert(byte[] input, AudioInfo targetParams);
67
}

Botticelli.Audio/UniversalConvertor.cs renamed to Botticelli.Audio/UniversalLowQualityConvertor.cs

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using FFMpegCore;
1+
using System.ComponentModel;
2+
using Botticelli.Audio.Exceptions;
3+
using FFMpegCore;
24
using FFMpegCore.Enums;
35
using FFMpegCore.Exceptions;
46
using FFMpegCore.Pipes;
@@ -8,24 +10,38 @@
810

911
namespace Botticelli.Audio;
1012

11-
public class UniversalConvertor : IConvertor
13+
public class UniversalLowQualityConvertor : IConvertor
1214
{
1315
private readonly IAnalyzer _analyzer;
1416

15-
public UniversalConvertor(IAnalyzer analyzer) => _analyzer = analyzer;
17+
public UniversalLowQualityConvertor(IAnalyzer analyzer) => _analyzer = analyzer;
1618

1719
public byte[] Convert(Stream input, AudioInfo targetParams)
1820
{
19-
if (targetParams.AudioFormat is AudioFormat.M4a or AudioFormat.Aac or AudioFormat.Opus)
20-
return ProcessByStreamEncoder(input, targetParams);
21+
try
22+
{
23+
if (targetParams.AudioFormat is AudioFormat.M4a or AudioFormat.Aac or AudioFormat.Opus or AudioFormat.Ogg)
24+
return ProcessByStreamEncoder(input, targetParams);
2125

22-
var srcParams = _analyzer.Analyze(input);
26+
var srcParams = _analyzer.Analyze(input);
2327

24-
using var resultStream = new MemoryStream();
25-
using var srcStream = GetSourceWaveStream(input, srcParams);
26-
using var tgtStream = GetTargetWaveStream(srcStream, targetParams);
28+
using var resultStream = new MemoryStream();
29+
using var srcStream = GetSourceWaveStream(input, srcParams);
30+
using var tgtStream = GetTargetWaveStream(srcStream, targetParams);
2731

28-
return tgtStream.ToArray();
32+
return tgtStream.ToArray();
33+
}
34+
catch (Exception ex)
35+
{
36+
throw new AudioConvertorException($"Audio conversion error: {ex.Message}", ex);
37+
}
38+
}
39+
40+
public byte[] Convert(byte[] input, AudioInfo targetParams)
41+
{
42+
using var ms = new MemoryStream(input);
43+
44+
return Convert(ms, targetParams);
2945
}
3046

3147
private static byte[] ProcessByStreamEncoder(Stream input, AudioInfo tgtParams)
@@ -47,6 +63,9 @@ private static byte[] ProcessByStreamEncoder(Stream input, AudioInfo tgtParams)
4763
case AudioFormat.Opus:
4864
codec = "opus";
4965
break;
66+
case AudioFormat.Wav:
67+
codec = "wav";
68+
break;
5069
case AudioFormat.Unknown:
5170
default:
5271
throw new ArgumentOutOfRangeException();
@@ -57,6 +76,7 @@ private static byte[] ProcessByStreamEncoder(Stream input, AudioInfo tgtParams)
5776
.FromPipeInput(new StreamPipeSource(input))
5877
.OutputToPipe(new StreamPipeSink(output), options => options
5978
.ForceFormat(codec)
79+
.WithAudioBitrate(16000)
6080
.WithAudioBitrate(AudioQuality.Low))
6181
.ProcessSynchronously();
6282

Botticelli.Framework.Vk/Botticelli.Framework.Vk.Messages.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
<ItemGroup>
1616
<ProjectReference Include="..\BotDataSecureStorage\BotDataSecureStorage.csproj" />
1717
<ProjectReference Include="..\Botticelli.API\Botticelli.BotBase.csproj" />
18+
<ProjectReference Include="..\Botticelli.Audio\Botticelli.Audio.csproj" />
1819
<ProjectReference Include="..\Botticelli.Framework\Botticelli.Framework.csproj" />
1920
<PackageReference Include="Flurl" Version="3.0.7" />
2021
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="7.0.10" />

Botticelli.Framework.Vk/Extensions/ServiceCollectionExtensions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using BotDataSecureStorage;
2+
using Botticelli.Audio;
23
using Botticelli.BotBase;
34
using Botticelli.BotBase.Settings;
45
using Botticelli.BotBase.Utils;
@@ -79,6 +80,7 @@ public static IServiceCollection AddVkBot(this IServiceCollection services,
7980
.AddSingleton<VkStorageUploader>()
8081
.AddSingleton<LongPollMessagesProvider>()
8182
.AddSingleton<MessagePublisher>()
83+
.AddSingleton<IConvertor, UniversalLowQualityConvertor>()
8284
.AddSingleton(secureStorage)
8385
.AddBotticelliFramework();
8486

Botticelli.Framework.Vk/VkStorageUploader.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Text.Json;
2+
using Botticelli.Audio;
23
using Botticelli.BotBase.Exceptions;
34
using Botticelli.Framework.Vk.API.Requests;
45
using Botticelli.Framework.Vk.API.Responses;
@@ -13,12 +14,16 @@ namespace Botticelli.Framework.Vk.Messages;
1314
public class VkStorageUploader
1415
{
1516
private readonly IHttpClientFactory _httpClientFactory;
17+
private readonly IConvertor _audioConvertor;
1618
private readonly ILogger<MessagePublisher> _logger;
1719
private string _apiKey;
1820

19-
public VkStorageUploader(IHttpClientFactory httpClientFactory, ILogger<MessagePublisher> logger)
21+
public VkStorageUploader(IHttpClientFactory httpClientFactory,
22+
IConvertor audioConvertor,
23+
ILogger<MessagePublisher> logger)
2024
{
2125
_httpClientFactory = httpClientFactory;
26+
_audioConvertor = audioConvertor;
2227
_logger = logger;
2328
}
2429

@@ -166,7 +171,14 @@ private async Task<UploadPhotoResult> UploadPhoto(string uploadUrl, string name,
166171
private async Task<UploadDocResult> UploadAudioMessage(string uploadUrl, string name, byte[] binaryContent, CancellationToken token)
167172
{
168173
using var httpClient = _httpClientFactory.CreateClient();
169-
using var memoryContentStream = new MemoryStream(binaryContent);
174+
// convert to ogg in order to meet VK requirements
175+
var oggContent = _audioConvertor.Convert(binaryContent, new AudioInfo()
176+
{
177+
AudioFormat = AudioFormat.Ogg,
178+
Bitrate = 16000
179+
});
180+
181+
using var memoryContentStream = new MemoryStream(oggContent);
170182
memoryContentStream.Seek(0, SeekOrigin.Begin);
171183

172184
var content = new MultipartFormDataContent { { new StreamContent(memoryContentStream), "audio", name } };

0 commit comments

Comments
 (0)