gdp-if / audio / capture.py @ master
History | View | Annotate | Download (4.38 KB)
1 | 44e6359c | Nitesh Mor | #!/usr/bin/env python
|
---|---|---|---|
2 | |||
3 | """ Capture audio data and write to a log in a non-blocking manner.
|
||
4 |
|
||
5 | Requires a recent-ish version of PyAudio, tested on a Ubuntu (laptop) and
|
||
6 | debian (beaglebone). See README for more information
|
||
7 | """
|
||
8 | |||
9 | import gdp |
||
10 | import sys |
||
11 | import time |
||
12 | import json # this is how we store data in the first record |
||
13 | import pyaudio |
||
14 | |||
15 | NUM_RECS_PER_SEC = 5
|
||
16 | |||
17 | |||
18 | def getDeviceParams(inputDevicePrefix=None): |
||
19 | """ returns the device ID and other parameters for the mic"""
|
||
20 | |||
21 | p = pyaudio.PyAudio() |
||
22 | mic_id = None
|
||
23 | |||
24 | num_devices = p.get_device_count() |
||
25 | for i in xrange(0, num_devices): |
||
26 | dev_info = p.get_device_info_by_index(i) |
||
27 | if dev_info.get('maxInputChannels')>0: |
||
28 | # in case we don't want default microphone?
|
||
29 | if inputDevicePrefix is not None: |
||
30 | if dev_info.get('name').startswith(inputDevicePrefix): |
||
31 | mic_id = i |
||
32 | break
|
||
33 | else:
|
||
34 | mic_id = i |
||
35 | break
|
||
36 | |||
37 | params = {} |
||
38 | params['sampleWidth'] = 2 # Quite arbitrary |
||
39 | params['samplingRate'] = int(p.get_device_info_by_index(mic_id).\ |
||
40 | get('defaultSampleRate'))
|
||
41 | params['channels'] = int(p.get_device_info_by_index(mic_id).\ |
||
42 | get('maxInputChannels'))
|
||
43 | params['samplesPerRecord'] = params['samplingRate']/NUM_RECS_PER_SEC |
||
44 | |||
45 | p.terminate() |
||
46 | |||
47 | return (mic_id, params)
|
||
48 | |||
49 | |||
50 | |||
51 | def recordToLog(logHandle, sampleWidth=2, channels=1, |
||
52 | samplingRate=44100, samplesPerRecord=8820, |
||
53 | device_id=0):
|
||
54 | """
|
||
55 | Append raw audio data to a GDP 'logHandle'. Captured audio data from
|
||
56 | either the default input device, or a device that starts with a
|
||
57 | certain prefix (useful in case of multiple input devices).
|
||
58 | """
|
||
59 | |||
60 | print ">>>", "sampleWidth:", sampleWidth, "channels:", channels, |
||
61 | print "samplingRate:", samplingRate, "samplesPerRecord", samplesPerRecord, |
||
62 | print "device_id:", device_id |
||
63 | |||
64 | def __helperCallback(in_data, frame_count, time_info, status): |
||
65 | "callback that the stream calls when more data is available"
|
||
66 | logHandle.append( {"data": in_data} )
|
||
67 | return (None, pyaudio.paContinue) |
||
68 | |||
69 | p = pyaudio.PyAudio() |
||
70 | stream = p.open(format=p.get_format_from_width(sampleWidth), |
||
71 | channels=channels, rate=samplingRate, |
||
72 | input=True, output=False, |
||
73 | input_device_index=device_id, |
||
74 | frames_per_buffer=samplesPerRecord, |
||
75 | stream_callback=__helperCallback) |
||
76 | |||
77 | stream.start_stream() |
||
78 | |||
79 | # need this to keep the main thread from terminating
|
||
80 | # IF you want to record for a finite time rather than indefinite
|
||
81 | # recording, this is where that logic would go.
|
||
82 | while stream.is_active():
|
||
83 | time.sleep(0.1)
|
||
84 | |||
85 | # cleanup. Although pointless in case of indefinite streaming
|
||
86 | stream.stop_stream() |
||
87 | stream.close() |
||
88 | p.terminate() |
||
89 | |||
90 | |||
91 | def main(logname, inputDevicePrefix=None): |
||
92 | |||
93 | gdp.gdp_init() |
||
94 | lh = gdp.GDP_GCL(gdp.GDP_NAME(logname), gdp.GDP_MODE_RA) |
||
95 | |||
96 | # Okay, get the parameters
|
||
97 | try:
|
||
98 | # try reading from the first record
|
||
99 | firstRecord = lh.read(1)
|
||
100 | audioParams = json.loads(firstRecord['data'])
|
||
101 | mic_id, max_params = getDeviceParams(inputDevicePrefix) |
||
102 | assert audioParams['samplingRate'] <= max_params['samplingRate'] |
||
103 | assert audioParams['channels'] <= max_params['channels'] |
||
104 | |||
105 | except gdp.MISC.EP_STAT_SEV_ERROR as e: |
||
106 | # in case first record does not exist, let's write it
|
||
107 | 4a434acf | Nitesh Mor | if e.msg.startswith("ERROR: 404 ") or \ |
108 | e.msg.startswith('ERROR: 4.04 '):
|
||
109 | 44e6359c | Nitesh Mor | mic_id, audioParams = getDeviceParams(inputDevicePrefix) |
110 | lh.append( {"data": json.dumps(audioParams)} )
|
||
111 | else:
|
||
112 | # this is some other error, let's just raise it as it is
|
||
113 | raise e
|
||
114 | |||
115 | # start recording
|
||
116 | recordToLog(lh, sampleWidth=audioParams['sampleWidth'],
|
||
117 | channels=audioParams['channels'],
|
||
118 | samplingRate=audioParams['samplingRate'],
|
||
119 | samplesPerRecord=audioParams['samplesPerRecord'],
|
||
120 | device_id=mic_id) |
||
121 | |||
122 | |||
123 | if __name__=="__main__": |
||
124 | |||
125 | if len(sys.argv)<2: |
||
126 | print "Usage: %s LOGNAME [inputDevicePrefix]" % sys.argv[0] |
||
127 | sys.exit(1)
|
||
128 | |||
129 | if len(sys.argv)==2: |
||
130 | main(sys.argv[1])
|
||
131 | else:
|
||
132 | main(sys.argv[1], sys.argv[2]) |