Giter VIP home page Giter VIP logo

Comments (19)

AndreiMisiukevich avatar AndreiMisiukevich commented on June 27, 2024 1
CrossOpenTok.Current.Permissions = OpenTokPermission.RecordAudio;

from opentok-xamarin.forms.

AndreiMisiukevich avatar AndreiMisiukevich commented on June 27, 2024

Hi, I think this can be enhanced.

Here is the requested permissions list: https://github.com/AndreiMisiukevich/OpenTok-Xamarin.Forms/blob/master/Lib/Xamarin.Forms.OpenTok.Android/Service/PlatformOpenTokService.cs#L23

But you can work around it now for your app if extend this class, override request permission method and put desired ones.
Then register your custom service instead default

// PlatformOpenTokService.Init(); REPLACE THIS LINE BY NEXT LINES

OpenTokPublisherViewRenderer.Preserve();
OpenTokSubscriberViewRenderer.Preserve();
CrossOpenTok.Init(() => new CustomPlatformOpenTokService()); // CustomPlatformOpenTokService your class

from opentok-xamarin.forms.

mr-johnlocke8 avatar mr-johnlocke8 commented on June 27, 2024

Hi, thank you for the help.
I've implemented a custom service like you said, but when I attempt to open a call page, I get Object reference not set to an instance of an object. This is the relevant stack trace:

OpenTokViewRenderer.OnElementChanged() : OpenTokViewRenderer.cs:31
OpenTokViewRenderer.ResetControl() : OpenTokViewRenderer.cs:40
OpenTokSubscriberViewRenderer.GetNativeView() : OpenTokSubscriberViewRenderer.cs:37 <-- Here the exception

from opentok-xamarin.forms.

AndreiMisiukevich avatar AndreiMisiukevich commented on June 27, 2024

Did you register it CrossOpenTok.Init(() => new CustomPlatformOpenTokService()) ?

from opentok-xamarin.forms.

mr-johnlocke8 avatar mr-johnlocke8 commented on June 27, 2024

Yes.

Did exactly like this:

// PlatformOpenTokService.Init(); REPLACE THIS LINE BY NEXT LINES

OpenTokPublisherViewRenderer.Preserve();
OpenTokSubscriberViewRenderer.Preserve();
CrossOpenTok.Init(() => new CustomPlatformOpenTokService()); // CustomPlatformOpenTokService your class

from opentok-xamarin.forms.

AndreiMisiukevich avatar AndreiMisiukevich commented on June 27, 2024

Please show me your CustomPlatformOpenTokService class

from opentok-xamarin.forms.

mr-johnlocke8 avatar mr-johnlocke8 commented on June 27, 2024

Sure. Basically copied PlatformOpenTokService and just changed the permissions.

    [Preserve(AllMembers = true)]
    public sealed class CustomPlatformOpenTokService : BaseOpenTokService
    {
        public event Action PublisherUpdated;
        public event Action SubscriberUpdated;

        private readonly string[] _requestPermissions = {
            Manifest.Permission.RecordAudio,
            Manifest.Permission.Internet,
            Manifest.Permission.AccessNetworkState
        };
        private readonly object _sessionLocker = new object();
        private readonly ObservableCollection<string> _subscriberStreamIds = new ObservableCollection<string>();
        private readonly Collection<SubscriberKit> _subscribers = new Collection<SubscriberKit>();

        public CustomPlatformOpenTokService()
        {
            _subscriberStreamIds.CollectionChanged += OnSubscriberStreamIdsCollectionChanged;
            PropertyChanged += OnPropertyChanged;
            StreamIdCollection = new ReadOnlyObservableCollection<string>(_subscriberStreamIds);
            Subscribers = new ReadOnlyCollection<SubscriberKit>(_subscribers);
        }

        public static CustomPlatformOpenTokService Instance => CrossOpenTok.Current as CustomPlatformOpenTokService;

        public override ReadOnlyObservableCollection<string> StreamIdCollection { get; }
        public ReadOnlyCollection<SubscriberKit> Subscribers { get; }
        public Session Session { get; private set; }
        public PublisherKit PublisherKit { get; private set; }

        public static void Init()
        {
            OpenTokPublisherViewRenderer.Preserve();
            OpenTokSubscriberViewRenderer.Preserve();
            CrossOpenTok.Init(() => new CustomPlatformOpenTokService());
        }

        public override bool TryStartSession()
        {
            lock (_sessionLocker)
            {
                if (!CheckPermissions() ||
                    string.IsNullOrWhiteSpace(ApiKey) ||
                    string.IsNullOrWhiteSpace(SessionId) ||
                    string.IsNullOrWhiteSpace(UserToken))
                {
                    return false;
                }

                EndSession();
                IsSessionStarted = true;

                using (var builder = new Session.Builder(CrossCurrentActivity.Current.AppContext, ApiKey, SessionId)
                    .SessionOptions(new SessionOptions()))
                {
                    Session = builder.Build();
                    Session.ConnectionDestroyed += OnConnectionDestroyed;
                    Session.Connected += OnConnected;
                    Session.StreamReceived += OnStreamReceived;
                    Session.StreamDropped += OnStreamDropped;
                    Session.Error += OnError;
                    Session.Signal += OnSignal;
                    Session.Connect(UserToken);
                }
                return true;
            }
        }

        public override void EndSession()
        {
            lock (_sessionLocker)
            {
                try
                {
                    if (Session == null)
                    {
                        return;
                    }

                    foreach (var subscriberKit in _subscribers)
                    {
                        ClearSubscriber(subscriberKit);
                    }
                    _subscribers.Clear();
                    _subscriberStreamIds.Clear();

                    if (PublisherKit != null)
                    {
                        using (PublisherKit)
                        {
                            PublisherKit.PublishAudio = false;
                            PublisherKit.PublishVideo = false;
                            PublisherKit.StreamCreated -= OnPublisherStreamCreated;
                        }
                        PublisherKit = null;
                    }

                    RaisePublisherUpdated().
                        RaiseSubscriberUpdated();

                    if (Session != null)
                    {
                        using (Session)
                        {
                            Session.ConnectionDestroyed -= OnConnectionDestroyed;
                            Session.Connected -= OnConnected;
                            Session.StreamReceived -= OnStreamReceived;
                            Session.StreamDropped -= OnStreamDropped;
                            Session.Error -= OnError;
                            Session.Signal -= OnSignal;
                            Session.Disconnect();
                        }
                        Session = null;
                    }

                }
                finally
                {
                    IsSessionStarted = false;
                    IsPublishingStarted = false;
                }
            }
        }

        public override bool CheckPermissions()
        {
            var activity = CrossCurrentActivity.Current.Activity;
            var shouldGrantPermissions = _requestPermissions.Any(permission => ContextCompat.CheckSelfPermission(activity, permission) != (int)Permission.Granted);
            if (shouldGrantPermissions)
            {
                ActivityCompat.RequestPermissions(activity, _requestPermissions, 0);
            }
            return !shouldGrantPermissions;
        }

        public override Task<bool> SendMessageAsync(string message)
        {
            Session.SendSignal(string.Empty, message);
            return Task.FromResult(true);
        }

        private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case nameof(IsVideoPublishingEnabled):
                    UpdatePublisherProperty(p => p.PublishVideo = IsVideoPublishingEnabled);
                    return;
                case nameof(IsAudioPublishingEnabled):
                    UpdatePublisherProperty(p => p.PublishAudio = IsAudioPublishingEnabled);
                    return;
                case nameof(IsVideoSubscriptionEnabled):
                    UpdateSubscriberProperty(s => s.SubscribeToVideo = IsVideoSubscriptionEnabled);
                    return;
                case nameof(IsAudioSubscriptionEnabled):
                    UpdateSubscriberProperty(s => s.SubscribeToAudio = IsAudioSubscriptionEnabled);
                    return;
            }
        }

        private void UpdatePublisherProperty(Action<PublisherKit> updateAction)
        {
            if (PublisherKit == null)
            {
                return;
            }
            updateAction?.Invoke(PublisherKit);
        }

        private void UpdateSubscriberProperty(Action<SubscriberKit> updateAction)
        {
            foreach (var subscriberKit in _subscribers)
            {
                updateAction?.Invoke(subscriberKit);
            }
        }

        public override void CycleCamera() => (PublisherKit as Publisher)?.CycleCamera();

        private void OnConnectionDestroyed(object sender, Session.ConnectionDestroyedEventArgs e)
            => RaiseSubscriberUpdated();
        
        private void OnConnected(object sender, Session.ConnectedEventArgs e)
        {
            if (Session == null || PublisherKit != null)
            {
                return;
            }
            
            using (var builder = new Publisher.Builder(CrossCurrentActivity.Current.AppContext)
                .Resolution(Publisher.CameraCaptureResolution.High)
                .Name("XamarinOpenTok"))
            {
                PublisherKit = builder.Build();
                PublisherKit.PublishVideo = IsVideoPublishingEnabled;
                PublisherKit.PublishAudio = IsAudioPublishingEnabled;
                PublisherKit.SetStyle(BaseVideoRenderer.StyleVideoScale, BaseVideoRenderer.StyleVideoFill);
                PublisherKit.StreamCreated += OnPublisherStreamCreated;

                Session.Publish(PublisherKit);
                RaisePublisherUpdated();
            }
        }

        private void OnStreamReceived(object sender, Session.StreamReceivedEventArgs e)
        {
            if (Session == null)
            {
                return;
            }

            DropStream(e.P1?.StreamId);

            using (var builder = new Subscriber.Builder(CrossCurrentActivity.Current.AppContext, e.P1))
            {
                var subscriberKit = builder.Build();
                subscriberKit.SubscribeToAudio = IsAudioSubscriptionEnabled;
                subscriberKit.SubscribeToVideo = IsVideoSubscriptionEnabled;
                subscriberKit.SetStyle(BaseVideoRenderer.StyleVideoScale, BaseVideoRenderer.StyleVideoFill);

                subscriberKit.Connected += OnSubscriberConnected;
                subscriberKit.StreamDisconnected += OnStreamDisconnected;
                subscriberKit.SubscriberDisconnected += OnSubscriberDisconnected;
                subscriberKit.VideoDataReceived += OnSubscriberVideoDataReceived;
                subscriberKit.VideoDisabled += OnSubscriberVideoDisabled;
                subscriberKit.VideoEnabled += OnSubscriberVideoEnabled;

                Session.Subscribe(subscriberKit);
                var streamId = e.P1.StreamId;
                _subscribers.Add(subscriberKit);
                _subscriberStreamIds.Add(streamId);
            }
        }

        private void OnStreamDropped(object sender, Session.StreamDroppedEventArgs e)
            => DropStream(e.P1?.StreamId);

        private void OnError(object sender, Session.ErrorEventArgs e)
        {
            RaiseError(e.P1?.Message);
            EndSession();
        }

        private void OnSubscriberVideoDisabled(object sender, SubscriberKit.VideoDisabledEventArgs e)
            => RaiseSubscriberUpdated();

        private void OnSubscriberVideoDataReceived(object sender, SubscriberKit.VideoDataReceivedEventArgs e)
            => RaiseSubscriberUpdated();

        private void OnSubscriberVideoEnabled(object sender, SubscriberKit.VideoEnabledEventArgs e)
            => RaiseSubscriberUpdated();

        private void OnSubscriberConnected(object sender, SubscriberKit.ConnectedEventArgs e)
            => RaisePublisherUpdated().RaiseSubscriberUpdated();

        private void OnSubscriberDisconnected(object sender, SubscriberKit.SubscriberListenerDisconnectedEventArgs e)
            => RaisePublisherUpdated().RaiseSubscriberUpdated();

        private void OnStreamDisconnected(object sender, SubscriberKit.StreamListenerDisconnectedEventArgs e)
            => RaisePublisherUpdated().RaiseSubscriberUpdated();

        private void DropStream(string streamId)
        {
            var subscriberKit = _subscribers.FirstOrDefault(x => x.Stream?.StreamId == streamId);
            if (subscriberKit != null)
            {
                ClearSubscriber(subscriberKit);
                _subscribers.Remove(subscriberKit);
            }
            _subscriberStreamIds.Remove(streamId);
            RaiseSubscriberUpdated();
        }

        private CustomPlatformOpenTokService RaiseSubscriberUpdated()
        {
            SubscriberUpdated?.Invoke();
            return this;
        }

        private CustomPlatformOpenTokService RaisePublisherUpdated()
        {
            PublisherUpdated?.Invoke();
            return this;
        }

        private void OnPublisherStreamCreated(object sender, PublisherKit.StreamCreatedEventArgs e)
            => IsPublishingStarted = true;

        private void OnSignal(object sender, Session.SignalEventArgs e)
            => RaiseMessageReceived(e.P2);

        private void ClearSubscriber(SubscriberKit subscriberKit)
        {
            using (subscriberKit)
            {
                subscriberKit.SubscribeToAudio = false;
                subscriberKit.SubscribeToVideo = false;
                subscriberKit.Connected -= OnSubscriberConnected;
                subscriberKit.StreamDisconnected -= OnStreamDisconnected;
                subscriberKit.SubscriberDisconnected -= OnSubscriberDisconnected;
                subscriberKit.VideoDataReceived -= OnSubscriberVideoDataReceived;
                subscriberKit.VideoDisabled -= OnSubscriberVideoDisabled;
                subscriberKit.VideoEnabled -= OnSubscriberVideoEnabled;
            }
        }

        public sealed class SessionOptions : Session.SessionOptions
        {
            public static bool IsCameraTwoCapable { private get; set; } = true;

            public override bool UseTextureViews() => true;

            public override bool IsCamera2Capable => IsCameraTwoCapable;
        }
    }

from opentok-xamarin.forms.

AndreiMisiukevich avatar AndreiMisiukevich commented on June 27, 2024

CustomPlatformOpenTokService

Wow) I meant just

[Preserve(AllMembers = true)]
class CustomPlatformOpenTokService: PlatformOpenTokService {
        private readonly string[] _requestPermissions = {
            Manifest.Permission.RecordAudio,
            Manifest.Permission.Internet,
            Manifest.Permission.AccessNetworkState
        };

        public override bool CheckPermissions()
        {
            var activity = CrossCurrentActivity.Current.Activity;
            var shouldGrantPermissions = _requestPermissions.Any(permission => ContextCompat.CheckSelfPermission(activity, permission) != (int)Permission.Granted);
            if (shouldGrantPermissions)
            {
                ActivityCompat.RequestPermissions(activity, _requestPermissions, 0);
            }
            return !shouldGrantPermissions;
        } 
}

Well if it doesn't help I need to take a look

from opentok-xamarin.forms.

mr-johnlocke8 avatar mr-johnlocke8 commented on June 27, 2024

You can't inherit from sealed class tho.

from opentok-xamarin.forms.

AndreiMisiukevich avatar AndreiMisiukevich commented on June 27, 2024

You can't inherit from sealed class tho.

Oh, you are right... Need to update it

from opentok-xamarin.forms.

mr-johnlocke8 avatar mr-johnlocke8 commented on June 27, 2024

I'd be happy to make those adjustments, but I need to make sure it works.
As a temporary hack I've "reimplemented" the entire class and just changed the permissions, but I get this error:

Hi, thank you for the help.
I've implemented a custom service like you said, but when I attempt to open a call page, I get Object reference not set to an instance of an object. This is the relevant stack trace:

OpenTokViewRenderer.OnElementChanged() : OpenTokViewRenderer.cs:31
OpenTokViewRenderer.ResetControl() : OpenTokViewRenderer.cs:40
OpenTokSubscriberViewRenderer.GetNativeView() : OpenTokSubscriberViewRenderer.cs:37 <-- Here the exception

Do you have an idea about this problem? Where can it be fixed?

from opentok-xamarin.forms.

AndreiMisiukevich avatar AndreiMisiukevich commented on June 27, 2024

Do you have an idea about this problem? Where can it be fixed?

Yes, sure. And I will fix it today

from opentok-xamarin.forms.

mr-johnlocke8 avatar mr-johnlocke8 commented on June 27, 2024

Hi Andrei,
Thank you for the changes.

Android
As soon as I open the call page, I get the following error:
validateClientPermissionsLocked:1120: Caller "com.example.app" (PID 10363, UID 24879) cannot open camera "1" without camera permission

iOS
It just asks me for Camera permissions.

This is the .xaml side

                <tok:OpenTokSubscriberView
                    AbsoluteLayout.LayoutBounds="0, 0, 1, 1"
                    AbsoluteLayout.LayoutFlags="All" />

                <tok:OpenTokPublisherView
                    IsVideoViewRunning="False" />

App.xaml.cs

            CrossOpenTok.Current.IsVideoPublishingEnabled = false;
            CrossOpenTok.Current.Permissions = OpenTokPermission.RecordAudio;

from opentok-xamarin.forms.

AndreiMisiukevich avatar AndreiMisiukevich commented on June 27, 2024

Do you see this bug on iOS only? Or both iOS and Android

from opentok-xamarin.forms.

mr-johnlocke8 avatar mr-johnlocke8 commented on June 27, 2024

Only Android raise the said exception. But iOS still ask for camera permissions.
I may add that the subscriber view does show video, only the publisher is voice only.

from opentok-xamarin.forms.

AndreiMisiukevich avatar AndreiMisiukevich commented on June 27, 2024

Only Android raise the said exception. But iOS still ask for camera permissions.
I may add that the subscriber view does show video, only the publisher is voice only.

Would you like to debug the plugin?)

from opentok-xamarin.forms.

mr-johnlocke8 avatar mr-johnlocke8 commented on June 27, 2024

Sure!
Should I clone the repository into my project and uninstall the nuget package?

from opentok-xamarin.forms.

AndreiMisiukevich avatar AndreiMisiukevich commented on June 27, 2024

Sure!
Should I clone the repository into my project and uninstall the nuget package?

I guess yes

from opentok-xamarin.forms.

AndreiMisiukevich avatar AndreiMisiukevich commented on June 27, 2024

1.3.1

from opentok-xamarin.forms.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.