Skip to content

Commit

Permalink
player: 更新大体布局,修正部分布局下的滚动问题
Browse files Browse the repository at this point in the history
player: 增加音质信息对话框
player: 支持更换播放列表的专辑图
player: 支持移动端导入音频和插件文件
player: 在安卓平台上保持屏幕常亮
player: 在 Windows 平台启用透明窗口
  • Loading branch information
Steve-xmh committed Oct 29, 2024
1 parent b39be4d commit cb1dcce
Show file tree
Hide file tree
Showing 39 changed files with 710 additions and 206 deletions.
78 changes: 59 additions & 19 deletions packages/player-core/src/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,15 +168,15 @@ fn get_buffer_format(decoded: &symphonia::core::audio::AudioBufferRef<'_>) -> &'
#[instrument(skip(output))]
fn init_audio_stream_inner<T: AudioOutputSample + Into<f64>>(
output: Device,
ring_buf_size_ms: usize,
selected_config: StreamConfig,
) -> Box<dyn AudioOutput> {
let channels = selected_config.channels;
const RING_BUF_SIZE_MS: usize = 50;
let ring_len =
((RING_BUF_SIZE_MS * selected_config.sample_rate.0 as usize) / 1000) * channels as usize;
((ring_buf_size_ms * selected_config.sample_rate.0 as usize) / 1000) * channels as usize;
info!(
"音频输出流环缓冲区大小为 {} 个样本(约为 {}ms 的缓冲)",
ring_len, RING_BUF_SIZE_MS
ring_len, ring_buf_size_ms
);
let ring = rb::SpscRb::<T>::new(ring_len);
let prod = ring.producer();
Expand Down Expand Up @@ -244,7 +244,11 @@ fn get_sample_format_quality_level(sample_format: SampleFormat) -> u8 {
}

#[instrument]
pub fn init_audio_player(output_device_name: &str) -> anyhow::Result<Box<dyn AudioOutput>> {
pub fn init_audio_player(
output_device_name: &str,
ring_buf_size_ms: Option<usize>,
) -> anyhow::Result<Box<dyn AudioOutput>> {
let ring_buf_size_ms = ring_buf_size_ms.unwrap_or(100);
let host = cpal::default_host();
let output = if output_device_name.is_empty() {
host.default_output_device().context("找不到默认输出设备")?
Expand Down Expand Up @@ -292,16 +296,32 @@ pub fn init_audio_player(output_device_name: &str) -> anyhow::Result<Box<dyn Aud
);

Ok((match selected_sample_format {
SampleFormat::I8 => init_audio_stream_inner::<i8>(output, selected_config),
SampleFormat::I16 => init_audio_stream_inner::<i16>(output, selected_config),
SampleFormat::I32 => init_audio_stream_inner::<i32>(output, selected_config),
// SampleFormat::I64 => init_audio_stream_inner::<i64>(output, selected_config),
SampleFormat::U8 => init_audio_stream_inner::<u8>(output, selected_config),
SampleFormat::U16 => init_audio_stream_inner::<u16>(output, selected_config),
SampleFormat::U32 => init_audio_stream_inner::<u32>(output, selected_config),
// SampleFormat::U64 => init_audio_stream_inner::<u64>(output, selected_config),
SampleFormat::F32 => init_audio_stream_inner::<f32>(output, selected_config),
SampleFormat::F64 => init_audio_stream_inner::<f64>(output, selected_config),
SampleFormat::I8 => {
init_audio_stream_inner::<i8>(output, ring_buf_size_ms, selected_config)
}
SampleFormat::I16 => {
init_audio_stream_inner::<i16>(output, ring_buf_size_ms, selected_config)
}
SampleFormat::I32 => {
init_audio_stream_inner::<i32>(output, ring_buf_size_ms, selected_config)
}
// SampleFormat::I64 => init_audio_stream_inner::<i64>(output, ring_buf_size_ms, selected_config),
SampleFormat::U8 => {
init_audio_stream_inner::<u8>(output, ring_buf_size_ms, selected_config)
}
SampleFormat::U16 => {
init_audio_stream_inner::<u16>(output, ring_buf_size_ms, selected_config)
}
SampleFormat::U32 => {
init_audio_stream_inner::<u32>(output, ring_buf_size_ms, selected_config)
}
// SampleFormat::U64 => init_audio_stream_inner::<u64>(output, ring_buf_size_ms, selected_config),
SampleFormat::F32 => {
init_audio_stream_inner::<f32>(output, ring_buf_size_ms, selected_config)
}
SampleFormat::F64 => {
init_audio_stream_inner::<f64>(output, ring_buf_size_ms, selected_config)
}
_ => unreachable!(),
}) as _)
}
Expand Down Expand Up @@ -339,6 +359,7 @@ impl AsAudioBufferRef for OwnedAudioBuffer {
enum AudioOutputMessage {
ClearBuffer,
ChangeOutput(String),
ChangeRingBufSize(usize),
SetVolume(f64),
}

Expand Down Expand Up @@ -421,7 +442,9 @@ pub fn create_audio_output_thread() -> AudioOutputSender {
});
let handle_c = handle.clone();
handle.spawn_blocking(move || {
let mut output = init_audio_player("").ok();
let mut output_name = "".to_string();
let mut ring_buf_size_ms = None;
let mut output = init_audio_player(&output_name, ring_buf_size_ms).ok();
let mut current_volume = 0.5;
if let Some(output) = &mut output {
output.set_volume(current_volume);
Expand Down Expand Up @@ -451,30 +474,47 @@ pub fn create_audio_output_thread() -> AudioOutputSender {
if let Some(output) = &mut output {
if output.is_dead() {
should_recrate = true;
output_name = "".to_string();
info!("现有输出设备已断开,正在重新初始化播放器");
} else {
output.write(pcm.as_audio_buffer_ref());
}
}
if should_recrate {
output = init_audio_player("").ok();
output = init_audio_player("", None).ok();
if let Some(output) = &mut output {
output.set_volume(current_volume);
output.stream().play().unwrap();
}
}
}
Some(PollResult::Msg(msg)) => match msg {
AudioOutputMessage::ChangeOutput(output_name) => {
match init_audio_player(&output_name) {
AudioOutputMessage::ChangeOutput(new_output_name) => {
match init_audio_player(&new_output_name, ring_buf_size_ms) {
Ok(mut new_output) => {
output_name = new_output_name;
new_output.set_volume(current_volume);
new_output.stream().play().unwrap();
output = Some(new_output);
info!("已切换输出设备")
}
Err(err) => {
warn!("无法切换到输出设备 {output_name}: {err}");
warn!("无法切换到输出设备 {new_output_name}: {err}");
output = None;
}
}
}
AudioOutputMessage::ChangeRingBufSize(new_size) => {
match init_audio_player(&output_name, Some(new_size)) {
Ok(mut new_output) => {
ring_buf_size_ms = Some(new_size);
new_output.set_volume(current_volume);
new_output.stream().play().unwrap();
output = Some(new_output);
info!("已切换输出设备(设置回环流大小)")
}
Err(err) => {
warn!("无法切换到输出设备(设置回环流大小) {output_name}: {err}");
output = None;
}
}
Expand Down
4 changes: 0 additions & 4 deletions packages/player/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<title>AMLL Player</title>
<style>
:root,
body {
background-color: #222;
}
</style>
</head>

Expand Down
42 changes: 27 additions & 15 deletions packages/player/locales/zh-CN/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@
"editMusicOverrideMessage": "编辑歌曲覆盖信息",
"exitLyricPage": "退出歌词页面"
},
"audioQuality": {
"title": "音频解码信息",
"codec": "音频解码器",
"channels": "音频通道数量",
"sampleRate": "采样率",
"sampleFormat": "采样率"
},
"qualityTag": {
"lossless": "无损",
"hires": "高解析度无损"
Expand All @@ -27,6 +34,22 @@
"noResults": "无结果"
}
},
"<0>音频解码信息</0>": "<0>音频解码信息</0>",
"common": {
"dialog": {
"close": "关闭",
"cancel": "取消",
"confirm": "确认",
"filter": {
"js": "JavaScript 文件 (*.js)",
"all": "全部文件 (*.*)"
},
"save": "保存"
},
"page": {
"back": "返回"
}
},
"extension": {
"inject": {
"error": {
Expand All @@ -48,21 +71,6 @@
"namePlaceholder": "歌单名称"
}
},
"common": {
"dialog": {
"cancel": "取消",
"confirm": "确认",
"close": "关闭",
"filter": {
"js": "JavaScript 文件 (*.js)",
"all": "全部文件 (*.*)"
},
"save": "保存"
},
"page": {
"back": "返回"
}
},
"playbar": {
"playlist": {
"title": "当前播放列表"
Expand Down Expand Up @@ -115,6 +123,10 @@
},
"label": "添加本地歌曲"
},
"cover": {
"changeCoverToAuto": "更换成自动封面",
"uploadCoverImage": "上传封面图片"
},
"totalMusicLabel": "{count, plural, other {#}} 首歌曲",
"playAll": "播放全部",
"shufflePlayAll": "随机播放"
Expand Down
4 changes: 4 additions & 0 deletions packages/player/src-tauri/capabilities/migrated.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ identifier = "shell:default"
[[permissions]]
identifier = "fs:default"
[[permissions]]
identifier = "fs:allow-write"
[[permissions]]
identifier = "fs:allow-app-write"
[[permissions]]
identifier = "fs:allow-rename"
[[permissions]]
identifier = "fs:allow-remove"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
package net.stevexmh.amllplayer

import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.provider.Settings
import android.view.WindowManager
import androidx.appcompat.app.AlertDialog
import androidx.core.view.WindowCompat

class MainActivity : TauriActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)
if (Build.VERSION.SDK_INT >= 30) {
if (!Environment.isExternalStorageManager()) {
AlertDialog.Builder(this).setTitle(R.string.all_files_access_required_title)
.setMessage(R.string.all_files_access_required_text)
.setPositiveButton(R.string.all_files_access_required_go_to_setting) { _, _ ->
startActivity(Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION))
}.setNegativeButton(R.string.all_files_access_required_ignore) { _, _ ->

}.setCancelable(true).create().show()
}
}
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="all_files_access_required_text">请在设置中启用完全存储访问权限,否则本地音乐将无法正确加载。\n如果您只使用 AMLL Player 的 WS Protocol 功能,则可以忽略此提示。</string>
<string name="all_files_access_required_title">需要完全存储访问权限</string>
<string name="all_files_access_required_go_to_setting">前往设置</string>
<string name="all_files_access_required_ignore">忽略</string>
</resources>
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
<resources>
<string name="app_name">AMLL Player</string>
<string name="main_activity_title">AMLL Player</string>
<string name="app_name" translatable="false">AMLL Player</string>
<string name="main_activity_title" translatable="false">AMLL Player</string>
<string name="all_files_access_required_text">Please enable full storage access for this app in the settings. Or local music won\'t be loaded properly.\nYou can ignored this if you are just use AMLL Player for WS Protocol.</string>
<string name="all_files_access_required_title">Full Storage Access Required</string>
<string name="all_files_access_required_go_to_setting">Go to Settings</string>
<string name="all_files_access_required_ignore">Ignore</string>
</resources>
19 changes: 18 additions & 1 deletion packages/player/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ use serde_json::Value;
use std::sync::RwLock;
use std::{net::SocketAddr, path::Path};
use symphonia::core::io::{MediaSourceStream, MediaSourceStreamOptions};
use tauri::{AppHandle, Manager, PhysicalSize, Runtime, Size, State, Theme, WebviewWindowBuilder};
use tauri::{
utils::config::WindowEffectsConfig, window::Effect, AppHandle, Manager, PhysicalSize, Runtime,
Size, State, Theme, WebviewWindowBuilder,
};
use tauri_plugin_fs::OpenOptions;
use tracing::*;

Expand Down Expand Up @@ -144,6 +147,20 @@ fn recreate_window(app: &AppHandle) {
let win = win
.center()
.inner_size(800.0, 600.0)
.effects(WindowEffectsConfig {
effects: vec![Effect::Tabbed, Effect::Mica],
..Default::default()
})
.transparent({
#[cfg(target_os = "windows")]
{
true
}
#[cfg(not(target_os = "windows"))]
{
false
}
})
.title({
#[cfg(target_os = "macos")]
{
Expand Down
3 changes: 2 additions & 1 deletion packages/player/src/App.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
--default-font-family: var(--amll-font-family);
--code-font-family: "Menlo", "Consolas (Custom)", "Bitstream Vera Sans Mono",
var(--amll-font-family), monospace, "Apple Color Emoji", "Segoe UI Emoji";
--color-panel-solid: var(--color-panel-translucent);
}

.container {
Expand Down Expand Up @@ -39,5 +40,5 @@
height: 100vh;
pointer-events: none;
opacity: 0;
background-color: #000;
/* background-color: #000; */
}
Loading

0 comments on commit cb1dcce

Please sign in to comment.