Guest User

Untitled

a guest
May 5th, 2024
9
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.66 KB | None | 0 0
  1. import asyncio
  2. import base64
  3. import json
  4. import sys
  5. import websockets
  6. import ssl
  7. from pydub import AudioSegment
  8.  
  9. subscribers = {}
  10.  
  11. def deepgram_connect():
  12. extra_headers = {
  13. 'Authorization': 'Token TOKEN_HERE'
  14. }
  15. deepgram_ws = websockets.connect('wss://api.deepgram.com/v1/listen?encoding=mulaw&sample_rate=8000&channels=2&multichannel=true', extra_headers=extra_headers)
  16.  
  17. return deepgram_ws
  18.  
  19. async def twilio_handler(twilio_ws):
  20. audio_queue = asyncio.Queue()
  21. callsid_queue = asyncio.Queue()
  22.  
  23. async with deepgram_connect() as deepgram_ws:
  24.  
  25. async def deepgram_sender(deepgram_ws):
  26. while True:
  27. chunk = await audio_queue.get()
  28. await deepgram_ws.send(chunk)
  29.  
  30. async def deepgram_receiver(deepgram_ws):
  31. callsid = await callsid_queue.get()
  32. subscribers[callsid] = []
  33. async for message in deepgram_ws:
  34. for client in subscribers[callsid]:
  35. client.put_nowait(message)
  36.  
  37. for client in subscribers[callsid]:
  38. client.put_nowait('close')
  39.  
  40. del subscribers[callsid]
  41.  
  42. async def twilio_receiver(twilio_ws):
  43. BUFFER_SIZE = 20 * 160
  44. inbuffer = bytearray(b'')
  45. outbuffer = bytearray(b'')
  46. inbound_chunks_started = False
  47. outbound_chunks_started = False
  48. latest_inbound_timestamp = 0
  49. latest_outbound_timestamp = 0
  50. async for message in twilio_ws:
  51. try:
  52. data = json.loads(message)
  53. if data['event'] == 'start':
  54. start = data['start']
  55. callsid = start['callSid']
  56. callsid_queue.put_nowait(callsid)
  57. if data['event'] == 'connected':
  58. continue
  59. if data['event'] == 'media':
  60. media = data['media']
  61. chunk = base64.b64decode(media['payload'])
  62. if media['track'] == 'inbound':
  63. if inbound_chunks_started:
  64. if latest_inbound_timestamp + 20 < int(media['timestamp']):
  65. bytes_to_fill = 8 * (int(media['timestamp']) - (latest_inbound_timestamp + 20))
  66. inbuffer.extend(b'\xff' * bytes_to_fill)
  67. else:
  68. inbound_chunks_started = True
  69. latest_inbound_timestamp = int(media['timestamp'])
  70. latest_outbound_timestamp = int(media['timestamp']) - 20
  71. latest_inbound_timestamp = int(media['timestamp'])
  72. inbuffer.extend(chunk)
  73. if media['track'] == 'outbound':
  74. outbound_chunked_started = True
  75. if latest_outbound_timestamp + 20 < int(media['timestamp']):
  76. bytes_to_fill = 8 * (int(media['timestamp']) - (latest_outbound_timestamp + 20))
  77. outbuffer.extend(b'\xff' * bytes_to_fill)
  78. latest_outbound_timestamp = int(media['timestamp'])
  79. outbuffer.extend(chunk)
  80. if data['event'] == 'stop':
  81. break
  82.  
  83. while len(inbuffer) >= BUFFER_SIZE and len(outbuffer) >= BUFFER_SIZE:
  84. asinbound = AudioSegment(inbuffer[:BUFFER_SIZE], sample_width=1, frame_rate=8000, channels=1)
  85. asoutbound = AudioSegment(outbuffer[:BUFFER_SIZE], sample_width=1, frame_rate=8000, channels=1)
  86. mixed = AudioSegment.from_mono_audiosegments(asinbound, asoutbound)
  87. audio_queue.put_nowait(mixed.raw_data)
  88. inbuffer = inbuffer[BUFFER_SIZE:]
  89. outbuffer = outbuffer[BUFFER_SIZE:]
  90. except:
  91. break
  92.  
  93. audio_queue.put_nowait(b'')
  94.  
  95. await asyncio.wait([
  96. asyncio.ensure_future(deepgram_sender(deepgram_ws)),
  97. asyncio.ensure_future(deepgram_receiver(deepgram_ws)),
  98. asyncio.ensure_future(twilio_receiver(twilio_ws))
  99. ])
  100.  
  101. await twilio_ws.close()
  102.  
  103. async def client_handler(client_ws):
  104. client_queue = asyncio.Queue()
  105.  
  106. await client_ws.send(json.dumps(list(subscribers.keys())))
  107.  
  108. try:
  109. callsid = await client_ws.recv()
  110. callsid = callsid.strip()
  111. if callsid in subscribers:
  112. subscribers[callsid].append(client_queue)
  113. else:
  114. await client_ws.close()
  115. except:
  116. await client_ws.close()
  117.  
  118. async def client_sender(client_ws):
  119. while True:
  120. message = await client_queue.get()
  121. if message == 'close':
  122. break
  123. try:
  124. await client_ws.send(message)
  125. except:
  126. subscribers[callsid].remove(client_queue)
  127. break
  128.  
  129. await asyncio.wait([
  130. asyncio.ensure_future(client_sender(client_ws)),
  131. ])
  132.  
  133. await client_ws.close()
  134.  
  135. async def router(websocket, path):
  136. if path == '/client':
  137. await client_handler(websocket)
  138. elif path == '/twilio':
  139. await twilio_handler(websocket)
  140.  
  141. def main():
  142. server = websockets.serve(router, 'localhost', 5000)
  143.  
  144. asyncio.get_event_loop().run_until_complete(server)
  145. asyncio.get_event_loop().run_forever()
  146.  
  147. if __name__ == '__main__':
  148. sys.exit(main() or 0)
  149.  
Add Comment
Please, Sign In to add comment