Mediastreamer2 VoIP เชเชจเซเชœเชฟเชจเชจเซ€ เชถเซ‹เชงเช–เซ‹เชณ. เชญเชพเช— 9

เชฒเซ‡เช–เชจเซ€ เชธเชพเชฎเช—เซเชฐเซ€ เชฎเชพเชฐเชพ เชชเชฐเชฅเซ€ เชฒเซ‡เชตเชพเชฎเชพเช‚ เช†เชตเซ€ เช›เซ‡ เชเซ‡เชจ เชšเซ‡เชจเชฒ.

เชกเซเชชเซเชฒเซ‡เช•เซเชธ เช‡เชจเซเชŸเชฐเช•เซ‹เชฎ

Mediastreamer2 VoIP เชเชจเซเชœเชฟเชจเชจเซ€ เชถเซ‹เชงเช–เซ‹เชณ. เชญเชพเช— 9

เช›เซ‡เชฒเซเชฒเชพเชฎเชพเช‚ เชฒเซ‡เช– เชกเซเชชเซเชฒเซ‡เช•เซเชธ เช‡เชจเซเชŸเชฐเช•เซ‹เชฎเชจเซ€ เชœเชพเชนเซ‡เชฐเชพเชค เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเซ€ เชนเชคเซ€, เช…เชจเซ‡ เช†เชฎเชพเช‚ เช…เชฎเซ‡ เชคเซ‡เชจเซ‡ เชฌเชจเชพเชตเซ€เชถเซเช‚.

เช†เช•เซƒเชคเชฟ เชถเซ€เชฐเซเชทเช• เช†เช•เซƒเชคเชฟเชฎเชพเช‚ เชฌเชคเชพเชตเชตเชพเชฎเชพเช‚ เช†เชตเซ€ เช›เซ‡. เชซเชฟเชฒเซเชŸเชฐเซเชธเชจเซ€ เชจเซ€เชšเซ‡เชจเซ€ เชธเชพเช‚เช•เชณ เชŸเซเชฐเชพเชจเซเชธเชฎเชฟเชถเชจ เชชเชพเชฅ เชฌเชจเชพเชตเซ‡ เช›เซ‡, เชœเซ‡ เชธเชพเช‰เชจเซเชก เช•เชพเชฐเซเชกเชฅเซ€ เชถเชฐเซ‚ เชฅเชพเชฏ เช›เซ‡. เชคเซ‡ เชฎเชพเช‡เช•เซเชฐเซ‹เชซเซ‹เชจเชฎเชพเช‚เชฅเซ€ เชธเชฟเช—เซเชจเชฒ เชจเชฎเซ‚เชจเชพเช“ เชชเซเชฐเชฆเชพเชจ เช•เชฐเซ‡ เช›เซ‡. เชฎเซ‚เชณเชญเซ‚เชค เชฐเซ€เชคเซ‡, เช† เชชเซเชฐเชคเชฟ เชธเซ‡เช•เชจเซเชก 8000 เชจเชฎเซ‚เชจเชพเชจเชพ เชฆเชฐเซ‡ เชฅเชพเชฏ เช›เซ‡. เชฎเซ€เชกเชฟเชฏเชพ เชธเซเชŸเซเชฐเซ€เชฎเชฐ เช“เชกเชฟเชฏเซ‹ เชซเชฟเชฒเซเชŸเชฐเซเชธ เชœเซ‡ เชกเซ‡เชŸเชพ เชฌเซ€เชŸ เชกเซ‡เชชเซเชฅเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ‡ เช›เซ‡ เชคเซ‡ 16 เชฌเชฟเชŸเซเชธ เช›เซ‡ (เช† เชฎเชนเชคเซเชตเชจเซเช‚ เชจเชฅเซ€; เชœเซ‹ เชคเชฎเซ‡ เชˆเชšเซเช›เซ‹ เชคเซ‹, เชคเชฎเซ‡ เชซเชฟเชฒเซเชŸเชฐเซเชธ เชฒเช–เซ€ เชถเช•เซ‹ เช›เซ‹ เชœเซ‡ เชตเชงเซ เชฌเซ€เชŸ เชกเซ‡เชชเซเชฅ เชธเชพเชฅเซ‡ เช•เชพเชฎ เช•เชฐเชถเซ‡). เชกเซ‡เชŸเชพเชจเซ‡ 160 เชจเชฎเซ‚เชจเชพเช“เชจเชพ เชฌเซเชฒเซ‹เช•เชฎเชพเช‚ เชœเซ‚เชฅเชฌเชฆเซเชง เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเซเชฏเซ‹ เช›เซ‡. เช†เชฎ, เชฆเชฐเซ‡เช• เชฌเซเชฒเซ‹เช•เชจเซเช‚ เช•เชฆ 320 เชฌเชพเช‡เชŸเซเชธ เช›เซ‡. เช†เช—เชณ, เช…เชฎเซ‡ เชœเชจเชฐเซ‡เชŸเชฐเชจเชพ เช‡เชจเชชเซเชŸ เชชเชฐ เชกเซ‡เชŸเชพ เชซเซ€เชก เช•เชฐเซ€เช เช›เซ€เช, เชœเซ‡, เชœเซเชฏเชพเชฐเซ‡ เชฌเช‚เชง เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡, เชคเซเชฏเชพเชฐเซ‡ เชกเซ‡เชŸเชพ เชฎเชพเชŸเซ‡ "เชชเชพเชฐเชฆเชฐเซเชถเช•" เชนเซ‹เชฏ เช›เซ‡. เชœเซ‹ เชคเชฎเซ‡ เชกเชฟเชฌเช—เซ€เช‚เช— เชฆเชฐเชฎเชฟเชฏเชพเชจ เชฎเชพเช‡เช•เซเชฐเซ‹เชซเซ‹เชจเชฎเชพเช‚ เชตเชพเชค เช•เชฐเซ€เชจเซ‡ เช•เช‚เชŸเชพเชณเซ€ เช—เชฏเชพ เชนเซ‹เชต เชคเซ‹ เชฎเซ‡เช‚ เชคเซ‡เชจเซ‡ เช‰เชฎเซ‡เชฐเซเชฏเซเช‚ เช›เซ‡ - เชคเชฎเซ‡ เชŸเซ‹เชจ เชธเชฟเช—เซเชจเชฒ เชธเชพเชฅเซ‡ เชชเชพเชฅเชจเซ‡ "เชถเซ‚เชŸ" เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡ เชœเชจเชฐเซ‡เชŸเชฐเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€ เชถเช•เซ‹ เช›เซ‹.

เชœเชจเชฐเซ‡เชŸเชฐ เชชเช›เซ€, เชธเชฟเช—เซเชจเชฒ เชเชจเซเช•เซ‹เชกเชฐ เชชเชฐ เชœเชพเชฏ เช›เซ‡, เชœเซ‡ ยต-เชฒเซ‹ (G.16 เชธเซเชŸเชพเชจเซเชกเชฐเซเชก) เช…เชจเซเชธเชพเชฐ เช…เชฎเชพเชฐเชพ 711-เชฌเซ€เชŸ เชจเชฎเซ‚เชจเชพเช“เชจเซ‡ เช†เช -เชฌเซ€เชŸเชฎเชพเช‚ เชฐเซ‚เชชเชพเช‚เชคเชฐเชฟเชค เช•เชฐเซ‡ เช›เซ‡. เชเชจเซเช•เซ‹เชกเชฐเชจเชพ เช†เช‰เชŸเชชเซเชŸ เชชเชฐ, เช…เชฎเชพเชฐเซ€ เชชเชพเชธเซ‡ เชชเชนเซ‡เชฒเชพเชฅเซ€ เชœ เช…เชกเชงเชพ เช•เชฆเชจเชพ เชกเซ‡เชŸเชพ เชฌเซเชฒเซ‹เช• เช›เซ‡. เชธเชพเชฎเชพเชจเซเชฏ เชฐเซ€เชคเซ‡, เชœเซ‹ เช…เชฎเชจเซ‡ เชŸเซเชฐเชพเชซเชฟเช• เชฌเชšเชพเชตเชตเชพเชจเซ€ เชœเชฐเซ‚เชฐ เชจ เชนเซ‹เชฏ เชคเซ‹ เช…เชฎเซ‡ เช•เชฎเซเชชเซเชฐเซ‡เชถเชจ เชตเชฟเชจเชพ เชกเซ‡เชŸเชพ เชŸเซเชฐเชพเชจเซเชธเชฎเชฟเชŸ เช•เชฐเซ€ เชถเช•เซ€เช เช›เซ€เช. เชชเชฐเช‚เชคเซ เช…เชนเซ€เช‚ เชเชจเซเช•เซ‹เชกเชฐเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเชตเซ‹ เช‰เชชเชฏเซ‹เช—เซ€ เช›เซ‡, เช•เชพเชฐเชฃ เช•เซ‡ เชตเชพเชฏเชฐเชถเชพเชฐเซเช• เช†เชฐเชŸเซ€เชชเซ€ เชธเซเชŸเซเชฐเซ€เชฎเชฎเชพเช‚เชฅเซ€ เช“เชกเชฟเชฏเซ‹ เชคเซเชฏเชพเชฐเซ‡ เชœ เชชเซเชจเชƒเช‰เชคเซเชชเชพเชฆเชฟเชค เช•เชฐเซ€ เชถเช•เซ‡ เช›เซ‡ เชœเซเชฏเชพเชฐเซ‡ เชคเซ‡เชจเซ‡ ยต-เชฒเซ‹ เช…เชฅเชตเชพ เช-เชฒเซ‹ เช…เชจเซเชธเชพเชฐ เชธเช‚เช•เซเชšเชฟเชค เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเซ‡.

เชเชจเซเช•เซ‹เชกเชฐ เชชเช›เซ€, เชกเซ‡เชŸเชพเชจเชพ เชนเชณเชตเชพ เชฌเซเชฒเซ‹เช•เซเชธ rtpsend เชซเชฟเชฒเซเชŸเชฐเชจเซ‡ เชฎเซ‹เช•เชฒเชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡, เชœเซ‡ เชคเซ‡เชฎเชจเซ‡ RTP เชชเซ‡เช•เซ‡เชŸเชฎเชพเช‚ เชฎเซ‚เช•เชถเซ‡, เชœเชฐเซ‚เชฐเซ€ เชซเซเชฒเซ‡เช— เชธเซ‡เชŸ เช•เชฐเชถเซ‡ เช…เชจเซ‡ UDP เชชเซ‡เช•เซ‡เชŸเชจเชพ เชฐเซ‚เชชเชฎเชพเช‚ เชจเซ‡เชŸเชตเชฐเซเช• เชชเชฐ เชŸเซเชฐเชพเชจเซเชธเชฎเชฟเชถเชจ เชฎเชพเชŸเซ‡ เชฎเซ€เชกเชฟเชฏเชพ เชธเซเชŸเซเชฐเซ€เชฎเชฐเชจเซ‡ เช†เชชเชถเซ‡.

เชซเชฟเชฒเซเชŸเชฐเซเชธเชจเซ€ เช‰เชชเชฒเซ€ เชธเชพเช‚เช•เชณ เชชเซเชฐเชพเชชเซเชคเชฟ เชชเชพเชฅ เชฌเชจเชพเชตเซ‡ เช›เซ‡; เชจเซ‡เชŸเชตเชฐเซเช•เชฎเชพเช‚เชฅเซ€ เชฎเซ€เชกเชฟเชฏเชพ เชธเซเชŸเซเชฐเซ€เชฎเชฐ เชฆเซเชตเชพเชฐเชพ เชฎเซ‡เชณเชตเซ‡เชฒเชพ RTP เชชเซ‡เช•เซ‡เชŸเซเชธ rtprecv เชซเชฟเชฒเซเชŸเชฐเชฎเชพเช‚ เชฆเชพเช–เชฒ เชฅเชพเชฏ เช›เซ‡, เชœเซ‡เชจเชพ เช†เช‰เชŸเชชเซเชŸ เชชเชฐ เชคเซ‡เช“ เชกเซ‡เชŸเชพ เชฌเซเชฒเซ‹เช•เซเชธเชจเชพ เชธเซเชตเชฐเซ‚เชชเชฎเชพเช‚ เชฆเซ‡เช–เชพเชฏ เช›เซ‡, เชœเซ‡เชฎเชพเช‚เชฅเซ€ เชฆเชฐเซ‡เช• เชเช• เชชเซเชฐเชพเชชเซเชค เชชเซ‡เช•เซ‡เชŸเชจเซ‡ เช…เชจเซเชฐเซ‚เชช เช›เซ‡. เชฌเซเชฒเซ‹เช•เชฎเชพเช‚ เชฎเชพเชคเซเชฐ เชชเซ‡เชฒเซ‹เชก เชกเซ‡เชŸเชพ เช›เซ‡; เช…เช—เชพเช‰เชจเชพ เชฒเซ‡เช–เชฎเชพเช‚ เชคเซ‡เช“ เชšเชฟเชคเซเชฐเชฎเชพเช‚ เชฒเซ€เชฒเชพ เชฐเช‚เช—เชฎเชพเช‚ เชฆเชฐเซเชถเชพเชตเชตเชพเชฎเชพเช‚ เช†เชตเซเชฏเชพ เชนเชคเชพ.

เช†เช—เชณ, เชฌเซเชฒเซ‹เช•เซเชธเชจเซ‡ เชกเซ€เช•เซ‹เชกเชฐ เชซเชฟเชฒเซเชŸเชฐเชฎเชพเช‚ เชฎเซ‹เช•เชฒเชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡, เชœเซ‡ เชคเซ‡เชฎเชพเช‚ เชฐเชนเซ‡เชฒเชพ เชธเชฟเช‚เช—เชฒ-เชฌเชพเช‡เชŸ เชจเชฎเซ‚เชจเชพเช“เชจเซ‡ เชฐเซ‡เช–เซ€เชฏ, 16-เชฌเซ€เชŸเชฎเชพเช‚ เชฐเซ‚เชชเชพเช‚เชคเชฐเชฟเชค เช•เชฐเซ‡ เช›เซ‡. เชœเซ‡ เชฎเซ€เชกเชฟเชฏเชพ เชธเซเชŸเซเชฐเซ€เชฎเชฐ เชซเชฟเชฒเซเชŸเชฐเซเชธ เชฆเซเชตเชพเชฐเชพ เชชเชนเซ‡เชฒเชพเชฅเซ€ เชœ เชชเซเชฐเซ‹เชธเซ‡เชธ เช•เชฐเซ€ เชถเช•เชพเชฏ เช›เซ‡. เช…เชฎเชพเชฐเชพ เช•เชฟเชธเซเชธเชพเชฎเชพเช‚, เช…เชฎเซ‡ เชคเซ‡เชฎเชจเซ‡ เชคเชฎเชพเชฐเชพ เชนเซ‡เชกเชธเซ‡เชŸเชจเชพ เชธเซเชชเซ€เช•เชฐเซเชธ เชชเชฐ เชชเซเชฒเซ‡เชฌเซ‡เช• เชฎเชพเชŸเซ‡ เชธเชพเช‰เชจเซเชก เช•เชพเชฐเซเชก เชชเชฐ เชฎเซ‹เช•เชฒเซ€เช เช›เซ€เช.

เชนเชตเซ‡ เชšเชพเชฒเซ‹ เชธเซ‹เชซเซเชŸเชตเซ‡เชฐ เช…เชฎเชฒเซ€เช•เชฐเชฃ เชคเชฐเชซ เช†เช—เชณ เชตเชงเซ€เช. เช† เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡, เช…เชฎเซ‡ เชฐเซ€เชธเซ€เชตเชฐ เช…เชจเซ‡ เชŸเซเชฐเชพเชจเซเชธเชฎเซ€เชŸเชฐ เชซเชพเช‡เชฒเซ‹เชจเซ‡ เชœเซ‹เชกเซ€เชถเซเช‚ เชœเซ‡ เช…เชฎเซ‡ เชชเชนเซ‡เชฒเชพ เช…เชฒเช— เช•เชฐเซ€ เชนเชคเซ€. เช† เชชเชนเซ‡เชฒเชพเช‚, เช…เชฎเซ‡ เชชเซ‹เชฐเซเชŸเซเชธ เช…เชจเซ‡ เชธเชฐเชจเชพเชฎเชพเช‚เช“ เชฎเชพเชŸเซ‡ เชจเชฟเชถเซเชšเชฟเชค เชธเซ‡เชŸเชฟเช‚เช—เซเชธเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซเชฏเซ‹ เชนเชคเซ‹, เชชเชฐเช‚เชคเซ เชนเชตเซ‡ เช…เชฎเชจเซ‡ เชธเซเชŸเชพเชฐเซเชŸเช…เชช เชตเช–เชคเซ‡ เช‰เชฒเซเชฒเซ‡เช–เชฟเชค เชธเซ‡เชŸเชฟเช‚เช—เซเชธเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡ เชธเช•เซเชทเชฎ เชฅเชตเชพ เชฎเชพเชŸเซ‡ เชชเซเชฐเซ‹เช—เซเชฐเชพเชฎเชจเซ€ เชœเชฐเซ‚เชฐ เช›เซ‡. เช† เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡, เช…เชฎเซ‡ เช†เชฆเซ‡เชถ เชตเชพเช•เซเชฏ เชฆเชฒเซ€เชฒเซ‹เชจเซ€ เชชเซเชฐเช•เซเชฐเชฟเชฏเชพ เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡ เช•เชพเชฐเซเชฏเช•เซเชทเชฎเชคเชพ เช‰เชฎเซ‡เชฐเซ€เชถเซเช‚. เชœเซ‡ เชชเช›เซ€ เช…เชฎเซ‡ เชœเซ‡ เช‡เชจเซเชŸเชฐเช•เซ‹เชฎ เชธเชพเชฅเซ‡ เช•เชจเซ‡เช•เซเชถเชจ เชธเซเชฅเชพเชชเชฟเชค เช•เชฐเชตเชพ เชฎเชพเช—เซ€เช เช›เซ€เช เชคเซ‡เชจเซเช‚ IP เชเชกเซเชฐเซ‡เชธ เช…เชจเซ‡ เชชเซ‹เชฐเซเชŸ เชธเซ‡เชŸ เช•เชฐเซ€ เชถเช•เซ€เชถเซเช‚.

เชชเซเชฐเชฅเชฎ, เชšเชพเชฒเซ‹ เชชเซเชฐเซ‹เช—เซเชฐเชพเชฎเชฎเชพเช‚ เชเช• เชฎเชพเชณเช–เซเช‚ เช‰เชฎเซ‡เชฐเซ€เช เชœเซ‡ เชคเซ‡เชจเซ€ เชธเซ‡เชŸเชฟเช‚เช—เซเชธ เชธเช‚เช—เซเชฐเชนเชฟเชค เช•เชฐเชถเซ‡:

struct _app_vars
{
  int  local_port;              /* ะ›ะพะบะฐะปัŒะฝั‹ะน ะฟะพั€ั‚. */
  int  remote_port;             /* ะŸะพั€ั‚ ะฟะตั€ะตะณะพะฒะพั€ะฝะพะณะพ ัƒัั‚ั€ะพะนัั‚ะฒะฐ ะฝะฐ ัƒะดะฐะปะตะฝะฝะพะผ ะบะพะผะฟัŒัŽั‚ะตั€ะต. */
  char remote_addr[128];        /* IP-ะฐะดั€ะตั ัƒะดะฐะปะตะฝะฝะพะณะพ ะบะพะผะฟัŒัŽั‚ะตั€ะฐ. */
  MSDtmfGenCustomTone dtmf_cfg; /* ะะฐัั‚ั€ะพะนะบะธ ั‚ะตัั‚ะพะฒะพะณะพ ัะธะณะฝะฐะปะฐ ะณะตะฝะตั€ะฐั‚ะพั€ะฐ. */
};

typedef struct _app_vars app_vars;

เชชเซเชฐเซ‹เช—เซเชฐเชพเชฎ เช† เชชเซเชฐเช•เชพเชฐเชจเซเช‚ เชฎเชพเชณเช–เซเช‚ เชœเชพเชนเซ‡เชฐ เช•เชฐเชถเซ‡ เชœเซ‡เชจเซ‡ vars เช•เชนเซ‡เชตเชพเชฏ เช›เซ‡.
เช†เช—เชณ, เชšเชพเชฒเซ‹ เช†เชฆเซ‡เชถ เชตเชพเช•เซเชฏ เชฆเชฒเซ€เชฒเซ‹เชจเซ‡ เชชเชพเชฐเซเชธ เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡ เชซเช‚เช•เซเชถเชจ เช‰เชฎเซ‡เชฐเซ€เช:

/* ะคัƒะฝะบั†ะธั ะฟั€ะตะพะฑั€ะฐะทะพะฒะฐะฝะธั ะฐั€ะณัƒะผะตะฝั‚ะพะฒ ะบะพะผะฐะฝะดะฝะพะน ัั‚ั€ะพะบะธ ะฒ
* ะฝะฐัั‚ั€ะพะนะบะธ ะฟั€ะพะณั€ะฐะผะผั‹. */
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");
            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]);
        }
    }
}

เชชเชฆเชšเซเช›เซ‡เชฆเชจเชจเชพ เชชเชฐเชฟเชฃเชพเชฎเซ‡, เช•เชฎเชพเชจเซเชก เชฒเชพเช‡เชจ เชฆเชฒเซ€เชฒเซ‹ vars เชธเซเชŸเซเชฐเช•เซเชšเชฐเชจเชพ เช•เซเชทเซ‡เชคเซเชฐเซ‹เชฎเชพเช‚ เชฎเซ‚เช•เชตเชพเชฎเชพเช‚ เช†เชตเชถเซ‡. เชเชชเซเชฒเชฟเช•เซ‡เชถเชจเชจเซเช‚ เชฎเซเช–เซเชฏ เช•เชพเชฐเซเชฏ เชซเชฟเชฒเซเชŸเชฐเซเชธเชฎเชพเช‚เชฅเซ€ เชŸเซเชฐเชพเชจเซเชธเชฎเชฟเชŸเชฟเช‚เช— เช…เชจเซ‡ เชชเซเชฐเชพเชชเซเชค เช•เชฐเชตเชพเชจเชพ เชชเชพเชฅ เชเช•เชคเซเชฐเชฟเชค เช•เชฐเชตเชพเชจเซเช‚ เชฐเชนเซ‡เชถเซ‡; เชŸเซ€เช•เชฐเชจเซ‡ เช•เชจเซ‡เช•เซเชŸ เช•เชฐเซเชฏเชพ เชชเช›เซ€, เชจเชฟเชฏเช‚เชคเซเชฐเชฃเชจเซ‡ เช…เชจเช‚เชค เชฒเซ‚เชชเชฎเชพเช‚ เชธเซเชฅเชพเชจเชพเช‚เชคเชฐเชฟเชค เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเชถเซ‡, เชœเซ‡, เชœเซ‹ เชœเชจเชฐเซ‡เชŸเชฐเชจเซ€ เช†เชตเชฐเซเชคเชจ เชฌเชฟเชจ-เชถเซ‚เชจเซเชฏ เชชเชฐ เชธเซ‡เชŸ เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเซ€ เชนเซ‹เชฏ, เชคเซ‹ เชชเชฐเซ€เช•เซเชทเชฃ เชœเชจเชฐเซ‡เชŸเชฐเชจเซ‡ เชชเซเชจเชƒเชชเซเชฐเชพเชฐเช‚เชญ เช•เชฐเชถเซ‡ เชœเซ‡เชฅเซ€ เช•เชฐเซ€เชจเซ‡ เชคเซ‡ เช…เชŸเช•เซเชฏเชพ เชตเชฟเชจเชพ เช•เชพเชฎ เช•เชฐเซ‡ เช›เซ‡.

เชœเชจเชฐเซ‡เชŸเชฐเชจเซ‡ เชคเซ‡เชจเซ€ เชกเชฟเชเชพเช‡เชจเชจเซ‡ เช•เชพเชฐเชฃเซ‡ เช† เชชเซเชจเชƒเชชเซเชฐเชพเชฐเช‚เชญเชจเซ€ เชœเชฐเซ‚เชฐ เชชเชกเชถเซ‡; เช•เซ‡เชŸเชฒเชพเช• เช•เชพเชฐเชฃเซ‹เชธเชฐ เชคเซ‡ 16 เชธเซ‡เช•เชจเซเชกเชฅเซ€ เชตเชงเซ เชธเชฎเชฏ เชธเซเชงเซ€ เชšเชพเชฒเชคเซเช‚ เชธเชฟเช—เซเชจเชฒ เช‰เชคเซเชชเชจเซเชจ เช•เชฐเซ€ เชถเช•เชคเซเช‚ เชจเชฅเซ€. เช เชจเซ‹เช‚เชงเชตเซเช‚ เชœเซ‹เช‡เช เช•เซ‡ เชคเซ‡เชจเซ€ เช…เชตเชงเชฟ 32-เชฌเซ€เชŸ เชจเช‚เชฌเชฐ เชฆเซเชตเชพเชฐเชพ เชจเชฟเชฐเซเชฆเชฟเชทเซเชŸ เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเซ€ เช›เซ‡.

เชธเชฎเช—เซเชฐ เช•เชพเชฐเซเชฏเช•เซเชฐเชฎ เช†เชจเชพ เชœเซ‡เชตเซ‹ เชฆเซ‡เช–เชพเชถเซ‡:

/* ะคะฐะนะป mstest8.c ะ˜ะผะธั‚ะฐั‚ะพั€ ะฟะตั€ะตะณะพะฒะพั€ะฝะพะณะพ ัƒัั‚ั€ะพะนัั‚ะฒะฐ. */

#include <mediastreamer2/mssndcard.h>
#include <mediastreamer2/dtmfgen.h>
#include <mediastreamer2/msrtp.h>

/* ะŸะพะดะบะปัŽั‡ะฐะตะผ ั„ะฐะนะป ะพะฑั‰ะธั… ั„ัƒะฝะบั†ะธะน. */
#include "mstest_common.c"

/*----------------------------------------------------------*/
struct _app_vars
{
    int  local_port;              /* ะ›ะพะบะฐะปัŒะฝั‹ะน ะฟะพั€ั‚. */
    int  remote_port;             /* ะŸะพั€ั‚ ะฟะตั€ะตะณะพะฒะพั€ะฝะพะณะพ ัƒัั‚ั€ะพะนัั‚ะฒะฐ ะฝะฐ ัƒะดะฐะปะตะฝะฝะพะผ ะบะพะผะฟัŒัŽั‚ะตั€ะต. */
    char remote_addr[128];        /* IP-ะฐะดั€ะตั ัƒะดะฐะปะตะฝะฝะพะณะพ ะบะพะผะฟัŒัŽั‚ะตั€ะฐ. */
    MSDtmfGenCustomTone dtmf_cfg; /* ะะฐัั‚ั€ะพะนะบะธ ั‚ะตัั‚ะพะฒะพะณะพ ัะธะณะฝะฐะปะฐ ะณะตะฝะตั€ะฐั‚ะพั€ะฐ. */
};

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");
            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]);
        }
    }
}

/*----------------------------------------------------------*/
int main(int argc, char *argv[])
{
    /* ะฃัั‚ะฐะฝะฐะฒะปะธะฒะฐะตะผ ะฝะฐัั‚ั€ะพะนะบะธ ะฟะพ ัƒะผะพะปั‡ะฐะฝะธัŽ. */
    app_vars vars={5004, 7010, "127.0.0.1", {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");

    /* ะกะพะทะดะฐะตะผ ั„ะธะปัŒั‚ั€ ะทะฒัƒะบะพะฒะพะน ะบะฐั€ั‚ั‹. */
    MSFilter *snd_card_write = ms_snd_card_create_writer(snd_card);

    /* ะกะพะตะดะธะฝัะตะผ ั„ะธะปัŒั‚ั€ั‹ ะฟั€ะธั‘ะผะฝะพะณะพ ั‚ั€ะฐะบั‚ะฐ. */
    ms_filter_link(rtprecv, 0, decoder, 0);
    ms_filter_link(decoder, 0,  snd_card_write, 0);

    /* ะกะพะทะดะฐะตะผ ะธัั‚ะพั‡ะฝะธะบ ั‚ะฐะบั‚ะพะฒ - ั‚ะธะบะตั€. */
    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;
    }

    /* ะžั€ะณะฐะฝะธะทัƒะตะผ ั†ะธะบะป ะฟะตั€ะตะทะฐะฟัƒัะบะฐ ะณะตะฝะตั€ะฐั‚ะพั€ะฐ. */
    while(TRUE)
    {
        if(vars.dtmf_cfg.frequencies[0])
        {
            /* ะ’ะบะปัŽั‡ะฐะตะผ ะทะฒัƒะบะพะฒะพะน ะณะตะฝะตั€ะฐั‚ะพั€. */
            ms_filter_call_method(dtmfgen, MS_DTMF_GEN_PLAY_CUSTOM,
                    (void*)&vars.dtmf_cfg);
        }
        /* ะฃะบะปะฐะดั‹ะฒะฐะตะผ ั‚ั€ะตะด ะฒ ัะฟัั‡ะบัƒ ะฝะฐ 20ะผั, ั‡ั‚ะพะฑั‹ ะดั€ัƒะณะธะต ั‚ั€ะตะดั‹
         * ะฟั€ะธะปะพะถะตะฝะธั ะฟะพะปัƒั‡ะธะปะธ ะฒั€ะตะผั ะฝะฐ ั€ะฐะฑะพั‚ัƒ. */
        ms_usleep(20000);
    }
}

เชšเชพเชฒเซ‹ เชธเช‚เช•เชฒเชจ เช•เชฐเซ€เช. เชชเช›เซ€ เชชเซเชฐเซ‹เช—เซเชฐเชพเชฎ เชฌเซ‡ เช•เชฎเซเชชเซเชฏเซเชŸเชฐ เชชเชฐ เชšเชฒเชพเชตเซ€ เชถเช•เชพเชฏ เช›เซ‡. เช…เชฅเชตเชพ เชเช• เชชเชฐ, เชœเซ‡เชฎ เชนเซเช‚ เชนเชตเซ‡ เช•เชฐเซ€เชถ. เช…เชฎเซ‡ เชจเซ€เชšเซ‡เชจเซ€ เชฆเชฒเซ€เชฒเซ‹ เชธเชพเชฅเซ‡ TShark เชฒเซ‹เชจเซเชš เช•เชฐเซ€เช เช›เซ€เช:

$ sudo tshark -i lo -f "udp dst port 7010" -P -V -O RTP -o rtp.heuristic_rtp:TRUE -x

เชœเซ‹ เช•เชจเซเชธเซ‹เชฒเชฎเชพเช‚ เชฒเซ‹เช‚เชš เชซเซ€เชฒเซเชก เชซเช•เซเชค เช•เซ‡เชชเซเชšเชฐเชจเซ€ เชถเชฐเซ‚เช†เชค เชตเชฟเชถเซ‡เชจเซ‹ เชธเช‚เชฆเซ‡เชถ เชชเซเชฐเชฆเชฐเซเชถเชฟเชค เช•เชฐเซ‡ เช›เซ‡, เชคเซ‹ เช† เชเช• เชธเชพเชฐเซ‹ เชธเช‚เช•เซ‡เชค เช›เซ‡ - เชคเซ‡เชจเซ‹ เช…เชฐเซเชฅ เช เช›เซ‡ เช•เซ‡ เช…เชฎเชพเชฐเซเช‚ เชชเซ‹เชฐเซเชŸ เชฎเซ‹เชŸเซ‡ เชญเชพเช—เซ‡ เช…เชจเซเชฏ เชชเซเชฐเซ‹เช—เซเชฐเชพเชฎเซเชธ เชฆเซเชตเชพเชฐเชพ เช•เชฌเชœเซ‡ เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเชคเซเช‚ เชจเชฅเซ€. เชฌเซ€เชœเชพ เชŸเชฐเซเชฎเชฟเชจเชฒเชฎเชพเช‚, เช…เชฎเซ‡ เชเช• เชชเซเชฐเซ‹เช—เซเชฐเชพเชฎ เช‡เชจเซเชธเซเชŸเชจเซเชธ เชฒเซ‹เชจเซเชš เช•เชฐเซ€เช เช›เซ€เช เชœเซ‡ เช† เชชเซ‹เชฐเซเชŸ เชจเช‚เชฌเชฐเชจเซ‹ เช‰เชฒเซเชฒเซ‡เช– เช•เชฐเซ€เชจเซ‡ "เชฐเชฟเชฎเซ‹เชŸ" เช‡เชจเซเชŸเชฐเช•เซ‹เชฎเชจเซเช‚ เช…เชจเซเช•เชฐเชฃ เช•เชฐเชถเซ‡:

$ ./mstest8 --port 9010 --lport 7010

เชชเซเชฐเซ‹เช—เซเชฐเชพเชฎ เชŸเซ‡เช•เซเชธเซเชŸเชฎเชพเช‚เชฅเซ€ เชœเซ‹เชˆ เชถเช•เชพเชฏ เช›เซ‡ เชคเซ‡เชฎ, เชกเชฟเชซเซ‹เชฒเซเชŸ IP เชธเชฐเชจเชพเชฎเซเช‚ 127.0.0.1 (เชธเซเชฅเชพเชจเชฟเช• เชฒเซ‚เชชเชฌเซ‡เช•) เช›เซ‡.

เชฌเซ€เชœเชพ เชŸเชฐเซเชฎเชฟเชจเชฒเชฎเชพเช‚, เช…เชฎเซ‡ เชชเซเชฐเซ‹เช—เซเชฐเชพเชฎเชจเซ‹ เชฌเซ€เชœเซ‹ เชฆเชพเช–เชฒเซ‹ เชถเชฐเซ‚ เช•เชฐเซ€เช เช›เซ€เช, เชœเซ‡ เชธเซเชฅเชพเชจเชฟเช• เช‰เชชเช•เชฐเชฃเชจเซเช‚ เช…เชจเซเช•เชฐเชฃ เช•เชฐเซ‡ เช›เซ‡. เช…เชฎเซ‡ เชตเชงเชพเชฐเชพเชจเซ€ เชฆเชฒเซ€เชฒเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เช เช›เซ€เช เชœเซ‡ เชฌเชฟเชฒเซเชŸ-เช‡เชจ เชŸเซ‡เชธเซเชŸ เชœเชจเชฐเซ‡เชŸเชฐเชจเซ‡ เช•เชพเชฎ เช•เชฐเชตเชพเชจเซ€ เชฎเช‚เชœเซ‚เชฐเซ€ เช†เชชเซ‡ เช›เซ‡:

$ ./mstest8  --port 7010 --lport 9010 --gen 440

เช† เช•เซเชทเชฃเซ‡, "เชฐเชฟเชฎเซ‹เชŸ" เช‰เชชเช•เชฐเชฃ เชคเชฐเชซ เชชเซเชฐเชธเชพเชฐเชฟเชค เชชเซ‡เช•เซ‡เชŸเซ‹ TShark เชธเชพเชฅเซ‡ เช•เชจเซเชธเซ‹เชฒเชฎเชพเช‚ เชซเซเชฒเซ‡เชถ เชฅเชตเชพเชจเซเช‚ เชถเชฐเซ‚ เชฅเชตเซเช‚ เชœเซ‹เชˆเช, เช…เชจเซ‡ เช•เชฎเซเชชเซเชฏเซเชŸเชฐ เชธเซเชชเซ€เช•เชฐเชฎเชพเช‚เชฅเซ€ เชธเชคเชค เชธเซเชตเชฐ เชธเชพเช‚เชญเชณเชตเชพเชฎเชพเช‚ เช†เชตเชถเซ‡.

เชœเซ‹ เชฌเชงเซเช‚ เชฒเช–เซเชฏเชพ เชชเซเชฐเชฎเชพเชฃเซ‡ เชฅเชฏเซเช‚ เชนเซ‹เชฏ, เชคเซ‹ เช…เชฎเซ‡ เชชเซเชฐเซ‹เช—เซเชฐเชพเชฎเชจเซ€ เชฌเซ€เชœเซ€ เชจเช•เชฒเชจเซ‡ เชซเชฐเซ€เชฅเซ€ เชถเชฐเซ‚ เช•เชฐเซ€เช เช›เซ€เช, เชชเชฐเช‚เชคเซ เช•เซ€ เช…เชจเซ‡ เชฆเชฒเซ€เชฒ เชตเชฟเชจเชพ โ€œโ€”gen 440โ€. เชนเชตเซ‡ เชคเชฎเซ‡ เชœเชจเชฐเซ‡เชŸเชฐเชจเซ€ เชญเซ‚เชฎเชฟเช•เชพ เชญเชœเชตเชถเซ‹. เช† เชชเช›เซ€, เชคเชฎเซ‡ เชฎเชพเช‡เช•เซเชฐเซ‹เชซเซ‹เชจเชฎเชพเช‚ เช…เชตเชพเชœ เช•เชฐเซ€ เชถเช•เซ‹ เช›เซ‹; เชคเชฎเชพเชฐเซ‡ เชธเซเชชเซ€เช•เชฐ เช…เชฅเชตเชพ เชนเซ‡เชกเชซเซ‹เชจเชฎเชพเช‚ เช…เชจเซเชฐเซ‚เชช เช…เชตเชพเชœ เชธเชพเช‚เชญเชณเชตเซ‹ เชœเซ‹เชˆเช. เชเช•เซ‹เชธเซเชŸเชฟเช• เชธเซเชต-เช‰เชคเซเชคเซ‡เชœเชจเชพ เชชเชฃ เชฅเชˆ เชถเช•เซ‡ เช›เซ‡; เชธเซเชชเซ€เช•เชฐเชจเชพ เชตเซ‹เชฒเซเชฏเซเชฎเชจเซ‡ เชฌเช‚เชง เช•เชฐเซ‹ เช…เชจเซ‡ เช…เชธเชฐ เช…เชฆเซƒเชถเซเชฏ เชฅเชˆ เชœเชถเซ‡.

เชœเซ‹ เชคเชฎเซ‡ เชคเซ‡เชจเซ‡ เชฌเซ‡ เช•เชฎเซเชชเซเชฏเซเชŸเชฐเซเชธ เชชเชฐ เชšเชฒเชพเชตเซเชฏเซเช‚ เช›เซ‡ เช…เชจเซ‡ IP เชธเชฐเชจเชพเชฎเชพเช“ เชตเชฟเชถเซ‡ เชฎเซ‚เช‚เชเชตเชฃเชฎเชพเช‚ เชจเชฅเซ€, เชคเซ‹ เชคเซ‡ เชœ เชชเชฐเชฟเชฃเชพเชฎ เชคเชฎเชพเชฐเซ€ เชฐเชพเชน เชœเซ‹เชถเซ‡ - เชฆเซเชตเชฟ-เชฎเชพเชฐเซเช—เซ€ เชกเชฟเชœเชฟเชŸเชฒ เช—เซเชฃเชตเชคเซเชคเชพเชฏเซเช•เซเชค เชตเซ‰เช‡เชธ เช•เชฎเซเชฏเซเชจเชฟเช•เซ‡เชถเชจ.

เชนเชตเซ‡ เชชเช›เซ€เชจเชพ เชฒเซ‡เช–เชฎเชพเช‚ เช†เชชเชฃเซ‡ เชถเซ€เช–เซ€เชถเซเช‚ เช•เซ‡ เช†เชชเชฃเชพ เชชเซ‹เชคเชพเชจเชพ เชซเชฟเชฒเซเชŸเชฐเซเชธ - เชชเซเชฒเช—เชˆเชจเซเชธ เช•เซ‡เชตเซ€ เชฐเซ€เชคเซ‡ เชฒเช–เชตเชพ, เช† เช•เซŒเชถเชฒเซเชฏเชจเซ‡ เช•เชพเชฐเชฃเซ‡ เชคเชฎเซ‡ เชฎเซ€เชกเชฟเชฏเชพ เชธเซเชŸเซเชฐเซ€เชฎเชฐเชจเซ‹ เช‰เชชเชฏเซ‹เช— เชฎเชพเชคเซเชฐ เช“เชกเชฟเชฏเซ‹ เช…เชจเซ‡ เชตเชฟเชกเชฟเชฏเซ‹ เชฎเชพเชŸเซ‡ เชœ เชจเชนเซ€เช‚, เชชเชฐเช‚เชคเซ เช…เชจเซเชฏ เช…เชฎเซเช• เชšเซ‹เช•เซเช•เชธ เช•เซเชทเซ‡เชคเซเชฐเชฎเชพเช‚ เชชเชฃ เช•เชฐเซ€ เชถเช•เชถเซ‹.

เชธเซ‹เชฐเซเชธ: www.habr.com

เชเช• เชŸเชฟเชชเซเชชเชฃเซ€ เช‰เชฎเซ‡เชฐเซ‹