Project

General

Profile

Statistics
| Branch: | Revision:

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])