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 from pyogg import OpusDecoder
import configparser import configparser
import ctypes import ctypes
import zlib import lz4.frame
from utils import * from utils import *
import appcomponent import appcomponent
@ -40,7 +40,7 @@ class App:
self.config = configparser.ConfigParser() self.config = configparser.ConfigParser()
self.config.read("config.ini") self.config.read("config.ini")
self.device_name_output = self.config["audio"]["device"] 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.working = False
self.readchannel = 1 self.readchannel = 1
@ -396,7 +396,7 @@ class App:
break break
try: try:
decompressed_data = zlib.decompress(data) decompressed_data = lz4.frame.decompress(data)
datadecoded = pickle.loads(decompressed_data) datadecoded = pickle.loads(decompressed_data)
except: 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 You should have received a copy of the GNU General Public License
along with IDRB Project. If not, see <https://www.gnu.org/licenses/>. along with IDRB Project. If not, see <https://www.gnu.org/licenses/>.
""" """
import threading import threading
from queue import Queue from queue import Queue
from pyogg import OpusBufferedEncoder
import numpy as np
import pyaudio import pyaudio
import RDS as _RDS import RDS as _RDS
import logging import logging
import tools
EncoderLog = logging.getLogger("Encoder") EncoderLog = logging.getLogger("Encoder")
@ -37,64 +35,28 @@ for i in range(p.get_device_count()):
device_index_input = dev['index'] device_index_input = dev['index']
break 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 # Create a shared queue for encoded audio packets
channel1 = Queue() channel1 = Queue()
channel2 = Queue() channel2 = Queue()
# Function to continuously encode audio and put it into the queue channel1option = {
def encode_audio(): "Bitrates": 64000,
encoder = OpusBufferedEncoder() "DeviceInputIndex": device_index_input
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)
while True: channel2option = {
pcm = np.frombuffer(streaminput.read(1024, exception_on_overflow=False), dtype=np.int16) "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(): EncoderChannel2 = tools.AudioEncoder(_RDS.RDS2, channel2option, channel2, "wav")
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
def StartEncoder(): def StartEncoder():
EncoderLog.info("Starting encoder") EncoderLog.info("Starting encoder")
audio_thread = threading.Thread(target=encode_audio)
audio_thread2 = threading.Thread(target=encode_audio2)
audio_thread.start() EncoderChannel1.startencoder()
audio_thread2.start() EncoderChannel2.startencoder()

View File

@ -19,7 +19,7 @@ import time
from datetime import datetime from datetime import datetime
import cv2 import cv2
import numpy as np import numpy as np
from damp11113 import scrollTextBySteps from damp11113.utils import scrollTextBySteps
import threading import threading
import Settings import Settings
import logging import logging
@ -96,12 +96,6 @@ RDS = {
"AS": [ # AS = Alternative Server "AS": [ # AS = Alternative Server
# can add more server here # can add more server here
], ],
"ContentInfo": {
"Codec": "opus",
"bitrate": 64000,
"channel": 2,
"samplerates": 48000
},
"images": { "images": {
"logo": { "logo": {
"lazy": False, "lazy": False,
@ -145,12 +139,6 @@ RDS2 = {
"AS": [ # AS = Alternative Server "AS": [ # AS = Alternative Server
# can add more server here # can add more server here
], ],
"ContentInfo": {
"Codec": "Opus",
"bitrate": 8000,
"channel": 2,
"samplerates": 48000
},
"images": { "images": {
"logo": None "logo": None
} }
@ -194,5 +182,5 @@ def startRDSThread():
thread.start() thread.start()
thread2.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/>. 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 Muxer you need to goto server.py and find "Config Muxer"
# To config RDS you need to goto RDS.py # To config RDS you need to goto RDS.py
# To config Encoder you need to goto Encoder.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 # Server Settings
protocol = "ZMQ_WS" # TCP ZMQ ZMQ_WS protocol = "ZMQ_WS" # TCP ZMQ ZMQ_WS
server_port = ('*', 6980) # if use other protocol ZMQ please use 0.0.0.0 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) buffersize = 32 # must be int (on working it use buffersize + (buffersize/2) to standby)
# low buffersize = low delay # 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 6. copy api key
""" """
public = True public = False
#ServerIP = "IDRB.damp11113.xyz" # do not add protocol before ip #ServerIP = "IDRB.damp11113.xyz" # do not add protocol before ip
ServerIP = "localhost" ServerIP = "localhost"
#ServerPort = server_port[1] #ServerPort = server_port[1]
ServerPort = 6980 ServerPort = 6980
<<<<<<< HEAD ThaiSDRkey = "1N5LURICLIN1U9QNYZ4MHJ6FNXISFXFELZAX135CFM0HSD17O2.63E60BE9EEA2339C113A15EB"
ThaiSDRkey = ""
=======
ThaiSDRkey = ""
>>>>>>> 53163be3dc12010715271f6020a0c07d2af720ec

Binary file not shown.

View File

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