github.com/CyCoreSystems/ari@v4.8.4+incompatible/ext/audiouri/uri.go (about) 1 // Package audiouri provides conversions for common sounds to asterisk-supported audio URIs 2 package audiouri 3 4 import ( 5 "fmt" 6 "sort" 7 "strings" 8 "time" 9 ) 10 11 // SupportedPlaybackPrefixes is a list of valid prefixes 12 // for media URIs. 13 var SupportedPlaybackPrefixes = []string{ 14 "sound", "recording", "number", "digits", "characters", "tone", 15 } 16 17 func init() { 18 sort.Strings(SupportedPlaybackPrefixes) 19 } 20 21 // WaitURI returns the set of media URIs for the 22 // given period of silence. 23 func WaitURI(t time.Duration) []string { 24 q := []string{} 25 for i := time.Duration(0); i <= t; i += time.Second { 26 q = append(q, "sound:silence/1") 27 } 28 return q 29 } 30 31 // NumberURI returns the media URI to play 32 // the given number. 33 func NumberURI(number int) string { 34 return fmt.Sprintf("number:%d", number) 35 } 36 37 // DigitsURI returns the set of media URIs to 38 // play the given digits. 39 func DigitsURI(digits string, hash string) []string { 40 // TODO: Strip anything which is not a digit or # 41 42 if strings.Contains(digits, "#") && hash != "" { 43 hash = "sound:char/" + hash 44 45 // Split the digits by each hash 46 pieces := strings.Split(digits, "#") 47 48 // Get the strings for each digit substring 49 newDigits := []string{} 50 for i, p := range pieces { 51 newDigits = append(newDigits, DigitsURI(p, hash)...) 52 if len(pieces) > i+1 { 53 // If this wasn't the last piece, add a hash 54 newDigits = append(newDigits, hash) 55 } 56 } 57 return newDigits 58 } 59 60 // Handle '*' to 'star' conversion 61 if strings.Contains(digits, "*") { 62 star := "sound:char/star" 63 64 // Split the digits by each * 65 pieces := strings.Split(digits, "*") 66 67 // Get the strings for each digit substring 68 newDigits := []string{} 69 for i, p := range pieces { 70 newDigits = append(newDigits, DigitsURI(p, hash)...) 71 if len(pieces) > i+1 { 72 // If this wasn't the last piece, add a star 73 newDigits = append(newDigits, star) 74 } 75 } 76 return newDigits 77 } 78 79 // Otherwise, we can simply use the normal "digits:" URI 80 if len(digits) < 1 { 81 return []string{} 82 } 83 return []string{"digits:" + digits} 84 } 85 86 // DateTimeURI returns the set of media URIs for playing 87 // the current date and time. 88 func DateTimeURI(t time.Time) (ret []string) { 89 ret = []string{} 90 91 ret = append(ret, 92 fmt.Sprintf("sound:digits/day-%d", t.Weekday()), 93 fmt.Sprintf("sound:digits/mon-%d", t.Month()-1), 94 NumberURI(t.Day()), 95 ) 96 97 // Convert to 12-hour time 98 pm := false 99 hour := t.Hour() 100 switch { 101 case hour == 0: 102 hour = 12 103 case hour == 12: 104 pm = true 105 case hour > 12: 106 hour -= 12 107 pm = true 108 default: 109 } 110 ret = append(ret, NumberURI(hour)) 111 112 // Humanize the minutes 113 minute := t.Minute() 114 switch { 115 case minute == 0: 116 ret = append(ret, "sound:digits/oclock") 117 case minute < 10: 118 ret = append(ret, 119 "sound:digits/oh", 120 NumberURI(minute), 121 ) 122 default: 123 ret = append(ret, NumberURI(minute)) 124 } 125 126 // Add am/pm suffix 127 if pm { 128 ret = append(ret, "sound:digits/p-m") 129 } else { 130 ret = append(ret, "sound:digits/a-m") 131 } 132 133 // Add the year 134 ret = append(ret, NumberURI(t.Year())) 135 136 return 137 } 138 139 // DurationURI returns the set of media URIs for playing 140 // the given duration, in human terms (days, hours, minutes, seconds). 141 // If any of these terms are zero, they will not be spoken. 142 func DurationURI(dur time.Duration) (ret []string) { 143 days := int(dur.Hours() / 24) 144 hours := int(dur.Hours()) % 24 145 minutes := int(dur.Minutes()) % 60 146 seconds := int(dur.Seconds()) % 60 147 148 ret = []string{} 149 150 if days > 0 { 151 ret = append(ret, NumberURI(days)) 152 if days > 1 { 153 ret = append(ret, "sound:time/days") 154 } else { 155 ret = append(ret, "sound:time/day") 156 } 157 } 158 159 if hours > 0 { 160 ret = append(ret, NumberURI(hours)) 161 if hours > 1 { 162 ret = append(ret, "sound:time/hours") 163 } else { 164 ret = append(ret, "sound:time/hour") 165 } 166 } 167 168 if minutes > 0 { 169 ret = append(ret, NumberURI(minutes)) 170 if minutes > 1 { 171 ret = append(ret, "sound:time/minutes") 172 } else { 173 ret = append(ret, "sound:time/minute") 174 } 175 } 176 177 if seconds > 0 { 178 ret = append(ret, NumberURI(seconds)) 179 if seconds > 1 { 180 ret = append(ret, "sound:time/seconds") 181 } else { 182 ret = append(ret, "sound:time/second") 183 } 184 } 185 186 return 187 } 188 189 // RecordingURI returns the media URI for playing an 190 // Asterisk StoredRecording 191 func RecordingURI(name string) string { 192 return "recording:" + name 193 } 194 195 // ToneURI returns the media URI for playing the 196 // given tone, which may be a system-defined indication 197 // or an explicit tone pattern construction. 198 func ToneURI(name string) string { 199 return "tone:" + name 200 } 201 202 // Check checks if the audio URI is formatted properly 203 func Check(uri string) error { 204 l := strings.Split(uri, ":") 205 if len(l) != 2 { 206 return fmt.Errorf("Audio URI %s is not formatted properly", uri) 207 } 208 209 if sort.SearchStrings(SupportedPlaybackPrefixes, l[0]) == len(SupportedPlaybackPrefixes) { 210 return fmt.Errorf("Audio URI prefix %s not supported", l[0]) 211 } 212 213 return nil 214 }