เทคนิคและวิธีการเขียน Asterisk Dialplan I ตอนที่ 2

Asterisk Opensource IP Pbx

เทคนิคและวิธีการเขียน Asterisk Dialplan I ตอนที่ 2

โพสต์โดย voip4share » 03 มี.ค. 2010 14:27

Asterisk Dialplan ตอนที่ 1

Asterisk Dialplan ตอนที่ 2

เทคนิคและวิธีการสร้าง Asterisk Dialplan ตอนที่ 2 นี้นะครับ จะมีตัวอย่างการสร้าง Dialplan อย่างง่ายซึ่งถ้าจะให้ดีสร้างเสร็จแล้วก็เทสการทำงานของมันไปด้วยเลยจะได้รู้ว่าเวอร์คหรือไม่เวอร์ค จะช่วยให้เราเข้าใจการทำงานของมันได้มากขึ้น การเทสอาจจะโทรเข้าทาง ZAP/DAHI หรือ SIP หรือ IAX Channel ก็ได้ แต่ถ้าเป็น ZAP/DAHDI เราก็ต้องมีการ์ดอินเตอร์เฟสด้วย ถ้าไม่ไม่มีการ์ดหรือไม่อยากลงทุนซื้อผมว่าเทสโทรเข้าทางแชนแนล SIP หรือ IAX ก็ได้ ซึ่งหาอ่านวิธีการสร้าง SIP Account ได้จากบทความอื่นๆของเว็บนี้ครับ

4. Dialplan อย่างง่าย
ตอนนี้เราก็พร้อมจะสร้าง Dialplan แรกแล้วนะครับ เริ่มต้นจาก Dialplan อย่างง่ายก่อน เราจะออกแบบ Dialplan ให้รับสายที่โทรเข้ามา เมื่อมีสายโทรเข้าให้ Asterisk รับสาย เล่นไฟล์เสียง แล้วก็วางสาย ทุกๆสายที่โทรเข้ามาให้ส่งมายัง context [incoming]

4.1 Extension 's'
ก่อนสร้าง Dialplan ผมขออนุญาตพูดถึง Extension พิเศษตัวหนึ่งที่ Asteriks รู้จัก มันชื่อว่า s ครับ ย่อมาจาก Start โดยที่เราจะใช้ Extension s นี้รับคอลที่ไม่ระบุเบอร์ปลายทาง ซึ่งก็เหมาะมากที่เราจะเอามาใช้ในตัวอย่างของเราครับ
เมื่อมีสายเรียกเข้ามายัง Context ที่ไม่ได้ระบุ Extension ปลายทาง (เช่นสายที่โทรเข้ามายังพอร์ต FXO) มันจะถูกเซอร์วิสโดยอัตโนมัติด้วย Extension และจากความต้องการของเราที่ต้องการรับสายที่โทรเข้ามา จากนั้นเล่นไฟล์เสียง แล้ววางสาย เราจะสร้าง Extension s พร้อมกับ 3 Priority ไว้ภายใน Context [incoming]

[incoming]
exten => s,1,application()
exten => s,2,applicatoin()
exten => s,3,application()


ต่อไปก็หาคำสั่งมาใส่ใน application แล้ว Dialplan แรกของเราก็จะสำเร็จ

4.2 Answer(), Playback(), Hangup() Applications
ถ้าเราจะหา Application อะไรก็ตามมาทำงานตามที่เราต้องการ เราต้องรู้ว่ามันทำงานได้อย่างที่เราต้องการหรือเปล่า ถ้าเราดูแล้วไม่มี Application ที่จะมารองรับความต้องการของเราได้ เราก็ต้องเขียนขึ้นมาใหม่ครับ โดยใช้ AGI ซึ่งผมจะเขียนบทความเกี่ยวกับเรื่อง AGI นี้โดยเฉพาะอีกครั้ง อย่าลืมรอติดตามอ่านนะครับ

Answer() เป็น Application ที่ทำหน้าที่รับสายแชนแนลที่กำลัง Ring อยู่ Applicatoin ส่วนใหญ่ที่ Asterisk รู้จักจะทำงานได้ก็ต่อเมื่อรับสายก่อน แต่มีบาง Application ที่ไม่จำเป็นต้องรับสายก่อนก็ทำงานได้ เราใช้ Answer() ได้โดยไม่ต้องมี Argument ใดๆเลย ซึ่ง Application ที่ไม่ต้องมี Argument เวลาเราเขียนไม่ต้องใส่ () ก็ได้นะครับ

Playback() เป็น Application ที่จะเล่นไฟล์เสียงที่ได้บันทึกไว้แล้ว ส่งไปยังแชนแนลที่รับสาย ในขณะที่ Asterisk กำลังทำงานตาม Application Playback() อยู่ มันจะไม่รับอินพุตจากยูสเซอร์ คือไม่สนใจว่าคนโทรจะกดเลขอะไรบนแป้นโทรศัพท์ของเขา
Asterisk มีไฟล์เสียงอยู่นับร้อยๆไฟล์ อยู่ในไดเร็คตอรี่ /var/lib/asterisk/sounds บันทึกไว้ในรูปแบบ GSM จึงมีนามสกุลไฟล์เป็น .gsm เราจะใช้ไฟล์เหล่านี้ในอีกหลายๆตัวอย่างเพราะไม่ต้องบันทึกเอง ถ้าต้องการไฟล์เสียงเพิ่มเติมก็ต้องอัดเพิ่มเองครับ
ในการใช้ Playback() นั้นนะครับ ให้ระบุชื่อไฟล์เสียง (ไม่ต้องใส่นามสกุล) เป็น Argument ยกตัวอย่างเช่น Playback(filename) ซึ่ง Asterisk จะเล่นไฟล์เสียงที่มีชื่อว่า filename.gsm สมมติว่าไฟล์นี้อยู่ในไดเร็คตอรี่ดีฟอลท์คือ /var/lib/asterisk/sounds นะครับ
ถ้าไฟล์เสียงไม่ได้อยู่ในไดเร็คตอรี่ /var/lib/asterisk/sounds เราก็ต้องใส่ Path ที่เก็บเข้าไปด้วย เช่น Playback(/path/to/sounds/filename)
ตัวอย่างนี้ Asterisk จะเล่นเสียงในไฟล์ filename.gsm จากไดเร็คตอรี่ /path/to/sounds/
ถ้าไฟล์เสียงถูกเก็บไว้ในไดเร็คตอรี่ย่อยของ /var/lib/asterisk/sounds เช่น /var/lib/asterisk/sounds/custom/ ก็ระบุแบบนี้ Playback(custom/filename)
ถ้าในไดเร็คตอรี่มีไฟล์ชื่อเดียวกันแต่คนละนามสกุล Asterisk จะเล่นไฟล์ที่ดีที่สุดโดยอัตโนมัติ
Asterisk จะเล่นไฟล์เสียงที่ดีที่สุดโดยตัดสินใจจากค่า Translation cost ที่ใช้ในการแปลงเสียงฟอร์แม็ตหนึ่งไปเป็นฟอร์แม๊ตอื่น Asterisk จะเลือกไฟล์ที่กิน CPU น้อยที่สุดในการแปลงไฟล์ไปสัญญาณเสียงที่จะเล่นให้คนโทรฟัง เมื่อเราสตาร์ท Asterisk มันจะคำนวณหาค่า Translation cost ดังกล่าว (ค่า translation cost นี้ ขึ้นอยู่กับ CPU ในเครื่อง) เราสามารถดูค่า Translation cost นี้ได้โดยการเข้า Asterisk Console แล้วพิมพ์คำสั่ง show translation (สำหรับ Asterisk 1.4) หรือ core show translation (สำหรับ Asterisk 1.6)

Hangup() เป็น Application ซึ่งทำงานเหมือนกับชื่อของมัน คือจะวางสายแชนแนลที่แอ๊คทีฟอยู่ ผู้โทรจะได้รับสัญญาณที่บ่งบอกว่าสายได้ถูกวางแล้ว เช่นได้ยินเสียง Busy Tone ให้ใช้ Application นี้บรรทัดสุดท้ายของ Context เมื่อเราต้องการวางสาย เพื่อให้แน่ใจได้ว่าคอลจะไม่ไปที่อื่นอีกใน Dialplan

4.3 Dialplan แรกของเรา
เมื่อเรารู้ว่าจะใช้ Application อะไร ต่อไปก็เขียน Dialplan ซึ่ง Priority แรกจะรับสาย Priority ที่สองจะเล่นไฟล์เสียงชื่อ hello-world.gsm และ Priority ที่สามจะวางสาย

[incoming]
exten => s,1,Answer()
exten => s,2,Playback(hello-world)
exten => s,3,Hangup()


ลองโทรเข้ามาทดสอบดูนะครับ ถ้าจะโทรจาก SIP Account นะครับ ในไฟล์ sip.conf ก็สร้าง SIP Account แล้วระบุ context=incoming จากนั้นเทสโดยกดเบอร์โทรอะไรก็ได้มั่วๆไป ซึ่งจะตรงกับคอนเซ็ปต์ Extensions s อย่าลืมเปิด Asterisk Console ด้วยก็ได้ ดูข้อความที่ปรากฏ โดยเฉพาะข้อความ Error

4.4 เพิ่ม Logic ให้ Dialplan
Dialplan ที่เราเพิ่งสร้างในหัวข้อที่ผ่านมาเป็น Dialplan แบบ Static ครับ หมายความว่าทุกสายที่โทรเข้ามามันก็จะทำงานแบบเดิม ซ้ำๆ ซึ่งมันธรรมดาไปสำหรับเรา ต่อไปเราลองมาเพิ่ม Logic อะไรบางอย่างเข้าไปใน Dialplan เพื่อให้มันทำงานแตกต่างออกไปแล้วว่าแต่ยูสเซอร์จะกดตัวเลขอะไรเข้ามา ซึ่งในการนี้ต้องใช้ Application เพิ่มเติมครับ

4.4.1 Background() และ Goto() Applications
ในระบบที่ Asterisk สามารถโต้ตอบกับยูสเซอร์ได้นั้นนะครับ จะขาด Application ตัวหนึ่งไปไม่ได้เลย นั่นก็คือ Application ที่มีชื่อว่า Background() ครับ ซึ่ง Background() ทำงานคล้ายกับ Playback() คือมันจะเล่นไฟล์เสียงให้ยูสเซอร์ฟัง แต่มันแตกต่างจาก Playback() ตรงที่เมื่อผู้ใช้งานกดปุ่มบนแป้นโทรศัพท์ (บนเครื่องโทรศัพท์แบบกดปุ่ม) มันจะหยุดเล่นไฟล์เสียงทันทีแล้วรับข้อมูลที่ยูสเซอร์กด ขัดจังหวะ playback แล้วไปยัง Extension ที่ตรงกับปุ่มที่กด เช่น ถ้ายูสเซอร์กดปุ่ม 5 จะทำให้ Asterisk หยุดเล่นไฟล์เสียงและส่งคอลไปยัง Priority แรกของ Extension 5

Background() มีใช้งานบ่อยใช้ในการสร้าง IVR หรือ Auto-Attendant หรือ Phone Trees (แล้วแต่จะเรียก) หลายๆบริษัทใช้ IVR เพื่อให้คนโทรเข้ามากดเบอร์ Extension ภายในได้เองโดยไม่ต้องให้โอเปอร์เรเตอร์โอนสายให้

การใช้งาน Background() ก็ใช้เหมือนกับ Playback() เลยครับ ดังตัวอย่าง
exten => 123,1,Background(hello-world)

อีก Application หนึ่งที่มีประโยชน์ในหัวข้อนี้คือ Goto() มันทำหน้าที่เหมือนชื่อของมันก็คือส่งคอล ไปยัง Context หรือ Extension หรือ Priority ที่ระบุไว้ข้างใน ก็นับว่า Goto() ทำให้เราย้ายคอลไปที่นู่นที่นี่ใน Dialplan ได้ง่ายๆเลยครับ และการใช้ Goto() เราต้องระบุ Argument ด้วยนะครับ ซึ่ง Argument ของ Application นี้ม่อยู่ 3 อย่างได้แก่ context ที่จะกระโดดไป อาจเป็น Context ปัจจุบันหรือ Context อื่นก็ได้นะครับ, extension เป็น Extension ที่จะกระโดดไป และ priority เป็น Priority ที่จะกระโดดไป เช่น

exten => 123,1,Goto(context,extension,priority)

ตัวอย่างต่อไปของเรา เราจะใช้ Background() และ Goto() สร้าง Dialplan ที่ซับซ้อนขึ้นมาอีกหน่อย ซี่งผู้โทรจะโต้ตอบกับระบบได้โดยการกดปุ่มบนแป้นโทรศัพท์ เริ่มต้นจากใช้ Background() รอรับอินพุตจากคนโทรก่อนเลยครับ

[incoming]
exten => s,1,Answer()
exten => s,2,Background(enter-ext-of-person)


ในตัวอย่างนี้เมื่อรับสายแล้วเราจะเล่นเสียงจากไฟล์ enter-ext-of-person.gsm ให้คนโทรเข้ามาฟัง แต่ตัวอย่างนี้อย่างมากก็ทำได้แค่รอรับอินพุตจากยูสเซอร์ได้เท่านั้น ยังทำงานอื่นไม่ได้ ต่อไปให้เราเพิ่มอีก 2 Extension ซึ่งจะทำงานเมื่อยูสเซอร์กดปุ่ม 1 หรือปุ่ม 2

[incoming]
exten => s,1,Answer()
exten => s,2,Background(enter-ext-of-person)
exten => 1,1,Playback(digits/1)
exten => 2,1,Playback(digits/2)


ก่อนที่จะไปหัวข้อต่อไป ลองมาทบทวนสิ่งที่เราได้ทำผ่านมากันก่อนนะครับ เมื่อยูสเซอร์โทรเข้ามายัง Dialplan ของเรา เขาจะได้ยินเสียงต้อนรับพูดว่า "please enter the number you wish to call" ในระหว่างที่ได้ยินเสียงนี้ ถ้าเขากด 1 เขาจะได้ยินเสียงพูดว่า 1 ถ้ากด 2 ก็จะได้ยินเสียงว่า 2 พอเข้าใจแล้วนะครับ เราอาจจะเพิ่ม Goto() เข้าไปด้วยเพื่อให้ Dialplan วนลูปกล่าวต้อนรับซ้ำอีกครั้งหลังจากพูดเสียงตัวเลขแล้ว

[incoming]
exten => s,1,Answer()
exten => s,2,Background(enter-ext-of-person)
exten => 1,1,Playback(digits/1)
exten => 1,2,Goto(incoming,s,1)
exten => 2,1,Playback(digits/2)
exten => 2,2,Goto(incoming,s,1)


บรรทัดที่เรียกใช้ Goto() จะส่งคอลกลับไปยัง Extensions s หลังจากเล่นไฟล์เสียงตัวเลขเสร็จ

แม้ว่า Goto() จะมีได้ 3 Argument ก็ตามนะครับ เราไม่จำเป็นต้องใส่ให้ครบทั้ง 3 Argument ก็ได้ ถ้าเป็นการกระโดดไป Extension อื่นใน Context ปัจจุบัน หรือ Priorty ใน Extension ปัจจุบัน เช่นถ้าเราใส่แค่ 1 Argument จะหมายถึง Priority ที่อยู่ใน Extension ปัจจุบัน ถ้าใส่แค่ 2 Argument จะหมายถึง Extension และ Priority ใน Context ปัจจุบัน แต่ถ้าจะให้ดี กันงง ผมว่าใส่ให้ครบ 3 เลยครับ

4.5 เมื่อยูสเซอร์กดตัวเลือกผิด (Invalid Entry) หรือไม่กดเลือกภายในเวลาที่กำหนด (Timeout)
ก็ยังไม่ถือว่า IVR แรกของเราสมบูรณ์นะครับ เพราะยังไม่มีอะไรมารองรับถ้ายูสเซอร์กดตัวเลือกผิดหรือไม่ได้กดเลือกในเวลาที่กำหนด ถ้าเราต้องการรองรับ 2 กรณีที่ว่านี้เราต้องใช้ Extension พิเศษเพิ่มอีกครับ คือต้องมี Extension ที่จะมารองรับเมื่อยูสเซอร์กดตัวเลือกผิด (Invalid entry) ซึ่งเมื่อเขากดตัวเลขผิด (เราให้กดแค่ 1 หรือ 2 แต่เขากด 3) ผู้โทรก็จะถูกส่งไปยัง Extension i อันนี้ Asterisk มันจะรู้เองครับว่ามันต้องมองหา Extension i ถ้ายูสเซอร์เลือกผิด และเราต้องมีอีก Extension หนึ่งที่จะมารองรับสถานการณ์เมื่อผู้โทรไม่ได้กดเลือกในเวลาที่กำหนด คือเขาใช้เวลานานไปหลังจาก Asterisk เล่นไฟล์เสียงใน Background() จบแล้ว (ค่าไทม์เอ๊าท์ดีฟอลท์คือ 10 วินาที) ผู้โทรจะถูกส่งไปยัง Extension t และนี่คือ Dialplan ของเราหลังจากที่เราได้เพิ่ม 2 extension พิเศษนี้เข้าไปแล้ว


[incoming]
exten => s,1,Answer()
exten => s,2,Background(enter-ext-of-person)
exten => 1,1,Playback(digits/1)
exten => 1,2,Goto(incoming,s,1)
exten => 2,1,Playback(digits/2)
exten => 2,2,Goto(incoming,s,1)
exten => i,1,Playback(pbx-invalid)
exten => i,2,Goto(incoming,s,1)
exten => t,1,Playback(vm-goodbye)
exten => t,2,Hangup()


การมี Extension i และ t ทำให้ Dialplan ดูสมบูรณ์ขึ้นและเป็นมิตรกับผู้โทรด้วย แต่มันยังมีข้อจำกัดอีกนิดหน่อยเพราะว่าผู้โทรยังไม่มีทางที่จะติดต่อกับเบอร์ Extension ภายในจริงๆได้ ซึ่งเราต้องใช้ Application อื่นเพิ่มเติมอีก ซึ่งมีชื่อว่า Dial() ครับ

4.6 การใช้งาน Dial()
Asterisk สามารถเชื่อมต่อหรือบริดจ์ยูสเซอร์ที่เข้ามาทางแชนแนลต่างๆให้สามารถสื่อสารกันได้ คุณสมบัตินี้เป็นประโยชน์มากเมื่อยูสเซอร์กำลังใช้แชนแนลสื่อสารที่แตกต่างกัน เช่น นาย A อาจจะกำลังโทรเข้ามาด้วยระบบโทรศัพท์พื้นฐาน แชนแนล DAHDI ในขณะที่นาย B อาจจะกำลังนั่งอยู่ในร้านกาแฟที่ไหนซักแห่งในโลกและกำลังคุยผ่านโทรศัพท์ไอพี เข้ามาทางแชนแนล SIP ซึ่ง Asterisk ก็สามารถเชื่อมโยงผู้ใช้ที่อยู่คนละเน็ตเวอร์คกันให้โทรหากันได้ และการที่ Asterisk สามารถโทรไปยังแชนแนลต่างๆได้ไม่ว่าจะเป็น DAHDI, SIP, IAX, H.323 ก็เพราะว่ามันมี Application ที่มีชื่อว่า Dial() หน่ะครับ

รูปแบบการใช้งาน Dial() จะซับซ้อนกว่า Application ที่เราได้ผ่านตามาแล้วเล็กน้อยครับ แต่ไม่ต้องกลัวไปครับ Dial() มันใช้แค่ 4 Argument เท่านั้น (ไม่ต้องให้ครบก็ได้) แต่ละ Argument มีดังต่อไปนี้

Argument แรกของ Dial() คือ destination เป็นปลายทางที่เราต้องการจะโทรไป ซึ่งประกอบไปด้วยชื่อเทคโนโลยี (หรือช่องทางการรับส่ง) ที่จะใช้ส่งคอลไป ตามด้วยเครื่องหมาย / และทรัพยากรที่สามารถใช้เพื่อไปถึงปลายทางได้ (ปกติคือชื่อแชนแนล หรือ เบอร์) อ่านแล้วงงป่ะครับ ยกตัวอย่างเช่น สมมติว่าต้องการโทรออกทางการ์ดฮาร์ดแวร์ DAHDI ที่มีชื่อว่า DAHDI/1 ซึ่งเป็นพอร์ต FXS มีหัวเครื่องโทรศัพท์ต่ออยู่ เราอธิบายได้ว่าเทคโนโลยีก็คือ DAHDI และทรัพยากรหรือแชนแนลก็คือ 1 และคล้ายๆกันเมื่อโทรไปยังอุปกรณ์ SIP ซึ่งมีเบอร์ 1234 เราก็ใส่เป็น SIP/1234 และทำนองเดียวกันโทรไปยังอุปกรณ์ IAX ซึ่งมีแชนแนลหรือชื่อเป็น Fred เราก็ใส่เป็น IAX/Fred เป็นต้น ลองมาดู Dialplan ซึ่งจะส่งสัญญาณริงไปยังแชนแนล DAHDI/1 เมื่อมีคนเรียกไปที่ Extension 123

exten => 123,1,Dial(DAHDI/1)

เมื่อ extension นี้ถูกทำงาน Asterisk จะ ring โทรศัพท์ที่ต่ออยู่กับแชนแนล DAHDI/1 ถ้ายูสเซอร์รับสาย Asterisk ก็จะเชื่อม (bridge) inbound call เข้ากับ DAHDI/1 channel และเรายังสามารถ Dial ได้หลายๆ channel ในเวลาเดียวกันได้อีกด้วย โดยใช้เครื่องหมาย & เชื่อมแต่ละ channel ที่ต้องการ เช่นแบบนี้

exten => 123,1,Dial(DAHDI/1&DAHDI/2&DAHDI/3)

ซึ่ง Dial() จะบริดจ์สายที่โทรเข้ามากับแชนแนลแรกที่รับสายก่อน

และถ้าเราจะเรียกไปยังเบอร์ SIP Account 120 เมื่อมีคนกด Extension 100 ก็เขียนว่า

exten => 100,Dial(SIP/120)

ไม่ยากเลยใช่มั๊ยครับ

Argument ที่สองของ Dial() คือ timeout มีหน่วยเป็นวินาที ถ้าเราระบุ timeout ด้วยจะทำให้ Dial() พยายามโทรไปยัง Destination เป็นระยะเวลาตามที่ได้กำหนดไว้ ก่อนที่จะเลิก (ถ้าไม่มีใครรับสาย) จากนั้นจะกระโดดไปยัง Priority ถัดไป ถ้าเราใช้โดยไม่ระบุ timeout จะทำให้ Dial() รอสายไปเรื่อยๆจนกว่าจะมีคนรับสายหรือคนโทรวางสายก่อน ลองเพิ่ม timeout เป็นเวลา 10 วินาทีดูครับ

exten => 123,1,Dial(DAHDI/1,10)

ถ้าปลายทางรับสายก่อนภายในระยะเวลา 10 วินาที นับจากที่ Asterisk ประมวลผล Dial() จะทำให้แชนแนลถูกบริดจ์และจะเชื่อมต้นทางและปลายทางเข้าหากัน ถ้าปลายทางไม่รับสายภายใน 10 วินาที Dial() จะกระโดดไปยัง Priority ถัดไปใน Extension 123 แต่ถ้า Destination สายไม่ว่าง Dial() จะไปยัง Priority n+101 ถ้าเรามีเขียนไว้ (โดยที่ n เป็น priority ของบรรทัด Dial() ที่ถูกเรียก) ก็คงพอเข้าใจแล้วนะครับว่าเราจะรับมือกับคอลที่ไม่มีคนรับสายในเวลาที่กำหนด และคอลที่เบอร์ปลายทางสายไม่ว่างได้ยังไง และ Dialplan ของเราก็จะกลายเป็นแบบนี้

exten => 123,1,Dial(DAHDI/1,10)
exten => 123,2,Playback(vm-nobodyavail)
exten => 123,3,Hangup()
exten => 123,102,Playback(tt-allbusy)
exten => 123,103,Hangup()


ตัวอย่างข้างบน ถ้าไม่มีคนรับสายใน 10 วินาที Asterisk จะเล่นเสียงจากไฟล์ vm-nobodyavail.gsm และถ้าสายไม่ว่างจะเล่นไฟล์ tt-allbusy.gsm แทน

Argument ที่สาม ของ Dial() คือ Option String ซึ่งอาจประกอบด้วยตัวอักษรตั้งแต่ 1 ตัวขึ้นไป (แต่ต้องอยู่ในรายการที่ยอมให้ใส่ด้วยนะครับ) ซึ่งจะเปลี่ยนแปลงพฤติกรรมธรรมชาติของ Dial() ในขณะนี้รายชื่อของ options นั้นมันมีมากมายจนเอามาแสดงให้ดูทั้งหมดไม่ได้ แต่ออปชั่นที่นิยมใช้มากที่สุดคือตัวอักษร r (ตัว r เล็ก) โดยถ้าเราใส่ตัวอักษร r เป็น Argument ที่ 3 ผู้โทรจะได้ยินเสียง Ringback Tone ในระหว่างที่กำลังรอปลายทางรับสาย เป็น Ringback ที่ Asterisk ปลอมขึ้นมาครับ ซึ่งการได้ Ring ปลอมนี้ผมไม่แนะนำให้ใช้เวลาโทรออกไปเบอร์ภายนอก Asterisk เช่นเบอร์บ้าน เบอร์มือถือ เพราะในกรณีที่ติดต่อไม่ได้เราจะไม่มีทางรู้เลยว่าเบอร์ปลายทางปิดเครื่อง สายไม่วาง หรือไม่รับสาย

exten => 123,1,Dial(DAHDI/1,10,r)
exten => 123,2,Playback(vm-nobodyavail)
exten => 123,3,Hangup()
exten => 123,102,Playback(tt-allbusy)
exten => 123,103,Hangup()


เราลองเพิ่ม Extension 101 และ 102 ใน Dialplan ซึ่งจะทำให้ผู้โทรกดหา John และ Jane ได้

[incoming]
exten => s,1,Answer()
exten => s,2,Background(enter-ext-of-person)
exten => 101,1,Dial(DAHDI/1,10)
exten => 101,2,Playback(vm-nobodyavail)
exten => 101,3,Hangup()
exten => 102,1,Dial(SIP/Jane,10)
exten => 102,2,Playback(vm-nobodyavail)
exten => 102,3,Hangup()
exten => i,1,Playback(pbx-invalid)
exten => i,2,Gogo(incoming,s,1)
exten => t,1,Playback(vm-goodbye)
exten => t,2,Hangup()


Argument ที่ 4 และเป็น Argument สุดท้ายของ Dial() ก็คือ URL เป็นลิ้งค์เหมือนกับที่เราใช้เรียกเข้าไปดูเว็บไซต์ ซึ่งถ้าแชนแนลปลายทางรองรับ URL มันก็จะโชว์หน้าเว็บขึ้นมาให้ดู เช่นตัวอย่างเช่น ถ้ามีเครื่อง IP Phone ที่สามารถแสดง URL ได้เราก็จะเห็นลิ้งค์ปรากฏบนหน้าจอเครื่อง และถ้าใช้ soft phone ก็จะมี URL โผล่ปรากฏขึ้นมาบนหน้าจอคอมพิวเตอร์ แต่ก็เป็น Argument ที่ไม่ค่อยใช้งานกันครับ

ถ้าเรากำลังโทรออกไปภายนอกผ่านการ์ด DAHDI โดยใช้แชนแนล FXO เราอาจจะสร้าง Dialplan เพื่อโทรออกได้แบบนี้

exten => 123,1,Dial(DAHDI/4/028888888)

เมื่อยูสเซอร์กด 123 ระบบจะโทรไปยังเบอร์ 028888888 ผ่านทางแชนแนล DAHDI/4 และสำหรับการโทรออกทางแชนแนลอื่นเช่น SIP และ IAX2 ใส่ Destination เป็น resource ดังตัวอย่าง

exten => 124,1,Dial(SIP/028888888)
exten => 125,1,Dial(IAX2/nuiz@voip4share.com)


อย่างที่ผมเคยบอกไปว่าเราไม่ต้องใส่ Argument ให้ครบก็ได้ เช่น ถ้าต้องการระบุ option แต่ไม่ต้องการระบุ timeout ก็ให้เว้นว่าง Argument ของ timeout ไว้ครับ ดังตัวอย่าง

exten => 123,1,Dial(DAHDI/1,,r)

เทคนิคการเขียน Asterisk Dialplan ตอนที่ 3
voip4share
Administrator
 
โพสต์: 656
ลงทะเบียนเมื่อ: 18 พ.ย. 2009 11:26
ที่อยู่: รามคำแหง กรุงเทพฯ

ย้อนกลับไปยัง Asterisk SIP Server

ผู้ใช้งานขณะนี้

กำลังดูบอร์ดนี้: ไม่มีสมาชิกใหม่ และ บุคคลทั่วไป 5 ท่าน