How to stop D/AudioTrack that working all the time
D/AudioTrack( 4586): [audioTrackData][fine] 55s(f:55205 m:985 s:0 k:0) : pid 4586 uid 10080 sessionId 12681 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 55s(f:55196 m:979 s:0 k:0) : pid 4586 uid 10080 sessionId 12665 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 55s(f:55203 m:983 s:0 k:0) : pid 4586 uid 10080 sessionId 12625 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 55s(f:55194 m:979 s:0 k:0) : pid 4586 uid 10080 sessionId 12617 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 55s(f:55176 m:979 s:0 k:0) : pid 4586 uid 10080 sessionId 12633 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 55s(f:55179 m:956 s:0 k:0) : pid 4586 uid 10080 sessionId 12609 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 55s(f:55177 m:972 s:1 k:0) : pid 4586 uid 10080 sessionId 12593 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 55s(f:55178 m:958 s:0 k:0) : pid 4586 uid 10080 sessionId 12689 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 55s(f:55199 m:968 s:0 k:0) : pid 4586 uid 10080 sessionId 12705 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 60s(f:60196 m:948 s:0 k:0) : pid 4586 uid 10080 sessionId 12513 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 60s(f:60217 m:953 s:0 k:0) : pid 4586 uid 10080 sessionId 12553 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 45s(f:45175 m:983 s:0 k:0) : pid 4586 uid 10080 sessionId 12257 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 60s(f:60256 m:974 s:0 k:0) : pid 4586 uid 10080 sessionId 12657 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 60s(f:60218 m:985 s:0 k:0) : pid 4586 uid 10080 sessionId 12681 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 60s(f:60216 m:979 s:0 k:0) : pid 4586 uid 10080 sessionId 12665 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 60s(f:60216 m:983 s:0 k:0) : pid 4586 uid 10080 sessionId 12625 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 60s(f:60205 m:979 s:0 k:0) : pid 4586 uid 10080 sessionId 12617 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 60s(f:60186 m:972 s:1 k:0) : pid 4586 uid 10080 sessionId 12593 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 60s(f:60186 m:979 s:0 k:0) : pid 4586 uid 10080 sessionId 12633 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 60s(f:60187 m:958 s:0 k:0) : pid 4586 uid 10080 sessionId 12689 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 60s(f:60189 m:956 s:0 k:0) : pid 4586 uid 10080 sessionId 12609 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 60s(f:60216 m:968 s:0 k:0) : pid 4586 uid 10080 sessionId 12705 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 5s(f:5019 m:948 s:0 k:0) : pid 4586 uid 10080 sessionId 12513 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 5s(f:5019 m:953 s:0 k:0) : pid 4586 uid 10080 sessionId 12553 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 50s(f:50198 m:983 s:0 k:0) : pid 4586 uid 10080 sessionId 12257 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 5s(f:5021 m:974 s:0 k:0) : pid 4586 uid 10080 sessionId 12657 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 5s(f:5017 m:985 s:0 k:0) : pid 4586 uid 10080 sessionId 12681 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 5s(f:5017 m:979 s:0 k:0) : pid 4586 uid 10080 sessionId 12665 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 5s(f:5019 m:983 s:0 k:0) : pid 4586 uid 10080 sessionId 12625 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 5s(f:5018 m:979 s:0 k:0) : pid 4586 uid 10080 sessionId 12617 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 5s(f:5010 m:972 s:1 k:0) : pid 4586 uid 10080 sessionId 12593 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 5s(f:5011 m:958 s:0 k:0) : pid 4586 uid 10080 sessionId 12689 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 5s(f:5012 m:979 s:0 k:0) : pid 4586 uid 10080 sessionId 12633 sr 16000 ch 1 fmt 1 D/AudioTrack( 4586): [audioTrackData][fine] 5s(f:5010 m:956 s:0 k:0) : pid 4586 uid 10080 sessionId 12609 sr 16000 ch 1 fmt 1
Dear Everyone, Please help me, I want to stop D/AudioTrack when I finish playing voice and It makes my app crash.
@MetaTouchDev Can you please share reproducible code so that we can help you debug the issue?
class PlayerWaveWidget extends StatefulWidget {
String pathVoice = '';
PlayerWaveWidget({super.key, required this.pathVoice});
@override
State<PlayerWaveWidget> createState() => _PlayerWaveWidgetState();
}
class _PlayerWaveWidgetState extends State<PlayerWaveWidget> {
final PlayerController playerController = PlayerController();
bool isPlay = false;
void _playAndPause() async {
if (playerController.playerState.isPlaying) {
isPlay = false;
await playerController.pausePlayer();
} else {
isPlay = true;
await playerController.startPlayer();
await playerController.setFinishMode(finishMode: FinishMode.pause);
playerController.onCompletion.listen((onStop) async {
await playerController.pausePlayer();
isPlay = false;
setState(() {});
});
}
// setState(() {});
// await playerController.preparePlayer(path: widget.pathVoice);
}
@override
void initState() {
// TODO: implement initState
initView();
super.initState();
}
@override
void dispose() {
// TODO: implement dispose
playerController.pausePlayer();
playerController.stopPlayer();
playerController.pauseAllPlayers();
playerController.release();
playerController.dispose();
super.dispose();
}
initView() async {
// downloadAudioFromUrl(widget.pathVoice);
try {
// Get the directory to store the file (ensure to request permissions if needed)
final directory = await getTemporaryDirectory();
final filePath =
'${directory.path}/voice_${DateTime.now().millisecondsSinceEpoch}.mp3';
// Use http to download the file
final response = await http.get(Uri.parse(widget.pathVoice));
if (response.statusCode == 200) {
// Write the file to the local storage
final file = File(filePath);
await file.writeAsBytes(response.bodyBytes);
// await player.play(DeviceFileSource(filePath));
await playerController.preparePlayer(
path: filePath,
shouldExtractWaveform: true,
noOfSamples: 80,
);
} else {}
} catch (e) {
print("Error downloading voice: $e");
}
}
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(left: 10, bottom: 10),
child: Row(
children: [
Container(
height: 70,
decoration: const BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(10), // Adjust the radius as needed
topLeft: Radius.circular(10),
),
color: Colors.blue,
),
child: IconButton(
onPressed: () async {
_playAndPause();
setState(() {});
playerController.onCompletion.listen((onStop) async {
await playerController.pausePlayer();
isPlay = false;
setState(() {});
});
},
icon: Icon(
isPlay ? Icons.pause_circle : Icons.play_circle,
color: Colors.white,
)),
),
AudioFileWaveforms(
continuousWaveform: false,
enableSeekGesture: true,
size: Size(MediaQuery.of(context).size.width / 1.55, 70),
playerController: playerController,
waveformType: WaveformType.fitWidth,
animationCurve: Curves.easeIn,
clipBehavior: Clip.none,
decoration: const BoxDecoration(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(10), // Adjust the radius as needed
topRight: Radius.circular(10),
),
color: Colors.blue,
),
playerWaveStyle: PlayerWaveStyle(
fixedWaveColor: Colors.grey.shade300,
seekLineThickness: 3,
waveThickness: 1.5,
spacing: 3,
liveWaveColor: Colors.white,
waveCap: StrokeCap.round,
),
),
],
),
);
}
}
class ChatBubbleScreen extends StatefulWidget {
const ChatBubbleScreen({super.key});
@override
State<ChatBubbleScreen> createState() => _ChatBubbleScreenState();
}
class _ChatBubbleScreenState extends State<ChatBubbleScreen> {
final ScrollController _scrollController = ScrollController();
final FocusNode _focusNode = FocusNode();
final ChatHistoryController chatHistoryController =
Get.put(ChatHistoryController());
final TextEditingController _textController = TextEditingController();
late io.Socket socket;
late RecorderController recorderController;
ValueNotifier<bool> _isButtonVisible = ValueNotifier(true);
ValueNotifier<bool> _isLoading = ValueNotifier(false);
int page = 1;
bool isFetchingPreviousPage = false;
@override
void initState() {
super.initState();
recorderController = RecorderController()
..androidEncoder = AndroidEncoder.aac
..androidOutputFormat = AndroidOutputFormat.mpeg4
..iosEncoder = IosEncoder.kAudioFormatMPEG4AAC
..sampleRate = 16000;
_focusNode.addListener(_scrollToBottom);
_fetchChatHistory();
_scrollController.addListener(_scrollListener);
}
void _scrollListener() {
if (_scrollController.position.pixels ==
_scrollController.position.minScrollExtent &&
!isFetchingPreviousPage) {
_loadPreviousPage();
}
bool shouldHideButton = _scrollController.position.pixels ==
_scrollController.position.maxScrollExtent;
if (_isButtonVisible.value != !shouldHideButton) {
_isButtonVisible.value = !shouldHideButton;
}
}
Future<void> _loadPreviousPage() async {
if (isFetchingPreviousPage) return;
isFetchingPreviousPage = true;
_isLoading.value = true;
await Future.delayed(const Duration(milliseconds: 500)); // Debounce
page++;
await _fetchChatHistory();
_isLoading.value = false;
isFetchingPreviousPage = false;
}
Future<void> _fetchChatHistory() async {
print("📥 Fetching Chat History for Page: $page");
await chatHistoryController.getChatHistory(
uniqueRoom: 'sdfdsf', page: page);
print("✅ Chat History Fetched");
}
void _scrollToBottom() {
Future.delayed(const Duration(milliseconds: 300), () {
if (_scrollController.hasClients) {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent + 100,
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
}
});
}
@override
void dispose() {
_focusNode.removeListener(_scrollToBottom);
_focusNode.dispose();
socket.disconnect();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const CustomAppBar(title: 'Chat App'),
body: GestureDetector(
onTap: () => FocusScope.of(context).requestFocus(FocusNode()),
child: Stack(
children: [
Column(
children: [
ValueListenableBuilder<bool>(
valueListenable: _isLoading,
builder: (context, isLoading, child) {
return isLoading
? const Center(child: CircularProgressIndicator())
: const SizedBox();
},
),
Expanded(
child: Obx(() {
final chatList = chatHistoryController.listChat.reversed
.toList(); // Reverse the list for displaying the latest messages at the bottom.
return ListView.separated(
controller: _scrollController,
padding: const EdgeInsets.symmetric(vertical: 10),
itemCount: chatList.length,
itemBuilder: (context, index) {
final chat = chatList[index];
final decryptedText = AES256CBC.decryptText(chat.value);
String formattedDate = DateFormat('yyyy-MM-dd')
.format(DateTime.parse(chat.date));
bool showDateChip = index == 0 ||
formattedDate !=
DateFormat('yyyy-MM-dd').format(
DateTime.parse(chatList[index - 1].date));
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (showDateChip)
DateChip(date: DateTime.parse(chat.date)),
ChatBubbleItem(
chat: chat,
decryptedText: decryptedText,
isSender: true,
recorderController: recorderController,
),
],
);
},
separatorBuilder: (_, __) => const SizedBox(height: 5),
);
}),
),
ChatInputField(
focusNode: _focusNode,
textViewController: _textController,
recorderController: recorderController,
onRecordingStateChange: () async {
final path = await recorderController.stop();
if (path != null && path.isNotEmpty) {}
},
textViewStateChange: () async {},
),
],
),
ValueListenableBuilder<bool>(
valueListenable: _isButtonVisible,
builder: (context, isVisible, child) {
return Visibility(
visible: isVisible,
child: Align(
alignment: Alignment.bottomCenter,
child: Container(
margin: EdgeInsets.only(bottom: 60),
height: 30,
width: 30,
child: FloatingActionButton(
onPressed: _scrollToBottom,
backgroundColor: Colors.grey,
child: const Icon(Icons.keyboard_arrow_down_rounded),
),
),
),
);
},
),
],
),
),
);
}
}
class ChatInputField extends StatefulWidget {
final FocusNode focusNode;
final RecorderController recorderController;
final VoidCallback onRecordingStateChange; // Add callback to update state
final VoidCallback textViewStateChange; // Add callback to update state
final TextEditingController textViewController;
const ChatInputField({
super.key,
required this.focusNode,
required this.textViewController,
required this.recorderController,
required this.onRecordingStateChange,
required this.textViewStateChange,
});
@override
_ChatInputFieldState createState() => _ChatInputFieldState();
}
class _ChatInputFieldState extends State<ChatInputField> {
bool isTyping = false;
bool isRecording = false;
@override
void initState() {
super.initState();
widget.textViewController.addListener(() {
setState(() {
isTyping = widget.textViewController.text.trim().isNotEmpty;
});
});
widget.focusNode.addListener(() {
if (widget.focusNode.hasFocus) {
Future.delayed(const Duration(milliseconds: 300), _scrollToBottom);
}
});
}
void _scrollToBottom() {
if (mounted) {
Scrollable.ensureVisible(context,
duration: const Duration(milliseconds: 300));
}
}
Future<void> _startRecording() async {
try {
await widget.recorderController.record();
setState(() => isRecording = true);
} catch (e) {
debugPrint("Error starting recording: $e");
}
}
Future<void> _stopRecording() async {
try {
final path = await widget.recorderController.stop();
setState(() => isRecording = false);
// debugPrint("Recording saved at: $path");
// Handle sending the recorded file
} catch (e) {
debugPrint("Error stopping recording: $e");
}
}
// This function will trigger the state update and call the parent's onPressed callback
void voiceCallBackOnPress() async {
setState(() {
isRecording = !isRecording; // Toggle recording state
});
if (isRecording) {
_startRecording();
} else {
_stopRecording();
}
// Call the parent callback to trigger state update
widget.onRecordingStateChange();
}
void textViewCallBackOnPress() async {
widget.textViewStateChange();
widget.textViewController.clear();
}
@override
void dispose() {
widget.recorderController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 10, left: 5, right: 5),
child: ClipRRect(
borderRadius: BorderRadius.circular(25), // Rounded corners
child: Container(
decoration: BoxDecoration(
color: Colors.grey[200], // Background color
borderRadius: BorderRadius.circular(25),
),
// padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 5),
child: Row(
children: [
Expanded(
child: isRecording
? ClipRRect(
borderRadius: BorderRadius.circular(25),
child: Container(
color: Colors.grey[100],
child: AudioWaveforms(
enableGesture: true,
size: Size(MediaQuery.sizeOf(context).width,
50), // Full width
recorderController: widget.recorderController,
waveStyle: const WaveStyle(
waveColor: Colors.blueAccent,
showMiddleLine: false,
extendWaveform: true,
),
),
),
)
: AppTextField(
controller: widget.textViewController,
focusNode: widget.focusNode,
contentPadding: const EdgeInsets.symmetric(
vertical: 10, horizontal: 10),
hintText: 'Message',
boxConstraints: const BoxConstraints(
maxHeight: 80,
minHeight: 40,
),
prefixIcon: !isTyping
? Padding(
padding: const EdgeInsets.all(5),
child: Container(
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(25),
),
child: const Icon(
Icons.camera_alt,
color: Colors.white,
),
),
)
: null,
),
),
if (!isTyping && !isRecording) ...[
IconButton(
onPressed: () async {
// Open Gallery
},
icon: const Icon(Icons.photo, color: Colors.blue),
),
IconButton(
onPressed: _startRecording,
icon: const Icon(Icons.keyboard_voice_rounded,
color: Colors.blue),
),
] else if (isRecording) ...[
IconButton(
onPressed: voiceCallBackOnPress,
icon: const Icon(Icons.stop, color: Colors.red),
),
IconButton(
onPressed: _stopRecording,
icon: const Icon(Icons.close, color: Colors.black),
),
] else ...[
IconButton(
onPressed: textViewCallBackOnPress,
icon: const Icon(Icons.send, color: Colors.blue),
),
],
],
),
),
),
);
}
}
Dear Mr,
My code is above, but you can customize and add voice in Listview.
The issue is when I try to voice a lot and scroll up and down and it makes my app crash.
Device: Xiaomi (Redmi K50Gaming or Poco F4GT) Version: Android 13
Thank you.