Skip to content

Commit 4ee799e

Browse files
replace base64 with raw data (#129)
* replace base64 with raw data * fix lint * fix unit test --------- Co-authored-by: openminddev <147775420+openminddev@users.noreply.github.com>
1 parent c600731 commit 4ee799e

3 files changed

Lines changed: 50 additions & 41 deletions

File tree

src/om1_speech/audio/audio_input_stream.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
import json
66
import logging
77
import queue
8+
import struct
89
import threading
910
import time
10-
from typing import Any, Callable, Dict, Generator, List, Optional, Tuple, Union
11+
from typing import Any, Callable, Generator, List, Optional, Tuple, Union
1112

1213
import pyaudio
1314
import zenoh
@@ -416,7 +417,7 @@ def fill_buffer_remote(self, data: str):
416417
self._rate = rate
417418
self._language_code = language_code
418419

419-
def generator(self) -> Generator[Dict[str, Union[bytes, int]], None, None]:
420+
def generator(self) -> Generator[bytes, None, None]:
420421
"""
421422
Generates a stream of audio data chunk.
422423
@@ -437,17 +438,17 @@ def generator(self) -> Generator[Dict[str, Union[bytes, int]], None, None]:
437438
if self._is_tts_active:
438439
continue
439440

440-
data = [chunk]
441-
442-
response = {
443-
"audio": base64.b64encode(b"".join(data)).decode("utf-8"),
441+
config = {
444442
"rate": self._rate,
445443
"language_code": self._language_code,
446444
"alternative_language_codes": self._alternative_language_codes,
447-
"timestamp": int(time.time()),
448445
}
446+
447+
config["timestamp"] = int(time.time() * 1000)
448+
header = json.dumps(config).encode("utf-8")
449+
response = struct.pack(">I", len(header)) + header + chunk
449450
for audio_callback in self._audio_data_callbacks:
450-
audio_callback(json.dumps(response))
451+
audio_callback(response)
451452

452453
yield response
453454

src/om1_speech/audio/audio_rtsp_input_stream.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
import json
33
import logging
44
import multiprocessing as mp
5+
import struct
56
import threading
67
import time
78
from queue import Empty, Full
8-
from typing import Callable, Dict, Generator, List, Optional, Union
9+
from typing import Callable, Generator, List, Optional, Union
910

1011
import av
1112
import numpy as np
@@ -414,7 +415,7 @@ def fill_buffer_remote(self, data: str):
414415
self._rate = rate
415416
self._language_code = language_code
416417

417-
def generator(self) -> Generator[Dict[str, Union[bytes, int]], None, None]:
418+
def generator(self) -> Generator[bytes, None, None]:
418419
"""
419420
Generates a stream of audio data chunk.
420421
@@ -435,17 +436,17 @@ def generator(self) -> Generator[Dict[str, Union[bytes, int]], None, None]:
435436
if self._is_tts_active:
436437
continue
437438

438-
data = [chunk]
439-
440-
response = {
441-
"audio": base64.b64encode(b"".join(data)).decode("utf-8"),
439+
config = {
442440
"rate": self._rate,
443441
"language_code": self._language_code,
444442
"alternative_language_codes": self._alternative_language_codes,
445-
"timestamp": int(time.time()),
446443
}
444+
445+
config["timestamp"] = int(time.time() * 1000)
446+
header = json.dumps(config).encode("utf-8")
447+
response = struct.pack(">I", len(header)) + header + chunk
447448
for audio_callback in self._audio_data_callbacks:
448-
audio_callback(json.dumps(response))
449+
audio_callback(response)
449450

450451
yield response
451452

tests/om1_speech/audio/test_audio_input_stream.py

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import base64
22
import json
33
import queue
4+
import struct
45
import threading
56
from unittest.mock import MagicMock, Mock, patch
67

@@ -146,7 +147,7 @@ def collect_data():
146147
audio_stream._buff.put(None)
147148

148149
assert len(collected_chunks) > 0
149-
assert all(isinstance(data, dict) for data in collected_chunks)
150+
assert all(isinstance(data, bytes) for data in collected_chunks)
150151

151152

152153
def test_stop(audio_stream, mock_pyaudio):
@@ -182,16 +183,17 @@ def test_callback(data):
182183
# Process one chunk through generator
183184
next(stream.generator())
184185

185-
# Verify callback was called with correct data
186-
assert callback_data == json.dumps(
187-
{
188-
"audio": base64.b64encode(test_data).decode("utf-8"),
189-
"rate": 16000,
190-
"language_code": "en-US",
191-
"alternative_language_codes": [],
192-
"timestamp": fixed_time,
193-
}
194-
)
186+
# Verify callback was called with binary header format
187+
assert isinstance(callback_data, bytes)
188+
header_len = struct.unpack(">I", callback_data[:4])[0]
189+
header = json.loads(callback_data[4 : 4 + header_len])
190+
audio = callback_data[4 + header_len :]
191+
192+
assert header["rate"] == 16000
193+
assert header["language_code"] == "en-US"
194+
assert header["alternative_language_codes"] == []
195+
assert header["timestamp"] == int(fixed_time * 1000)
196+
assert audio == test_data
195197

196198
stream.stop()
197199

@@ -258,10 +260,15 @@ def test_generator_with_alternative_languages(mock_pyaudio):
258260

259261
generated = next(stream.generator())
260262

261-
assert generated["language_code"] == "en-GB"
262-
assert generated["alternative_language_codes"] == alt_langs
263-
assert generated["audio"] == base64.b64encode(test_data).decode("utf-8")
264-
assert generated["rate"] == 16000
263+
assert isinstance(generated, bytes)
264+
header_len = struct.unpack(">I", generated[:4])[0]
265+
header = json.loads(generated[4 : 4 + header_len])
266+
audio = generated[4 + header_len :]
267+
268+
assert header["language_code"] == "en-GB"
269+
assert header["alternative_language_codes"] == alt_langs
270+
assert header["rate"] == 16000
271+
assert audio == test_data
265272

266273
stream.stop()
267274

@@ -318,15 +325,15 @@ def test_callback(data):
318325

319326
next(stream.generator())
320327

321-
expected_data = json.dumps(
322-
{
323-
"audio": base64.b64encode(test_data).decode("utf-8"),
324-
"rate": 16000,
325-
"language_code": "es-MX",
326-
"alternative_language_codes": alt_langs,
327-
"timestamp": fixed_time,
328-
}
329-
)
330-
assert callback_data == expected_data
328+
assert isinstance(callback_data, bytes)
329+
header_len = struct.unpack(">I", callback_data[:4])[0]
330+
header = json.loads(callback_data[4 : 4 + header_len])
331+
audio = callback_data[4 + header_len :]
332+
333+
assert header["rate"] == 16000
334+
assert header["language_code"] == "es-MX"
335+
assert header["alternative_language_codes"] == alt_langs
336+
assert header["timestamp"] == int(fixed_time * 1000)
337+
assert audio == test_data
331338

332339
stream.stop()

0 commit comments

Comments
 (0)