на один канал курите связку dir-320[с usb-портом на борту]+asterisk+dongle. более дешевое решение для дома найти маловероятно. вот, кстати, и решение без винды(и октелла), тихое, бесшумное, работающее 365х24... на хабре была очень подробная статья. там через usb-хаб парень зацепил несколько модемов = несколько операторов
Для виртуалок вполне рабочий вариант - использовать SIP GSM GATE от Oktell. Не так давно он стал полностью бесплатным. Отдельный комп на винде, утыканный модемами как ёжик. Софтина поддерживает до 10 модемов одновременно/бесплатно. В локалку отдает SIP- стык для каждого канала.
Тестировал - работало. Под нагрузкой не гонял.
Вот кусок действующего диалплана:
exten => s,n,NoOP("USLOVIE CHANNEL 1")
exten => s,n(dial_ch1),GotoIf($["${DB(GSM-Channels/GSM-Channel-1_status)}" = "off"]?dial_ch2) ; проверяем включен ли канал
; в базе данных GSM-Channels
exten => s,n,Dial(${GSM-Channel-1}/00${ARG1},30,gmt) ; Звоним через 1-й GSM-канал - 0116
exten => s,n,Set(Call_Dial_status=${DIALSTATUS}) ; передаем результат вызова для анализа
exten => s,n,Noop("Dialstatus is - ${Call_Dial_status}")
exten => s,n,GotoIf($["${Call_Dial_status}" = "BUSY"]?sms) ; если абонент занят или отбил звонок
exten => s,n,GotoIf($["${Call_Dial_status}" = "CANCEL"]?sms) ; если нет - продолжаем
exten => s,n,GotoIf($["${Call_Dial_status}" = "CONGESTION"]?sms) ; если нет - продолжаем
exten => s,n,GotoIf($["${Call_Dial_status}" = "NOANSWER"]?sms) ; если нет - продолжаем
exten => s,n,GotoIf($["${Call_Dial_status}" = "ANSWER"]?complete_call) ; если нет - продолжаем
exten => s,n,NoOP("USLOVIE CHANNEL 2")
exten => s,n(dial_ch2),GotoIf($["${DB(GSM-Channels/GSM-Channel-2_status)}" = "off"]?dial_ch3) ; проверяем включен ли канал
; в базе данных GSM-Channels
exten => s,n,Dial(${GSM-Channel-2}/01${ARG1},30,gmt) ; Звоним через 2-й GSM-канал - 0117
exten => s,n,Set(Call_Dial_status=${DIALSTATUS}) ; передаем результат вызова для анализа
exten => s,n,Noop("Dialstatus is - ${Call_Dial_status}")
exten => s,n,GotoIf($["${Call_Dial_status}" = "BUSY"]?sms) ; если абонент занят или отбил звонок
exten => s,n,GotoIf($["${Call_Dial_status}" = "CANCEL"]?sms) ; если нет - продолжаем
exten => s,n,GotoIf($["${Call_Dial_status}" = "CONGESTION"]?sms) ; если нет - продолжаем
exten => s,n,GotoIf($["${Call_Dial_status}" = "NOANSWER"]?sms) ; если нет - продолжаем
exten => s,n,GotoIf($["${Call_Dial_status}" = "ANSWER"]?complete_call) ; если нет - продолжаем
По метке "sms" у меня исполняется кусок кода отправляющий СМС абоненту до которого не дозвонились. Отправка выполняется через email2sms сервис Мегафона. То есть asterisk отправляет сформированный специальным образом e-mail, а "сервер" мегафона отправляет текст письма в виде смс абоненту. ВСЁ БЕСПЛАТНО.