mirror of
https://github.com/damp11113/IDRB.git
synced 2025-04-27 22:48:09 +00:00
update 1.6.1 r2
change Zlib to LZ4 better settings encoder in server side
This commit is contained in:
parent
221fc180c3
commit
93bfe055db
Binary file not shown.
@ -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:
|
||||
|
@ -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()
|
@ -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()
|
||||
|
||||
|
BIN
Server/Samples/audiotest.wav
Normal file
BIN
Server/Samples/audiotest.wav
Normal file
Binary file not shown.
@ -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.
Binary file not shown.
Binary file not shown.
BIN
Server/__pycache__/tools.cpython-310.pyc
Normal file
BIN
Server/__pycache__/tools.cpython-310.pyc
Normal file
Binary file not shown.
@ -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
|
||||
|
||||
ENchannel2 = Encoder.channel2.get()
|
||||
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
141
Server/tools.py
Normal 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()
|
Loading…
x
Reference in New Issue
Block a user