Added suport to build custom tones from config and specify a tone language. Imported tone descriptions from Asterisk indications.conf.
git-svn-id: http://yate.null.ro/svn/yate/trunk@4031 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
parent
4801fa3f7c
commit
cb37e92229
|
@ -0,0 +1,578 @@
|
|||
; This file configures the tone generator
|
||||
; If not explicitly specified, all parameters are processed at startup only (no reload)
|
||||
; Each section, except for 'general' configures a lang list
|
||||
;
|
||||
; Here is an example of lang list
|
||||
;
|
||||
;[example]
|
||||
;
|
||||
; alias: string: Comma separated list of tone languages sharing the same tones
|
||||
; This parameter is ignored in 'itu' section
|
||||
; Subsequent sections may override tones specified for aliases
|
||||
;alias=
|
||||
;
|
||||
; All other parameters must have the format
|
||||
; name=tone[,tone]
|
||||
; Each tone must be specified in the format [!]freq[/duration]
|
||||
; !: Don't repeat this tone (play it on first pass only)
|
||||
; freq: Tone frequency
|
||||
; f: This is the frequency used to build the tone
|
||||
; f1+f2: The frequency is a mixture of f1 and f2
|
||||
; f1*f2: The frequency f1 is modulated by f2
|
||||
; Frequency can be 0 for silence
|
||||
; duration: Tone duration in milliseconds. Defaults to 1000 if missing or invalid
|
||||
; Note: if all tones start with '!' (not repeated) playing will stop after the
|
||||
; last tone in the list
|
||||
;
|
||||
;
|
||||
; The algorithm used to play a requested tone is the following:
|
||||
; 1. If a language is specified in the call.execute or chan.attach message,
|
||||
; find the tone using the specified language
|
||||
; 2. Find the tone using the configured language if any
|
||||
; 3. Find the tone using the default ('itu')
|
||||
; If 'itu' language is specified in the handled message the tone is searched in
|
||||
; the default list only: any configured language is ignored
|
||||
|
||||
|
||||
[general]
|
||||
|
||||
; lang: string: Default tones language
|
||||
; This is the name of the section containing the tones to play if no language
|
||||
; is specified in processed messages or the tone is not found for the specified
|
||||
; language section
|
||||
;lang=
|
||||
|
||||
|
||||
[itu]
|
||||
; This section configures the default tones to play
|
||||
; The following tones are pre-generated: dial,busy,ring,specdial,congestion,
|
||||
; outoforder,info,milliwatt,silence,noise,probe/0,probe/1,probe/2,cotv,cots
|
||||
|
||||
|
||||
[at]
|
||||
; Austria
|
||||
dial=420
|
||||
busy=420/400,0/400
|
||||
ring=420/1000,0/5000
|
||||
congestion=420/200,0/200
|
||||
callwaiting=420/40,0/1960
|
||||
dialrecall=420
|
||||
record=1400/80,0/14920
|
||||
info=950/330,1450/330,1850/330,0/1000
|
||||
stutter=380+420
|
||||
|
||||
|
||||
[au]
|
||||
; Australia
|
||||
dial=413+438
|
||||
busy=425/375,0/375
|
||||
ring=413+438/400,0/200,413+438/400,0/2000
|
||||
congestion=425/375,0/375,420/375,0/375
|
||||
callwaiting=425/200,0/200,425/200,0/4400
|
||||
dialrecall=413+438
|
||||
record=!425/1000,!0/15000,425/360,0/15000
|
||||
info=425/2500,0/500
|
||||
std=!525/100,!0/100,!525/100,!0/100,!525/100,!0/100,!525/100,!0/100,!525/100
|
||||
facility=425
|
||||
stutter=413+438/100,0/40
|
||||
ringmobile=400+450/400,0/200,400+450/400,0/2000
|
||||
|
||||
|
||||
[bg]
|
||||
; Bulgaria
|
||||
dial=425
|
||||
busy=425/500,0/500
|
||||
ring=425/1000,0/4000
|
||||
congestion=425/250,0/250
|
||||
callwaiting=425/150,0/150,425/150,0/4000
|
||||
dialrecall=!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425
|
||||
record=1400/425,0/15000
|
||||
info=950/330,1400/330,1800/330,0/1000
|
||||
stutter=425/1500,0/100
|
||||
|
||||
|
||||
[br]
|
||||
; Brazil
|
||||
dial=425
|
||||
busy=425/250,0/250
|
||||
ring=425/1000,0/4000
|
||||
congestion=425/250,0/250,425/750,0/250
|
||||
callwaiting=425/50,0/1000
|
||||
dialrecall=350+440
|
||||
record=425/250,0/250
|
||||
info=950/330,1400/330,1800/330
|
||||
stutter=350+440
|
||||
|
||||
|
||||
[be]
|
||||
; Belgium
|
||||
dial=425
|
||||
busy=425/500,0/500
|
||||
ring=425/1000,0/3000
|
||||
congestion=425/167,0/167
|
||||
callwaiting=1400/175,0/175,1400/175,0/3500
|
||||
dialrecall=!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440"
|
||||
record=1400/500,0/15000
|
||||
info=900/330,1400/330,1800/330,0/1000
|
||||
stutter=425/1000,0/250
|
||||
|
||||
|
||||
[ch]
|
||||
; Switzerland
|
||||
dial=425
|
||||
busy=425/500,0/500
|
||||
ring=425/1000,0/4000
|
||||
congestion=425/200,0/200
|
||||
callwaiting=425/200,0/200,425/200,0/4000
|
||||
dialrecall=!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425
|
||||
record=1400/80,0/15000
|
||||
info=950/330,1400/330,1800/330,0/1000
|
||||
stutter=425+340/1100,0/1100
|
||||
|
||||
|
||||
[cl]
|
||||
; Chile
|
||||
dial=400
|
||||
busy=400/500,0/500
|
||||
ring=400/1000,0/3000
|
||||
congestion=400/200,0/200
|
||||
callwaiting=400/250,0/8750
|
||||
dialrecall=!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,400
|
||||
record=1400/500,0/15000
|
||||
info=950/333,1400/333,1800/333,0/1000
|
||||
stutter=!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,400
|
||||
|
||||
|
||||
[cn]
|
||||
; China
|
||||
dial=450
|
||||
busy=450/350,0/350
|
||||
ring=450/1000,0/4000
|
||||
congestion=450/700,0/700
|
||||
callwaiting=450/400,0/4000
|
||||
dialrecall=450
|
||||
record=950/400,0/10000
|
||||
info=450/100,0/100,450/100,0/100,450/100,0/100,450/400,0/400
|
||||
stutter=450+425
|
||||
|
||||
|
||||
[cz]
|
||||
; Czech Republic
|
||||
dial=425/330,0/330,425/660,0/660
|
||||
busy=425/330,0/330
|
||||
ring=425/1000,0/4000
|
||||
congestion=425/165,0/165
|
||||
callwaiting=425/330,0/9000
|
||||
dialrecall=!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425/330,0/330,425/660,0/660
|
||||
record=1400/500,0/14000
|
||||
info=950/330,0/30,1400/330,0/30,1800/330,0/1000
|
||||
stutter=425/450,0/50
|
||||
|
||||
|
||||
[de]
|
||||
; Germany
|
||||
dial=425
|
||||
busy=425/480,0/480
|
||||
ring=425/1000,0/4000
|
||||
congestion=425/240,0/240
|
||||
callwaiting=!425/200,!0/200,!425/200,!0/5000,!425/200,!0/200,!425/200,!0/5000,!425/200,!0/200,!425/200,!0/5000,!425/200,!0/200,!425/200,!0/5000,!425/200,!0/200,!425/200,0
|
||||
dialrecall=!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425
|
||||
record=1400/80,0/15000
|
||||
info=950/330,1400/330,1800/330,0/1000
|
||||
stutter=425+400
|
||||
|
||||
|
||||
[dk]
|
||||
; Denmark
|
||||
dial=425
|
||||
busy=425/500,0/500
|
||||
ring=425/1000,0/4000
|
||||
congestion=425/200,0/200
|
||||
callwaiting=!425/200,!0/600,!425/200,!0/3000,!425/200,!0/200,!425/200,0
|
||||
dialrecall=!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425
|
||||
record=1400/80,0/15000
|
||||
info=950/330,1400/330,1800/330,0/1000
|
||||
stutter=425/450,0/50
|
||||
|
||||
|
||||
[ee]
|
||||
; Estonia
|
||||
dial=425
|
||||
busy=425/300,0/300
|
||||
ring=425/1000,0/4000
|
||||
congestion=425/200,0/200
|
||||
callwaiting=950/650,0/325,950/325,0/30,1400/1300,0/2600
|
||||
dialrecall=425/650,0/25
|
||||
record=1400/500,0/15000
|
||||
info=950/650,0/325,950/325,0/30,1400/1300,0/2600
|
||||
stutter=!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425
|
||||
|
||||
|
||||
[es]
|
||||
; Spain
|
||||
dial=425
|
||||
busy=425/200,0/200
|
||||
ring=425/1500,0/3000
|
||||
congestion=425/200,0/200,425/200,0/200,425/200,0/600
|
||||
callwaiting=425/175,0/175,425/175,0/3500
|
||||
dialrecall=!425/200,!0/200,!425/200,!0/200,!425/200,!0/200,425
|
||||
record=1400/500,0/15000
|
||||
info=950/330,0/1000
|
||||
dialout=500
|
||||
|
||||
|
||||
[fi]
|
||||
; Finland
|
||||
dial=425
|
||||
busy=425/300,0/300
|
||||
ring=425/1000,0/4000
|
||||
congestion=425/200,0/200
|
||||
callwaiting=425/150,0/150,425/150,0/8000
|
||||
dialrecall=425/650,0/25
|
||||
record=1400/500,0/15000
|
||||
info=950/650,0/325,950/325,0/30,1400/1300,0/2600
|
||||
stutter=425/650,0/25
|
||||
|
||||
|
||||
[fr]
|
||||
; France
|
||||
dial=440
|
||||
busy=440/500,0/500
|
||||
ring=440/1500,0/3500
|
||||
congestion=440/250,0/250
|
||||
callwait=440/300,0/10000
|
||||
dialrecall=!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440
|
||||
record=1400/500,0/15000
|
||||
info=!950/330,!1400/330,!1800/330
|
||||
stutter=!440/100,!0/100,!440/100,!0/100,!440/100,!0/100,!440/100,!0/100,!440/100,!0/100,!440/100,!0/100,440
|
||||
|
||||
|
||||
[gr]
|
||||
; Greece
|
||||
dial=425/200,0/300,425/700,0/800
|
||||
busy=425/300,0/300
|
||||
ring=425/1000,0/4000
|
||||
congestion=425/200,0/200
|
||||
callwaiting=425/150,0/150,425/150,0/8000
|
||||
dialrecall=425/650,0/25
|
||||
record=1400/400,0/15000
|
||||
info=!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0
|
||||
stutter=425/650,0/25
|
||||
|
||||
|
||||
[hu]
|
||||
; Hungary
|
||||
dial=425
|
||||
busy=425/300,0/300
|
||||
ring=425/1250,0/3750
|
||||
congestion=425/300,0/300
|
||||
callwaiting=425/40,0/1960
|
||||
dialrecall=425+450
|
||||
record=1400/400,0/15000
|
||||
info=!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0
|
||||
stutter=350+375+400
|
||||
|
||||
|
||||
[il]
|
||||
; Israel
|
||||
dial=414
|
||||
busy=414/500,0/500
|
||||
ring=414/1000,0/3000
|
||||
congestion=414/250,0/250
|
||||
callwaiting=414/100,0/100,414/100,0/100,414/600,0/3000
|
||||
dialrecall=!414/100,!0/100,!414/100,!0/100,!414/100,!0/100,414
|
||||
record=1400/500,0/15000
|
||||
info=1000/330,1400/330,1800/330,0/1000
|
||||
stutter=!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,414
|
||||
|
||||
|
||||
[in]
|
||||
; India
|
||||
dial=400*25
|
||||
busy=400/750,0/750
|
||||
ring=400*25/400,0/200,400*25/400,0/2000
|
||||
congestion=400/250,0/250
|
||||
callwaiting=400/200,0/100,400/200,0/7500
|
||||
dialrecall=!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440
|
||||
record=1400/500,0/15000
|
||||
info=!950/330,!1400/330,!1800/330,0/1000
|
||||
stutter=!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440
|
||||
|
||||
|
||||
[it]
|
||||
; Italy
|
||||
dial=425/200,0/200,425/600,0/1000
|
||||
busy=425/500,0/500
|
||||
ring=425/1000,0/4000
|
||||
congestion=425/200,0/200
|
||||
callwaiting=425/400,0/100,425/250,0/100,425/150,0/14000
|
||||
dialrecall=470/400,425/400
|
||||
record=1400/400,0/15000
|
||||
info=!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0
|
||||
stutter=470/400,425/400
|
||||
|
||||
|
||||
[lt]
|
||||
; Lithuania
|
||||
dial=425
|
||||
busy=425/350,0/350
|
||||
ring=425/1000,0/4000
|
||||
congestion=425/200,0/200
|
||||
callwaiting=425/150,0/150,425/150,0/4000
|
||||
dialrecall=425/500,0/50
|
||||
record=1400/500,0/15000
|
||||
info=!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0
|
||||
stutter=!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425
|
||||
|
||||
|
||||
[jp]
|
||||
; Japan
|
||||
dial=400
|
||||
busy=400/500,0/500
|
||||
ring=400+15/1000,0/2000
|
||||
congestion=400/500,0/500
|
||||
callwaiting=400+16/500,0/8000
|
||||
dialrecall=!400/200,!0/200,!400/200,!0/200,!400/200,!0/200,400
|
||||
record=1400/500,0/15000
|
||||
info=!950/330,!1400/330,!1800/330,0
|
||||
stutter=!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,400
|
||||
|
||||
|
||||
[mx]
|
||||
; Mexico
|
||||
dial=425
|
||||
busy=425/250,0/250
|
||||
ring=425/1000,0/4000
|
||||
congestion=425/250,0/250
|
||||
callwaiting=425/200,0/600,425/200,0/10000
|
||||
dialrecall=!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440
|
||||
record=1400/500,0/15000
|
||||
info=950/330,0/30,1400/330,0/30,1800/330,0/1000
|
||||
stutter=!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440
|
||||
|
||||
|
||||
[my]
|
||||
; Malaysia
|
||||
dial=425
|
||||
busy=425/500,0/500
|
||||
ring=425/400,0/200
|
||||
congestion=425/500,0/500
|
||||
|
||||
|
||||
[nl]
|
||||
; Netherlands
|
||||
dial=425
|
||||
busy=425/500,0/500
|
||||
ring=425/1000,0/4000
|
||||
congestion=425/250,0/250
|
||||
callwaiting=425/500,0/9500
|
||||
dialrecall=425/500,0/50
|
||||
record=1400/500,0/15000
|
||||
info=950/330,1400/330,1800/330,0/1000
|
||||
stutter=425/500,0/50
|
||||
|
||||
|
||||
[no]
|
||||
; Norway
|
||||
dial=425
|
||||
busy=425/500,0/500
|
||||
ring=425/1000,0/4000
|
||||
congestion=425/200,0/200
|
||||
callwaiting=425/200,0/600,425/200,0/10000
|
||||
dialrecall=470/400,425/400
|
||||
record=1400/400,0/15000
|
||||
info=!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0
|
||||
stutter=470/400,425/400
|
||||
|
||||
|
||||
[nz]
|
||||
; New Zealand
|
||||
dial=400
|
||||
busy=400/250,0/250
|
||||
ring=400+450/400,0/200,400+450/400,0/2000
|
||||
congestion=400/375,0/375
|
||||
callwaiting=!400/200,!0/3000,!400/200,!0/3000,!400/200,!0/3000,!400/200
|
||||
dialrecall=!400/100!0/100,!400/100,!0/100,!400/100,!0/100,400
|
||||
record=1400/425,0/15000
|
||||
info=400/750,0/100,400/750,0/100,400/750,0/100,400/750,0/400
|
||||
stutter=!400/100!0/100,!400/100,!0/100,!400/100,!0/100,!400/100!0/100,!400/100,!0/100,!400/100,!0/100,400
|
||||
unobtainable=400/75,0/100,400/75,0/100,400/75,0/100,400/75,0/400
|
||||
|
||||
|
||||
[ph]
|
||||
; Philippines
|
||||
dial=425
|
||||
busy=480+620/500,0/500
|
||||
ring=425+480/1000,0/4000
|
||||
congestion=480+620/250,0/250
|
||||
callwaiting=440/300,0/10000
|
||||
dialrecall=!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440
|
||||
record=1400/500,0/15000
|
||||
info=!950/330,!1400/330,!1800/330,0
|
||||
stutter=!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440
|
||||
|
||||
|
||||
[pl]
|
||||
; Poland
|
||||
dial=425
|
||||
busy=425/500,0/500
|
||||
ring=425/1000,0/4000
|
||||
congestion=425/500,0/500
|
||||
callwaiting=425/150,0/150,425/150,0/4000
|
||||
dialrecall=425/500,0/50
|
||||
record=1400/500,0/15000
|
||||
info=!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000
|
||||
stutter=!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425
|
||||
|
||||
|
||||
[pt]
|
||||
; Portugal
|
||||
dial=425
|
||||
busy=425/500,0/500
|
||||
ring=425/1000,0/5000
|
||||
congestion=425/200,0/200
|
||||
callwaiting=440/300,0/10000
|
||||
dialrecall=425/1000,0/200
|
||||
record=1400/500,0/15000
|
||||
info=950/330,1400/330,1800/330,0/1000
|
||||
stutter=!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425
|
||||
|
||||
|
||||
[ru]
|
||||
; Russia / ex Soviet Union
|
||||
dial=425
|
||||
busy=425/350,0/350
|
||||
ring=425/800,0/3200
|
||||
congestion=425/350,0/350
|
||||
callwaiting=425/200,0/5000
|
||||
dialrecall=!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440
|
||||
record=1400/500,0/15000
|
||||
info=!950/330,!1400/330,!1800/330,0
|
||||
|
||||
|
||||
[se]
|
||||
; Sweden
|
||||
dial=425
|
||||
busy=425/250,0/250
|
||||
ring=425/1000,0/5000
|
||||
congestion=425/250,0/750
|
||||
callwaiting=425/200,0/500,425/200,0/9100
|
||||
dialrecall=!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425
|
||||
record=1400/500,0/15000
|
||||
info=!950/332,!0/24,!1400/332,!0/24,!1800/332,!0/2024,!950/332,!0/24,!1400/332,!0/24,!1800/332,!0/2024,!950/332,!0/24,!1400/332,!0/24,!1800/332,!0/2024,!950/332,!0/24,!1400/332,!0/24,!1800/332,!0/2024,!950/332,!0/24,!1400/332,!0/24,!1800/332,0
|
||||
stutter=!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425
|
||||
|
||||
|
||||
[sg]
|
||||
; Singapore
|
||||
dial=425
|
||||
ring=425*24/400,0/200,425*24/400,0/2000
|
||||
busy=425/750,0/750
|
||||
congestion=425/250,0/250
|
||||
callwaiting=425*24/300,0/200,425*24/300,0/3200
|
||||
stutter=!425/200,!0/200,!425/600,!0/200,!425/200,!0/200,!425/600,!0/200,!425/200,!0/200,!425/600,!0/200,!425/200,!0/200,!425/600,!0/200,425
|
||||
info=950/330,1400/330,1800/330,0/1000
|
||||
dialrecall=425*24/500,0/500,425/500,0/2500
|
||||
record=1400/500,0/15000
|
||||
nutone=425/2500,0/500
|
||||
intrusion=425/250,0/2000
|
||||
warning=425/624,0/4376
|
||||
acceptance=425/125,0/125
|
||||
holdinga=!425*24/500,!0/500
|
||||
holdingb=!425/500,!0/2500
|
||||
|
||||
|
||||
[th]
|
||||
; Thailand
|
||||
dial=400*50
|
||||
busy=400/500,0/500
|
||||
ring=420/1000,0/5000
|
||||
congestion=400/300,0/300
|
||||
callwaiting=1000/400,10000/400,1000/400
|
||||
dialrecall=400*50/400,0/100,400*50/400,0/100
|
||||
record=1400/500,0/15000
|
||||
info=950/330,1400/330,1800/330
|
||||
stutter=!400/200,!0/200,!400/600,!0/200,!400/200,!0/200,!400/600,!0/200,!400/200,!0/200,!400/600,!0/200,!400/200,!0/200,!400/600,!0/200,400
|
||||
|
||||
|
||||
[uk]
|
||||
; United Kingdom
|
||||
dial=350+440
|
||||
specdial=350+440/750,440/750
|
||||
busy=400/375,0/375
|
||||
congestion=400/400,0/350,400/225,0/525
|
||||
speccongestion=400/200,1004/300
|
||||
unobtainable=400
|
||||
ring=400+450/400,0/200,400+450/400,0/2000
|
||||
callwaiting=400/100,0/4000
|
||||
speccallwaiting=400/250,0/250,400/250,0/250,400/250,0/5000
|
||||
creditexpired=400/125,0/125
|
||||
confirm=1400
|
||||
switching=400/200,0/400,400/2000,0/400
|
||||
info=950/330,0/15,1400/330,0/15,1800/330,0/1000
|
||||
record=1400/500,0/60000
|
||||
stutter=350+440/750,440/750
|
||||
|
||||
|
||||
[us]
|
||||
; United States / North America
|
||||
dial=350+440
|
||||
busy=480+620/500,0/500
|
||||
ring=440+480/2000,0/4000
|
||||
congestion=480+620/250,0/250
|
||||
callwaiting=440/300,0/10000
|
||||
dialrecall=!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440
|
||||
record=1400/500,0/15000
|
||||
info=!950/330,!1400/330,!1800/330,0
|
||||
stutter=!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440
|
||||
|
||||
|
||||
[us-old]
|
||||
; United States Circa 1950 / North America
|
||||
dial=600*120
|
||||
busy=500*100/500,0/500
|
||||
ring=420*40/2000,0/4000
|
||||
congestion=500*100/250,0/250
|
||||
callwaiting=440/300,0/10000
|
||||
dialrecall=!600*120/100,!0/100,!600*120/100,!0/100,!600*120/100,!0/100,600*120
|
||||
record=1400/500,0/15000
|
||||
info=!950/330,!1400/330,!1800/330,0
|
||||
stutter=!600*120/100,!0/100,!600*120/100,!0/100,!600*120/100,!0/100,!600*120/100,!0/100,!600*120/100,!0/100,!600*120/100,!0/100,600*120
|
||||
|
||||
|
||||
[tw]
|
||||
; Taiwan
|
||||
dial=350+440
|
||||
busy=480+620/500,0/500
|
||||
ring=440+480/1000,0/2000
|
||||
congestion=480+620/250,0/250
|
||||
callwaiting=350+440/250,0/250,350+440/250,0/3250
|
||||
dialrecall=300/1500,0/500
|
||||
record=1400/500,0/15000
|
||||
info=!950/330,!1400/330,!1800/330,0
|
||||
stutter=!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440
|
||||
|
||||
|
||||
[ve]
|
||||
; Venezuela / South America
|
||||
dial=425
|
||||
busy=425/500,0/500
|
||||
ring=425/1000,0/4000
|
||||
congestion=425/250,0/250
|
||||
callwaiting=400+450/300,0/6000
|
||||
dialrecall=425
|
||||
record=1400/500,0/15000
|
||||
info=!950/330,!1440/330,!1800/330,0/1000
|
||||
|
||||
|
||||
[za]
|
||||
; South Africa
|
||||
dial=400*33
|
||||
ring=400*33/400,0/200,400*33/400,0/2000
|
||||
callwaiting=400*33/250,0/250,400*33/250,0/250,400*33/250,0/250,400*33/250,0/250
|
||||
congestion=400/250,0/250
|
||||
busy=400/500,0/500
|
||||
dialrecall=350+440
|
||||
record=1400/500,0/10000
|
||||
info=950/330,1400/330,1800/330,0/330
|
||||
stutter=!400*33/100,!0/100,!400*33/100,!0/100,!400*33/100,!0/100,!400*33/100,!0/100,!400*33/100,!0/100,!400*33/100,!0/100,400*33
|
|
@ -45,13 +45,41 @@ static ObjList datas;
|
|||
typedef struct {
|
||||
int nsamples;
|
||||
const short* data;
|
||||
bool repeat;
|
||||
} Tone;
|
||||
|
||||
typedef struct {
|
||||
const Tone* tone;
|
||||
const char* name;
|
||||
const char* alias;
|
||||
} ToneDesc;
|
||||
class ToneDesc : public String
|
||||
{
|
||||
public:
|
||||
ToneDesc(const Tone* tone, const String& name,
|
||||
const String& prefix = String::empty());
|
||||
~ToneDesc();
|
||||
inline const Tone* tones() const
|
||||
{ return m_tones; }
|
||||
inline bool repeatAll() const
|
||||
{ return m_repeatAll; }
|
||||
// Init this tone description from comma separated list of tone data
|
||||
bool setTones(const String& desc);
|
||||
// Tone name/alias match.
|
||||
// Set name to this object's name if true is returned and alias matches
|
||||
bool isName(String& name) const;
|
||||
// Build tones from a list
|
||||
static void buildTones(const String& name, const NamedList& list);
|
||||
private:
|
||||
inline void clearTones() {
|
||||
if (m_tones && m_ownTones)
|
||||
delete[] m_tones;
|
||||
m_tones = 0;
|
||||
m_ownTones = true;
|
||||
toneListChanged();
|
||||
}
|
||||
// Called when tones list changed to update data
|
||||
void toneListChanged();
|
||||
String m_alias; // Tone name alias
|
||||
Tone* m_tones; // Tones array. Ends with an invalid one (zero)
|
||||
bool m_ownTones; // Clear tones when reset/destroyed
|
||||
bool m_repeatAll; // True if all tones repeated
|
||||
};
|
||||
|
||||
class ToneData : public GenObject
|
||||
{
|
||||
|
@ -80,6 +108,11 @@ public:
|
|||
{ return (m_f1 == other.f1()) && (m_f2 == other.f2()); }
|
||||
const short* data();
|
||||
static ToneData* getData(const char* desc);
|
||||
// Decode a tone description from [!]desc[/duration]
|
||||
// Build a tone data if needded
|
||||
// Return true on success
|
||||
static bool decode(const String& desc, int& samples, const short*& data,
|
||||
bool& repeat);
|
||||
private:
|
||||
bool parse(const char* desc);
|
||||
int m_f1;
|
||||
|
@ -96,8 +129,8 @@ public:
|
|||
inline const String& name()
|
||||
{ return m_name; }
|
||||
bool startup();
|
||||
static ToneSource* getTone(String& tone);
|
||||
static const ToneDesc* getBlock(String& tone, bool oneShot = false);
|
||||
static ToneSource* getTone(String& tone, const String& prefix);
|
||||
static const ToneDesc* getBlock(String& tone, const String& prefix, bool oneShot = false);
|
||||
static Tone* buildCadence(const String& desc);
|
||||
static Tone* buildDtmf(const String& dtmf, int len = DTMF_LEN, int gap = DTMF_GAP);
|
||||
protected:
|
||||
|
@ -105,10 +138,13 @@ protected:
|
|||
virtual bool noChan() const
|
||||
{ return false; }
|
||||
virtual void cleanup();
|
||||
void advanceTone(const Tone*& tone);
|
||||
static const ToneDesc* getBlock(String& tone, const ToneDesc* table);
|
||||
static const ToneDesc* findToneDesc(String& tone, const String& prefix);
|
||||
String m_name;
|
||||
const Tone* m_tone;
|
||||
int m_repeat;
|
||||
bool m_firstPass;
|
||||
private:
|
||||
DataBlock m_data;
|
||||
unsigned m_brate;
|
||||
|
@ -119,7 +155,7 @@ private:
|
|||
class TempSource : public ToneSource
|
||||
{
|
||||
public:
|
||||
TempSource(String& desc, DataBlock* rawdata);
|
||||
TempSource(String& desc, const String& prefix, DataBlock* rawdata);
|
||||
virtual ~TempSource();
|
||||
protected:
|
||||
virtual bool noChan() const
|
||||
|
@ -132,7 +168,7 @@ private:
|
|||
class ToneChan : public Channel
|
||||
{
|
||||
public:
|
||||
ToneChan(String& tone);
|
||||
ToneChan(String& tone, const String& prefix);
|
||||
~ToneChan();
|
||||
bool attachConsumer(const char* consumer);
|
||||
};
|
||||
|
@ -159,6 +195,10 @@ private:
|
|||
};
|
||||
|
||||
INIT_PLUGIN(ToneGenDriver);
|
||||
static ObjList s_toneDesc; // List of configured tones
|
||||
static ObjList s_defToneDesc; // List of default tones
|
||||
static String s_defLang; // Default tone language
|
||||
static const String s_default = "itu";
|
||||
|
||||
// 421.052Hz (19 samples @ 8kHz) sine wave, pretty close to standard 425Hz
|
||||
static const short tone421hz[] = {
|
||||
|
@ -195,45 +235,45 @@ static const short tone1777hz[] = {
|
|||
6429, 8659, -3420, -9848,
|
||||
0 };
|
||||
|
||||
static const Tone t_dial[] = { { 8000, tone421hz }, { 0, 0 } };
|
||||
static const Tone t_dial[] = { { 8000, tone421hz, true }, { 0, 0 } };
|
||||
|
||||
static const Tone t_busy[] = { { 4000, tone421hz }, { 4000, 0 }, { 0, 0 } };
|
||||
static const Tone t_busy[] = { { 4000, tone421hz, true }, { 4000, 0, true }, { 0, 0 } };
|
||||
|
||||
static const Tone t_specdial[] = { { 7600, tone421hz }, { 400, 0 }, { 0, 0 } };
|
||||
static const Tone t_specdial[] = { { 7600, tone421hz, true }, { 400, 0, true }, { 0, 0 } };
|
||||
|
||||
static const Tone t_ring[] = { { 8000, tone421hz }, { 32000, 0 }, { 0, 0 } };
|
||||
static const Tone t_ring[] = { { 8000, tone421hz, true }, { 32000, 0, true }, { 0, 0 } };
|
||||
|
||||
static const Tone t_congestion[] = { { 2000, tone421hz }, { 2000, 0 }, { 0, 0 } };
|
||||
static const Tone t_congestion[] = { { 2000, tone421hz, true }, { 2000, 0, true }, { 0, 0 } };
|
||||
|
||||
static const Tone t_outoforder[] = {
|
||||
{ 800, tone421hz }, { 800, 0 },
|
||||
{ 800, tone421hz }, { 800, 0 },
|
||||
{ 800, tone421hz }, { 800, 0 },
|
||||
{ 1600, tone421hz }, { 1600, 0 },
|
||||
{ 800, tone421hz, true }, { 800, 0, true },
|
||||
{ 800, tone421hz, true }, { 800, 0, true },
|
||||
{ 800, tone421hz, true }, { 800, 0, true },
|
||||
{ 1600, tone421hz, true }, { 1600, 0, true },
|
||||
{ 0, 0 } };
|
||||
|
||||
static const Tone t_callwait[] = {
|
||||
{ 160, 0 },
|
||||
{ 800, tone421hz }, { 800, 0 }, { 800, tone421hz },
|
||||
{ 160, 0 },
|
||||
{ 160, 0, true },
|
||||
{ 800, tone421hz, true }, { 800, 0, true }, { 800, tone421hz, true },
|
||||
{ 160, 0, true },
|
||||
{ 0, 0 } };
|
||||
|
||||
static const Tone t_info[] = {
|
||||
{ 2640, tone941hz }, { 240, 0 },
|
||||
{ 2640, tone1454hz }, { 240, 0 },
|
||||
{ 2640, tone1777hz }, { 8000, 0 },
|
||||
{ 2640, tone941hz, true }, { 240, 0, true },
|
||||
{ 2640, tone1454hz, true }, { 240, 0, true },
|
||||
{ 2640, tone1777hz, true }, { 8000, 0, true },
|
||||
{ 0, 0 } };
|
||||
|
||||
static const Tone t_mwatt[] = { { 8000, tone1000hz }, { 0, 0 } };
|
||||
static const Tone t_mwatt[] = { { 8000, tone1000hz, true }, { 0, 0 } };
|
||||
|
||||
static const Tone t_silence[] = { { 8000, 0 }, { 0, 0 } };
|
||||
static const Tone t_silence[] = { { 8000, 0, true }, { 0, 0 } };
|
||||
|
||||
static const Tone t_noise[] = { { 2000, ToneData::getData("noise")->data() }, { 0, 0 } };
|
||||
static const Tone t_noise[] = { { 2000, ToneData::getData("noise")->data(), true }, { 0, 0 } };
|
||||
|
||||
#define MAKE_DTMF(s) { \
|
||||
{ DTMF_GAP, 0 }, \
|
||||
{ DTMF_LEN, ToneData::getData(s)->data() }, \
|
||||
{ DTMF_GAP, 0 }, \
|
||||
{ DTMF_GAP, 0, true }, \
|
||||
{ DTMF_LEN, ToneData::getData(s)->data(), true }, \
|
||||
{ DTMF_GAP, 0, true }, \
|
||||
{ 0, 0 } \
|
||||
}
|
||||
static const Tone t_dtmf[][4] = {
|
||||
|
@ -257,7 +297,7 @@ static const Tone t_dtmf[][4] = {
|
|||
#undef MAKE_DTMF
|
||||
|
||||
#define MAKE_PROBE(s) { \
|
||||
{ 8000, ToneData::getData(s)->data() }, \
|
||||
{ 8000, ToneData::getData(s)->data(), true }, \
|
||||
{ 0, 0 } \
|
||||
}
|
||||
static const Tone t_probes[][2] = {
|
||||
|
@ -269,44 +309,25 @@ static const Tone t_probes[][2] = {
|
|||
};
|
||||
#undef MAKE_PROBE
|
||||
|
||||
static const ToneDesc s_desc[] = {
|
||||
{ t_dial, "dial", "dt" },
|
||||
{ t_busy, "busy", "bs" },
|
||||
{ t_ring, "ring", "rt" },
|
||||
{ t_specdial, "specdial", "sd" },
|
||||
{ t_congestion, "congestion", "cg" },
|
||||
{ t_outoforder, "outoforder", "oo" },
|
||||
{ t_info, "info", "in" },
|
||||
{ t_mwatt, "milliwatt", "mw" },
|
||||
{ t_silence, "silence", 0 },
|
||||
{ t_noise, "noise", "cn" },
|
||||
{ t_probes[0], "probe/0", "probe" },
|
||||
{ t_probes[1], "probe/1", 0 },
|
||||
{ t_probes[2], "probe/2", 0 },
|
||||
{ t_probes[3], "cotv", "co1" },
|
||||
{ t_probes[4], "cots", "co2" },
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
|
||||
static const ToneDesc s_descOne[] = {
|
||||
{ t_callwait, "callwaiting", "cw" },
|
||||
{ t_dtmf[0], "dtmf/0", "0" },
|
||||
{ t_dtmf[1], "dtmf/1", "1" },
|
||||
{ t_dtmf[2], "dtmf/2", "2" },
|
||||
{ t_dtmf[3], "dtmf/3", "3" },
|
||||
{ t_dtmf[4], "dtmf/4", "4" },
|
||||
{ t_dtmf[5], "dtmf/5", "5" },
|
||||
{ t_dtmf[6], "dtmf/6", "6" },
|
||||
{ t_dtmf[7], "dtmf/7", "7" },
|
||||
{ t_dtmf[8], "dtmf/8", "8" },
|
||||
{ t_dtmf[9], "dtmf/9", "9" },
|
||||
{ t_dtmf[10], "dtmf/*", "*" },
|
||||
{ t_dtmf[11], "dtmf/#", "#" },
|
||||
{ t_dtmf[12], "dtmf/a", "a" },
|
||||
{ t_dtmf[13], "dtmf/b", "b" },
|
||||
{ t_dtmf[14], "dtmf/c", "c" },
|
||||
{ t_dtmf[15], "dtmf/d", "d" },
|
||||
{ 0, 0, 0 }
|
||||
ToneDesc(t_callwait,"callwaiting"),
|
||||
ToneDesc(t_dtmf[0],"dtmf/0"),
|
||||
ToneDesc(t_dtmf[1],"dtmf/1"),
|
||||
ToneDesc(t_dtmf[2],"dtmf/2"),
|
||||
ToneDesc(t_dtmf[3],"dtmf/3"),
|
||||
ToneDesc(t_dtmf[4],"dtmf/4"),
|
||||
ToneDesc(t_dtmf[5],"dtmf/5"),
|
||||
ToneDesc(t_dtmf[6],"dtmf/6"),
|
||||
ToneDesc(t_dtmf[7],"dtmf/7"),
|
||||
ToneDesc(t_dtmf[8],"dtmf/8"),
|
||||
ToneDesc(t_dtmf[9],"dtmf/9"),
|
||||
ToneDesc(t_dtmf[10],"dtmf/*"),
|
||||
ToneDesc(t_dtmf[11],"dtmf/#"),
|
||||
ToneDesc(t_dtmf[12],"dtmf/a"),
|
||||
ToneDesc(t_dtmf[13],"dtmf/b"),
|
||||
ToneDesc(t_dtmf[14],"dtmf/c"),
|
||||
ToneDesc(t_dtmf[15],"dtmf/d"),
|
||||
ToneDesc((Tone*)0,"")
|
||||
};
|
||||
|
||||
// This function is here mainly to avoid 64bit gcc b0rking optimizations
|
||||
|
@ -320,6 +341,156 @@ static unsigned int byteRate(u_int64_t time, unsigned int bytes)
|
|||
return (unsigned int)((bytes*(u_int64_t)1000000 + time/2) / time);
|
||||
}
|
||||
|
||||
// Retrieve the alias associated with a given name
|
||||
static const char* getAlias(const String& name)
|
||||
{
|
||||
#define TONE_GETALIAS(n,a) { if (name == n) return a; }
|
||||
if (!name)
|
||||
return 0;
|
||||
TONE_GETALIAS("dial","dt");
|
||||
TONE_GETALIAS("busy","bs");
|
||||
TONE_GETALIAS("ring","rt");
|
||||
TONE_GETALIAS("specdial","sd");
|
||||
TONE_GETALIAS("congestion","cg");
|
||||
TONE_GETALIAS("outoforder","oo");
|
||||
TONE_GETALIAS("info","in");
|
||||
TONE_GETALIAS("milliwatt","mw");
|
||||
TONE_GETALIAS("silence",0);
|
||||
TONE_GETALIAS("noise","cn");
|
||||
TONE_GETALIAS("probe/0","probe");
|
||||
TONE_GETALIAS("probe/1",0);
|
||||
TONE_GETALIAS("probe/2",0);
|
||||
TONE_GETALIAS("cotv","co1");
|
||||
TONE_GETALIAS("cots","co2");
|
||||
TONE_GETALIAS("callwaiting","cw");
|
||||
TONE_GETALIAS("dtmf/0","0");
|
||||
TONE_GETALIAS("dtmf/1","1");
|
||||
TONE_GETALIAS("dtmf/2","2");
|
||||
TONE_GETALIAS("dtmf/3","3");
|
||||
TONE_GETALIAS("dtmf/4","4");
|
||||
TONE_GETALIAS("dtmf/5","5");
|
||||
TONE_GETALIAS("dtmf/6","6");
|
||||
TONE_GETALIAS("dtmf/7","7");
|
||||
TONE_GETALIAS("dtmf/8","8");
|
||||
TONE_GETALIAS("dtmf/9","9");
|
||||
TONE_GETALIAS("dtmf/*","*");
|
||||
TONE_GETALIAS("dtmf/#","#");
|
||||
TONE_GETALIAS("dtmf/a","a");
|
||||
TONE_GETALIAS("dtmf/b","b");
|
||||
TONE_GETALIAS("dtmf/c","c");
|
||||
TONE_GETALIAS("dtmf/d","d");
|
||||
return 0;
|
||||
#undef TONE_GETALIAS
|
||||
}
|
||||
|
||||
ToneDesc::ToneDesc(const Tone* tone, const String& name, const String& prefix)
|
||||
: String(prefix + name),
|
||||
m_tones((Tone*)tone),
|
||||
m_ownTones(false),
|
||||
m_repeatAll(true)
|
||||
{
|
||||
const char* alias = getAlias(name);
|
||||
if (alias)
|
||||
m_alias = prefix + alias;
|
||||
toneListChanged();
|
||||
XDebug(&__plugin,DebugAll,"ToneDesc(%s) [%p]",c_str(),this);
|
||||
}
|
||||
|
||||
ToneDesc::~ToneDesc()
|
||||
{
|
||||
clearTones();
|
||||
}
|
||||
|
||||
// Init this tone description from comma separated list if tone data
|
||||
bool ToneDesc::setTones(const String& desc)
|
||||
{
|
||||
Debug(&__plugin,DebugAll,"ToneDesc(%s) initializing from '%s' [%p]",
|
||||
c_str(),desc.c_str(),this);
|
||||
clearTones();
|
||||
ObjList* list = desc.split(',',false);
|
||||
m_tones = new Tone[list->count() + 1];
|
||||
m_ownTones = true;
|
||||
int n = 0;
|
||||
for (ObjList* o = list->skipNull(); o; o = o->skipNext(), n++) {
|
||||
const String& s = o->get()->toString();
|
||||
if (ToneData::decode(s,m_tones[n].nsamples,m_tones[n].data,m_tones[n].repeat))
|
||||
DDebug(&__plugin,DebugAll,
|
||||
"ToneDesc(%s) added tone '%s' samples=%d data=%p repeat=%d [%p]",
|
||||
c_str(),s.c_str(),m_tones[n].nsamples,m_tones[n].data,
|
||||
m_tones[n].repeat,this);
|
||||
else {
|
||||
Debug(&__plugin,DebugNote,"ToneDesc(%s) invalid tone description '%s' [%p]",
|
||||
c_str(),s.c_str(),this);
|
||||
n = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
TelEngine::destruct(list);
|
||||
if (n > 0)
|
||||
// Invalidate the last tone in the list
|
||||
::memset(m_tones + n,0,sizeof(Tone));
|
||||
else
|
||||
clearTones();
|
||||
toneListChanged();
|
||||
return n != 0;
|
||||
}
|
||||
|
||||
// Tone name/alias equality operator. Set name if true is returned
|
||||
bool ToneDesc::isName(String& name) const
|
||||
{
|
||||
if (name == *this)
|
||||
return true;
|
||||
if (!m_alias || m_alias != name)
|
||||
return false;
|
||||
name = *this;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Build tone descriptions from a list
|
||||
void ToneDesc::buildTones(const String& name, const NamedList& list)
|
||||
{
|
||||
DDebug(&__plugin,DebugAll,"Building tones lang=%s from list=%s",
|
||||
name.c_str(),list.c_str());
|
||||
String prefix;
|
||||
ObjList* target = &s_defToneDesc;
|
||||
if (name && name != s_default) {
|
||||
prefix << name << "/";
|
||||
target = &s_toneDesc;
|
||||
}
|
||||
unsigned int n = list.length();
|
||||
for (unsigned int i = 0; i < n; i++) {
|
||||
NamedString* ns = list.getParam(i);
|
||||
if (TelEngine::null(ns))
|
||||
continue;
|
||||
ToneDesc* d = new ToneDesc(0,ns->name(),prefix);
|
||||
if (d->setTones(*ns)) {
|
||||
ObjList* o = target->find(d->toString());
|
||||
if (!o)
|
||||
target->append(d);
|
||||
else {
|
||||
Debug(&__plugin,DebugInfo,"Replacing tone '%s' (from list '%s')",
|
||||
d->toString().c_str(),list.c_str());
|
||||
o->set(d);
|
||||
}
|
||||
}
|
||||
else
|
||||
TelEngine::destruct(d);
|
||||
}
|
||||
}
|
||||
|
||||
// Called when tones list changed to update data
|
||||
void ToneDesc::toneListChanged()
|
||||
{
|
||||
m_repeatAll = true;
|
||||
if (!m_tones)
|
||||
return;
|
||||
for (Tone* tone = m_tones; tone->nsamples; tone++)
|
||||
if (!tone->repeat) {
|
||||
m_repeatAll = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ToneData::ToneData(const char* desc)
|
||||
: m_f1(0), m_f2(0), m_mod(false), m_data(0)
|
||||
|
@ -446,14 +617,47 @@ ToneData* ToneData::getData(const char* desc)
|
|||
return d;
|
||||
}
|
||||
|
||||
// Decode a tone description from [!]desc[/duration]
|
||||
// Build a tone data if needded
|
||||
// Return true on success
|
||||
bool ToneData::decode(const String& desc, int& samples, const short*& data, bool& repeat)
|
||||
{
|
||||
if (!desc)
|
||||
return false;
|
||||
samples = 8000;
|
||||
data = 0;
|
||||
repeat = (desc[0] != '!');
|
||||
int start = repeat ? 0 : 1;
|
||||
int pos = desc.find('/',start);
|
||||
String freq;
|
||||
if (pos > 0) {
|
||||
String dur = desc.substr(pos + 1);
|
||||
int duration = dur.toInteger();
|
||||
if (duration > 0) {
|
||||
// Round up to a multiple of 20
|
||||
duration += 19;
|
||||
samples = duration / 20 * 160;
|
||||
}
|
||||
freq = desc.substr(start,pos - start);
|
||||
}
|
||||
else
|
||||
freq = desc.substr(start);
|
||||
// Silence ?
|
||||
if (freq.toInteger(-1) == 0)
|
||||
return true;
|
||||
ToneData* td = ToneData::getData(freq);
|
||||
if (td)
|
||||
data = td->data();
|
||||
return td != 0;
|
||||
}
|
||||
|
||||
ToneSource::ToneSource(const ToneDesc* tone)
|
||||
: m_tone(0), m_repeat(tone == 0),
|
||||
: m_tone(0), m_repeat(tone == 0), m_firstPass(true),
|
||||
m_data(0,320), m_brate(16000), m_total(0), m_time(0)
|
||||
{
|
||||
if (tone) {
|
||||
m_tone = tone->tone;
|
||||
m_name = tone->name;
|
||||
m_tone = tone->tones();
|
||||
m_name = *tone;
|
||||
}
|
||||
Debug(&__plugin,DebugAll,"ToneSource::ToneSource(%p) '%s' [%p]",
|
||||
tone,m_name.c_str(),this);
|
||||
|
@ -483,24 +687,80 @@ void ToneSource::cleanup()
|
|||
ThreadedSource::cleanup();
|
||||
}
|
||||
|
||||
void ToneSource::advanceTone(const Tone*& tone)
|
||||
{
|
||||
if (!tone)
|
||||
return;
|
||||
const Tone* start = tone;
|
||||
tone++;
|
||||
while (tone && tone != start) {
|
||||
if (!tone->nsamples) {
|
||||
if ((m_repeat > 0) && !(--m_repeat))
|
||||
m_tone = 0;
|
||||
tone = m_tone;
|
||||
m_firstPass = false;
|
||||
continue;
|
||||
}
|
||||
if (m_firstPass || tone->repeat)
|
||||
break;
|
||||
tone++;
|
||||
}
|
||||
if (tone == start && !m_firstPass && !tone->repeat) {
|
||||
m_tone = 0;
|
||||
tone = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const ToneDesc* ToneSource::getBlock(String& tone, const ToneDesc* table)
|
||||
{
|
||||
for (; table->tone; table++) {
|
||||
if (tone == table->name)
|
||||
for (; table->tones(); table++) {
|
||||
if (table->isName(tone))
|
||||
return table;
|
||||
if (table->alias && (tone == table->alias)) {
|
||||
tone = table->name;
|
||||
return table;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const ToneDesc* ToneSource::getBlock(String& tone, bool oneShot)
|
||||
const ToneDesc* ToneSource::findToneDesc(String& tone, const String& prefix)
|
||||
{
|
||||
XDebug(&__plugin,DebugAll,"ToneSource::findToneDesc(%s,%s)",
|
||||
tone.c_str(),prefix.c_str());
|
||||
ObjList* target = &s_defToneDesc;
|
||||
if (prefix) {
|
||||
tone = prefix + "/" + tone;
|
||||
target = &s_toneDesc;
|
||||
}
|
||||
for (ObjList* o = target->skipNull(); o; o = o->skipNext()) {
|
||||
const ToneDesc* d = static_cast<ToneDesc*>(o->get());
|
||||
if (d->isName(tone))
|
||||
return d;
|
||||
}
|
||||
if (prefix)
|
||||
tone.startSkip(prefix + "/",false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const ToneDesc* ToneSource::getBlock(String& tone, const String& prefix, bool oneShot)
|
||||
{
|
||||
if (tone.trimBlanks().toLower().null())
|
||||
return 0;
|
||||
const ToneDesc* d = getBlock(tone,s_desc);
|
||||
XDebug(&__plugin,DebugAll,"ToneSource::getBlock(%s,%s,%u)",
|
||||
tone.c_str(),prefix.c_str(),oneShot);
|
||||
const ToneDesc* d = 0;
|
||||
if (prefix) {
|
||||
if (prefix != s_default)
|
||||
d = findToneDesc(tone,prefix);
|
||||
else {
|
||||
// Default tone explicitly required
|
||||
d = findToneDesc(tone,String::empty());
|
||||
if (!d && oneShot)
|
||||
d = getBlock(tone,s_descOne);
|
||||
return d;
|
||||
}
|
||||
}
|
||||
if (!d && s_defLang && s_defLang != prefix)
|
||||
d = findToneDesc(tone,s_defLang);
|
||||
if (!d)
|
||||
d = findToneDesc(tone,String::empty());
|
||||
if (d)
|
||||
return d;
|
||||
if (oneShot)
|
||||
|
@ -528,6 +788,7 @@ Tone* ToneSource::buildDtmf(const String& dtmf, int len, int gap)
|
|||
for (unsigned int i = 0; i < dtmf.length(); i++) {
|
||||
t->nsamples = gap;
|
||||
t->data = 0;
|
||||
t->repeat = true;
|
||||
t++;
|
||||
|
||||
int c = dtmf.at(i);
|
||||
|
@ -543,11 +804,13 @@ Tone* ToneSource::buildDtmf(const String& dtmf, int len, int gap)
|
|||
|
||||
t->nsamples = len;
|
||||
t->data = ((c >= 0) && (c < 16)) ? t_dtmf[c][1].data : 0;
|
||||
t->repeat = true;
|
||||
t++;
|
||||
}
|
||||
|
||||
t->nsamples = gap;
|
||||
t->data = 0;
|
||||
t->repeat = true;
|
||||
t++;
|
||||
t->nsamples = 0;
|
||||
t->data = 0;
|
||||
|
@ -555,11 +818,15 @@ Tone* ToneSource::buildDtmf(const String& dtmf, int len, int gap)
|
|||
return tmp;
|
||||
}
|
||||
|
||||
ToneSource* ToneSource::getTone(String& tone)
|
||||
ToneSource* ToneSource::getTone(String& tone, const String& prefix)
|
||||
{
|
||||
const ToneDesc* td = ToneSource::getBlock(tone);
|
||||
const ToneDesc* td = ToneSource::getBlock(tone,prefix);
|
||||
bool repeat = !td || td->repeatAll();
|
||||
XDebug(&__plugin,DebugAll,"ToneSource::getTone(%s,%s) found %p '%s' repeatall=%s",
|
||||
tone.c_str(),prefix.c_str(),td,td ? td->c_str() : "",String::boolText(repeat));
|
||||
// tone name is now canonical
|
||||
ObjList* l = &tones;
|
||||
// Build a fresh source if the list contains tones not repeated
|
||||
ObjList* l = repeat ? &tones : 0;
|
||||
for (; l; l = l->next()) {
|
||||
ToneSource* t = static_cast<ToneSource*>(l->get());
|
||||
if (t && (t->name() == tone) && t->running() && (t->refcount() > 1)) {
|
||||
|
@ -594,12 +861,7 @@ void ToneSource::run()
|
|||
// go to the start of the next tone
|
||||
samp = 0;
|
||||
const Tone *otone = tone;
|
||||
tone++;
|
||||
if (!tone->nsamples) {
|
||||
if ((m_repeat > 0) && !(--m_repeat))
|
||||
m_tone = 0;
|
||||
tone = m_tone;
|
||||
}
|
||||
advanceTone(tone);
|
||||
nsam = tone ? tone->nsamples : 32000;
|
||||
if (nsam < 0) {
|
||||
nsam = -nsam;
|
||||
|
@ -634,10 +896,11 @@ void ToneSource::run()
|
|||
}
|
||||
|
||||
|
||||
TempSource::TempSource(String& desc, DataBlock* rawdata)
|
||||
TempSource::TempSource(String& desc, const String& prefix, DataBlock* rawdata)
|
||||
: m_single(0), m_rawdata(rawdata)
|
||||
{
|
||||
Debug(&__plugin,DebugAll,"TempSource::TempSource(\"%s\") [%p]",desc.c_str(),this);
|
||||
Debug(&__plugin,DebugAll,"TempSource::TempSource(\"%s\",\"%s\") [%p]",
|
||||
desc.c_str(),prefix.safe(),this);
|
||||
if (desc.null())
|
||||
return;
|
||||
m_name = desc;
|
||||
|
@ -654,14 +917,15 @@ TempSource::TempSource(String& desc, DataBlock* rawdata)
|
|||
m_tone = m_single = (Tone*)::malloc(2*sizeof(Tone));
|
||||
m_single[0].nsamples = m_rawdata->length() / sizeof(short);
|
||||
m_single[0].data = (short*)m_rawdata->data();
|
||||
m_single[0].repeat = true;
|
||||
m_single[1].nsamples = 0;
|
||||
m_single[1].data = 0;
|
||||
return;
|
||||
}
|
||||
// try first the named tones
|
||||
const ToneDesc* tde = getBlock(desc,true);
|
||||
const ToneDesc* tde = getBlock(desc,prefix,true);
|
||||
if (tde) {
|
||||
m_tone = tde->tone;
|
||||
m_tone = tde->tones();
|
||||
return;
|
||||
}
|
||||
// for performance reason accept an entire string of DTMFs
|
||||
|
@ -675,12 +939,15 @@ TempSource::TempSource(String& desc, DataBlock* rawdata)
|
|||
return;
|
||||
}
|
||||
// now try to build a single tone
|
||||
ToneData* td = ToneData::getData(desc);
|
||||
if (!td)
|
||||
int samples = 8000;
|
||||
const short* data = 0;
|
||||
bool repeat = true;
|
||||
if (!ToneData::decode(desc,samples,data,repeat))
|
||||
return;
|
||||
m_single = (Tone*)::malloc(2*sizeof(Tone));
|
||||
m_single[0].nsamples = 8000;
|
||||
m_single[0].data = td->data();
|
||||
m_single[0].nsamples = samples;
|
||||
m_single[0].data = data;
|
||||
m_single[0].repeat = repeat;
|
||||
m_single[1].nsamples = 0;
|
||||
m_single[1].data = 0;
|
||||
m_tone = m_single;
|
||||
|
@ -697,13 +964,13 @@ TempSource::~TempSource()
|
|||
}
|
||||
|
||||
|
||||
ToneChan::ToneChan(String& tone)
|
||||
ToneChan::ToneChan(String& tone, const String& prefix)
|
||||
: Channel(__plugin)
|
||||
{
|
||||
Debug(this,DebugAll,"ToneChan::ToneChan(\"%s\") [%p]",tone.c_str(),this);
|
||||
Debug(this,DebugAll,"ToneChan::ToneChan(\"%s\",\"%s\") [%p]",tone.c_str(),prefix.safe(),this);
|
||||
// protect the list while the new tone source is added to it
|
||||
__plugin.lock();
|
||||
ToneSource* t = ToneSource::getTone(tone);
|
||||
ToneSource* t = ToneSource::getTone(tone,prefix);
|
||||
__plugin.unlock();
|
||||
if (t) {
|
||||
setSource(t);
|
||||
|
@ -781,7 +1048,7 @@ bool AttachHandler::received(Message& msg)
|
|||
|
||||
Lock lock(__plugin);
|
||||
if (src) {
|
||||
ToneSource* t = ToneSource::getTone(src);
|
||||
ToneSource* t = ToneSource::getTone(src,msg["lang"]);
|
||||
if (t) {
|
||||
de->setSource(t);
|
||||
t->deref();
|
||||
|
@ -797,7 +1064,7 @@ bool AttachHandler::received(Message& msg)
|
|||
RefPointer<DataConsumer> c = de->getConsumer();
|
||||
DataEndpoint::commonMutex().unlock();
|
||||
if (c) {
|
||||
TempSource* t = new TempSource(ovr,getRawData(msg));
|
||||
TempSource* t = new TempSource(ovr,msg["lang"],getRawData(msg));
|
||||
if (DataTranslator::attachChain(t,c,true) && t->startup())
|
||||
msg.clearParam("override");
|
||||
else {
|
||||
|
@ -816,7 +1083,7 @@ bool AttachHandler::received(Message& msg)
|
|||
RefPointer<DataConsumer> c = de->getConsumer();
|
||||
DataEndpoint::commonMutex().unlock();
|
||||
if (c) {
|
||||
TempSource* t = new TempSource(repl,getRawData(msg));
|
||||
TempSource* t = new TempSource(repl,msg["lang"],getRawData(msg));
|
||||
if (DataTranslator::attachChain(t,c,false) && t->startup())
|
||||
msg.clearParam("replace");
|
||||
else {
|
||||
|
@ -838,7 +1105,7 @@ bool ToneGenDriver::msgExecute(Message& msg, String& dest)
|
|||
{
|
||||
CallEndpoint* ch = static_cast<CallEndpoint*>(msg.userData());
|
||||
if (ch) {
|
||||
ToneChan *tc = new ToneChan(dest);
|
||||
ToneChan *tc = new ToneChan(dest,msg["lang"]);
|
||||
tc->initChan();
|
||||
tc->attachConsumer(msg.getValue("consumer"));
|
||||
if (ch->connect(tc,msg.getValue("reason"))) {
|
||||
|
@ -881,7 +1148,7 @@ bool ToneGenDriver::msgExecute(Message& msg, String& dest)
|
|||
}
|
||||
m = "call.execute";
|
||||
m.setParam("callto",callto);
|
||||
ToneChan *tc = new ToneChan(dest);
|
||||
ToneChan *tc = new ToneChan(dest,msg["lang"]);
|
||||
tc->initChan();
|
||||
tc->attachConsumer(msg.getValue("consumer"));
|
||||
m.setParam("id",tc->id());
|
||||
|
@ -936,11 +1203,53 @@ void ToneGenDriver::initialize()
|
|||
Output("Initializing module ToneGen");
|
||||
setup(0,true); // no need to install notifications
|
||||
Driver::initialize();
|
||||
if (!m_handler) {
|
||||
m_handler = new AttachHandler;
|
||||
Engine::install(m_handler);
|
||||
installRelay(Halt);
|
||||
if (m_handler)
|
||||
return;
|
||||
// Init default tones
|
||||
s_defToneDesc.append(new ToneDesc(t_dial,"dial"));
|
||||
s_defToneDesc.append(new ToneDesc(t_busy,"busy"));
|
||||
s_defToneDesc.append(new ToneDesc(t_ring,"ring"));
|
||||
s_defToneDesc.append(new ToneDesc(t_specdial,"specdial"));
|
||||
s_defToneDesc.append(new ToneDesc(t_congestion,"congestion"));
|
||||
s_defToneDesc.append(new ToneDesc(t_outoforder,"outoforder"));
|
||||
s_defToneDesc.append(new ToneDesc(t_info,"info"));
|
||||
s_defToneDesc.append(new ToneDesc(t_mwatt,"milliwatt"));
|
||||
s_defToneDesc.append(new ToneDesc(t_silence,"silence"));
|
||||
s_defToneDesc.append(new ToneDesc(t_noise,"noise"));
|
||||
s_defToneDesc.append(new ToneDesc(t_probes[0],"probe/0"));
|
||||
s_defToneDesc.append(new ToneDesc(t_probes[1],"probe/1"));
|
||||
s_defToneDesc.append(new ToneDesc(t_probes[2],"probe/2"));
|
||||
s_defToneDesc.append(new ToneDesc(t_probes[3],"cotv"));
|
||||
s_defToneDesc.append(new ToneDesc(t_probes[4],"cots"));
|
||||
// Init tones from config
|
||||
Configuration cfg(Engine::configFile("tonegen"));
|
||||
s_defLang = cfg.getValue("general","lang");
|
||||
if (s_defLang == s_default)
|
||||
s_defLang.clear();
|
||||
unsigned int n = cfg.sections();
|
||||
for (unsigned int i = 0; i < n; i++) {
|
||||
NamedList* l = cfg.getSection(i);
|
||||
if (!l || *l == "general")
|
||||
continue;
|
||||
String aliases;
|
||||
if (*l != s_default)
|
||||
aliases = l->getValue("alias");
|
||||
l->clearParam("alias");
|
||||
ToneDesc::buildTones(*l,*l);
|
||||
if (aliases) {
|
||||
ObjList* list = aliases.split(',',false);
|
||||
for (ObjList* o = list->skipNull(); o; o = o->skipNext()) {
|
||||
const String& name = o->get()->toString();
|
||||
if (name != s_default)
|
||||
ToneDesc::buildTones(name,*l);
|
||||
}
|
||||
TelEngine::destruct(list);
|
||||
}
|
||||
}
|
||||
// Init module
|
||||
m_handler = new AttachHandler;
|
||||
Engine::install(m_handler);
|
||||
installRelay(Halt);
|
||||
}
|
||||
|
||||
}; // anonymous namespace
|
||||
|
|
Loading…
Reference in New Issue