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
|
import struct
import pyaudio
from utils import *
# Receiver Class: Used to continuos listen for sound waves in the corresponding frequency range
# and decode the data being sent
class Recv:
def __init__(self, start_freq=18500):
# initialize frequency related variables with default values
self.start_freq = start_freq
self.freq_range = 500
self.sampling_rate = 44100
self.p = pyaudio.PyAudio()
self.bytes_per_transmit = 1
# initialize stream variables
self.CHUNK = 2048 * 2
self.FORMAT = pyaudio.paInt32
self.CHANNELS = 1
self.RATE = 44100
self.pause = False
# initialize stream object
self.p = pyaudio.PyAudio()
self.stream = self.p.open(
format=self.FORMAT,
channels=self.CHANNELS,
rate=self.RATE,
input=True,
output=True,
frames_per_buffer=self.CHUNK,
)
# reads and unpacks the incoming audio stream
def read_audio_stream(self):
data = self.stream.read(self.CHUNK)
data_int = struct.unpack(str(self.CHUNK) + 'i', data)
return data_int
# checks if the byte is safe to add to the data structure
def safe_check_byte(self, bytes_seen):
safe_byte = []
if len(bytes_seen) > 0:
for col in range(len(bytes_seen[0])):
count1s = 0
count0s = 0
for row in range(len(bytes_seen)):
bit = bytes_seen[row][col]
if bit == '1':
count1s += 1
else:
count0s += 1
if count1s > count0s:
safe_byte.append('1')
else:
safe_byte.append('0')
return safe_byte
# listens for incoming data
# uses two extra bits to handle data transmission protocol
def listen(self):
prev_is_data_flag = '0'
prev_is_new_byte_flag = '0'
bytes_seen = []
recv_buffer = []
while True:
data = self.read_audio_stream()
bits = wave_to_bits(data, self.start_freq, self.freq_range, self.bytes_per_transmit)
# handle the data flags
is_data_flag = bits[-1]
is_new_byte_flag = bits[-2]
if prev_is_data_flag == '0' and is_data_flag == '1':
prev_is_data_flag = is_data_flag
# just started receiving data
bytes_seen = []
recv_buffer = []
print("started receiving data!")
is_data_flag = bits[-1]
if prev_is_data_flag == '0' and is_data_flag == '0':
prev_is_data_flag = is_data_flag
# just waiting for new data
continue
if prev_is_data_flag == '1' and is_data_flag == '0':
prev_is_data_flag = is_data_flag
# just finished the last byte of data, add it to buffer, then write buffer to terminal
recv_buffer.append(self.safe_check_byte(bytes_seen))
# FIXME: what to do with buffer?
# for now print buffer as string
buffer_as_string = ''.join([receive_string(byte) for byte in recv_buffer])
print("data received: ", buffer_as_string)
# clear data structure & buffer
continue
# at this point, we know we are receiving data
if prev_is_new_byte_flag == is_new_byte_flag:
prev_is_new_byte_flag = is_new_byte_flag
# we are still receiving the same byte, store it in the data structure
byte = bits[:-2]
bytes_seen.append(byte)
continue
else:
prev_is_new_byte_flag = is_new_byte_flag
# we are receiving a new byte, so we need to write the old byte to the recv buffer
recv_buffer.append(self.safe_check_byte(bytes_seen))
# clear the data structure
bytes_seen = []
# append the new byte to the data structure
byte = bits[:-2]
bytes_seen.append(byte)
continue
def main():
recv = Recv()
recv.listen()
if __name__ == "__main__":
main()
|