Xamarin. Возникли проблемы с правильной реализацией AudioManager AudioFocus и слушателей. - PullRequest
0 голосов
/ 16 февраля 2020

У меня есть мультимедийное приложение для подкастов, созданное с помощью форм xamarin, и я пытаюсь реализовать AudioFocus MediaManager, чтобы мое приложение могло хорошо работать с другими мультимедийными приложениями. Моя основная проблема заключается в возможности вызова RequestAudioFocus (), когда пользователь сначала нажимает кнопку воспроизведения, а затем заставить слушателя работать, если другое приложение начинает воспроизводить мультимедиа, когда мое приложение находится в фоновом режиме. Так что оба aud ios не играют одновременно.

Если я прикреплю этот код в MainActivity, то запрос будет работать нормально, но я также не хочу, чтобы этот запрос происходил, когда пользователь открывает приложение. Я хочу, чтобы это произошло, когда пользователь нажимает кнопку воспроизведения.

Некоторое время назад я создал уведомление, которое выскакивает уведомление, когда пользователь впервые загружает эпизод, в котором также есть кнопка воспроизведения / паузы, которая запускает действие для воспроизведения / приостановки эпизода. Если я вставлю этот код в это действие, то все будет работать очень хорошо, даже слушатель в отношении других приложений, создающих помехи. Но опять же, я не хочу запрашивать фокусировку звука только тогда, когда они нажимают на уведомление за пределами приложения, я хочу, чтобы оно запускалось, когда они также нажимали кнопку воспроизведения внутри приложения.

Итак, теперь я создал другое действие (отличное от уведомлений). Но я пока не совсем понимаю, как назвать это занятие. Если бы кто-то мог указать мне правильное направление, это было бы здорово. Я изучал документы и другие учебные пособия, но я мог использовать толчок в правильном направлении. Спасибо за ваше время.

Один из ресурсов, которые я использую, можно найти по адресу https://www.sitepoint.com/managing-multiple-sound-sources-in-android-with-audio-focus/

Каждый раз возвращается значение false. Не проходит инициализацию AudioManager.

 public bool RequestAudioFocus()
        {
            AudioManager audioManager = (AudioManager)GetSystemService(AudioService);
            AudioFocusRequest audioFocusRequest;
            if (Build.VERSION.SdkInt > BuildVersionCodes.O)
            {
                audioFocusRequest = audioManager.RequestAudioFocus(new AudioFocusRequestClass.Builder(AudioFocus.Gain)
                .SetAudioAttributes(new AudioAttributes.Builder().SetLegacyStreamType(Android.Media.Stream.Music).Build()).SetOnAudioFocusChangeListener(this)
                .Build());
            }
            else
            {
                audioFocusRequest = audioManager.RequestAudioFocus(this, Android.Media.Stream.Music, AudioFocus.Gain);
            }

            if (audioFocusRequest == AudioFocusRequest.Granted)
            {
                return true;
            }
            return false;
        }

        public void Init(DabPlayer Player, bool IntegrateWithLockScreen)
        {
            dabplayer = Player;
            var mSession = new MediaSessionCompat(Application.Context, "MusicService");
            mSession.SetFlags(MediaSessionCompat.FlagHandlesMediaButtons | MediaSessionCompat.FlagHandlesTransportControls);
            var controller = mSession.Controller;
            var description = GlobalResources.playerPodcast;

            if (IntegrateWithLockScreen)
            {
                /* SET UP LOCK SCREEN */
                CreateNotificationChannel();

                dabplayer.EpisodeDataChanged += (sender, e) =>
                {
                    bool focus = RequestAudioFocus();

                    if (focus)
                    {
                        // Set up an intent so that tapping the notifications returns to this app:
                        Intent intent = new Intent(Application.Context, typeof(MainActivity));
                        Intent playPauseIntent = new Intent(Application.Context, typeof(SecondActivity));
                        //Intent audioFocusIntent = new Intent(Application.Context, typeof(AudioFocusActivity));

                        // Create a PendingIntent; 
                        const int pendingIntentId = 0;
                        const int firstPendingIntentId = 1;
                        //const int audioFocusIntentId = 2;
                        //PendingIntent audioFocusPendingIntent =
                        //    PendingIntent.GetActivity(Application.Context, audioFocusIntentId, audioFocusIntent, 0);
                        PendingIntent firstPendingIntent =
                            PendingIntent.GetActivity(Application.Context, firstPendingIntentId, intent, 0);
                        PendingIntent pendingIntent =
                            PendingIntent.GetActivity(Application.Context, pendingIntentId, playPauseIntent, 0);

                        // Build the notification:
                        var builder = new NotificationCompat.Builder(Application.Context, CHANNEL_ID)
                                      .SetStyle(new Android.Support.V4.Media.App.NotificationCompat.MediaStyle()
                                                .SetMediaSession(mSession.SessionToken)
                                                .SetShowActionsInCompactView(0))
                                      .SetVisibility(NotificationCompat.VisibilityPublic)
                                      .SetContentIntent(firstPendingIntent) // Start up this activity when the user clicks the intent.
                                      .SetDeleteIntent(MediaButtonReceiver.BuildMediaButtonPendingIntent(Application.Context, PlaybackState.ActionStop))
                                      .SetSmallIcon(Resource.Drawable.app_icon) // This is the icon to display
                                      .AddAction(Resource.Drawable.ic_media_play_pause, "Play", pendingIntent)
                                      .SetContentText(GlobalResources.playerPodcast.EpisodeTitle)
                                      .SetContentTitle(GlobalResources.playerPodcast.ChannelTitle);

                        // Finally, publish the notification:
                        var notificationManager = NotificationManagerCompat.From(Application.Context);
                        notificationManager.Notify(NOTIFICATION_ID, builder.Build());


                        //StartActivity(audioFocusIntent);  causes trying to invoke virtual method on 
                        //null object reference when code and code above is uncommented
                    }
                };

                dabplayer.EpisodeProgressChanged += (object sender, EventArgs e) =>
                {

                };               
            }
        }

Это действие, которое первоначально должно было использоваться для области уведомлений

[Activity]
    public class SecondActivity :  Activity, AudioManager.IOnAudioFocusChangeListener
    {
        DabPlayer player = GlobalResources.playerPodcast;
        EpisodeViewModel Episode;

        public bool RequestAudioFocus()
        {
            AudioManager audioManager = (AudioManager)GetSystemService(AudioService);
            AudioFocusRequest audioFocusRequest;
            if (Build.VERSION.SdkInt > BuildVersionCodes.O)
            {
                audioFocusRequest = audioManager.RequestAudioFocus(new AudioFocusRequestClass.Builder(AudioFocus.Gain)
                .SetAudioAttributes(new AudioAttributes.Builder().SetLegacyStreamType(Android.Media.Stream.Music).Build()).SetOnAudioFocusChangeListener(this)
                .Build());
            }
            else
            {
                audioFocusRequest = audioManager.RequestAudioFocus(this, Android.Media.Stream.Music, AudioFocus.Gain);
            }

            if (audioFocusRequest == AudioFocusRequest.Granted)
            {
                return true;
            }
            return false;
        }


        public void OnAudioFocusChange([GeneratedEnum] AudioFocus focusChange)
        {
            switch (focusChange)
            {
                case AudioFocus.Gain:
                    player.Play();
                    //Gain when other Music Player app releases the audio service   
                    break;
                case AudioFocus.Loss:
                    //We have lost focus stop!   
                    player.Stop();
                    break;
                case AudioFocus.LossTransient:
                    //We have lost focus for a short time, but likely to resume so pause   
                    player.Pause();
                    break;
                case AudioFocus.LossTransientCanDuck:
                    //We have lost focus but should till play at a muted 10% volume   
                    //player.SetVolume(.1);
                    break;
            }
        }

        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);



            if (player.IsReady)
            {
                if (player.IsPlaying)
                {
                    player.Pause();
                }
                else
                {
                    if (RequestAudioFocus())
                    {
                        player.Play();
                    }
                }
            }
            else
            {
                if (player.Load(Episode.Episode))
                {
                    if (RequestAudioFocus())
                    {
                        player.Play();
                    }
                }
                else
                {
                    //DisplayAlert("Episode Unavailable", "The episode you are attempting to play is currently unavailable. Please try again later.", "OK");
                }

            }

            Finish();          
        }      
    }

Это новое действие, которое я построил и надеюсь использовать, когда пользователь взаимодействует с игрок, но я не уверен, как позвонить / реализовать его.

[Activity]
    public class AudioFocusActivity : Activity, AudioManager.IOnAudioFocusChangeListener
    {
        DabPlayer player = GlobalResources.playerPodcast;
        DroidDabNativePlayer droid = new DroidDabNativePlayer();
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
            RequestAudioFocus();
        }

        public bool RequestAudioFocus()
        {
            AudioManager audioManager = (AudioManager)GetSystemService(AudioService);
            AudioFocusRequest audioFocusRequest;
            if (Build.VERSION.SdkInt > BuildVersionCodes.O)
            {
                audioFocusRequest = audioManager.RequestAudioFocus(new AudioFocusRequestClass.Builder(AudioFocus.Gain)
                .SetAudioAttributes(new AudioAttributes.Builder().SetLegacyStreamType(Android.Media.Stream.Music).Build()).SetOnAudioFocusChangeListener(this)
                .Build());
            }
            else
            {
                audioFocusRequest = audioManager.RequestAudioFocus(this, Android.Media.Stream.Music, AudioFocus.Gain);
            }

            if (audioFocusRequest == AudioFocusRequest.Granted)
            {
                return true;
            }
            return false;
        }


        public void OnAudioFocusChange([GeneratedEnum] AudioFocus focusChange)
        {
            switch (focusChange)
            {
                case AudioFocus.Gain:
                    player.Play();
                    //Gain when other Music Player app releases the audio service   
                    break;
                case AudioFocus.Loss:
                    //We have lost focus stop!   
                    player.Stop();
                    break;
                case AudioFocus.LossTransient:
                    //We have lost focus for a short time, but likely to resume so pause   
                    player.Pause();
                    break;
                case AudioFocus.LossTransientCanDuck:
                    //We have lost focus but should till play at a muted 10% volume   
                    //player.SetVolume(.1);
                    break;
            }
        }
    }

Это просто мой метод игры в моем классе androidplayer

 /// Begin playback or resume if paused
        public void Play()
        {
            if (player == null)
                return;

            if (IsPlaying)
            {
                //Go back to the beginning (don't start playing)... not sure what this is here for if if it ever gets hit.
                Pause();
                Seek(0);
            }
            else if (player.CurrentPosition >= player.Duration)
            {
                //Start over from the beginning if at the end of the file
                player.Pause();
                Seek(0);
            }
            else
            {
                //Play from where we're at

            }


            player.Start();
        }

1 Ответ

1 голос
/ 17 февраля 2020

Если бы я был вами, я бы поместил ваш код Audio Focus и код вашего Audio Player в ForegroundService, а не в Activity, таким образом вы можете переходить к различным действиям, не прерывая воспроизведение Audio. В любом случае вам нужно будет сделать что-то подобное, если вы хотите воспроизвести, когда приложение находится в фоновом режиме.

Реализация ForegroundService также позволит вам добавлять кнопки к вашему уведомлению или если вы используете одно из богатых звуковых уведомлений затем вы можете отправлять намерения непосредственно в ForegroundService с помощью кнопок в уведомлении, а не открывать приложение. Таким образом, для ожидающих ваших намерений вы могли бы вместо этого напрямую связаться со службой.

Также при запросе аудио-фокуса вы должны учитывать, был ли предоставлен аудио-фокус или нет. Прямо сейчас вы просто запрашиваете его и выбрасываете результат. Только если фокус был предоставлен, вы должны начать воспроизведение аудио.

...