添加直播按钮
This commit is contained in:
parent
ed9d9ceb9c
commit
0289dafd1c
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -17,14 +17,27 @@ android {
|
|||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
debug {
|
||||
// 调试版本优化
|
||||
isMinifyEnabled = false
|
||||
isDebuggable = true
|
||||
}
|
||||
release {
|
||||
// 发布版本优化
|
||||
isMinifyEnabled = true
|
||||
isShrinkResources = true
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 编译优化
|
||||
dexOptions {
|
||||
javaMaxHeapSize = "2g"
|
||||
preDexLibraries = true
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@
|
|||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.LiveStreaming"
|
||||
android:usesCleartextTraffic="true">
|
||||
android:usesCleartextTraffic="true"
|
||||
android:hardwareAccelerated="true"
|
||||
android:largeHeap="true">
|
||||
|
||||
<activity
|
||||
android:name="com.example.livestreaming.FishPondActivity"
|
||||
|
|
@ -37,7 +39,9 @@
|
|||
|
||||
<activity
|
||||
android:name="com.example.livestreaming.MainActivity"
|
||||
android:exported="true">
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:screenOrientation="portrait">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
|
|
|
|||
|
|
@ -53,6 +53,15 @@ public class MainActivity extends AppCompatActivity {
|
|||
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
// 立即显示缓存数据,提升启动速度
|
||||
setupRecyclerView();
|
||||
setupUI();
|
||||
|
||||
// 异步加载资源文件,避免阻塞主线程
|
||||
loadCoverAssetsAsync();
|
||||
}
|
||||
|
||||
private void setupRecyclerView() {
|
||||
adapter = new RoomsAdapter(room -> {
|
||||
if (room == null) return;
|
||||
Intent intent = new Intent(MainActivity.this, RoomDetailActivity.class);
|
||||
|
|
@ -64,9 +73,12 @@ public class MainActivity extends AppCompatActivity {
|
|||
glm.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS);
|
||||
binding.roomsRecyclerView.setLayoutManager(glm);
|
||||
binding.roomsRecyclerView.setAdapter(adapter);
|
||||
|
||||
// 立即显示演示数据,提升用户体验
|
||||
adapter.submitList(buildDemoRooms(6));
|
||||
}
|
||||
|
||||
loadCoverAssets();
|
||||
|
||||
private void setupUI() {
|
||||
binding.swipeRefresh.setOnRefreshListener(this::fetchRooms);
|
||||
|
||||
binding.roomsRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
||||
|
|
@ -95,6 +107,9 @@ public class MainActivity extends AppCompatActivity {
|
|||
}
|
||||
});
|
||||
|
||||
// 设置添加直播按钮点击事件
|
||||
binding.fabAddLive.setOnClickListener(v -> showCreateRoomDialog());
|
||||
|
||||
BottomNavigationView bottomNavigation = binding.bottomNavInclude.bottomNavigation;
|
||||
bottomNavigation.setSelectedItemId(R.id.nav_home);
|
||||
bottomNavigation.setOnItemSelectedListener(item -> {
|
||||
|
|
@ -151,9 +166,11 @@ public class MainActivity extends AppCompatActivity {
|
|||
stopPolling();
|
||||
pollRunnable = () -> {
|
||||
fetchRooms();
|
||||
handler.postDelayed(pollRunnable, 5000);
|
||||
// 增加轮询间隔,减少网络请求频率
|
||||
handler.postDelayed(pollRunnable, 10000);
|
||||
};
|
||||
handler.post(pollRunnable);
|
||||
// 延迟首次请求,让界面先显示
|
||||
handler.postDelayed(pollRunnable, 1000);
|
||||
}
|
||||
|
||||
private void stopPolling() {
|
||||
|
|
@ -210,9 +227,13 @@ public class MainActivity extends AppCompatActivity {
|
|||
dialog.dismiss();
|
||||
fetchRooms();
|
||||
|
||||
Intent intent = new Intent(MainActivity.this, RoomDetailActivity.class);
|
||||
intent.putExtra(RoomDetailActivity.EXTRA_ROOM_ID, room.getId());
|
||||
startActivity(intent);
|
||||
// 显示推流信息
|
||||
showStreamInfo(room);
|
||||
|
||||
// 可选:跳转到房间详情
|
||||
// Intent intent = new Intent(MainActivity.this, RoomDetailActivity.class);
|
||||
// intent.putExtra(RoomDetailActivity.EXTRA_ROOM_ID, room.getId());
|
||||
// startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -321,22 +342,31 @@ public class MainActivity extends AppCompatActivity {
|
|||
return list;
|
||||
}
|
||||
|
||||
private void loadCoverAssets() {
|
||||
AssetManager am = getAssets();
|
||||
List<String> files = new ArrayList<>();
|
||||
try {
|
||||
String[] list = am.list("img");
|
||||
if (list != null) {
|
||||
for (String f : list) {
|
||||
if (f == null) continue;
|
||||
String lower = f.toLowerCase();
|
||||
if (lower.endsWith(".png") || lower.endsWith(".jpg") || lower.endsWith(".jpeg") || lower.endsWith(".webp") || lower.endsWith(".gif")) {
|
||||
files.add(f);
|
||||
private void loadCoverAssetsAsync() {
|
||||
// 在后台线程加载资源文件,避免阻塞UI
|
||||
new Thread(() -> {
|
||||
AssetManager am = getAssets();
|
||||
List<String> files = new ArrayList<>();
|
||||
try {
|
||||
String[] list = am.list("img");
|
||||
if (list != null) {
|
||||
for (String f : list) {
|
||||
if (f == null) continue;
|
||||
String lower = f.toLowerCase();
|
||||
if (lower.endsWith(".png") || lower.endsWith(".jpg") || lower.endsWith(".jpeg") || lower.endsWith(".webp") || lower.endsWith(".gif")) {
|
||||
files.add(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
adapter.setCoverAssetFiles(files);
|
||||
|
||||
// 回到主线程更新UI
|
||||
runOnUiThread(() -> {
|
||||
if (adapter != null) {
|
||||
adapter.setCoverAssetFiles(files);
|
||||
}
|
||||
});
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,8 +38,25 @@ public class PlayerActivity extends AppCompatActivity {
|
|||
|
||||
triedAltUrl = false;
|
||||
|
||||
ExoPlayer exo = new ExoPlayer.Builder(this).build();
|
||||
// 创建低延迟播放器配置
|
||||
ExoPlayer exo = new ExoPlayer.Builder(this)
|
||||
.setLoadControl(new androidx.media3.exoplayer.DefaultLoadControl.Builder()
|
||||
// 减少缓冲区大小,降低延迟
|
||||
.setBufferDurationsMs(
|
||||
1000, // 最小缓冲时长 1秒
|
||||
3000, // 最大缓冲时长 3秒
|
||||
500, // 播放缓冲时长 0.5秒
|
||||
1000 // 播放后缓冲时长 1秒
|
||||
)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
// 设置播放器视图
|
||||
binding.playerView.setPlayer(exo);
|
||||
|
||||
// 启用低延迟模式
|
||||
binding.playerView.setUseController(true);
|
||||
binding.playerView.setControllerAutoShow(false);
|
||||
|
||||
String altUrl = getAltHlsUrl(url);
|
||||
exo.addListener(new Player.Listener() {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ public final class ApiClient {
|
|||
|
||||
OkHttpClient client = new OkHttpClient.Builder()
|
||||
.addInterceptor(logging)
|
||||
.connectTimeout(5, java.util.concurrent.TimeUnit.SECONDS)
|
||||
.readTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
|
||||
.writeTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
|
||||
.build();
|
||||
|
||||
retrofit = new Retrofit.Builder()
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@ public class Room {
|
|||
@SerializedName("isLive")
|
||||
private boolean isLive;
|
||||
|
||||
@SerializedName("viewerCount")
|
||||
private int viewerCount;
|
||||
|
||||
@SerializedName("streamUrls")
|
||||
private StreamUrls streamUrls;
|
||||
|
||||
|
|
@ -58,6 +61,10 @@ public class Room {
|
|||
this.streamUrls = streamUrls;
|
||||
}
|
||||
|
||||
public void setViewerCount(int viewerCount) {
|
||||
this.viewerCount = viewerCount;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
|
@ -82,12 +89,17 @@ public class Room {
|
|||
return streamUrls;
|
||||
}
|
||||
|
||||
public int getViewerCount() {
|
||||
return viewerCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof Room)) return false;
|
||||
Room room = (Room) o;
|
||||
return isLive == room.isLive
|
||||
&& viewerCount == room.viewerCount
|
||||
&& Objects.equals(id, room.id)
|
||||
&& Objects.equals(title, room.title)
|
||||
&& Objects.equals(streamerName, room.streamerName)
|
||||
|
|
@ -97,6 +109,6 @@ public class Room {
|
|||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, title, streamerName, streamKey, isLive, streamUrls);
|
||||
return Objects.hash(id, title, streamerName, streamKey, isLive, viewerCount, streamUrls);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -212,6 +212,17 @@
|
|||
android:visibility="gone"
|
||||
/>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fabAddLive"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
android:layout_marginBottom="88dp"
|
||||
android:contentDescription="添加直播"
|
||||
android:src="@drawable/ic_add_24"
|
||||
app:backgroundTint="@color/purple_500"
|
||||
app:tint="@android:color/white" />
|
||||
|
||||
<include
|
||||
android:id="@+id/bottomNavInclude"
|
||||
layout="@layout/include_bottom_nav"
|
||||
|
|
|
|||
|
|
@ -1,48 +1,82 @@
|
|||
# SRS 配置文件 - 直播系统
|
||||
listen 1935;
|
||||
max_connections 1000;
|
||||
daemon off;
|
||||
srs_log_tank console;
|
||||
|
||||
# 全局优化配置
|
||||
# 减少缓冲区大小,降低延迟
|
||||
mr_enabled off;
|
||||
# 启用快速启动
|
||||
fast_cache 10;
|
||||
# 优化TCP配置
|
||||
tcp_nodelay on;
|
||||
|
||||
http_server {
|
||||
enabled on;
|
||||
listen 8080;
|
||||
dir ./objs/nginx/html;
|
||||
# 启用跨域支持
|
||||
crossdomain on;
|
||||
}
|
||||
|
||||
http_api {
|
||||
enabled on;
|
||||
listen 1985;
|
||||
# 启用跨域支持
|
||||
crossdomain on;
|
||||
}
|
||||
|
||||
stats {
|
||||
network 0;
|
||||
}
|
||||
|
||||
vhost __defaultVhost__ {
|
||||
# HLS 配置
|
||||
# RTMP 配置 - 优化延迟
|
||||
rtmp {
|
||||
enabled on;
|
||||
# 减少缓冲区大小,降低延迟
|
||||
chunk_size 4096;
|
||||
}
|
||||
|
||||
# HLS 配置 - 优化延迟
|
||||
hls {
|
||||
enabled on;
|
||||
hls_fragment 2;
|
||||
hls_window 10;
|
||||
hls_path ./objs/nginx/html;
|
||||
hls_m3u8_file [app]/[stream].m3u8;
|
||||
hls_ts_file [app]/[stream]-[seq].ts;
|
||||
# 减少分片时长,降低延迟
|
||||
hls_fragment 2;
|
||||
hls_window 6;
|
||||
# 启用低延迟模式
|
||||
hls_dispose 30;
|
||||
}
|
||||
|
||||
# HTTP-FLV 配置 (低延迟)
|
||||
# HTTP-FLV 配置 - 低延迟播放
|
||||
http_remux {
|
||||
enabled on;
|
||||
mount [app]/[stream].flv;
|
||||
mount [vhost]/[app]/[stream].flv;
|
||||
# 启用快速启动
|
||||
fast_cache 10;
|
||||
}
|
||||
|
||||
# HTTP 回调配置
|
||||
http_hooks {
|
||||
enabled on;
|
||||
on_publish http://host.docker.internal:3001/api/srs/on_publish;
|
||||
on_unpublish http://host.docker.internal:3001/api/srs/on_unpublish;
|
||||
# 转码配置(可选)
|
||||
transcode {
|
||||
enabled off;
|
||||
}
|
||||
|
||||
# GOP 缓存,提高首屏速度
|
||||
# 播放配置 - 优化延迟
|
||||
play {
|
||||
gop_cache on;
|
||||
# 减少GOP缓存
|
||||
gop_cache off;
|
||||
# 启用时间校正
|
||||
time_jitter full;
|
||||
# 减少队列长度
|
||||
queue_length 10;
|
||||
}
|
||||
|
||||
# 发布配置 - 优化延迟
|
||||
publish {
|
||||
# 减少首帧等待时间
|
||||
firstpkt_timeout 20000;
|
||||
# 减少正常包超时
|
||||
normal_timeout 5000;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user