You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# Xamarin Android后台实时语音识别功能实现可行性咨询

Implementing Background, Button-Free Voice Recognition in Xamarin Android (C#)

Absolutely, you can build this! Implementing background, real-time voice recognition to detect commands like "top" and "back" in your C# Xamarin Android app is totally feasible—here's a practical, step-by-step breakdown tailored to your use case:

1. First, Configure Permissions

You'll need to declare and request the necessary permissions to access the microphone and run background services.

Add Permissions to AndroidManifest.xml

Include these lines inside the <manifest> tag:

<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" /> <!-- For cloud-based recognition -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

Request Runtime Permissions (Android 6.0+)

Add this code to your main activity to prompt users for microphone access:

private readonly string[] _requiredPermissions = { Manifest.Permission.RecordAudio };
private const int PermissionRequestId = 101;

protected override void OnCreate(Bundle savedInstanceState)
{
    base.OnCreate(savedInstanceState);
    // Your existing initialization code here

    if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.RecordAudio) != Permission.Granted)
    {
        ActivityCompat.RequestPermissions(this, _requiredPermissions, PermissionRequestId);
    }
    else
    {
        StartVoiceRecognitionService();
    }
}

public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
    base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == PermissionRequestId && grantResults.Any(r => r == Permission.Granted))
    {
        StartVoiceRecognitionService();
    }
}

private void StartVoiceRecognitionService()
{
    StartForegroundService(new Intent(this, typeof(VoiceCommandService)));
}

2. Build a Foreground Service for Continuous Listening

Android restricts background tasks, so we'll use a foreground service (with a persistent notification) to keep listening without being killed by the system.

Create the Voice Recognition Service

Make a new class that inherits from Service:

[Service(ForegroundServiceType = ForegroundService.TypeMicrophone)]
public class VoiceCommandService : Service
{
    private SpeechRecognizer _speechRecognizer;
    private Intent _recognitionIntent;
    private const int NotificationId = 1001;

    public override IBinder OnBind(Intent intent) => null;

    public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
    {
        // Create a persistent notification for the foreground service
        var notification = new NotificationCompat.Builder(this, "voice_command_channel")
            .SetContentTitle("Voice Listener Active")
            .SetContentText("Listening for 'top' or 'back'")
            .SetSmallIcon(Resource.Drawable.ic_mic)
            .SetPriority(NotificationCompat.PriorityLow)
            .Build();

        // Create a notification channel (required for Android 8.0+)
        if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
        {
            var channel = new NotificationChannel(
                "voice_command_channel", 
                "Voice Command Service", 
                NotificationImportance.Low)
            {
                Description = "Runs background voice recognition"
            };
            var notificationManager = GetSystemService(NotificationService) as NotificationManager;
            notificationManager?.CreateNotificationChannel(channel);
        }

        StartForeground(NotificationId, notification);
        InitializeSpeechRecognizer();

        return StartCommandResult.Sticky;
    }

    private void InitializeSpeechRecognizer()
    {
        _speechRecognizer = SpeechRecognizer.CreateSpeechRecognizer(this);
        _speechRecognizer.SetRecognitionListener(new VoiceCommandListener(this));

        _recognitionIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech);
        _recognitionIntent.PutExtra(RecognizerIntent.ExtraLanguageModel, RecognizerIntent.LanguageModelFreeForm);
        _recognitionIntent.PutExtra(RecognizerIntent.ExtraPartialResults, true); // Get real-time partial matches
        _recognitionIntent.PutExtra(RecognizerIntent.ExtraLanguage, Java.Util.Locale.Default);

        StartListening();
    }

    private void StartListening()
    {
        try
        {
            _speechRecognizer.StartListening(_recognitionIntent);
        }
        catch (Exception ex)
        {
            Log.Error("VoiceService", $"Failed to start listening: {ex.Message}");
            // Retry after a short delay if there's an error
            new Handler(Looper.MainLooper).PostDelayed(StartListening, 1000);
        }
    }

    public override void OnDestroy()
    {
        _speechRecognizer?.StopListening();
        _speechRecognizer?.Destroy();
        base.OnDestroy();
    }

    // Custom listener to handle recognition results
    private class VoiceCommandListener : Java.Lang.Object, IRecognitionListener
    {
        private readonly VoiceCommandService _service;

        public VoiceCommandListener(VoiceCommandService service)
        {
            _service = service;
        }

        public void OnReadyForSpeech(Bundle @params) { }
        public void OnBeginningOfSpeech() { }
        public void OnRmsChanged(float rmsdB) { }
        public void OnBufferReceived(byte[] buffer) { }

        public void OnEndOfSpeech()
        {
            // Restart listening immediately after a recognition session ends
            _service.StartListening();
        }

        public void OnError(RecognizerError error)
        {
            Log.Error("VoiceListener", $"Recognition error: {error}");
            _service.StartListening();
        }

        public void OnResults(Bundle results)
        {
            var matches = results.GetStringArrayList(SpeechRecognizer.ResultsRecognition);
            if (matches != null && matches.Any())
            {
                ProcessCommand(matches[0].ToLower());
            }
        }

        public void OnPartialResults(Bundle partialResults)
        {
            // Detect commands mid-speech for faster response
            var partialMatches = partialResults.GetStringArrayList(SpeechRecognizer.ResultsRecognition);
            if (partialMatches != null && partialMatches.Any())
            {
                var partialText = partialMatches[0].ToLower();
                if (partialText.Contains("top") || partialText.Contains("back"))
                {
                    ProcessCommand(partialText);
                }
            }
        }

        public void OnEvent(int eventType, Bundle @params) { }

        private void ProcessCommand(string commandText)
        {
            if (commandText.Contains("top"))
            {
                // Send broadcast to trigger "top" action in your activity
                LocalBroadcastManager.GetInstance(_service)
                    .SendBroadcast(new Intent("com.yourapp.VOICE_COMMAND_TOP"));
            }
            else if (commandText.Contains("back"))
            {
                // Send broadcast to trigger "back" action
                LocalBroadcastManager.GetInstance(_service)
                    .SendBroadcast(new Intent("com.yourapp.VOICE_COMMAND_BACK"));
            }
        }
    }
}

3. Receive Commands in Your Activity

Add a broadcast receiver to your main activity to listen for commands and execute corresponding actions:

private BroadcastReceiver _commandReceiver;

protected override void OnResume()
{
    base.OnResume();
    _commandReceiver = new VoiceCommandReceiver();
    var broadcastManager = LocalBroadcastManager.GetInstance(this);
    
    broadcastManager.RegisterReceiver(
        _commandReceiver, 
        new IntentFilter("com.yourapp.VOICE_COMMAND_TOP"));
    broadcastManager.RegisterReceiver(
        _commandReceiver, 
        new IntentFilter("com.yourapp.VOICE_COMMAND_BACK"));
}

protected override void OnPause()
{
    base.OnPause();
    LocalBroadcastManager.GetInstance(this).UnregisterReceiver(_commandReceiver);
}

private class VoiceCommandReceiver : BroadcastReceiver
{
    public override void OnReceive(Context context, Intent intent)
    {
        switch (intent.Action)
        {
            case "com.yourapp.VOICE_COMMAND_TOP":
                // Replace with your "top" action (e.g., scroll a RecyclerView to top)
                Toast.MakeText(context, "'Top' command detected!", ToastLength.Short).Show();
                break;
            case "com.yourapp.VOICE_COMMAND_BACK":
                // Replace with your "back" action (e.g., simulate back button press)
                Toast.MakeText(context, "'Back' command detected!", ToastLength.Short).Show();
                break;
        }
    }
}

Key Notes for Success

  • Battery Optimization: Advise users to exclude your app from battery optimization settings—otherwise, Android may kill the foreground service during low-power modes.
  • Recognition Accuracy: Adjust the language model or add keyword-specific filters (like regex) to reduce false positives.
  • Resource Usage: Continuous listening uses battery and memory—add a toggle in your app to let users enable/disable the background listener.

内容的提问来源于stack exchange,提问作者Artur Lodklif

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 09:46:13