αž€αžΆαžšαžšαž»αž€αžšαž€αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“ Mediastreamer2 VoIP αŸ” αž•αŸ’αž“αŸ‚αž€αž‘αžΈ 10

αžŸαž˜αŸ’αž—αžΆαžšαŸˆαž“αŸƒαž’αžαŸ’αžαž”αž‘αž‚αžΊαž™αž€αž–αžΈαžαŸ’αž‰αž»αŸ† αž”αŸ‰αž»αžŸαŸ’αžαž·αŸ zen.

αž€αŸ’αž“αž»αž„β€‹αž’αžαžΈαžαž€αžΆαž› αž’αžαŸ’αžαž”αž‘ αž™αžΎαž„αž”αžΆαž“αž”αž„αŸ’αž€αžΎαž duplex intercom αžŠαŸ‚αž›αž•αŸ’αž›αžΆαžŸαŸ‹αž”αŸ’αžαžΌαžšαžŸαž‰αŸ’αž‰αžΆαžŸαŸ†αž‘αŸαž„αžαžΆαž˜αžšαž™αŸˆαžœαž‚αŸ’αž‚ RTP αž–αžΈαžšαŸ” αž“αŸ…αž€αŸ’αž“αž»αž„αž’αžαŸ’αžαž”αž‘αž“αŸαŸ‡ αž™αžΎαž„αž“αžΉαž„αžšαŸ€αž“αž–αžΈαžšαž”αŸ€αž”αžŸαžšαžŸαŸαžšαžαž˜αŸ’αžšαž„ αž“αž·αž„αž”αž“αŸ’αžαŸ‚αž˜αžαž˜αŸ’αžšαž„ DIY αž‘αŸ… intercom DIY αŸ”

αž™αžΎαž„αž€αŸ†αž–αž»αž„αž”αž„αŸ’αž€αžΎαžαž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž‡αŸ†αž“αž½αž™

αž€αžΆαžšαžšαž»αž€αžšαž€αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“ Mediastreamer2 VoIP αŸ” αž•αŸ’αž“αŸ‚αž€αž‘αžΈ 10

αž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž‡αŸ†αž“αž½αž™αž“αŸ…αž€αŸ’αž“αž»αž„αž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž•αŸ’αžŸαžΆαž™αž˜αŸαžŒαŸ€ αžŠαžΌαž…αž“αŸ…αž€αŸ’αž“αž»αž„αž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž‡αžΆαž…αŸ’αžšαžΎαž“αž•αŸ’αžŸαŸαž„αž‘αŸ€αž αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αŸ’αžšαžΎαžŠαžΎαž˜αŸ’αž”αžΈαž–αž„αŸ’αžšαžΈαž€αž˜αž»αžαž„αžΆαžšαžŠαŸ„αž™αž˜αž·αž“αž…αžΆαŸ†αž”αžΆαž…αŸ‹αž…αž„αž€αŸ’αžšαž„αž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž•αŸ’αžŸαžΆαž™αž˜αŸαžŒαŸ€αž‘αžΎαž„αžœαž·αž‰αŸ”

αžŠαžΎαž˜αŸ’αž”αžΈαž”αŸ’αžšαžΎαž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž‡αŸ†αž“αž½αž™αž€αŸ’αž“αž»αž„αž€αž˜αŸ’αž˜αžœαž·αž’αžΈαžšαž”αžŸαŸ‹αž’αŸ’αž“αž€ αž’αŸ’αž“αž€αžαŸ’αžšαžΌαžœαž”αŸ’αžšαžΎ αžšαž½αž˜αž”αž‰αŸ’αž…αžΌαž›αž‘αžΆαŸ†αž„ αžαŸ’αžšαžΌαžœαžαŸ‚αžšαž½αž˜αž”αž‰αŸ’αž…αžΌαž›αž―αž€αžŸαžΆαžšαž”αž‹αž˜αž€αžαžΆαž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž‡αŸ†αž“αž½αž™αŸ” αž“αŸ…αž€αŸ’αž“αž»αž„αžαž½αž“αŸƒαž€αž˜αŸ’αž˜αžœαž·αž’αžΈαžŠαŸ„αž™αž”αŸ’αžšαžΎαž˜αž»αžαž„αžΆαžš y ms_filter_register() αž…αž»αŸ‡αžˆαŸ’αž˜αŸ„αŸ‡αžαž˜αŸ’αžšαž„αžαŸ’αž˜αžΈαŸ” αž‡αžΆαž’αž˜αŸ’αž˜αžαžΆ αž€αž˜αŸ’αž˜αžœαž·αž’αžΈαžšαž”αžŸαŸ‹αž’αŸ’αž“αž€ αž“αž·αž„αž”αŸ’αžšαž—αž–αž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž‡αŸ†αž“αž½αž™αžαŸ’αžšαžΌαžœαžαŸ‚αžαŸ’αžšαžΌαžœαž”αžΆαž“αž…αž„αž€αŸ’αžšαž„ αž“αž·αž„αž”αž‰αŸ’αž…αžΌαž›αž‘αŸ…αž€αŸ’αž“αž»αž„αž€αž˜αŸ’αž˜αžœαž·αž’αžΈαžαŸ‚αž˜αž½αž™αŸ”

αž₯αž‘αžΌαžœαž“αŸαŸ‡ αž…αžΌαžšαž™αžΎαž„αž„αžΆαž€αž‘αŸ…αžŸαžšαžŸαŸαžšαž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž‡αŸ†αž“αž½αž™αŸ” αžαž˜αŸ’αžšαž„ αž“αž·αž„αž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž‡αŸ†αž“αž½αž™αž”αŸ’αžšαž–αŸαž“αŸ’αž’αž•αŸ’αžŸαž–αŸ’αžœαž•αŸ’αžŸαžΆαž™αž‘αžΆαŸ†αž„αž’αžŸαŸ‹αž’αŸ’αžœαžΎαžαžΆαž˜ Canon αž‘αžΌαž‘αŸ…αž“αŸ…αž€αŸ’αž“αž»αž„αž€αžΆαžšαžŸαžšαžŸαŸαžšαžšαž”αžŸαŸ‹αž–αž½αž€αž‚αŸ αžŠαŸ‚αž›αž’αŸ’αžœαžΎαž±αŸ’αž™αžœαžΆαž€αžΆαž“αŸ‹αžαŸ‚αž„αžΆαž™αžŸαŸ’αžšαž½αž›αž™αž›αŸ‹αž’αŸ†αž–αžΈαžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αž“αŸƒαžαž˜αŸ’αžšαž„αž”αž“αŸ’αž‘αžΆαž”αŸ‹αžŠαŸ‚αž›αž’αŸ’αž“αž€αž…αž„αŸ‹αžŸαž·αž€αŸ’αžŸαžΆαŸ” αžŠαžΌαž…αŸ’αž“αŸαŸ‡ αž”αž“αŸ’αžαŸ‚αž˜αž‘αŸ€αž αžŠαžΎαž˜αŸ’αž”αžΈαž€αž»αŸ†αž±αŸ’αž™αž‚αž»αžŽαž’αžΆαžαž» αžαŸ’αž‰αž»αŸ†αž“αžΉαž„αž αŸ…αž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž‡αŸ†αž“αž½αž™αžαž˜αŸ’αžšαž„αŸ”

αž…αžΌαžšαž“αž·αž™αžΆαž™αžαžΆαž™αžΎαž„αž…αž„αŸ‹αž”αž„αŸ’αž€αžΎαžαžαž˜αŸ’αžšαž„αžαŸ’αž˜αžΈαž˜αž½αž™αžŠαŸ‚αž›αž˜αžΆαž“αžˆαŸ’αž˜αŸ„αŸ‡αžαžΆ NASH_FILTR αŸ” αžœαžΆαž“αžΉαž„αž’αŸ’αžœαžΎαžšαžΏαž„αžŸαžΆαž˜αž‰αŸ’αž‰αž˜αž½αž™ - αž‘αž‘αž½αž›αž”αŸ’αž›αž»αž€αž–αžΈαž€αžΆαžšαž”αž‰αŸ’αž…αžΌαž›αžαŸ‚αž˜αž½αž™αžšαž”αžŸαŸ‹αžœαžΆ αž αžΎαž™αž”αž‰αŸ’αž‡αžΌαž“αžœαžΆαž‘αŸ…αž›αž‘αŸ’αž’αž•αž›αž‘αžΆαŸ†αž„αž”αŸ’αžšαžΆαŸ†αžšαž”αžŸαŸ‹αžœαžΆαŸ” αžœαžΆαž€αŸαž“αžΉαž„αž”αž„αŸ’αž€αžΎαžαž–αŸ’αžšαžΉαžαŸ’αžαž·αž€αžΆαžšαžŽαŸαž˜αž½αž™αž•αž„αžŠαŸ‚αžš αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž”αŸ’αž›αž»αž€αž…αŸ’αžšαžΎαž“αž‡αžΆαž„αž”αŸ’αžšαžΆαŸ†αžŠαŸ‚αž›αž˜αžΆαž“αž€αž˜αŸ’αžšαž·αžαžŸαž‰αŸ’αž‰αžΆαž‘αžΆαž”αž‡αžΆαž„αž€αž˜αŸ’αžšαž·αžαžŠαŸ‚αž›αž”αžΆαž“αž•αŸ’αžαž›αŸ‹αž±αŸ’αž™αž†αŸ’αž›αž„αž€αžΆαžαŸ‹αžœαžΆ αž αžΎαž™αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž…αŸ’αžšαžΎαž“αž‡αžΆαž„αž”αŸ’αžšαžΆαŸ†αž”αŸ’αž›αž»αž€αžŠαŸ‚αž›αž˜αžΆαž“αž€αž˜αŸ’αžšαž·αžαžŸαž‰αŸ’αž‰αžΆαž›αžΎαžŸαž–αžΈαž€αž˜αŸ’αžšαž·αžαž€αŸ†αžŽαžαŸ‹αž†αŸ’αž›αž„αž€αžΆαžαŸ‹αžœαžΆ αžœαžΆαž€αŸαž“αžΉαž„αž”αž„αŸ’αž€αžΎαžαž–αŸ’αžšαžΉαžαŸ’αžαž·αž€αžΆαžšαžŽαŸαž•αž„αžŠαŸ‚αžšαŸ”

αž€αž˜αŸ’αžšαž·αžαž“αžΉαž„αžαŸ’αžšαžΌαžœαž”αžΆαž“αž€αŸ†αžŽαžαŸ‹αžŠαŸ„αž™αž”αŸ’αžšαžΎαžœαž·αž’αžΈαžŸαžΆαžŸαŸ’αžαŸ’αžšαžαž˜αŸ’αžšαž„αŸ” αžœαž·αž’αžΈαžŸαžΆαžŸαŸ’αžšαŸ’αžαž‘αžΈαž–αžΈαžš αž“αž·αž„αž‘αžΈαž”αžΈαž“αžΉαž„αž’αž“αž»αž‰αŸ’αž‰αžΆαž/αž αžΆαž˜αžƒαžΆαžαŸ‹αž€αžΆαžšαž†αŸ’αž›αž„αž€αžΆαžαŸ‹αž”αŸ’αž›αž»αž€αž‘αŸ…αž€αžΆαž“αŸ‹αž…αŸ’αžšαž€αž…αŸαž‰αŸ”

αžαŸ„αŸ‡β€‹αž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜αŸ” αž“αŸ…αž–αŸαž›αžŸαžšαžŸαŸαžšαžαž˜αŸ’αžšαž„ αž’αŸ’αž“αž€αžαŸ’αžšαžΌαžœαž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜αž‡αžΆαž˜αž½αž™αž―αž€αžŸαžΆαžšαž”αž‹αž˜αž€αžαžΆαŸ” αž“αŸ…αž€αŸ’αž“αž»αž„αž‡αž½αžšαž‘αžΈαž˜αž½αž™αžœαžΆαž‚αž½αžšαžαŸ‚αžšαž½αž˜αž”αž‰αŸ’αž…αžΌαž›αž―αž€αžŸαžΆαžš msfilter.hαžŠαŸ„αž™αž”αŸ’αžšαžΎαž˜αŸ‰αžΆαž€αŸ’αžšαžΌ MS_FILTER_METHOD αž”αŸ’αžšαž€αžΆαžŸαžœαž·αž’αžΈαžŸαžΆαžŸαŸ’αžšαŸ’αžαž“αŸƒαžαž˜αŸ’αžšαž„αžαŸ’αž˜αžΈ (αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž˜αžΆαž“) αž”αŸ’αžšαž€αžΆαžŸαž–αŸ’αžšαžΉαžαŸ’αžαž·αž€αžΆαžšαžŽαŸαžŠαŸ‚αž›αž”αž„αŸ’αž€αžΎαžαžŠαŸ„αž™αžαž˜αŸ’αžšαž„ (αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž˜αžΆαž“) αž“αž·αž„αž”αŸ’αžšαž€αžΆαžŸαžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αžŠαŸ‚αž›αž”αžΆαž“αž“αžΆαŸ†αž…αŸαž‰αž“αŸƒαž”αŸ’αžšαž—αŸαž‘ MSFilterDesc αž‡αžΆαž˜αž½αž™αž“αžΉαž„αž€αžΆαžšαž–αž·αž–αžŽαŸŒαž“αžΆαž’αŸ†αž–αžΈαž”αŸ‰αžΆαžšαŸ‰αžΆαž˜αŸ‰αŸ‚αžαŸ’αžšαžαž˜αŸ’αžšαž„αŸ–

/* Π€Π°ΠΉΠ» nash_filter.h, описываСт Ρ„ΠΈΠ»ΡŒΡ‚Ρ€-Ρ€Π°Π·Π²Π΅Ρ‚Π²ΠΈΡ‚Π΅Π»ΡŒ ΠΈ Π½ΠΎΠΉΠ·Π³Π΅ΠΉΡ‚. */

#ifndef myfilter_h
#define myfilter_h

/* ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» с пСрСчислСниСм Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ΠΎΠ² мСдиастримСра. */
#include <mediastreamer2/msticker.h>

/* 
   Π—Π°Π΄Π°Π΅ΠΌ числовой ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ Π½ΠΎΠ²ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ° Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°.  Π­Ρ‚ΠΎ число Π½Π΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ
   ΡΠΎΠ²ΠΏΠ°Π΄Π°Ρ‚ΡŒ Π½ΠΈ с ΠΎΠ΄Π½ΠΈΠΌ ΠΈΠ· Π΄Ρ€ΡƒΠ³ΠΈΡ… Ρ‚ΠΈΠΏΠΎΠ².  Π’ мСдиастримСрС  Π² Ρ„Π°ΠΉΠ»Π΅ allfilters.h
   Π΅ΡΡ‚ΡŒ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π΅Π΅ пСрСчислСниС enum MSFilterId. К соТалСнию, нСпонятно
   ΠΊΠ°ΠΊ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ максимальноС занятоС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, ΠΊΡ€ΠΎΠΌΠ΅ ΠΊΠ°ΠΊ Π·Π°Π³Π»ΡΠ½ΡƒΡ‚ΡŒ Π² этот
   Ρ„Π°ΠΉΠ». Но ΠΌΡ‹ возьмСм Π² качСствС id для нашСго Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π° Π·Π°Π²Π΅Π΄ΠΎΠΌΠΎ большСС
   Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅: 4000.  Π‘ΡƒΠ΄Π΅ΠΌ ΠΏΠΎΠ»Π°Π³Π°Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ добавляя Π½ΠΎΠ²Ρ‹Π΅ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Ρ‹, Π½Π΅
   скоро добСрутся Π΄ΠΎ этого Π½ΠΎΠΌΠ΅Ρ€Π°.  
   */
#define NASH_FILTER_ID 4000

/* 
   ΠžΠΏΡ€Π΅Π΄Π΅Π»ΡΠ΅ΠΌ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ нашСго Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°. Π’Ρ‚ΠΎΡ€Ρ‹ΠΌ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠΌ макроса Π΄ΠΎΠ»ΠΆΠ΅Π½
   порядковый Π½ΠΎΠΌΠ΅Ρ€ ΠΌΠ΅Ρ‚ΠΎΠ΄Π°, число ΠΎΡ‚ 0.  Π’Ρ€Π΅Ρ‚ΠΈΠΉ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ это Ρ‚ΠΈΠΏ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π°
   ΠΌΠ΅Ρ‚ΠΎΠ΄Π°, ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Ρ‚ΡŒΡΡ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρƒ ΠΏΡ€ΠΈ Π²Ρ‹Π·ΠΎΠ²Π΅. Π£ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ²
   Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ² ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈ Π½Π΅ Π±Ρ‹Ρ‚ΡŒ, ΠΊΠ°ΠΊ ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ Π½ΠΈΠΆΠ΅. 
   */
#define NASH_FILTER_SET_TRESHOLD MS_FILTER_METHOD(NASH_FILTER_ID , 0, float)
#define NASH_FILTER_TUNE_OFF     MS_FILTER_METHOD_NO_ARG(NASH_FILTER_ID ,1)
#define NASH_FILTER_TUNE_ON      MS_FILTER_METHOD_NO_ARG(NASH_FILTER_ID ,2)

/* Π’Π΅ΠΏΠ΅Ρ€ΡŒ опрСдСляСм структуру, которая Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Ρ‚ΡŒΡΡ вмСстС с событиСм. */
struct _NASHFilterEvent
{
    /* Π­Ρ‚ΠΎ ΠΏΠΎΠ»Π΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒ Ρ€ΠΎΠ»ΡŒ Ρ„Π»Π°Π³Π°,
       0 - появились Π½ΡƒΠ»ΠΈ, 1 - появился сигнал.*/
    char state; 
    /* ВрСмя, ΠΊΠΎΠ³Π΄Π° ΠΏΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»ΠΎ событиС. */
    uint64_t time;
};
typedef struct _NASHFilterEvent NASHFilterEvent;

/* ΠžΠΏΡ€Π΅Π΄Π΅Π»ΡΠ΅ΠΌ событиС для нашСго Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°. */
#define NASH_FILTER_EVENT MS_FILTER_EVENT(MS_RTP_RECV_ID, 0, NASHFilterEvent)

/* ΠžΠΏΡ€Π΅Π΄Π΅Π»ΡΠ΅ΠΌ ΡΠΊΡΠΏΠΎΡ€Ρ‚ΠΈΡ€ΡƒΠ΅ΠΌΡƒΡŽ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ, которая Π±ΡƒΠ΄Π΅Ρ‚
   Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ характСристики для Π΄Π°Π½Π½ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ° Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ΠΎΠ². */
extern MSFilterDesc nash_filter_desc;

#endif /* myfilter_h */

αž₯αž‘αžΌαžœαž’αŸ’αž“αž€αž’αžΆαž…αž”αž“αŸ’αžαž‘αŸ…αž―αž€αžŸαžΆαžšαž”αŸ’αžšαž—αž–αŸ” αž€αžΌαžŠαž”αŸ’αžšαž—αž–αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžαž˜αŸ’αžšαž„αžŠαŸ‚αž›αž˜αžΆαž“αž˜αžαž·αž™αŸ„αž”αž›αŸ‹αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αž„αŸ’αž αžΆαž‰αžαžΆαž„αž€αŸ’αžšαŸ„αž˜αŸ” αžœαž·αž’αžΈαžŸαžΆαžŸαŸ’αžαŸ’αžšαžαž˜αŸ’αžšαž„ αž“αž·αž„αž˜αž»αžαž„αžΆαžšαžαž˜αŸ’αžšαž„αžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαž€αžΆαžšαžαŸ’αžšαžΌαžœαž”αžΆαž“αž€αŸ†αžŽαžαŸ‹αž“αŸ…αž‘αžΈαž“αŸαŸ‡αŸ” αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž˜αž€αžŸαŸαž…αž€αŸ’αžαžΈαž™αŸ„αž„αž‘αŸ…αžœαž·αž’αžΈαžŸαžΆαžŸαŸ’αžšαŸ’αž αž“αž·αž„αž˜αž»αžαž„αžΆαžšαžαŸ’αžšαžΌαžœαž”αžΆαž“αžŠαžΆαž€αŸ‹αž€αŸ’αž“αž»αž„αž›αŸ†αžŠαžΆαž”αŸ‹αž‡αžΆαž€αŸ‹αž›αžΆαž€αŸ‹αž˜αž½αž™αž“αŸ…αž€αŸ’αž“αž»αž„αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αžŠαŸ‚αž›αž”αžΆαž“αž“αžΆαŸ†αž…αŸαž‰ our_filter_desc. αžŠαŸ‚αž›β€‹αžαŸ’αžšαžΌαžœβ€‹αž”αžΆαž“β€‹αž”αŸ’αžšαžΎβ€‹αžŠαŸ„αž™β€‹αž’αŸ’αž“αž€β€‹αž•αŸ’αžŸαžΆαž™β€‹αž˜αŸαžŒαŸ€β€‹αžŠαžΎαž˜αŸ’αž”αžΈ "αž•αŸ’αžŸαžΆαŸ†" αžαž˜αŸ’αžšαž„β€‹αž”αŸ’αžšαž—αŸαž‘β€‹αž“αŸαŸ‡β€‹αž‘αŸ…αž€αŸ’αž“αž»αž„β€‹αž›αŸ†αž αžΌαžšβ€‹αž€αžΆαžšαž„αžΆαžšβ€‹αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšβ€‹αž‘αž·αž“αŸ’αž“αž“αŸαž™αŸ”

/* Π€Π°ΠΉΠ» nash_filter.с, описываСт Ρ„ΠΈΠ»ΡŒΡ‚Ρ€-Ρ€Π°Π·Π²Π΅Ρ‚Π²ΠΈΡ‚Π΅Π»ΡŒ ΠΈ Π½ΠΎΠΉΠ·Π³Π΅ΠΉΡ‚. */

#include "nash_filter.h"
#include <math.h>

#define NASH_FILTER_NOUTPUTS 5

/* ΠžΠΏΡ€Π΅Π΄Π΅Π»ΡΠ΅ΠΌ структуру, которая Ρ…Ρ€Π°Π½ΠΈΡ‚ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½Π΅Π΅ состояниС Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°. */
typedef struct _nash_filterData
{
    bool_t disable_out;  /* Π Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ Π±Π»ΠΎΠΊΠΎΠ² Π½Π° Π²Ρ‹Ρ…ΠΎΠ΄. */
    int last_state;   /* Π’Π΅ΠΊΡƒΡ‰Π΅Π΅ состояниС ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡Π°Ρ‚Π΅Π»Ρ. */
    char zero_count;     /* Π‘Ρ‡Π΅Ρ‚Ρ‡ΠΈΠΊ Π½ΡƒΠ»Π΅Π²Ρ‹Ρ… Π±Π»ΠΎΠΊΠΎΠ². */
    char lag;            /* ΠšΠΎΠ»ΠΈΡ‡Π΅ΡΡ‚Π²ΠΎ Π±Π»ΠΎΠΊΠΎΠ² для принятия Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ Π½ΠΎΠΉΠ·Π³Π΅ΠΉΡ‚ΠΎΠΌ. */
    char n_count;        /* Π‘Ρ‡Π΅Ρ‚Ρ‡ΠΈΠΊ НЕнулСвых Π±Π»ΠΎΠΊΠΎΠ². */
    float skz_level;     /* БрСднСквадратичСскоС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ сигнала Π²Π½ΡƒΡ‚Ρ€ΠΈ
Π±Π»ΠΎΠΊΠ°, ΠΏΡ€ΠΈ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΡ€ΠΎΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ сигнал. ΠžΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ это ΠΏΠΎΡ€ΠΎΠ³
срабатывания, ΠΏΠΎ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌΡƒ Π±ΡƒΠ΄Π΅Ρ‚ Ρ„ΠΎΡ€ΠΌΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒΡΡ событиС.  */

} nash_filterData;

/*----------------------------------------------------------*/
/* ΠžΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Π°Ρ функция ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ. */
static void nash_filter_init(MSFilter *f)
{
    nash_filterData *d=ms_new0(nash_filterData, 1);
    d->lag=5;
    f->data=d;
}

/*----------------------------------------------------------*/
/* ΠžΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Π°Ρ функция Ρ„ΠΈΠ½Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ Ρ€Π°Π±ΠΎΡ‚Ρ‹ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°,
   освобоТдаСтся ΠΏΠ°ΠΌΡΡ‚ΡŒ. */
static void nash_filter_uninit(MSFilter *f)
{
    ms_free(f->data);
}

/*----------------------------------------------------------*/
/* ΠžΠΏΡ€Π΅Π΄Π΅Π»ΡΠ΅ΠΌ ΠΎΠ±Ρ€Π°Π·Ρ†ΠΎΠ²Ρ‹ΠΉ массив с нулями, Π·Π°Π²Π΅Π΄ΠΎΠΌΠΎ
   большСго Ρ€Π°Π·ΠΌΠ΅Ρ€Π° Ρ‡Π΅ΠΌ Π±Π»ΠΎΠΊ. */
char zero_array[1024]={0};

/* ΠžΠΏΡ€Π΅Π΄Π΅Π»ΡΠ΅ΠΌ событиС Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°. */
NASHFilterEvent event;

/*----------------------------------------------------------*/
/* Ѐункция ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠΈ события. */
static void send_event(MSFilter *f, int state)
{
    nash_filterData *d =( nash_filterData* ) f->data;
     d->last_state = state;
    /* УстанавливаСм врСмя возникновСния события,
       ΠΎΡ‚ ΠΌΠΎΠΌΠ΅Π½Ρ‚Π° ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ Ρ‚ΠΈΠΊΠ°. ВрСмя Π² миллисСкундах. */
    event.time=f -> ticker -> time;
    event.state=state;  
    ms_filter_notify(f, NASH_FILTER_EVENT, &event);
}   

/*----------------------------------------------------------*/
/* Ѐункция вычисляСт срСднСквадратичСскоС (эффСктивноС) Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ сигнала Π²Π½ΡƒΡ‚Ρ€ΠΈ
  Π±Π»ΠΎΠΊΠ°. */
static float calc_skz(nash_filterData *d, int16_t *signal, int numsamples)
{
    int i;
    float acc = 0;
    for (i=0; i<numsamples; i++)
    {
        int s=signal[i];
        acc = acc + s * s;
    }
    float skz = (float)sqrt(acc / numsamples);
    return skz;
}

/*----------------------------------------------------------*/
/* ΠžΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Π°Ρ функция основного Ρ†ΠΈΠΊΠ»Π° Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°,
   вызываСтся с ΠΊΠ°ΠΆΠ΄Ρ‹ΠΌ Ρ‚ΠΈΠΊΠΎΠΌ. */
static void nash_filter_process(MSFilter *f)
{
    nash_filterData *d=(nash_filterData*)f->data;

    /* Π£ΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° Π²Ρ…ΠΎΠ΄Π½ΠΎΠ΅ сообщСниС содСрТащСС Π±Π»ΠΎΠΊ Π΄Π°Π½Π½Ρ‹Ρ…. */
    mblk_t *im;
    int i;
    int state;
    /* Π’Ρ‹Ρ‡ΠΈΡ‚Ρ‹Π²Π°Π΅ΠΌ сообщСния ΠΈΠ· Π²Ρ…ΠΎΠ΄Π½ΠΎΠΉ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ
       Π΄ΠΎ ΠΏΠΎΠ»Π½ΠΎΠ³ΠΎ Π΅Ρ‘ ΠΎΠΏΡƒΡΡ‚ΠΎΡˆΠ΅Π½ΠΈΡ. */
    while((im=ms_queue_get(f->inputs[0]))!=NULL)
    {
        /* Если Π²Ρ‹Ρ…ΠΎΠ΄Ρ‹ Π·Π°ΠΏΡ€Π΅Ρ‰Π΅Π½Ρ‹, Ρ‚ΠΎ просто удаляСм Π²Ρ…ΠΎΠ΄Π½ΠΎΠ΅ сообщСниС. */
        if ( d -> disable_out)
        {
          freemsg(im);
          continue;
        }

        /* Π˜Π·ΠΌΠ΅Ρ€ΡΠ΅ΠΌ ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ сигнала ΠΈ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅ΠΌ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ ΠΎΠ± ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠ΅ сигнала. */
        float skz = calc_skz(d, (int16_t*)im->b_rptr, msgdsize(im));
        state = (skz > d->skz_level) ? 1 : 0; 
        if (state) 
        {
            d->n_count++;
            d->zero_count = 0;
        }
        else
        {
            d->n_count = 0;
            d->zero_count++;
        }
        if (((d->zero_count > d->lag) || (d->n_count > d->lag))
            &&  (d->last_state != state)) send_event(f, state);

        /* ΠŸΡ€ΠΈΡΡ‚ΡƒΠΏΠ°Π΅ΠΌ ΠΊ ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Π½ΠΈΡŽ Π²Ρ…ΠΎΠ΄Π½ΠΎΠ³ΠΎ сообщСния ΠΈ раскладкС ΠΏΠΎ Π²Ρ‹Ρ…ΠΎΠ΄Π°ΠΌ. Но
         * Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏΠΎ Ρ‚Π΅ΠΌ, ΠΊ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½Π° Π½Π°Π³Ρ€ΡƒΠ·ΠΊΠ°. ΠžΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠ΅ сообщСниС
         * ΡƒΠΉΠ΄Π΅Ρ‚ Π½Π° Π²Ρ‹Ρ…ΠΎΠ΄ с индСксом 0, Π° Π΅Π³ΠΎ ΠΊΠΎΠΏΠΈΠΈ ΠΏΠΎΠΏΠ°Π΄ΡƒΡ‚ Π½Π° ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅
         * Π²Ρ‹Ρ…ΠΎΠ΄Ρ‹. */ 
        int output_count = 0;
        mblk_t *outm; /* Π£ΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° сообщСниС с Π²Ρ‹Ρ…ΠΎΠ΄Π½Ρ‹ΠΌ Π±Π»ΠΎΠΊΠΎΠΌ Π΄Π°Π½Π½Ρ‹Ρ…. */
        for(i=0; i < f->desc->noutputs; i++)
        {
            if (f->outputs[i]!=NULL)
            {
                if (output_count == 0)
                {
                    outm = im;
                }
                else
                {
                    /* Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ Π»Π΅Π³ΠΊΡƒΡŽ копию сообщСния. */       
                    outm = dupmsg(im);
                }
                /* ΠŸΠΎΠΌΠ΅Ρ‰Π°Π΅ΠΌ копию ΠΈΠ»ΠΈ ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π» Π²Ρ…ΠΎΠ΄Π½ΠΎΠ³ΠΎ сообщСния Π½Π° ΠΎΡ‡Π΅Ρ€Π΅Π΄Π½ΠΎΠΉ
                 * Π²Ρ‹Ρ…ΠΎΠ΄ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°. */ 
                ms_queue_put(f->outputs[i], outm);
                output_count++;
            }
        }
    }
}

/*----------------------------------------------------------*/
/* Ѐункция-ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Π²Ρ‹Π·ΠΎΠ²Π° ΠΌΠ΅Ρ‚ΠΎΠ΄Π° NASH_FILTER_SET_LAG. */
static int nash_filter_set_treshold(MSFilter *f, void *arg)
{
    nash_filterData *d=(nash_filterData*)f->data;
    d->skz_level=*(float*)arg;
    return 0;
}

/*----------------------------------------------------------*/
/* Ѐункция-ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Π²Ρ‹Π·ΠΎΠ²Π° ΠΌΠ΅Ρ‚ΠΎΠ΄Π° NASH_FILTER_TUNE_OFF. */
static int nash_filter_tune_off(MSFilter *f, void *arg)
{
    nash_filterData *d=(nash_filterData*)f->data;
    d->disable_out=TRUE;
    return 0;
}

/*----------------------------------------------------------*/
/* Ѐункция-ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Π²Ρ‹Π·ΠΎΠ²Π° ΠΌΠ΅Ρ‚ΠΎΠ΄Π° NASH_FILTER_TUNE_ON. */
static int nash_filter_tune_on(MSFilter *f, void *arg)
{
    nash_filterData *d=(nash_filterData*)f->data;
    d->disable_out=FALSE;
    return 0;
}

/*----------------------------------------------------------*/
/* ЗаполняСм Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°, сколько ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ²
   ΠΌΡ‹ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΠ»ΠΈ Π² Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΡ‡Π½ΠΎΠΌ Ρ„Π°ΠΉΠ»Π΅ ΡΡ‚ΠΎΠ»ΡŒΠΊΠΎ Π½Π΅Π½ΡƒΠ»Π΅Π²Ρ‹Ρ…
   строк. */
static MSFilterMethod nash_filter_methods[]={
    { NASH_FILTER_SET_TRESHOLD, nash_filter_set_treshold },
    { NASH_FILTER_TUNE_OFF, nash_filter_tune_off },
    { NASH_FILTER_TUNE_ON, nash_filter_tune_on },
    { 0 , NULL } /* ΠœΠ°Ρ€ΠΊΠ΅Ρ€ ΠΊΠΎΠ½Ρ†Π° Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹. */
};

/*----------------------------------------------------------*/
/* ОписаниС Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π° для мСдиастримСра. */
MSFilterDesc nash_filter_desc=
{
    NASH_FILTER_ID,
    "NASH_FILTER",
    "A filter with noise gate that reads from input and copy to it's five outputs.",
    MS_FILTER_OTHER,
    NULL,
    1,
    NASH_FILTER_NOUTPUTS,
    nash_filter_init,
    NULL,
    nash_filter_process,
    NULL,
    nash_filter_uninit,
    nash_filter_methods
};

MS_FILTER_DESC_EXPORT(nash_filter_desc)

αž₯αž‘αžΌαžœαž“αŸαŸ‡αžŠαŸ„αž™αž‚αŸ’αž˜αžΆαž“αž€αžΆαžšαž–αž“αŸ’αž™αžΆαž–αŸαž› αž…αžΌαžšαž™αžΎαž„αž”αŸ’αžšαžΎαžαž˜αŸ’αžšαž„αžšαž”αžŸαŸ‹αž™αžΎαž„αž“αŸ…αž€αŸ’αž“αž»αž„ intercom αžŠαŸ‚αž›αž™αžΎαž„αž”αžΆαž“αž”αž„αŸ’αž€αžΎαžαž˜αž»αž“αŸ” αžšαžΌαž”αž—αžΆαž–αž…αŸ†αžŽαž„αž‡αžΎαž„αž”αž„αŸ’αž αžΆαž‰αž–αžΈαžŠαŸ’αž™αžΆαž€αŸ’αžšαžΆαž˜αž“αŸƒ intercom αžŠαŸ‚αž›αž”αžΆαž“αž€αŸ‚αž”αŸ’αžšαŸ‚αŸ”
αž™αžΎαž„αž…αž„αŸ‹αž–αžŽαŸŒαž“αžΆαžαž˜αŸ’αžšαž„αž’αŸ’αžœαžΎαžŠαŸ„αž™αžŠαŸƒαžšαž”αžŸαŸ‹αž™αžΎαž„αžαžΆαž˜αžšαž”αŸ€αž”αž—αŸ’αž›αžΊαž–αž·αžŸαŸαžŸαŸ” αžŠαžΌαž…αŸ’αž“αŸαŸ‡αž’αŸ’αž“αž€αž“αžΉαž„αžƒαžΎαž‰αžαž˜αŸ’αžšαž„αžšαž”αžŸαŸ‹αž™αžΎαž„αž—αŸ’αž›αžΆαž˜αŸ—αž“αŸ…αž€αŸ’αž“αž»αž„αžŠαŸ’αž™αžΆαž€αŸ’αžšαžΆαž˜αŸ”

αž§αž”αž€αžšαžŽαŸαžαžαž…αž˜αŸ’αž›αž„αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αž“αŸ’αžαŸ‚αž˜αž‘αŸ…αžŸαŸ€αž‚αŸ’αžœαžΈαžŠαŸ‚αž›αžŸαžšαžŸαŸαžšαžŸαž‰αŸ’αž‰αžΆαž”αž‰αŸ’αž…αžΌαž›αž‘αŸ…αž―αž€αžŸαžΆαžš wav αŸ” αžŠαžΌαž…αžŠαŸ‚αž›αž”αžΆαž“αž‚αŸ’αžšαŸ„αž„αž‘αž»αž€ αžαž˜αŸ’αžšαž„αžšαž”αžŸαŸ‹αž™αžΎαž„αž“αžΉαž„αž’αž“αž»αž‰αŸ’αž‰αžΆαžαž±αŸ’αž™αž’αŸ’αž“αž€αž‡αŸ€αžŸαžœαžΆαž„αž€αžΆαžšαžŸαžšαžŸαŸαžšαž•αŸ’αž’αžΆαž€αž€αŸ’αž“αž»αž„αž€αžΆαžšαž“αž·αž™αžΆαž™αž‘αŸ…αž€αŸ’αž“αž»αž„αž―αž€αžŸαžΆαžšαŸ” αžŠαžΌαž…αŸ’αž“αŸαŸ‡αž€αžΆαžαŸ‹αž”αž“αŸ’αžαž™αž‘αŸ†αž αŸ†αžšαž”αžŸαŸ‹αžœαžΆαŸ”
αž“αŸ…αžŠαžΎαž˜αž’αžαŸ’αžαž”αž‘ αž™αžΎαž„αž”αžΆαž“αž–αžŽαŸŒαž“αžΆαž’αŸ†αž–αžΈαž€αŸ’αž”αž½αž“αžŠαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™αžšαž”αžŸαŸ‹αžαž˜αŸ’αžšαž„αŸ” αž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž…αž˜αŸ’αž”αž„αž‚αŸ’αžšαž”αŸ‹αž‚αŸ’αžšαž„αž–αŸ’αžšαžΉαžαŸ’αžαž·αž€αžΆαžšαžŽαŸαžŠαŸ‚αž›αžœαžΆαž”αž„αŸ’αž€αžΎαžαŸ” αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž–αŸ’αžšαžΉαžαŸ’αžαž·αž€αžΆαžšαžŽαŸαž˜αžΆαž“αž‘αž„αŸ‹ "0" αž“αŸ„αŸ‡αž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž“αžΉαž„αž•αŸ’αž’αžΆαž€αž€αžΆαžšαžαžαŸ” αžŠαžšαžΆαž”αžŽαžΆαž–αŸ’αžšαžΉαžαŸ’αžαž·αž€αžΆαžšαžŽαŸαžŠαŸ‚αž›αž˜αžΆαž“αž‘αž„αŸ‹ β€œ1” αž˜αž€αžŠαž›αŸ‹ αž€αžΆαžšαžαžαž“αžΉαž„αž”αž“αŸ’αžαŸ”

αž’αžΆαž‚αž»αž™αž˜αŸ‰αž„αŸ‹β€‹αž”αž“αŸ’αž‘αžΆαžαŸ‹β€‹αž–αžΆαž€αŸ’αž™β€‹αž”αž‰αŸ’αž‡αžΆβ€‹αž–αžΈαžšβ€‹αž‘αŸ€αžβ€‹αžαŸ’αžšαžΌαžœβ€‹αž”αžΆαž“β€‹αž”αž“αŸ’αžαŸ‚αž˜β€‹αž‘αŸ…β€‹αž…αŸ†αžŽαž»αž…β€‹αž˜αž»αž“β€‹αŸ—αŸ– --ngαžŠαŸ‚αž›αž€αŸ†αžŽαžαŸ‹αž€αž˜αŸ’αžšαž·αžαž€αž˜αŸ’αžšαž·αžαžαž˜αŸ’αžšαž„ αž“αž·αž„ --recαžŠαŸ‚αž›αž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜αžŸαžšαžŸαŸαžšαž‘αŸ…αž―αž€αžŸαžΆαžšαžŠαŸ‚αž›αž αŸ…αžαžΆ record.wav.

/* Π€Π°ΠΉΠ» mstest9.c Π˜ΠΌΠΈΡ‚Π°Ρ‚ΠΎΡ€ ΠΏΠ΅Ρ€Π΅Π³ΠΎΠ²ΠΎΡ€Π½ΠΎΠ³ΠΎ устройства c рСгистратором ΠΈ
* Π½ΠΎΠΉΠ·Π³Π΅ΠΉΡ‚ΠΎΠΌ. */
#include <mediastreamer2/mssndcard.h>
#include <mediastreamer2/dtmfgen.h>
#include <mediastreamer2/msrtp.h>
#include <mediastreamer2/msfilerec.h>
/* ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ наш Ρ„ΠΈΠ»ΡŒΡ‚Ρ€. */
#include "nash_filter.h"
/* ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ Ρ„Π°ΠΉΠ» ΠΎΠ±Ρ‰ΠΈΡ… Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ. */
#include "mstest_common.c"
/*----------------------------------------------------------*/
struct _app_vars
{
int  local_port;              /* Π›ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΉ ΠΏΠΎΡ€Ρ‚. */
int  remote_port;             /* ΠŸΠΎΡ€Ρ‚ ΠΏΠ΅Ρ€Π΅Π³ΠΎΠ²ΠΎΡ€Π½ΠΎΠ³ΠΎ устройства Π½Π° ΡƒΠ΄Π°Π»Π΅Π½Π½ΠΎΠΌ ΠΊΠΎΠΌΠΏΡŒΡŽΡ‚Π΅Ρ€Π΅. */
char remote_addr[128];        /* IP-адрСс ΡƒΠ΄Π°Π»Π΅Π½Π½ΠΎΠ³ΠΎ ΠΊΠΎΠΌΠΏΡŒΡŽΡ‚Π΅Ρ€Π°. */
MSDtmfGenCustomTone dtmf_cfg; /* Настройки тСстового сигнала Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€Π°. */
MSFilter* recorder;           /* Π£ΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ рСгистратор. */
bool_t file_is_open;          /* Π€Π»Π°Π³ Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ Ρ„Π°ΠΉΠ» для записи ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚. */
/* ΠŸΠΎΡ€ΠΎΠ³, ΠΏΡ€ΠΈ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ прСкращаСтся запись ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅ΠΌΠΎΠ³ΠΎ сигнала Π² Ρ„Π°ΠΉΠ». */
float treshold; 
bool_t en_rec;                /*Π’ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ запись Π² Ρ„Π°ΠΉΠ».*/    
};
typedef struct _app_vars app_vars;
/*----------------------------------------------------------*/
/* Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ Π΄ΡƒΠΏΠ»Π΅ΠΊΡΠ½ΡƒΡŽ RTP-сСссию. */
RtpSession* create_duplex_rtp_session(app_vars v)
{
RtpSession *session = create_rtpsession (v.local_port, v.local_port + 1,
FALSE, RTP_SESSION_SENDRECV);
rtp_session_set_remote_addr_and_port(session, v.remote_addr, v.remote_port,
v.remote_port + 1);
rtp_session_set_send_payload_type(session, PCMU);
return session;
}
/*----------------------------------------------------------*/
/* Ѐункция прСобразования Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ² ΠΊΠΎΠΌΠ°Π½Π΄Π½ΠΎΠΉ строки Π² 
* настройки ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹. */
void  scan_args(int argc, char *argv[], app_vars *v)
{
char i;
for (i=0; i<argc; i++)
{
if (!strcmp(argv[i], "--help"))
{
char *p=argv[0]; p=p + 2;
printf("  %s walkie talkienn", p);
printf("--help      List of options.n");
printf("--version   Version of application.n");
printf("--addr      Remote abonent IP address string.n");
printf("--port      Remote abonent port number.n");
printf("--lport     Local port number.n");
printf("--gen       Generator frequency.n");
printf("--ng        Noise gate treshold level from 0. to 1.0n");
printf("--rec       record to file 'record.wav'.n");
exit(0);
}
if (!strcmp(argv[i], "--version"))
{
printf("0.1n");
exit(0);
}
if (!strcmp(argv[i], "--addr"))
{
strncpy(v->remote_addr, argv[i+1], 16);
v->remote_addr[16]=0;
printf("remote addr: %sn", v->remote_addr);
}
if (!strcmp(argv[i], "--port"))
{
v->remote_port=atoi(argv[i+1]);
printf("remote port: %in", v->remote_port);
}
if (!strcmp(argv[i], "--lport"))
{
v->local_port=atoi(argv[i+1]);
printf("local port : %in", v->local_port);
}
if (!strcmp(argv[i], "--gen"))
{
v -> dtmf_cfg.frequencies[0] = atoi(argv[i+1]);
printf("gen freq : %in", v -> dtmf_cfg.frequencies[0]);
}
if (!strcmp(argv[i], "--ng"))
{
v -> dtmf_cfg.frequencies[0] = atoi(argv[i+1]);
printf("noise gate treshold: %fn", v -> treshold);
}
if (!strcmp(argv[i], "--rec"))
{
v -> en_rec = TRUE;
printf("enable recording: %in", v -> en_rec);
}
}
}
/*----------------------------------------------------------*/
/* Ѐункция ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠ³ΠΎ Π²Ρ‹Π·ΠΎΠ²Π°, ΠΎΠ½Π° Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π·Π²Π°Π½Π° Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ΠΎΠΌ, ΠΊΠ°ΠΊ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ½
* Π·Π°ΠΌΠ΅Ρ‚ΠΈΡ‚, Ρ‡Ρ‚ΠΎ наступила Ρ‚ΠΈΡˆΠΈΠ½Π° ΠΈΠ»ΠΈ Π½Π°ΠΎΠ±ΠΎΡ€ΠΎΡ‚ Ρ‚ΠΈΡˆΠΈΠ½Π° смСнилась Π·Π²ΡƒΠΊΠ°ΠΌΠΈ. */
static void change_detected_cb(void *data, MSFilter *f, unsigned int event_id,
NASHFilterEvent *ev)
{
app_vars *vars = (app_vars*) data;
/* Если запись Π½Π΅ Π±Ρ‹Π»Π° Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½Π°, Ρ‚ΠΎ Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΠΌ. */
if (! vars -> en_rec) return; 
if (ev -> state)
{
/* ВозобновляСм запись. */
if(!vars->file_is_open)
{
ms_filter_call_method(vars->recorder, MS_FILE_REC_OPEN, "record.wav");
vars->file_is_open = 1;
}
ms_filter_call_method(vars->recorder, MS_FILE_REC_START, 0);
printf("Recording...n");
}
else
{
/* ΠŸΡ€ΠΈΠΎΡΡ‚Π°Π½Π°Π²Π»ΠΈΠ²Π°Π΅ΠΌ запись. */
ms_filter_call_method(vars->recorder, MS_FILE_REC_STOP, 0);
printf("Pause...n");
}
}
/*----------------------------------------------------------*/
int main(int argc, char *argv[])
{
/* УстанавливаСм настройки ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ. */
app_vars vars={5004, 7010, "127.0.0.1", {0}, 0, 0, 0.01, 0};
/* УстанавливаСм настройки настройки ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ Π² 
* соотвСтствии с Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π°ΠΌΠΈ ΠΊΠΎΠΌΠ°Π½Π΄Π½ΠΎΠΉ строки. */
scan_args(argc, argv, &vars);
ms_init();
/* Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ экзСмпляры Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ΠΎΠ² ΠΏΠ΅Ρ€Π΅Π΄Π°ΡŽΡ‰Π΅Π³ΠΎ Ρ‚Ρ€Π°ΠΊΡ‚Π°. */
MSSndCard *snd_card =
ms_snd_card_manager_get_default_card(ms_snd_card_manager_get());
MSFilter *snd_card_read = ms_snd_card_create_reader(snd_card);
MSFilter *dtmfgen = ms_filter_new(MS_DTMF_GEN_ID);
MSFilter *rtpsend = ms_filter_new(MS_RTP_SEND_ID);
/* Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ ΠΊΠΎΠ΄Π΅Ρ€Π°. */
MSFilter *encoder = ms_filter_create_encoder("PCMU");
/* РСгистрируСм Ρ‚ΠΈΠΏΡ‹ Π½Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ. */
register_payloads();
/* Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ Π΄ΡƒΠΏΠ»Π΅ΠΊΡΠ½ΡƒΡŽ RTP-сСссию. */
RtpSession* rtp_session = create_duplex_rtp_session(vars);
ms_filter_call_method(rtpsend, MS_RTP_SEND_SET_SESSION, rtp_session);
/* БоСдиняСм Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Ρ‹ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚Ρ‡ΠΈΠΊΠ°. */
ms_filter_link(snd_card_read, 0, dtmfgen, 0);
ms_filter_link(dtmfgen, 0, encoder, 0);
ms_filter_link(encoder, 0, rtpsend, 0);
/* Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Ρ‹ ΠΏΡ€ΠΈΠ΅ΠΌΠ½ΠΎΠ³ΠΎ Ρ‚Ρ€Π°ΠΊΡ‚Π°. */
MSFilter *rtprecv = ms_filter_new(MS_RTP_RECV_ID);
ms_filter_call_method(rtprecv, MS_RTP_RECV_SET_SESSION, rtp_session);
/* Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ Π΄Π΅ΠΊΠΎΠ΄Π΅Ρ€Π°. */
MSFilter *decoder=ms_filter_create_decoder("PCMU");
//MS_FILE_REC_ID
/* РСгистрируСм наш Ρ„ΠΈΠ»ΡŒΡ‚Ρ€. */
ms_filter_register(&nash_filter_desc);
MSFilter *nash = ms_filter_new(NASH_FILTER_ID);
/* Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ Π·Π²ΡƒΠΊΠΎΠ²ΠΎΠΉ ΠΊΠ°Ρ€Ρ‚Ρ‹. */
MSFilter *snd_card_write = ms_snd_card_create_writer(snd_card);
/* Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ рСгистратора. */
MSFilter *recorder=ms_filter_new(MS_FILE_REC_ID);
vars.recorder = recorder; 
/* БоСдиняСм Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Ρ‹ ΠΏΡ€ΠΈΡ‘ΠΌΠ½ΠΎΠ³ΠΎ Ρ‚Ρ€Π°ΠΊΡ‚Π°. */
ms_filter_link(rtprecv, 0, decoder, 0);
ms_filter_link(decoder, 0, nash, 0);
ms_filter_link(nash, 0, snd_card_write, 0);
ms_filter_link(nash, 1, recorder, 0);
/* ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΊ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Ρƒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠ³ΠΎ Π²Ρ‹Π·ΠΎΠ²Π°, ΠΈ ΠΏΠ΅Ρ€Π΅Π΄Π°Π΅ΠΌ Π΅ΠΉ Π²
* качСствС ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΡ… Π΄Π°Π½Π½Ρ‹Ρ… ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° структуру с настройками
* ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ срСди ΠΏΡ€ΠΎΡ‡ΠΈΡ… Π΅ΡΡ‚ΡŒ ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ Π½Π° Ρ„ΠΈΠ»ΡŒΡ‚Ρ€
* рСгистратора. */
ms_filter_set_notify_callback(nash,
(MSFilterNotifyFunc)change_detected_cb, &vars);
ms_filter_call_method(nash,NASH_FILTER_SET_TRESHOLD, &vars.treshold); 
/* Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ источник Ρ‚Π°ΠΊΡ‚ΠΎΠ² - Ρ‚ΠΈΠΊΠ΅Ρ€. */
MSTicker *ticker = ms_ticker_new();
/* ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ источник Ρ‚Π°ΠΊΡ‚ΠΎΠ². */
ms_ticker_attach(ticker, snd_card_read);
ms_ticker_attach(ticker, rtprecv);
/* Если настройка частоты Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€Π° ΠΎΡ‚Π»ΠΈΡ‡Π½Π° ΠΎΡ‚ нуля, Ρ‚ΠΎ запускаСм Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€. */   
if (vars.dtmf_cfg.frequencies[0])
{
/* НастраиваСм структуру, ΡƒΠΏΡ€Π°Π²Π»ΡΡŽΡ‰ΡƒΡŽ Π²Ρ‹Ρ…ΠΎΠ΄Π½Ρ‹ΠΌ сигналом Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€Π°. */
vars.dtmf_cfg.duration = 10000;
vars.dtmf_cfg.amplitude = 1.0;
}
/* ΠžΡ€Π³Π°Π½ΠΈΠ·ΡƒΠ΅ΠΌ Ρ†ΠΈΠΊΠ» пСрСзапуска Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€Π°. */
printf("Press ENTER to exit.n ");
char c=getchar();
while(c != 'n')
{
if(vars.dtmf_cfg.frequencies[0])
{
/* Π’ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ Π·Π²ΡƒΠΊΠΎΠ²ΠΎΠΉ Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€. */
ms_filter_call_method(dtmfgen, MS_DTMF_GEN_PLAY_CUSTOM,
(void*)&vars.dtmf_cfg);
}
char c=getchar();
printf("--n");
}
if (vars.en_rec ) ms_filter_call_method(recorder, MS_FILE_REC_CLOSE, 0);
}

αžŠαŸ„αž™αžŸαžΆαžšαžαŸ‚αž™αžΎαž„αž”αž“αŸ’αžαŸ‚αž˜αž―αž€αžŸαžΆαžš αž“αž·αž„αž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹αž”αžŽαŸ’αžŽαžΆαž›αŸαž™ αž‚αžŽαž·αžαžœαž·αž‘αŸ’αž™αžΆαž”αž“αŸ’αž‘αžΆαžαŸ‹αž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž…αž„αž€αŸ’αžšαž„αž€αžΆαž“αŸ‹αžαŸ‚αžŸαŸ’αž˜αž»αž‚αžŸαŸ’αž˜αžΆαž‰ αž αžΎαž™αž˜αžΎαž›αž‘αŸ…αžŠαžΌαž…αž“αŸαŸ‡αŸ–

$ gcc mstest9.c nash_filter.c -o mstest9   `pkg-config mediastreamer   --libs --cflags`  -lm

αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž–αžΈαž”αž„αŸ’αž€αžΎαžαž€αž˜αŸ’αž˜αžœαž·αž’αžΈ αžŸαžΌαž˜αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαžœαžΆαž“αŸ…αž›αžΎαž€αž»αŸ†αž–αŸ’αž™αžΌαž‘αŸαžšαžŠαŸ†αž”αžΌαž„αžŠαŸ‚αž›αž˜αžΆαž“αž’αžΆαž‚αž»αž™αž˜αŸ‰αž„αŸ‹αžŠαžΌαž…αžαžΆαž„αž€αŸ’αžšαŸ„αž˜αŸ–

$ ./mstest9  --lport 7010  --port 8010 --addr <Ρ‚ΡƒΡ‚ адрСс Π²Ρ‚ΠΎΡ€ΠΎΠ³ΠΎ ΠΊΠΎΠΌΠΏΡŒΡŽΡ‚Π΅Ρ€Π°> --rec

αž“αŸ…αž›αžΎαž€αž»αŸ†αž–αŸ’αž™αžΌαž‘αŸαžšαž‘αžΈαž–αžΈαžš αž™αžΎαž„αž”αžΎαž€αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž‡αžΆαž˜αž½αž™αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹αžŠαžΌαž…αžαžΆαž„αž€αŸ’αžšαŸ„αž˜αŸ–

$ ./mstest9  --lport 8010  --port 7010 --addr <Ρ‚ΡƒΡ‚ адрСс ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ ΠΊΠΎΠΌΠΏΡŒΡŽΡ‚Π΅Ρ€Π°>

αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž–αžΈαž“αŸαŸ‡αž€αž»αŸ†αž–αŸ’αž™αžΌαž‘αŸαžšαž‘αžΈαž˜αž½αž™αž“αžΉαž„αž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜αž€αžαŸ‹αžαŸ’αžšαžΆαž’αŸ’αžœαžΈαž‚αŸ’αžšαž”αŸ‹αž™αŸ‰αžΆαž„αžŠαŸ‚αž›αž’αŸ’αž“αž€αž“αž·αž™αžΆαž™αž‘αŸ…αž€αŸ’αž“αž»αž„αž˜αžΈαž€αŸ’αžšαžΌαž αŸ’αžœαžΌαž“αž‘αžΈαž–αžΈαžšαŸ” αž€αŸ’αž“αž»αž„αž€αžšαžŽαžΈαž“αŸαŸ‡αž–αžΆαž€αŸ’αž™ "αž€αŸ†αž–αž»αž„αžαžβ€¦"αŸ” αžŠαžšαžΆαž”αžŽαžΆαž’αŸ’αž“αž€αžŸαŸ’αž„αžΆαžαŸ‹ αž€αžΆαžšαžαžαž“αžΉαž„αžαŸ’αžšαžΌαžœαž”αžΆαž“αž•αŸ’αž’αžΆαž€αž‡αžΆαž˜αž½αž™αž“αžΉαž„αžŸαžΆαžšαžŠαŸ‚αž›αž”αž„αŸ’αž αžΆαž‰"αž•αŸ’αž’αžΆαž€ ...msgstr "αž’αŸ’αž“αž€β€‹αž”αŸ’αžšαž αŸ‚αž›β€‹αž‡αžΆβ€‹αžαŸ’αžšαžΌαžœβ€‹αž’αŸ’αžœαžΎβ€‹αž€αžΆαžšβ€‹αž–αž·αžŸαŸ„αž’αž“αŸβ€‹αž‡αžΆαž˜αž½αž™β€‹αž€αž˜αŸ’αžšαž·αžβ€‹αž€αž˜αŸ’αžšαž·αžβ€‹αž…αžΆαž”αŸ‹αž•αŸ’αžŠαžΎαž˜αŸ”

αž“αŸ…αž€αŸ’αž“αž»αž„αž’αžαŸ’αžαž”αž‘αž“αŸαŸ‡ αž™αžΎαž„αž”αžΆαž“αžšαŸ€αž“αž–αžΈαžšαž”αŸ€αž”αžŸαžšαžŸαŸαžšαžαž˜αŸ’αžšαž„αŸ” αžŠαžΌαž…αžŠαŸ‚αž›αž’αŸ’αž“αž€αž”αŸ’αžšαž αŸ‚αž›αž‡αžΆαž”αžΆαž“αž€αžαŸ‹αžŸαž˜αŸ’αž‚αžΆαž›αŸ‹ αž˜αž»αžαž„αžΆαžš nash_filter_process() αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž§αž”αžΆαž™αž€αž›αž‡αžΆαž˜αž½αž™αž”αŸ’αž›αž»αž€αž‘αž·αž“αŸ’αž“αž“αŸαž™αŸ” αžŠαŸ„αž™αžŸαžΆαžšαž§αž‘αžΆαž αžšαžŽαŸαž“αŸαŸ‡αž˜αžΆαž“αž›αž€αŸ’αžαžŽαŸˆαž’αž”αŸ‹αžšαŸ† αžŸαž˜αžαŸ’αžαž—αžΆαž–αž’αž”αŸ’αž”αž”αžšαž˜αžΆαžšαž”αžŸαŸ‹αž§αž”αž€αžšαžŽαŸαž•αŸ’αžŸαžΆαž™αž–αŸαžαŸŒαž˜αžΆαž“αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžšαŸ€αž”αž…αŸ†αž”αŸ’αž›αž»αž€αž‘αž·αž“αŸ’αž“αž“αŸαž™αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹αŸ”

αž”αž“αŸ’αž‘αžΆαž”αŸ‹ αž’αžαŸ’αžαž”αž‘ αž™αžΎαž„β€‹αž“αžΉαž„β€‹αž–αž·αž“αž·αžαŸ’αž™β€‹αž˜αžΎαž›β€‹αž˜αž»αžαž„αžΆαžšβ€‹αžαž˜αŸ’αžšαž„αŸ‹β€‹αž‡αž½αžšβ€‹αžŸαžΆαžš αž“αž·αž„β€‹αž˜αž»αžαž„αžΆαžšβ€‹αž‚αŸ’αžšαž”αŸ‹αž‚αŸ’αžšαž„β€‹αžŸαžΆαžšαŸ” αžœαžΆαž“αžΉαž„αž‡αž½αž™αž“αŸ…αž–αŸαž›αž’αž“αžΆαž‚αžαžŠαžΎαž˜αŸ’αž”αžΈαž’αž—αž·αžœαžŒαŸ’αžαžαž˜αŸ’αžšαž„αž‡αžΆαž˜αž½αž™αž“αžΉαž„αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž–αŸαžαŸŒαž˜αžΆαž“αžŸαŸ’αž˜αž»αž‚αžŸαŸ’αž˜αžΆαž‰αž”αž“αŸ’αžαŸ‚αž˜αž‘αŸ€αžαŸ”

αž”αŸ’αžšαž—αž–: www.habr.com

αž”αž“αŸ’αžαŸ‚αž˜αž˜αžαž·αž™αŸ„αž”αž›αŸ‹