Skip to content

Commit 8d20ecb

Browse files
committed
Chunk size/streaming tweaks
1 parent 2b5ed83 commit 8d20ecb

File tree

2 files changed

+24
-15
lines changed

2 files changed

+24
-15
lines changed

dlna.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
This module provides the HTTP request handler for a DLNA media server,
55
implementing the necessary DLNA and UPnP protocols for media streaming.
66
"""
7+
78
import html
89
import traceback
910
import os
11+
import socket
1012
import struct
1113
import subprocess
1214
import uuid
@@ -116,6 +118,11 @@ def setup(self):
116118
super().setup()
117119
# Set socket timeout to prevent hanging connections
118120
self.connection.settimeout(self.timeout)
121+
# Set TCP_NODELAY on the socket
122+
self.connection.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
123+
buffer_size = 32 * 1024 * 1024 # 32MB buffer
124+
self.connection.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, buffer_size)
125+
self.connection.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, buffer_size)
119126

120127
def log_message(self, format, *args): # pylint: disable=redefined-builtin
121128
"""Override BaseHTTPRequestHandler's log_message to only log when verbose mode is enabled"""
@@ -843,7 +850,7 @@ def serve_media_file(self, filename, head_only=False):
843850
if self.verbose:
844851
print(f"MEDIA ACCESS: {self.path} from {client_addr}")
845852
print(f"MEDIA HEADERS: {dict(self.headers)}")
846-
853+
847854
# Set the current playing file for DLNA clients
848855
# Get filename after the last slash for display
849856
self.now_playing = os.path.basename(decoded_filename)
@@ -985,9 +992,7 @@ def serve_media_file(self, filename, head_only=False):
985992
try:
986993
with open(file_path, "rb") as f:
987994
# Use larger chunks for better performance with large files
988-
chunk_size = (
989-
65536 # 64KB chunks for better streaming performance
990-
)
995+
chunk_size = 512 * 1024 # 512KB chunks
991996

992997
# Set a timeout for socket operations to prevent blocking
993998
self.wfile.flush()
@@ -1138,7 +1143,7 @@ def handle_range_request(self, file_path, file_size, mime_type, range_header):
11381143

11391144
# Use smaller chunks for range requests to improve resume/seek performance
11401145
# Large chunks can cause choppy playback when resuming video
1141-
base_chunk_size = 8192 # 8KB base chunk size for range requests
1146+
base_chunk_size = 512 * 1024 # 512KB
11421147

11431148
while remaining > 0:
11441149
# For range requests, use smaller chunks for better streaming
@@ -2049,8 +2054,10 @@ def _get_media_duration(self, file_path, mime_type):
20492054
}
20502055

20512056
# Try to get duration using ffprobe if available (skip if fast mode is enabled)
2052-
if not self.fast and mime_type and (
2053-
mime_type.startswith("video/") or mime_type.startswith("audio/")
2057+
if (
2058+
not self.fast
2059+
and mime_type
2060+
and (mime_type.startswith("video/") or mime_type.startswith("audio/"))
20542061
):
20552062
try:
20562063
# Try ffprobe first (most reliable)

ssdp.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import time
1212
import struct
1313
import select
14+
1415
try:
1516
from .constants import (
1617
SERVER_AGENT,
@@ -137,7 +138,6 @@ def _handle_request(self, data, addr):
137138
def _send_search_response(self, addr, search_target="upnp:rootdevice"):
138139
"""Send response to M-SEARCH request"""
139140
location = f"http://{self.server_instance.server_ip}:{self.server_instance.port}/description.xml"
140-
141141
# Determine the appropriate ST and USN based on search target
142142
if search_target.lower() == "upnp:rootdevice":
143143
st = "upnp:rootdevice"
@@ -158,17 +158,19 @@ def _send_search_response(self, addr, search_target="upnp:rootdevice"):
158158
st = "upnp:rootdevice"
159159
usn = f"uuid:{self.server_instance.device_uuid}::upnp:rootdevice"
160160

161+
# Build response using f-strings
162+
current_date = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime())
161163
response = (
162-
"HTTP/1.1 200 OK\r\n"
163-
"CACHE-CONTROL: max-age=1800\r\n"
164-
"DATE: {}\r\n"
164+
f"HTTP/1.1 200 OK\r\n"
165+
f"CACHE-CONTROL: max-age=1800\r\n"
166+
f"DATE: {current_date}\r\n"
165167
f"EXT:\r\n"
166168
f"LOCATION: {location}\r\n"
167169
f"SERVER: {SERVER_AGENT}\r\n"
168170
f"ST: {st}\r\n"
169171
f"USN: {usn}\r\n"
170172
"\r\n"
171-
).format(time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()))
173+
)
172174

173175
try:
174176
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
@@ -252,7 +254,7 @@ def _send_notify_alive(self):
252254
sock.sendto(message.encode(), (self.MULTICAST_IP, self.MULTICAST_PORT))
253255
time.sleep(0.1) # Small delay between messages
254256
sock.close()
255-
257+
256258
self.notify_count += 1
257259
if self.verbose:
258260
print(f"Sent SSDP NOTIFY alive messages (#{self.notify_count})")
@@ -313,11 +315,11 @@ def _periodic_notify(self):
313315
else:
314316
# After first 30 messages: send every 60 seconds (1 minute)
315317
sleep_time = 60
316-
318+
317319
for _ in range(sleep_time):
318320
if not self.running:
319321
return
320322
time.sleep(1)
321-
323+
322324
if self.running:
323325
self._send_notify_alive()

0 commit comments

Comments
 (0)