2023-2024年度总结

时间过的真快啊,一年又要过完了。还是要记录一下这一年的成长和收获,以及对未来的展望。

今年的行情很不好,不管是就业还是A股市场。虽说疫情已经放开管控,可不见经济快速的复苏,身边讨论的更多的是裁员、领“大礼包”。年中,公司也经历了两次裁员,自己也在反思要保持什么样的状态才能在这个时代生存下去。

今年做了哪些事情呢?

看电影

目前为数不多的爱好了,应该有三十几部。

Read More

北京游玩总攻略

很小的时候就希望能去北京看看,看看古时候皇帝生活的地方,看看为了抵御外敌而修建的万里长城,看看皇帝的陵墓。那就做一份北京游玩攻略吧。以下从游住吃三个方面来介绍。推荐自由行

门票预约

!!!!!作为自由行,一定要提前预约门票,万一没约到门票,将会打乱所有计划。

北京各景区放票时间:

  • 毛记:提前6天12:00
Read More

flutter_sound

Flutter中音频的处理库,可以用来播放、录制。播放支持主流的格式,支持网络地址。

播放音频

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

import 'package:flutter_sound/flutter_sound.dart';
import 'package:xtechpark/ws_utils/ws_log/ws_logger.dart';

class WSAudioPlayer {
factory WSAudioPlayer() => _getInstance();

static WSAudioPlayer get instance => _getInstance();
static WSAudioPlayer? _instance;

WSAudioPlayer._internal();

static WSAudioPlayer _getInstance() {
_instance ??= WSAudioPlayer._internal();
return _instance!;
}

FlutterSoundPlayer? _player;

Future init() async {
_player = FlutterSoundPlayer();

await _player?.openPlayer().then((value) {
WSLogger.debug('WSAudioPlayer init ');
});
await _player?.setSubscriptionDuration(const Duration(milliseconds: 100));
_player?.onProgress?.listen((event) {
WSLogger.debug('WSAudioPlayer onProgress ${event.duration}');
});
}

Future play(String url, [Function()? onFinished]) async {
if (_player == null) {
await init();
}
if (_player?.playerState == PlayerState.isPlaying) {
await stop();
}
return _player?.startPlayer(fromURI: url, codec: Codec.mp3, whenFinished: onFinished);
}

Future stop() async {
await _player?.stopPlayer();
}
}


录制音频

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import 'dart:io';

import 'package:audio_session/audio_session.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_sound/flutter_sound.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:xtechpark/ws_utils/ws_file_util.dart';
import 'package:xtechpark/ws_utils/ws_log/ws_logger.dart';
import 'package:xtechpark/ws_utils/ws_toast_util.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter_sound_platform_interface/flutter_sound_recorder_platform_interface.dart';

class WSAudioRecorder {
factory WSAudioRecorder() => _getInstance();

static WSAudioRecorder get instance => _getInstance();
static WSAudioRecorder? _instance;

WSAudioRecorder._internal();

static WSAudioRecorder _getInstance() {
_instance ??= WSAudioRecorder._internal();
return _instance!;
}

FlutterSoundRecorder? _recorder;
final Codec _codec = Codec.aacADTS;
String _mPath = 'temp.aac';

/// 录音时长
Duration? duration;

/// 初始化
Future init() async {
_recorder = FlutterSoundRecorder();
await openTheRecorder();
}

/// 释放
dispose() {
_recorder?.closeRecorder();
_recorder = null;
}

/// 初始化配置
Future<void> openTheRecorder() async {
var status = await Permission.microphone.request();
if (status != PermissionStatus.granted) {
WSToastUtil.show('Microphone permission not granted');
return;
}
await _recorder?.openRecorder();
final session = await AudioSession.instance;
await session.configure(AudioSessionConfiguration(
avAudioSessionCategory: AVAudioSessionCategory.playAndRecord,
avAudioSessionCategoryOptions:
AVAudioSessionCategoryOptions.allowBluetooth | AVAudioSessionCategoryOptions.defaultToSpeaker,
avAudioSessionMode: AVAudioSessionMode.spokenAudio,
avAudioSessionRouteSharingPolicy: AVAudioSessionRouteSharingPolicy.defaultPolicy,
avAudioSessionSetActiveOptions: AVAudioSessionSetActiveOptions.none,
androidAudioAttributes: const AndroidAudioAttributes(
contentType: AndroidAudioContentType.speech,
flags: AndroidAudioFlags.none,
usage: AndroidAudioUsage.voiceCommunication,
),
androidAudioFocusGainType: AndroidAudioFocusGainType.gain,
androidWillPauseWhenDucked: true,
));

_recorder?.dispositionStream()?.listen((event) {
WSLogger.debug('debug dispositionStream:$event');
});

_recorder?.setSubscriptionDuration(const Duration(milliseconds: 100));
_recorder?.onProgress?.listen((e) {
WSLogger.debug("debug onProgress:${e.decibels} / ${e.duration}");
duration = e.duration;
});
// _mRecorderIsInited = true;
}

void startRecord() async {
if(_recorder == null) {
await init();
}
if(_recorder?.recorderState == RecorderState.isRecording) {
await _recorder?.stopRecorder();
return;
}
WSLogger.debug("debug startRecord");
var status = await Permission.microphone.request();
if (status != PermissionStatus.granted) {
WSToastUtil.show("Microphone permission not granted");
} else {
Directory tempDir = await getTemporaryDirectory();
_mPath = "${tempDir.path}/${DateTime.now().millisecondsSinceEpoch}.aac";
_recorder?.startRecorder(
toFile: _mPath,
codec: _codec,
audioSource: AudioSource.microphone,
);

WSLogger.debug("debug recording");
}
}

/// 停止录音
void stopRecord(Function(String path, int duration) finished) async {
String? path = await _recorder?.stopRecorder();
if (path == null) {
WSToastUtil.show('record failed');
WSLogger.error('record failed ${_recorder?.recorderState}');
return;
}
if(!await WSFileUtil.isFileExists(path)) {
WSToastUtil.show('record failed');
return;
}
if(duration != null && duration!.inSeconds < 1) {
WSToastUtil.show('recording can\'t be less than 1 second');
return;
}
WSLogger.debug("Stop recording: path = $path,duration = ${duration?.inSeconds}");
if (TargetPlatform.android == defaultTargetPlatform) {
path = "file://$path";
}
finished(path, duration?.inSeconds ?? 0);
}
}

Read More