update 1.6.1 r2

change Zlib to LZ4

better settings encoder in server side
This commit is contained in:
dharm pimsen 2024-02-28 19:30:10 +07:00
parent 221fc180c3
commit 93bfe055db
12 changed files with 174 additions and 79 deletions

View File

@ -28,7 +28,7 @@ import zmq
from pyogg import OpusDecoder
import configparser
import ctypes
import zlib
import lz4.frame
from utils import *
import appcomponent
@ -40,7 +40,7 @@ class App:
self.config = configparser.ConfigParser()
self.config.read("config.ini")
self.device_name_output = self.config["audio"]["device"]
self.buffersize = self.config["network"]["buffersize"]
self.buffersize = int(self.config["network"]["buffersize"])
self.working = False
self.readchannel = 1
@ -396,7 +396,7 @@ class App:
break
try:
decompressed_data = zlib.decompress(data)
decompressed_data = lz4.frame.decompress(data)
datadecoded = pickle.loads(decompressed_data)
except:

View File

@ -14,14 +14,12 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with IDRB Project. If not, see <https://www.gnu.org/licenses/>.
"""
import threading
from queue import Queue
from pyogg import OpusBufferedEncoder
import numpy as np
import pyaudio
import RDS as _RDS
import logging
import tools
EncoderLog = logging.getLogger("Encoder")
@ -37,64 +35,28 @@ for i in range(p.get_device_count()):
device_index_input = dev['index']
break
device_name_input = "Line 4 (Virtual Audio Cable)"
device_index_input2 = 0
for i in range(p.get_device_count()):
dev = p.get_device_info_by_index(i)
if dev['name'] == device_name_input:
device_index_input2 = dev['index']
break
streaminput = p.open(format=pyaudio.paInt16, channels=2, rate=48000, input=True, input_device_index=device_index_input)
streaminput2 = p.open(format=pyaudio.paInt16, channels=2, rate=48000, input=True, input_device_index=device_index_input2)
# Create a shared queue for encoded audio packets
channel1 = Queue()
channel2 = Queue()
# Function to continuously encode audio and put it into the queue
def encode_audio():
encoder = OpusBufferedEncoder()
encoder.set_application("audio")
encoder.set_sampling_frequency(_RDS.RDS["ContentInfo"]["samplerates"])
encoder.set_channels(_RDS.RDS["ContentInfo"]["channel"])
encoder.set_bitrates(_RDS.RDS["ContentInfo"]["bitrate"])
encoder.set_frame_size(60)
encoder.set_bitrate_mode("VBR")
encoder.set_compresion_complex(10)
channel1option = {
"Bitrates": 64000,
"DeviceInputIndex": device_index_input
}
while True:
pcm = np.frombuffer(streaminput.read(1024, exception_on_overflow=False), dtype=np.int16)
channel2option = {
"Bitrates": 18000,
"InputWAVFile": "./Samples/audiotest.wav"
}
encoded_packets = encoder.buffered_encode(memoryview(bytearray(pcm)))
for encoded_packet, _, _ in encoded_packets:
# Put the encoded audio into the buffer
channel1.put(encoded_packet.tobytes())
EncoderChannel1 = tools.AudioEncoder(_RDS.RDS, channel1option, channel1)
def encode_audio2():
encoder2 = OpusBufferedEncoder()
encoder2.set_application("audio")
encoder2.set_sampling_frequency(_RDS.RDS2["ContentInfo"]["samplerates"])
encoder2.set_channels(_RDS.RDS2["ContentInfo"]["channel"])
encoder2.set_bitrates(_RDS.RDS2["ContentInfo"]["bitrate"])
encoder2.set_frame_size(60)
while True:
pcm2 = np.frombuffer(streaminput2.read(1024, exception_on_overflow=False), dtype=np.int16)
encoded_packets = encoder2.buffered_encode(memoryview(bytearray(pcm2)))
for encoded_packet, _, _ in encoded_packets:
# Put the encoded audio into the buffer
channel2.put(encoded_packet.tobytes())
#channel2.put(pcm2.tobytes()) # if you use pcm
EncoderChannel2 = tools.AudioEncoder(_RDS.RDS2, channel2option, channel2, "wav")
def StartEncoder():
EncoderLog.info("Starting encoder")
audio_thread = threading.Thread(target=encode_audio)
audio_thread2 = threading.Thread(target=encode_audio2)
audio_thread.start()
audio_thread2.start()
EncoderChannel1.startencoder()
EncoderChannel2.startencoder()

View File

@ -19,7 +19,7 @@ import time
from datetime import datetime
import cv2
import numpy as np
from damp11113 import scrollTextBySteps
from damp11113.utils import scrollTextBySteps
import threading
import Settings
import logging
@ -96,12 +96,6 @@ RDS = {
"AS": [ # AS = Alternative Server
# can add more server here
],
"ContentInfo": {
"Codec": "opus",
"bitrate": 64000,
"channel": 2,
"samplerates": 48000
},
"images": {
"logo": {
"lazy": False,
@ -145,12 +139,6 @@ RDS2 = {
"AS": [ # AS = Alternative Server
# can add more server here
],
"ContentInfo": {
"Codec": "Opus",
"bitrate": 8000,
"channel": 2,
"samplerates": 48000
},
"images": {
"logo": None
}
@ -194,5 +182,5 @@ def startRDSThread():
thread.start()
thread2.start()
thread3.start()
#thread3.start()

Binary file not shown.

View File

@ -15,6 +15,8 @@ You should have received a copy of the GNU General Public License
along with IDRB Project. If not, see <https://www.gnu.org/licenses/>.
"""
import lz4.frame
# To config Muxer you need to goto server.py and find "Config Muxer"
# To config RDS you need to goto RDS.py
# To config Encoder you need to goto Encoder.py
@ -23,7 +25,7 @@ along with IDRB Project. If not, see <https://www.gnu.org/licenses/>.
# Server Settings
protocol = "ZMQ_WS" # TCP ZMQ ZMQ_WS
server_port = ('*', 6980) # if use other protocol ZMQ please use 0.0.0.0
compression_level = 9 # 0-9
compression_level = lz4.frame.COMPRESSIONLEVEL_MAX
buffersize = 32 # must be int (on working it use buffersize + (buffersize/2) to standby)
# low buffersize = low delay
@ -42,13 +44,9 @@ If you want your server to be listed publicly on ThaiSDR Directory, following th
6. copy api key
"""
public = True
public = False
#ServerIP = "IDRB.damp11113.xyz" # do not add protocol before ip
ServerIP = "localhost"
#ServerPort = server_port[1]
ServerPort = 6980
<<<<<<< HEAD
ThaiSDRkey = ""
=======
ThaiSDRkey = ""
>>>>>>> 53163be3dc12010715271f6020a0c07d2af720ec
ThaiSDRkey = "1N5LURICLIN1U9QNYZ4MHJ6FNXISFXFELZAX135CFM0HSD17O2.63E60BE9EEA2339C113A15EB"

Binary file not shown.

View File

@ -21,9 +21,13 @@ import pickle
import threading
import zmq
import logging
import zlib
import lz4.frame
import queue
import math
import os
os.environ["damp11113_load_all_module"] = "NO"
os.environ["damp11113_check_update"] = "NO"
logging.basicConfig(level=logging.INFO, format='[%(asctime)s] [%(name)s] [%(levelname)s] %(message)s')
ServerLog = logging.getLogger("IDRBServer")
@ -88,8 +92,10 @@ def Muxer():
# ENC1encrypted, ENC1salt, ENC1iv = utils.encrypt_data(ENchannel1, "password")
# ENchannel1 = ENC1encrypted + b'|||||' + ENC1salt + b'|||||' + ENC1iv
try:
ENchannel2 = Encoder.channel2.get()
except:
ENchannel2 = b""
content = {
"first": False,
"mainchannel": 1,
@ -119,7 +125,7 @@ def Muxer():
}
ThaiSDRDir.content = content
compressedcontent = zlib.compress(pickle.dumps(content), level=Settings.compression_level)
compressedcontent = lz4.frame.compress(pickle.dumps(content), compression_level=Settings.compression_level)
Buffer.put(compressedcontent)

141
Server/tools.py Normal file
View File

@ -0,0 +1,141 @@
"""
This file is part of IDRB Project.
IDRB Project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
IDRB Project is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with IDRB Project. If not, see <https://www.gnu.org/licenses/>.
"""
import socket
import time
from pyogg import OpusBufferedEncoder
import numpy as np
import pyaudio
import wave
import threading
from damp11113.randoms import rannum
class AudioEncoder:
def __init__(self, RDS: dict, option: dict, queuebuffer, audioinputtype="device", audiocodec="opus", standalone=False):
self.audiocodec = audiocodec.upper()
self.audioinput = audioinputtype.upper()
self.RDS = RDS
self.option = option
self.buffer = queuebuffer
self.running = False
self.encoder = None
self.standalone = standalone
self.runningthread = threading.Thread(target=self._running)
self.sourceinput = None
self._temp_ip = None
self._temp_port = None
self._temp_socket = None
def _createencoder(self):
self.RDS.update({
"ContentInfo": {
"Codec": self.audiocodec,
"bitrate": self.option.get("Bitrates", 64000),
"channel": self.option.get("Channel", 2),
"samplerates": self.option.get("SamplesRates", 48000)
}
})
if self.audiocodec == "PCM":
pass
elif self.audiocodec == "OPUS":
self.encoder = OpusBufferedEncoder()
self.encoder.set_application("audio")
self.encoder.set_sampling_frequency(self.option.get("SamplesRates", 48000))
self.encoder.set_channels(self.option.get("Channel", 2))
self.encoder.set_bitrates(self.option.get("Bitrates", 64000))
self.encoder.set_frame_size(self.option.get("opusFrameSize", 60))
self.encoder.set_bitrate_mode(self.option.get("BitrateMode", "VBR").upper())
self.encoder.set_compresion_complex(self.option.get("opusCompressionLevel", 10))
def _createaudiosource(self):
if self.audioinput == "DEVICE":
p = pyaudio.PyAudio()
self.sourceinput = p.open(format=pyaudio.paInt16, channels=self.option.get("Channel", 2), rate=self.option.get("SamplesRates", 48000), input=True, input_device_index=self.option.get("DeviceInputIndex", 0))
elif self.audioinput == "WAV":
file = self.option.get("InputWAVFile", "")
if file == "":
raise "No Audio wav Input Please use option 'InputWAVFile' to set wav file path"
self.sourceinput = wave.open(file, "rb")
elif self.audioinput == "SOCKET":
IP = self.option.get("InputSocketIP", "0.0.0.0")
Port = self.option.get("InputSocketPort", rannum(12000, 12300))
self._temp_ip = IP
self._temp_port = Port
self._temp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._temp_socket.bind((IP, Port))
else:
raise "No Audio Device Supported"
def _running(self):
framesize = self.option.get("InputFrameSize", 1024)
samplesrates = self.option.get("SamplesRates", 48000)
while self.running:
# get audio
if self.audioinput == "DEVICE":
pcm = np.frombuffer(self.sourceinput.read(framesize, exception_on_overflow=False), dtype=np.int16)
elif self.audioinput == "WAV":
pcm = np.frombuffer(self.sourceinput.readframes(framesize * 2), dtype=np.int16)
if len(pcm) == 0:
self.sourceinput.rewind()
if self.standalone:
time.sleep(framesize / samplesrates)
elif self.audioinput == "SOCKET":
pcm = np.frombuffer(self.sourceinput.recv(framesize), dtype=np.int16)
else:
raise "no input data support"
# encode audio
if self.audiocodec == "PCM":
self.buffer.put(pcm.tobytes())
elif self.audiocodec == "OPUS":
encoded_packets = self.encoder.buffered_encode(memoryview(bytearray(pcm)))
for encoded_packet, _, _ in encoded_packets:
self.buffer.put(encoded_packet.tobytes())
def startencoder(self):
self._createaudiosource()
self._createencoder()
if self.audioinput == "SOCKET":
self._temp_socket.listen(2)
print(f"[Socket Input Beta] {self.__class__.__name__} audio incoming server is running on {self._temp_ip}:{self._temp_port}. (PCM Data only)")
print(f"[Socket Input Beta] {self.__class__.__name__} waiting for data for start encoder")
self.sourceinput, addr = self._temp_socket.accept()
print(f"[Socket Input Beta] {self.__class__.__name__} {addr} is connected. encoder is starting")
self._temp_socket.settimeout(self.option.get("InputSocketTimeout", 0.1))
self.running = True
self.runningthread.start()
def stopencoder(self):
self.running = False
self.runningthread.join()