در نسخه بتا تلگرام برای اندروید 13.0.3 (بیلد 7179)، پیام صوتی ضبط شده را می‌شد به صورت متن ارسال کرد: دکمه «Aa» در کنار دکمه مکث، ضبط را حتی قبل از ارسال رونویسی می‌کرد، و کاربر انتخاب می‌کرد که چه چیزی برای مخاطب ارسال شود — متن یا خود صدا. این قابلیت به عنوان قابلیتی که فقط با Premium در دسترس است مشخص شده بود. بعداً، قابلیت رونویسی از نسخه بتا حذف شد؛ این یک آزمایش موقت توسط یکی از توسعه‌دهندگان بود. اما نوآوری دوم همان بیلد باقی ماند — ضبط آزمایشی پیام‌های صوتی با حذف نویز مبتنی بر شبکه عصبی RNNoise. این موضوع مربوط به کسانی است که از نسخه بتا استفاده می‌کنند: در نسخه پایدار 13.0.2، هیچ یک از این دو قابلیت وجود ندارد.

نحوه عملکرد در نسخه بتا

دکمه «Aa» در حالت ضبط قفل شده (hands-free recording) ظاهر می‌شد — زمانی که انگشت در حین ضبط به سمت بالا کشیده می‌شود و ضبط بدون نگه داشتن ادامه می‌یابد. با فشار دادن «Aa»، رونویسی نمایش داده می‌شد و سپس باید انتخاب می‌کردید که چه چیزی را ارسال کنید. اگر پیام صوتی ویرایش یا کوتاه می‌شد، نسخه بتا پیشنهاد می‌کرد که آن را دوباره رونویسی کند.

ضبط با حذف نویز در تنظیمات آزمایشی نسخه بتا فعال می‌شود. نویز از صدا حذف می‌شود قبل از اینکه به فرمت Opus فشرده شود — فرمتی که تلگرام پیام‌های صوتی را در آن ذخیره و ارسال می‌کند. هشدار از همان بیلد: حذف نویز ممکن است ضبط موسیقی و گفتار بسیار آرام را خراب کند. زمزمه کردن یک ملودی در پیام صوتی با این حالت، ایده خوبی نیست: از نظر شبکه، موسیقی شبیه نویز است، دلیل آن در ادامه توضیح داده می‌شود.

چرا رونویسی قبل از ارسال یک مکانیسم جدید است

رونویسی پیام‌های صوتی در تلگرام مدت‌هاست که وجود دارد، اما فقط برای پیام‌هایی که قبلاً در چت قرار گرفته‌اند. این کار توسط سرور انجام می‌شود: کلاینت متد messages.transcribeAudio را فراخوانی می‌کند، و این متد دو پارامتر دارد — چت و شماره پیام در آن. پاسخ با شناسه رونویسی و متن برمی‌گردد؛ یک ضبط طولانی ممکن است با برچسب «در حال انجام» بازگردانده شود، و سپس متن با به‌روزرسانی‌های جداگانه updateTranscribedAudio تکمیل می‌شود.

یک پیام صوتی ارسال نشده شماره پیام ندارد، بنابراین این متد برای آن قابل استفاده نیست. متدی که خود فایل را بپذیرد، نه در طرح عمومی API (در TDLib در 8 اکتبر) و نه در کدهای منبع Android نسخه 13.0.2 با لایه 231 وجود ندارد. تشخیص‌دهنده گفتار سیستمی Android (android.speech) نیز در کد 13.0.2 استفاده نمی‌شود.

نحوه دور زدن این محدودیت توسط نسخه بتا، از طریق آرتیفکت‌های عمومی قابل مشاهده نیست: کدهای منبع بیلد 13.0.3 منتشر نشده‌اند، مخزن در نسخه 13.0.2 (7175) که در 13 اکتبر منتشر شد، به پایان می‌رسد. خطوط مربوط به دکمه جدید حتی در پلتفرم ترجمه نیز وجود ندارد — این با نسخه مربوط به یک آزمایش شخصی که به مرحله بومی‌سازی نرسیده است، مطابقت دارد. یک فرضیه، نه یک واقعیت از کد: تشخیص یا از طریق یک متد سرور انجام شده که هنوز در طرح عمومی نیست، یا مستقیماً روی دستگاه.

رونویسی در حال حاضر برای چه کسانی در دسترس است

برای پیام‌های صوتی دریافت شده، قوانین در کد کلاینت قابل مشاهده است. رونویسی بدون محدودیت بخشی از Premium است — در توضیحات اشتراک، این خط مربوط به رونویسی هر پیام صوتی دریافتی است. بدون Premium، سرور رونویسی‌های آزمایشی را ارائه می‌دهد: تعداد آنها در هفته و حداکثر طول ضبط توسط کلاینت از پیکربندی سرور خوانده می‌شود، با کلیدهای transcribe_audio_trial_weekly_number و transcribe_audio_trial_duration_max. حداکثر طول در اسنپ‌شات‌های پیکربندی اکتبر 300 ثانیه است، تعداد آزمایش‌ها در هفته بین 0 و 2 متغیر بود. وقتی آزمایش‌ها تمام می‌شوند، کلاینت تاریخی را نشان می‌دهد که باید تا آن زمان صبر کرد، یا Premium را پیشنهاد می‌کند.

RNNoise چگونه کار می‌کند

RNNoise یک کتابخانه حذف نویز متن‌باز از Xiph.Org تحت مجوز BSD است. نویسنده آن Jean-Marc Valin، یکی از سازندگان کدک Opus است؛ ساختار آن در مقاله او در سال 2017 توضیح داده شده است.

رویکرد آن ترکیبی است. پردازش سیگنال کلاسیک، صدا را به فریم‌های 10 میلی‌ثانیه‌ای (480 نمونه در 48 کیلوهرتز) تقسیم می‌کند و طیف هر فریم را به 22 باند فرکانسی تجزیه می‌کند، که عرض آنها نزدیک به نحوه تشخیص فرکانس‌ها توسط گوش است. یک شبکه عصبی بازگشتی کوچک — که فریم‌های قبلی را به خاطر می‌آورد — به ویژگی‌های باندها نگاه می‌کند و برای هر یک ضریبی بین 0 تا 1 ارائه می‌دهد: چه مقدار انرژی در این باند باقی بماند. یک فیلتر جداگانه بر اساس گام صدا، نویز بین هارمونیک‌های صدا را پاک می‌کند. همزمان، شبکه احتمال وجود گفتار در فریم را نیز ارائه می‌دهد.

شبکه 22 ضریب را کنترل می‌کند، نه صدها نمونه فرکانسی، بنابراین کوچک است و در زمان واقعی روی پردازنده تلفن کار می‌کند. نقطه ضعف آن این است که برای جداسازی گفتار از نویز آموزش دیده است، و هر چیزی که شبیه گفتار نباشد، آن را نویز تلقی می‌کند. از اینجا هشدار مربوط به موسیقی می‌آید؛ صدای آرام نیز به همین دلیل از بین می‌رود — ویژگی‌های آن در باندها نزدیک به پس‌زمینه است.

RNNoise قبلاً در برنامه وجود داشت

نیازی به اضافه کردن کتابخانه نبود. کدهای منبع در مخزن کلاینت Android در jni/voip/rnnoise قرار دارند، به عنوان یک کتابخانه استاتیک کامپایل شده و در کتابخانه اصلی بومی برنامه تعبیه می‌شوند. تا کنون در چت‌های ویدیویی کار می‌کرد: ماژول تماس، هر فریم از میکروفون را از طریق RNNoise عبور می‌دهد، ارزیابی گفتار را برای نشانگر گوینده می‌گیرد و صدا را با صدای پاک شده جایگزین می‌کند، زمانی که «حذف نویز» در تنظیمات چت ویدیویی فعال باشد.

کلاینت پیام‌های صوتی را با میکروفون به صورت مونو با فرکانس 48 کیلوهرتز ضبط می‌کند و با کدک Opus در حالت گفتار فشرده می‌کند. فرکانس ضبط با فرکانسی که RNNoise روی آن کار می‌کند مطابقت دارد، بنابراین آزمایش نسخه بتا به یک حلقه بین میکروفون و کدک خلاصه می‌شود — همان حلقه‌ای که مدت‌هاست در چت‌های ویدیویی وجود دارد.