Я не могу открыть свой микрофон мобильных приложений FlutterAndroid

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Я не могу открыть свой микрофон мобильных приложений Flutter

Сообщение Anonymous »

Я хотел сделать видео и не видео в моем приложении. В видеозвонках нет проблем, но микрофон физически не открывается как на страницах вызовов видео, так и на не-видео. Эмблема зеленого микрофона в разделе уведомлений на устройствах Android 12+ не появляется. Я подумываю сделать эту систему поиска самостоятельно, используя Socket_io и Flutter_Webrtc. Что мне делать? Я не думаю, что в фоновом режиме возникают проблемы. Когда я пробую камеру в приложении, проблем нет, но есть проблема с микрофоном, она вообще не открывается.import 'package:flutter/material.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:socket_io_client/socket_io_client.dart' as IO;
import 'package:permission_handler/permission_handler.dart';

class CallScreen extends StatefulWidget {
final String callerId;
final String callerName;
final String receiverId;
final String receiverName;
final IO.Socket socket;
final bool isCaller;

const CallScreen({
Key? key,
required this.callerId,
required this.callerName,
required this.receiverId,
required this.receiverName,
required this.socket,
required this.isCaller,
}) : super(key: key);

@override
State createState() => _CallScreenState();
}

class _CallScreenState extends State {
late IO.Socket socket;
RTCPeerConnection? _peerConnection;
MediaStream? _localStream;
MediaStream? _remoteStream;
final RTCVideoRenderer _localRenderer = RTCVideoRenderer();
final RTCVideoRenderer _remoteRenderer = RTCVideoRenderer();

bool isMicOn = true;
bool isSpeakerOn = true;

@override
void initState() {
super.initState();
socket = widget.socket;
_initCall();
}

Future _initCall() async {
await _checkMicPermissionBeforeCall();
await _initRenderers();
await _setupPeerConnection();
debugPrint('✅ PeerConnection & local stream hazır');

socket.emit('join', widget.callerId);
socket.emit('join', widget.receiverId);
_registerSocketHandlers();

if (widget.isCaller) {
debugPrint('🚀 Teklif (offer) oluşturuluyor…');
await _startCall();
}
}

Future _checkMicPermissionBeforeCall() async {
if (!await Permission.microphone.request().isGranted) {
debugPrint('❌ Mikrofon izni aktif değil!');
// Burada kullanıcıyı bilgilendiren bir dialog açabilirsiniz.
} else {
debugPrint('✅ Mikrofon izni aktif');
}
}

Future _initRenderers() async {
await _localRenderer.initialize();
await _remoteRenderer.initialize();
}

void _registerSocketHandlers() {
socket.on('offer', _onOffer);
socket.on('answer', _onAnswer);
socket.on('accepted', _onAccepted);
socket.on('ice-candidate', _onIceCandidate);
socket.on('call-cancelled', _onCallCancelled);
}

void _unregisterSocketHandlers() {
socket.off('offer', _onOffer);
socket.off('answer', _onAnswer);
socket.off('accepted', _onAccepted);
socket.off('ice-candidate', _onIceCandidate);
socket.off('call-cancelled', _onCallCancelled);
}

Future _setupPeerConnection() async {
// 1) Lokal audio stream
_localStream = await navigator.mediaDevices.getUserMedia({
'audio': true,
'video': false,
});
_localRenderer.srcObject = _localStream;
debugPrint('🎤 Lokal stream alındı');

// 2) PeerConnection oluştur
final config = {
'iceServers': [
{'urls': 'stun:stun.l.google.com:19302'},
{
'urls': 'turn:openrelay.metered.ca:80',
'username': 'openrelayproject',
'credential': 'openrelayproject'
},
]
};
_peerConnection = await createPeerConnection(config);
debugPrint('🔌 PeerConnection oluşturuldu');

// 3) Track ekle
for (var track in _localStream!.getTracks()) {
await _peerConnection!.addTrack(track, _localStream!);
}

// 4) Remote track geldiğinde renderer’a ata
_peerConnection!.onTrack = (RTCTrackEvent event) {
if (event.streams.isNotEmpty) {
setState(() {
_remoteStream = event.streams[0];
_remoteRenderer.srcObject = _remoteStream;
});
debugPrint('📺 Remote stream geldi');
}
};

// 5) ICE adaylarını signalling server’a gönder
_peerConnection!.onIceCandidate = (RTCIceCandidate c) {
debugPrint('❄️ ICE candidate: ${c.candidate}');
socket.emit('ice-candidate', {
'roomId': widget.isCaller ? widget.receiverId : widget.callerId,
'candidate': {
'candidate': c.candidate,
'sdpMid': c.sdpMid,
'sdpMLineIndex': c.sdpMLineIndex,
},
});
};

// Opsiyonel loglar
_peerConnection!.onConnectionState = (s) => debugPrint('📡 connection state: $s');
_peerConnection!.onIceConnectionState = (s) => debugPrint('❄️ ICE state: $s');
_peerConnection!.onSignalingState = (s) => debugPrint('📶 Signaling state: $s');
}

Future _startCall() async {
final offer = await _peerConnection!.createOffer();
await _peerConnection!.setLocalDescription(offer);
socket.emit('offer', {
'roomId': widget.receiverId,
'offer': {'sdp': offer.sdp, 'type': offer.type},
'callerId': widget.callerId,
'callerName': widget.callerName,
});
debugPrint('📤 Offer emit edildi');
}

Future _onOffer(dynamic payload) async {
if (widget.isCaller) return;
final data = (payload is List && payload.isNotEmpty) ? payload[0] : payload;
debugPrint('📥 Offer alındı: ${data['sdp']}');
await _peerConnection!.setRemoteDescription(
RTCSessionDescription(data['sdp'], data['type'])
);
final answer = await _peerConnection!.createAnswer();
await _peerConnection!.setLocalDescription(answer);
socket.emit('answer', {
'roomId': widget.callerId,
'answer': {'sdp': answer.sdp, 'type': answer.type},
});
socket.emit('accepted', widget.callerId);
debugPrint('📤 Answer emit edildi');
}

Future _onAnswer(dynamic payload) async {
if (!widget.isCaller) return;
final data = (payload is List && payload.isNotEmpty) ? payload[0] : payload;
debugPrint('📥 Answer alındı: ${data['sdp']}');
await _peerConnection!.setRemoteDescription(
RTCSessionDescription(data['sdp'], data['type'])
);
}

Future _onAccepted(dynamic _) async {
if (!widget.isCaller) return;
debugPrint('📩 Karşı taraf kabul etti');
}

Future _onIceCandidate(dynamic payload) async {
final data = (payload is List && payload.isNotEmpty) ? payload[0] : payload;
final cand = RTCIceCandidate(
data['candidate'], data['sdpMid'], data['sdpMLineIndex']
);
await _peerConnection?.addCandidate(cand);
debugPrint('❄️ ICE candidate eklendi');
}

Future _onCallCancelled(dynamic _) async {
// Çağrı iptal edildi, temizleyip başa dön
_cleanupAndExit();
}

void _endCall() {
socket.emit(
'cancel-call',
widget.isCaller ? widget.receiverId : widget.callerId,
);
_cleanupAndExit();
}

void _cleanupAndExit() {
// 1) Stream ve PeerConnection’ı durdur / kapat
_localStream?.getTracks().forEach((t) => t.stop());
_peerConnection?.close();

// 2) Navigation: en baştaki route’a dön
if (mounted) {
Navigator.of(context).popUntil((route) => route.isFirst);
}
}

@override
void dispose() {
_unregisterSocketHandlers();
_localStream?.dispose();
_remoteStream?.dispose();
_peerConnection?.dispose();
_localRenderer.dispose();
_remoteRenderer.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
final otherName = widget.isCaller ? widget.receiverName : widget.callerName;
return Scaffold(
backgroundColor: Colors.black87,
body: SafeArea(
child: Column(
children: [
SizedBox(height: 10),
Expanded(child: RTCVideoView(_remoteRenderer)),
SizedBox(height: 10),
SizedBox(
height: 120,
child: RTCVideoView(_localRenderer, mirror: true),
),
SizedBox(height: 20),
Text(
'$otherName ile görüşülüyor...',
style: TextStyle(color: Colors.white, fontSize: 20),
),
Spacer(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
// Mikrofon toggle
IconButton(
icon: Icon(
isMicOn ? Icons.mic : Icons.mic_off,
color: Colors.white,
),
onPressed: () {
setState(() => isMicOn = !isMicOn);
final audioTrack = _localStream?.getAudioTracks().first;
if (audioTrack != null) {
audioTrack.enabled = isMicOn;
debugPrint(
'🎙 Mikrofon şimdi ${isMicOn ? "açık" : "kapalı"}'
);
}
},
),
// Çağrıyı bitir
IconButton(
icon: Icon(Icons.call_end, color: Colors.red),
onPressed: _endCall,
),
// Hoparlör toggle
IconButton(
icon: Icon(
isSpeakerOn ? Icons.volume_up : Icons.hearing,
color: Colors.white,
),
onPressed: () {
setState(() => isSpeakerOn = !isSpeakerOn);
Helper.setSpeakerphoneOn(isSpeakerOn);
},
),
],
),
SizedBox(height: 40),
],
),
),
);
}
} ElevatedButton.icon(
icon: const Icon(Icons.call),
label: const Text('Ara'),
onPressed: () async {
final prefs = await SharedPreferences.getInstance();
final vid = prefs.getString('user_id') ?? '';
final vname = prefs.getString('user_name') ?? '';
if (vid.isEmpty || vname.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
'Kullanıcı bilgileri eksik. Giriş yapın.'),
),
);
return;
}
final socket = IO.io(
'http://192-----',
IO.OptionBuilder()
.setTransports(['websocket'])
.disableAutoConnect()
.build(),
);
socket.connect();
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => CallScreen(
callerId: vid,
callerName: vname,
receiverId: _selectedGuide!['_id'] as String,
receiverName: _selectedGuide!['name'] as String,
socket: socket,
isCaller: true,
),
),
);
},import 'package:socket_io_client/socket_io_client.dart' as IO;
import 'package:flutter_application_1/services/api.dart';

class SignalingService {
late IO.Socket _socket;

void connect() {
_socket = IO.io(
Api.socketUrl,
IO.OptionBuilder()
.setTransports(['websocket'])
.disableAutoConnect()
.build(),
);

_socket.connect();

_socket.onConnect((_) {
print('✅ WebSocket bağlandı: ${_socket.id}');
});

_socket.onDisconnect((_) {
print('🔌 WebSocket bağlantısı kesildi');
});
}

void joinRoom(String roomId) {
_socket.emit('join', roomId);
}

void sendOffer(String roomId, dynamic offer) {
_socket.emit('offer', {'roomId': roomId, 'offer': offer});
}

void sendAnswer(String roomId, dynamic answer) {
_socket.emit('answer', {'roomId': roomId, 'answer': answer});
}

void sendCandidate(String roomId, dynamic candidate) {
_socket.emit('ice-candidate', {'roomId': roomId, 'candidate': candidate});
}

void onOffer(Function(dynamic offer) callback) {
_socket.on('offer', callback);
}

void onAnswer(Function(dynamic answer) callback) {
_socket.on('answer', callback);
}

void onCandidate(Function(dynamic candidate) callback) {
_socket.on('ice-candidate', callback);
}

void disconnect() {
_socket.disconnect();
}
}
import 'package:flutter/material.dart';
import 'package:flutter_application_1/call_screen.dart';
// import 'package:flutter_application_1/utils/audio_service.dart'; // _currentIndex = i),
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.bar_chart),
label: 'İstatistiklerim',
),
BottomNavigationBarItem(
icon: Icon(Icons.chat),
label: 'Görüşmelerim',
),
BottomNavigationBarItem(
icon: Icon(Icons.notifications),
label: 'Bildirimler',
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'Profilim',
),
],
),
);
}
}
< /code>
androidmanifest.xml
















































Подробнее здесь: https://stackoverflow.com/questions/796 ... microphone
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»