forked from mmornati/ruby-noise-detection
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnoise_detection.rb
More file actions
executable file
·193 lines (167 loc) · 5.43 KB
/
noise_detection.rb
File metadata and controls
executable file
·193 lines (167 loc) · 5.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#!/usr/bin/ruby -w
#
# Copyright (C) 2013 Marco Mornati [http://www.mornati.net]
# Based on Thomer M. Gil First [http://thomer.com/] version template
#
# Oct 05, 2012: Initial version
#
# This program is free software. You may distribute it under the terms of
# the GNU General Public License as published by the Free Software
# Foundation, version 3.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# This program detects the presence of sound and invokes a program.
#
require 'getoptlong'
require 'optparse'
require 'net/smtp'
require 'logger'
require 'date'
HW_DETECTION_CMD = "cat /proc/asound/cards"
# You need to replace MICROPHONE with the name of your microphone, as reported
# by /proc/asound/cards
SAMPLE_DURATION = 5 # seconds
FORMAT = 'S16_LE' # this is the format that my USB microphone generates
THRESHOLD = 0.05
RECORD_FILENAME='/tmp/noise.wav'
LOG_FILE='/var/log/noise_detector.log'
PID_FILE='/etc/noised/noised.pid'
logger = Logger.new(LOG_FILE)
logger.level = Logger::DEBUG
logger.info("Noise detector started @ #{DateTime.now.strftime('%d/%m/%Y %H:%M:%S')}")
def self.check_required()
if !File.exists?('/usr/bin/arecord')
warn "/usr/bin/arecord not found; install package alsa-utils"
exit 1
end
if !File.exists?('/usr/bin/sox')
warn "/usr/bin/sox not found; install package sox"
exit 1
end
if !File.exists?('/proc/asound/cards')
warn "/proc/asound/cards not found"
exit 1
end
end
# Parsing script parameters
options = {}
optparse = OptionParser.new do |opts|
opts.banner = "Usage: noise_detection.rb -m ID [options]"
opts.on("-m", "--microphone SOUND_CARD_ID", "REQUIRED: Set microphone id") do |m|
options[:microphone] = m
end
opts.on("-s", "--sample SECONDS", "Sample duration") do |s|
options[:sample] = s
end
opts.on("-n", "--threshold NOISE_THRESHOLD", "Set Activation noise Threshold. EX. 0.1") do |n|
options[:threshold] = n
end
opts.on("-e", "--email DEST_EMAIL", "Alert destination email") do |e|
options[:email] = e
end
opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
options[:verbose] = v
end
opts.on("-d", "--detect", "Detect your sound cards") do |d|
options[:detection] = d
end
opts.on("-t", "--test SOUND_CARD_ID", "Test soundcard with the given id") do |t|
options[:test] = t
end
opts.on("-k", "--kill", "Terminating background script") do |k|
options[:kill] = k
end
end.parse!
if options[:kill]
logger.info("Terminating script");
logger.debug("Looking for pid file in #{PID_FILE}")
begin
pidfile = File.open(PID_FILE, "r")
storedpid = pidfile.read
Process.kill("TERM", Integer(storedpid))
rescue Exception => e
logger.error("Cannot read pid file: " + e.message)
exit 1
end
exit 0
end
if options[:detection]
puts "Detecting your soundcard..."
puts `#{HW_DETECTION_CMD}`
exit 0
end
#Check required binaries
check_required()
if options[:sample]
SAMPLE_DURATION = options[:sample]
end
if options[:threshold]
THRESHOLD = options[:threshold].to_f
end
if options[:test]
puts "Testing soundcard..."
puts `/usr/bin/arecord -D plughw:#{options[:test]},0 -d #{SAMPLE_DURATION} -f #{FORMAT} 2>/dev/null | /usr/bin/sox -t .wav - -n stat 2>&1`
exit 0
end
optparse.parse!
#Now raise an exception if we have not found a host option
raise OptionParser::MissingArgument if options[:microphone].nil?
raise OptionParser::MissingArgument if options[:email].nil?
if options[:verbose]
logger.debug("Script parameters configurations:")
logger.debug("SoundCard ID: #{options[:microphone]}")
logger.debug("Sample Duration: #{SAMPLE_DURATION}")
logger.debug("Output Format: #{FORMAT}")
logger.debug("Noise Threshold: #{THRESHOLD}")
logger.debug("Record filename (overwritten): #{RECORD_FILENAME}")
logger.debug("Destination email: #{options[:email]}")
end
#Starting script part
pid = fork do
stop_process = false
Signal.trap("USR1") do
logger.debug("Running...")
end
Signal.trap("TERM") do
logger.info("Terminating...")
File.delete(PID_FILE)
stop_process = true
end
loop do
if (stop_process)
logger.info("Noise detector stopped @ #{DateTime.now.strftime('%d/%m/%Y %H:%M:%S')}")
break
end
rec_out = `/usr/bin/arecord -D plughw:#{options[:microphone]},0 -d #{SAMPLE_DURATION} -f #{FORMAT} -t wav #{RECORD_FILENAME} 2>/dev/null`
out = `/usr/bin/sox -t .wav #{RECORD_FILENAME} -n stat 2>&1`
out.match(/Maximum amplitude:\s+(.*)/m)
amplitude = $1.to_f
logger.debug("Detected amplitude: #{amplitude}") if options[:verbose]
if amplitude > THRESHOLD
logger.info("Sound detected!!!")
# Play sound
current_directory_contents = `/root/playsound`
# Read a file
filecontent = File.open(RECORD_FILENAME ,"rb") {|io| io.read}
encoded = [filecontent].pack("m") # base64 econding
puts value = %x[/usr/sbin/sendmail #{options[:email]} << EOF
subject: WARNING: Noise Detected
from: home@mornati.net
Content-Description: "noise.wav"
Content-Type: audio/x-wav; name="noise.wav"
Content-Transfer-Encoding:base64
Content-Disposition: attachment; filename="noise.wav"
#{encoded}
EOF]
else
logger.debug("No sound detected...")
end
end
end
Process.detach(pid)
logger.debug("Started... (#{pid})")
File.open(PID_FILE, "w") { |file| file.write(pid) }