python-audio-autotest-3.10 1.5.12rc1__py3-none-any.whl → 1.5.12rc3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyaatlibs/__init__.py +3 -2
- pyaatlibs/aatapp.py +92 -26
- pyaatlibs/activitystatemachine.py +4 -1
- pyaatlibs/adbutils.py +63 -35
- pyaatlibs/apk/audioworker.apk +0 -0
- pyaatlibs/appinterface.py +57 -22
- pyaatlibs/argutils.py +2 -0
- pyaatlibs/audiofunction.py +59 -27
- pyaatlibs/audiosignalframelogger.py +10 -9
- pyaatlibs/audiothread.py +32 -25
- pyaatlibs/audioworker.py +190 -87
- pyaatlibs/logcatlistener.py +19 -8
- pyaatlibs/logger.py +21 -8
- pyaatlibs/signalanalyzer.py +3 -1
- pyaatlibs/signalmatcher.py +14 -9
- pyaatlibs/tests/audioworker_test.py +168 -162
- pyaatlibs/timeutils.py +14 -5
- pyaatlibs/trials.py +9 -3
- {python_audio_autotest_3_10-1.5.12rc1.dist-info → python_audio_autotest_3_10-1.5.12rc3.dist-info}/METADATA +1 -1
- python_audio_autotest_3_10-1.5.12rc3.dist-info/RECORD +25 -0
- python_audio_autotest_3_10-1.5.12rc1.dist-info/RECORD +0 -25
- {python_audio_autotest_3_10-1.5.12rc1.dist-info → python_audio_autotest_3_10-1.5.12rc3.dist-info}/WHEEL +0 -0
- {python_audio_autotest_3_10-1.5.12rc1.dist-info → python_audio_autotest_3_10-1.5.12rc3.dist-info}/licenses/LICENSE +0 -0
- {python_audio_autotest_3_10-1.5.12rc1.dist-info → python_audio_autotest_3_10-1.5.12rc3.dist-info}/top_level.txt +0 -0
pyaatlibs/audiofunction.py
CHANGED
@@ -9,8 +9,10 @@ from pyaatlibs.adbutils import Adb
|
|
9
9
|
from pyaatlibs.logger import Logger
|
10
10
|
from pyaatlibs.timeutils import TimeUtils
|
11
11
|
|
12
|
+
|
12
13
|
# Initialization of used variables
|
13
14
|
class CommandHandler(object):
|
15
|
+
|
14
16
|
def __init__(self):
|
15
17
|
self.cmd = None
|
16
18
|
|
@@ -18,6 +20,7 @@ class CommandHandler(object):
|
|
18
20
|
if self.cmd:
|
19
21
|
self.cmd.stop()
|
20
22
|
|
23
|
+
|
21
24
|
class AudioFunction(object):
|
22
25
|
WORK_THREAD = AudioCommandThread()
|
23
26
|
WORK_THREAD.daemon = True
|
@@ -46,7 +49,9 @@ class AudioFunction(object):
|
|
46
49
|
if not AudioFunction.HAS_BEEN_INIT:
|
47
50
|
raise RuntimeError("The AudioFunction should be initialized before calling APIs")
|
48
51
|
AudioFunction.COMMAND.stop()
|
49
|
-
AudioFunction.COMMAND.cmd = TonePlayCommand(
|
52
|
+
AudioFunction.COMMAND.cmd = TonePlayCommand(
|
53
|
+
config=AudioFunction.AUDIO_CONFIG, out_freq=out_freq
|
54
|
+
)
|
50
55
|
AudioFunction.WORK_THREAD.push(AudioFunction.COMMAND.cmd)
|
51
56
|
|
52
57
|
@staticmethod
|
@@ -59,11 +64,16 @@ class AudioFunction(object):
|
|
59
64
|
raise RuntimeError("The AudioFunction should be initialized before calling APIs")
|
60
65
|
AudioFunction.COMMAND.stop()
|
61
66
|
AudioFunction.AUDIO_CONFIG.cb = cb
|
62
|
-
AudioFunction.COMMAND.cmd =
|
63
|
-
|
67
|
+
AudioFunction.COMMAND.cmd = (
|
68
|
+
cmd
|
69
|
+
if cmd is not None
|
70
|
+
else ToneDetectCommand(config=AudioFunction.AUDIO_CONFIG, framemillis=50, nfft=2048)
|
71
|
+
)
|
64
72
|
AudioFunction.WORK_THREAD.push(AudioFunction.COMMAND.cmd)
|
65
73
|
|
74
|
+
|
66
75
|
class ToneDetectorThread(threading.Thread):
|
76
|
+
|
67
77
|
def __init__(self, target_freq, callback):
|
68
78
|
super(ToneDetectorThread, self).__init__()
|
69
79
|
self.daemon = True
|
@@ -87,21 +97,22 @@ class ToneDetectorThread(threading.Thread):
|
|
87
97
|
if self.target_freq == None:
|
88
98
|
return True
|
89
99
|
|
90
|
-
diff_semitone = np.abs(np.log(1.0*freq/self.target_freq) / np.log(2) * 12)
|
100
|
+
diff_semitone = np.abs(np.log(1.0 * freq / self.target_freq) / np.log(2) * 12)
|
91
101
|
return diff_semitone < 2
|
92
102
|
|
103
|
+
|
93
104
|
class ToneDetectorForServerThread(ToneDetectorThread):
|
105
|
+
|
94
106
|
def __init__(self, target_freq, callback):
|
95
|
-
super(ToneDetectorForServerThread, self).__init__(
|
107
|
+
super(ToneDetectorForServerThread, self).__init__(
|
108
|
+
target_freq=target_freq, callback=callback
|
109
|
+
)
|
96
110
|
|
97
111
|
def join(self, timeout=None):
|
98
112
|
super(ToneDetectorForServerThread, self).join(timeout)
|
99
113
|
|
100
114
|
def run(self):
|
101
|
-
shared_vars = {
|
102
|
-
"start_time": None,
|
103
|
-
"last_event": None
|
104
|
-
}
|
115
|
+
shared_vars = {"start_time": None, "last_event": None}
|
105
116
|
|
106
117
|
def freq_cb(detected_tones):
|
107
118
|
if len(detected_tones) == 0:
|
@@ -115,14 +126,20 @@ class ToneDetectorForServerThread(ToneDetectorThread):
|
|
115
126
|
if self.event_counter == 1:
|
116
127
|
shared_vars["start_time"] = time_str
|
117
128
|
if self.event_counter == thresh:
|
118
|
-
if
|
129
|
+
if (
|
130
|
+
not shared_vars["last_event"]
|
131
|
+
or shared_vars["last_event"] != ToneDetector.Event.TONE_DETECTED
|
132
|
+
):
|
119
133
|
self.cb((shared_vars["start_time"], ToneDetector.Event.TONE_DETECTED))
|
120
134
|
shared_vars["last_event"] = ToneDetector.Event.TONE_DETECTED
|
121
135
|
|
122
136
|
else:
|
123
137
|
if self.event_counter > thresh:
|
124
138
|
shared_vars["start_time"] = None
|
125
|
-
if
|
139
|
+
if (
|
140
|
+
not shared_vars["last_event"]
|
141
|
+
or shared_vars["last_event"] != ToneDetector.Event.TONE_MISSING
|
142
|
+
):
|
126
143
|
self.cb((time_str, ToneDetector.Event.TONE_MISSING))
|
127
144
|
shared_vars["last_event"] = ToneDetector.Event.TONE_MISSING
|
128
145
|
self.event_counter = 0
|
@@ -173,7 +190,9 @@ class ToneDetector(object):
|
|
173
190
|
ToneDetector.WORK_THREADS.clear()
|
174
191
|
ToneDetector.WORK_THREADS = None
|
175
192
|
|
193
|
+
|
176
194
|
class DetectionStateListener(object):
|
195
|
+
|
177
196
|
class Event(object):
|
178
197
|
ACTIVE = "active"
|
179
198
|
INACTIVE = "inactive"
|
@@ -204,14 +223,18 @@ class DetectionStateListener(object):
|
|
204
223
|
with self.event_q.mutex:
|
205
224
|
current_event = self.current_event
|
206
225
|
if current_event:
|
207
|
-
active_or_inactive =
|
208
|
-
|
209
|
-
|
226
|
+
active_or_inactive = (
|
227
|
+
DetectionStateListener.Event.ACTIVE
|
228
|
+
if current_event[1] == ToneDetector.Event.TONE_DETECTED
|
229
|
+
else DetectionStateListener.Event.INACTIVE
|
230
|
+
)
|
210
231
|
|
211
232
|
self.clear()
|
212
233
|
|
213
234
|
if active_or_inactive:
|
214
|
-
Logger.log(
|
235
|
+
Logger.log(
|
236
|
+
self.get_tag(), "reset and resend the event ({}, 0)".format(active_or_inactive)
|
237
|
+
)
|
215
238
|
self.event_q.put((active_or_inactive, 0))
|
216
239
|
|
217
240
|
def tone_detected_event_cb(self, event):
|
@@ -219,27 +242,31 @@ class DetectionStateListener(object):
|
|
219
242
|
self._handle_event(event)
|
220
243
|
|
221
244
|
def _handle_event(self, event):
|
222
|
-
active_or_inactive =
|
223
|
-
|
224
|
-
|
245
|
+
active_or_inactive = (
|
246
|
+
DetectionStateListener.Event.ACTIVE
|
247
|
+
if event[1] == ToneDetector.Event.TONE_DETECTED
|
248
|
+
else DetectionStateListener.Event.INACTIVE
|
249
|
+
)
|
225
250
|
|
226
251
|
self.event_q.put((active_or_inactive, 0))
|
227
252
|
|
228
253
|
if self.current_event and self.current_event[1] != event[1]:
|
229
|
-
rising_or_falling =
|
230
|
-
|
231
|
-
|
254
|
+
rising_or_falling = (
|
255
|
+
DetectionStateListener.Event.RISING_EDGE
|
256
|
+
if event[1] == ToneDetector.Event.TONE_DETECTED
|
257
|
+
else DetectionStateListener.Event.FALLING_EDGE
|
258
|
+
)
|
232
259
|
|
233
260
|
t2 = TimeUtils.time_from_str(event[0])
|
234
261
|
t1 = TimeUtils.time_from_str(self.current_event[0])
|
235
262
|
t_diff = t2 - t1
|
236
|
-
self.event_q.put((rising_or_falling, t_diff.total_seconds()*1000.0))
|
263
|
+
self.event_q.put((rising_or_falling, t_diff.total_seconds() * 1000.0))
|
237
264
|
|
238
265
|
self.current_event = event
|
239
266
|
|
240
267
|
def wait_for_event(self, event, timeout):
|
241
268
|
cnt = 0
|
242
|
-
while cnt < timeout*10:
|
269
|
+
while cnt < timeout * 10:
|
243
270
|
cnt += 1
|
244
271
|
if self.stoprequest.isSet():
|
245
272
|
return -1
|
@@ -252,10 +279,15 @@ class DetectionStateListener(object):
|
|
252
279
|
with self.event_q.mutex:
|
253
280
|
current_event = self.current_event
|
254
281
|
if current_event:
|
255
|
-
active_or_inactive =
|
256
|
-
|
257
|
-
|
282
|
+
active_or_inactive = (
|
283
|
+
DetectionStateListener.Event.ACTIVE
|
284
|
+
if current_event[1] == ToneDetector.Event.TONE_DETECTED
|
285
|
+
else DetectionStateListener.Event.INACTIVE
|
286
|
+
)
|
258
287
|
if active_or_inactive == event:
|
259
|
-
Logger.log(
|
288
|
+
Logger.log(
|
289
|
+
self.get_tag(),
|
290
|
+
"the current state '{}' fits the waited event".format(event),
|
291
|
+
)
|
260
292
|
return 0
|
261
293
|
return -1
|
@@ -7,6 +7,7 @@ import numpy as np
|
|
7
7
|
|
8
8
|
from pyaatlibs import SEP
|
9
9
|
|
10
|
+
|
10
11
|
class AudioSignalFrameLogger(object):
|
11
12
|
INFO_FILE = "info.json"
|
12
13
|
BIN_FILE = "stream.bin"
|
@@ -18,14 +19,12 @@ class AudioSignalFrameLogger(object):
|
|
18
19
|
|
19
20
|
def push(self, name, fs, values):
|
20
21
|
self.lock.acquire()
|
21
|
-
self.info.append(
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
}
|
28
|
-
)
|
22
|
+
self.info.append({
|
23
|
+
"name": name,
|
24
|
+
"fs": fs,
|
25
|
+
"datasize-in-double": values.shape[0],
|
26
|
+
"createAt": "{} (UTF+8)".format(str(datetime.datetime.now())[:-3]),
|
27
|
+
})
|
29
28
|
self.databuf.append(np.array(values, dtype=np.float64))
|
30
29
|
self.lock.release()
|
31
30
|
|
@@ -33,7 +32,9 @@ class AudioSignalFrameLogger(object):
|
|
33
32
|
if path.endswith(SEP):
|
34
33
|
path = path[:-1]
|
35
34
|
self.lock.acquire()
|
36
|
-
out, _ = subprocess.Popen(
|
35
|
+
out, _ = subprocess.Popen(
|
36
|
+
["mkdir", "-p", path], stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
37
|
+
).communicate()
|
37
38
|
|
38
39
|
with open("{}{}{}".format(path, SEP, AudioSignalFrameLogger.INFO_FILE), "w") as f:
|
39
40
|
f.write(json.dumps(self.info, indent=4) + "\n")
|
pyaatlibs/audiothread.py
CHANGED
@@ -10,18 +10,24 @@ try:
|
|
10
10
|
except ImportError:
|
11
11
|
import Queue as queue
|
12
12
|
|
13
|
+
|
13
14
|
class AudioConfig(object):
|
15
|
+
|
14
16
|
def __init__(self, fs, ch=1, dtype="float32", cb=None):
|
15
17
|
self.fs = fs
|
16
18
|
self.ch = ch
|
17
19
|
self.dtype = dtype
|
18
20
|
self.cb = cb
|
19
21
|
|
22
|
+
|
20
23
|
class AudioCommand(object):
|
24
|
+
|
21
25
|
def __init__(self, config):
|
22
26
|
self.config = config
|
23
27
|
|
28
|
+
|
24
29
|
class RawRecordCommand(AudioCommand):
|
30
|
+
|
25
31
|
def __init__(self, config, framemillis=100):
|
26
32
|
super(RawRecordCommand, self).__init__(config)
|
27
33
|
self.framemillis = framemillis
|
@@ -33,7 +39,9 @@ class RawRecordCommand(AudioCommand):
|
|
33
39
|
def reset(self):
|
34
40
|
self.is_recording = True
|
35
41
|
|
42
|
+
|
36
43
|
class TonePlayCommand(AudioCommand):
|
44
|
+
|
37
45
|
def __init__(self, config, out_freq):
|
38
46
|
super(TonePlayCommand, self).__init__(config)
|
39
47
|
self.out_freq = out_freq
|
@@ -45,13 +53,15 @@ class TonePlayCommand(AudioCommand):
|
|
45
53
|
def reset(self):
|
46
54
|
self.is_playing = True
|
47
55
|
|
56
|
+
|
48
57
|
class ToneDetectCommand(AudioCommand):
|
58
|
+
|
49
59
|
def __init__(self, config, framemillis=100, nfft=-1):
|
50
60
|
super(ToneDetectCommand, self).__init__(config)
|
51
61
|
self.framemillis = framemillis
|
52
62
|
self.nfft = nfft
|
53
63
|
if self.nfft < 0:
|
54
|
-
self.nfft = int(framemillis*self.config.fs/1000)
|
64
|
+
self.nfft = int(framemillis * self.config.fs / 1000)
|
55
65
|
self.is_detecting = True
|
56
66
|
|
57
67
|
def stop(self):
|
@@ -60,7 +70,9 @@ class ToneDetectCommand(AudioCommand):
|
|
60
70
|
def reset(self):
|
61
71
|
self.is_detecting = True
|
62
72
|
|
73
|
+
|
63
74
|
class AudioCommandThread(threading.Thread):
|
75
|
+
|
64
76
|
def __init__(self, cmd_q=None):
|
65
77
|
super(AudioCommandThread, self).__init__()
|
66
78
|
self.cmd_q = cmd_q if cmd_q else queue.Queue()
|
@@ -103,10 +115,7 @@ class AudioCommandThread(threading.Thread):
|
|
103
115
|
cfg = cmd.config
|
104
116
|
|
105
117
|
# Make the code adaptive to both python 2 and 3
|
106
|
-
shared_vars = {
|
107
|
-
"cmd" : cmd,
|
108
|
-
"phase_offset": phase_offset
|
109
|
-
}
|
118
|
+
shared_vars = {"cmd": cmd, "phase_offset": phase_offset}
|
110
119
|
|
111
120
|
def playback_cb(outdata, frames, time, status):
|
112
121
|
phase_offset = shared_vars["phase_offset"]
|
@@ -114,8 +123,8 @@ class AudioCommandThread(threading.Thread):
|
|
114
123
|
cfg = cmd.config
|
115
124
|
|
116
125
|
signal = np.arange(outdata.shape[0])
|
117
|
-
signal = signal * 2*np.pi/cfg.fs + phase_offset
|
118
|
-
phase_offset += outdata.shape[0] * 2*np.pi/cfg.fs
|
126
|
+
signal = signal * 2 * np.pi / cfg.fs + phase_offset
|
127
|
+
phase_offset += outdata.shape[0] * 2 * np.pi / cfg.fs
|
119
128
|
signal = 0.99 * np.sin(signal * cmd.out_freq)
|
120
129
|
|
121
130
|
for cidx in range(outdata.shape[1]):
|
@@ -124,21 +133,19 @@ class AudioCommandThread(threading.Thread):
|
|
124
133
|
shared_vars["phase_offset"] = phase_offset
|
125
134
|
shared_vars["cmd"] = cmd
|
126
135
|
|
127
|
-
with sd.OutputStream(
|
136
|
+
with sd.OutputStream(
|
137
|
+
channels=cfg.ch, callback=playback_cb, samplerate=cfg.fs, dtype="float32"
|
138
|
+
):
|
128
139
|
while cmd.is_playing:
|
129
140
|
sd.sleep(500)
|
130
141
|
|
131
142
|
def _process_tone_detect_command(self, cmd):
|
132
143
|
cfg = cmd.config
|
133
144
|
buff = np.array([])
|
134
|
-
framesize = int(cfg.fs*cmd.framemillis/1000)
|
145
|
+
framesize = int(cfg.fs * cmd.framemillis / 1000)
|
135
146
|
|
136
147
|
# Make the code adaptive to both python 2 and 3
|
137
|
-
shared_vars = {
|
138
|
-
"cmd" : cmd,
|
139
|
-
"buff" : buff,
|
140
|
-
"framesize": framesize
|
141
|
-
}
|
148
|
+
shared_vars = {"cmd": cmd, "buff": buff, "framesize": framesize}
|
142
149
|
|
143
150
|
def record_cb(indata, frames, time, status):
|
144
151
|
cmd = shared_vars["cmd"]
|
@@ -153,10 +160,10 @@ class AudioCommandThread(threading.Thread):
|
|
153
160
|
|
154
161
|
while buff.size >= framesize:
|
155
162
|
spectrum = np.abs(fft(buff[:framesize, 0], cmd.nfft))
|
156
|
-
spectrum = spectrum[:int(cmd.nfft/2.0)]
|
157
|
-
unit_freq = 1.0*cfg.fs / cmd.nfft
|
163
|
+
spectrum = spectrum[: int(cmd.nfft / 2.0)]
|
164
|
+
unit_freq = 1.0 * cfg.fs / cmd.nfft
|
158
165
|
peaks = find_peaks(spectrum)
|
159
|
-
tones = list(map(lambda x: (x[0]*unit_freq, 20*np.log10(x[1])), peaks))
|
166
|
+
tones = list(map(lambda x: (x[0] * unit_freq, 20 * np.log10(x[1])), peaks))
|
160
167
|
if cfg.cb:
|
161
168
|
cfg.cb(detected_tones=tones)
|
162
169
|
|
@@ -166,21 +173,19 @@ class AudioCommandThread(threading.Thread):
|
|
166
173
|
shared_vars["buff"] = buff
|
167
174
|
shared_vars["framesize"] = framesize
|
168
175
|
|
169
|
-
with sd.InputStream(
|
176
|
+
with sd.InputStream(
|
177
|
+
channels=cfg.ch, callback=record_cb, samplerate=cfg.fs, dtype="float32"
|
178
|
+
):
|
170
179
|
while cmd.is_detecting:
|
171
180
|
sd.sleep(500)
|
172
181
|
|
173
182
|
def _process_raw_record_command(self, cmd):
|
174
183
|
cfg = cmd.config
|
175
184
|
buff = np.array([])
|
176
|
-
framesize = int(cfg.fs*cmd.framemillis/1000)
|
185
|
+
framesize = int(cfg.fs * cmd.framemillis / 1000)
|
177
186
|
|
178
187
|
# Make the code adaptive to both python 2 and 3
|
179
|
-
shared_vars = {
|
180
|
-
"cmd" : cmd,
|
181
|
-
"buff" : buff,
|
182
|
-
"framesize": framesize
|
183
|
-
}
|
188
|
+
shared_vars = {"cmd": cmd, "buff": buff, "framesize": framesize}
|
184
189
|
|
185
190
|
def record_cb(indata, frames, time, status):
|
186
191
|
cmd = shared_vars["cmd"]
|
@@ -203,6 +208,8 @@ class AudioCommandThread(threading.Thread):
|
|
203
208
|
shared_vars["buff"] = buff
|
204
209
|
shared_vars["framesize"] = framesize
|
205
210
|
|
206
|
-
with sd.InputStream(
|
211
|
+
with sd.InputStream(
|
212
|
+
channels=cfg.ch, callback=record_cb, samplerate=cfg.fs, dtype="float32"
|
213
|
+
):
|
207
214
|
while cmd.is_recording:
|
208
215
|
sd.sleep(500)
|