How to play webm in Android.Media.Mediaplayer? (error (1, -2147483648)) - c#

I want to stream webm (opus) audio in my Xamarin Android App but I keep getting a UNKNOWN_ERROR by preparing the player.
My code looks like that:
public class AndroidAudioPlayerHelper : AudioPlayerHelper {
private readonly Media Player player;
public AndroidAudioPlayerHelper() => player = new MediaPlayer();
private void PlayNew() {
player.Prepared += (sender, e) => {
player.Start();
};
player.PrepareAsync();
}
public override void PlayStream(string url) {
player.SetDataSource(url);
PlayNew();
}
}
My url looks like http://localhost:9001/api/v1/song/stream/00000000000000000000000000000000.
And everything is working fine when I point on a mp3-file or use my UWP-App.
I already tried to set AudioAttributes but it didn't work either.

If you are using a newer version of Android, your resource has to be a https resource, or allow insecure connections in your manifest.
Try adding: android:usesCleartextTraffic="true" to your Application node in your AndroidManifest.xml file.
This should preferably be disabled for release builds when you have a properly configured server.

Related

Showing local pdf files from documents folder in xamarin ios webview [duplicate]

Im currently having an issue loading a local pdf into a webview. I have the code which works without any errors and when I run it on the iPad simulator, it works absolutely perfect. However, the issue comes when I try to run it on a physical iPad device. When I run it and it gets to the point where it needs to show the PDF, the webview loads but there is no PDF shown in the webview.
The PDF is actually generated by the app and I store it inside a directory inside the library folder.
Code to show the PDF in the WebView:
public void LoadPdfToWebView(string pdfPath)
{
//Console.WriteLine("Load request started");
WebView.LoadRequest(new NSUrlRequest(new NSUrl(pdfPath, false)));
View.AddSubview(WebView);
//Console.WriteLine("Load request Finished");
}
Not really sure why this would be the case and hopefully somebody can help.
I've just had to fix this for an app and thought I'd post the solution
This is for WKWebView which is a requirement from Apple as of Dec 2020 though the deadline has been temporarily extended
Xaml PdfWebView ContentPage
<controls:PdfWebView
Source="{Binding PDFSource}"
HeightRequest="1000"
WidthRequest="1000"/>
control
namespace XForms.Controls
{
public class PdfWebView : WebView { }
}
VM, only the relevant part
private string _pdfSource;
public string PDFSource
{
get => _pdfSource;
set
{
if (Device.RuntimePlatform == Device.Android && value.StartsWith("file:") == false)
{
value = $"file:///android_asset/pdfjs/web/viewer.html?file=file:///{WebUtility.UrlEncode(value)}";
}
SetProperty(ref _pdfSource, value);
}
}
iOS renderer for PdfWebView
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using XForms.Controls;
using WebKit;
using Foundation;
[assembly: ExportRenderer(typeof(PdfWebView), typeof(iOSUI.Renderers.PdfWebViewRenderer))]
namespace iOSUI.Renderers
{
public class PdfWebViewRenderer : ViewRenderer<WebView, WKWebView>
{
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
var wkWebViewConfiguration = new WKWebViewConfiguration();
var wkWebView = new WKWebView(Frame, wkWebViewConfiguration)
{
AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight
};
SetNativeControl(wkWebView);
}
if (e.NewElement != null)
{
if (string.IsNullOrEmpty(((UrlWebViewSource)e.NewElement.Source)?.Url) == false)
{
var url = ((UrlWebViewSource)e.NewElement.Source).Url;
if(url.StartsWith("http"))
{
Control.LoadRequest(new NSUrlRequest(new NSUrl(url)));
}
else
{
Control.LoadFileUrl(new NSUrl($"file://{url}"), new NSUrl($"file://{url}"));
}
}
}
}
}
}
Android Renderer
using System.Net;
using Android.Content;
using Android.Views;
using Android.Webkit;
using XForms.Controls;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(PdfWebView), typeof(AndroidUI.Renderers.PDFViewRenderer))]
namespace AndroidUI.Renderers
{
public class PDFViewRenderer : WebViewRenderer
{
public PDFViewRenderer(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
Control.Settings.JavaScriptEnabled = true;
Control.Settings.DomStorageEnabled = true;
Control.Settings.AllowFileAccess = true;
Control.Settings.AllowFileAccessFromFileURLs = true;
Control.Settings.AllowUniversalAccessFromFileURLs = true;
Control.SetWebChromeClient(new WebChromeClient());
}
}
// If you want to enable scrolling in WebView uncomment the following lines.
public override bool DispatchTouchEvent(MotionEvent e)
{
Parent.RequestDisallowInterceptTouchEvent(true);
return base.DispatchTouchEvent(e);
}
}
}
This solution uses pdfjs in Android and WKWebview in iOS to render the PDF
The PDFSource is the full path to the file, I use System.IO .net standard calls to handle this in a cross platform way
All the files are stored in (I have a method called GetFullPath to return the cross platform common path)
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
Combined with a filename with Path.Combine
Path.Combine(GetFullPath(), fileName);
That is the PDFSource that gets set in the VM
The Pdfjs library files are just copied into Assets/pdfjs for Android
The magic for iOS is just calling LoadFileUrl instead of LoadRequest and prepending "file://"
I've slightly sanitised our namespaces so some of them wont resolve like XForms.Controls and so on that refer to our internal code
In Xamarin.IOS to show a document type other than HTML in a UIWebView:
Add the document (for example, a PDF) to your Xamarin.iOS project. Set the Build Action to BundleResource. You can set the build action for a file by right-clicking on that file and and choosing Build Action in the menu that opens.
Create a UIWebView and add it to a view:
webView = new UIWebView (View.Bounds);
View.AddSubview(webView);
Load the file using NSUrl and NSUrlRequest classes:
string fileName = "Loading a Web Page.pdf"; // remember case-sensitive
string localDocUrl = Path.Combine (NSBundle.MainBundle.BundlePath, fileName);
webView.LoadRequest(new NSUrlRequest(new NSUrl(localDocUrl, false)));
webView.ScalesPageToFit = true;
You can refer to this officical steps.If have problems or other needs, you can refer to this link
If you can't read the resources in the bundle, you can put the resource cache in the temp directory of the sandbox and try to read it using LoadRequest.

How can I acces microphone input in .Net MAUI?

I am developing .net maui app that measures sound volume and sends it with bluetooth to pc that logs data and makes graph as a hobby project. My problem is accesing microphone input. There seems to be no multiplatform way to do this in maui. So i tried to do it using platform specific android api, but when I tried so, it seemed like class that I needed was not fully implemented in maui Android namespace.
The part of my code I have trouble with is this:
using Android.Media;
using Java.Util;
public static class MicIn
{
static MediaRecorder mRecorder;
// Other functions
public static void startRecorder()
{
if (mRecorder == null)
{
mRecorder = new MediaRecorder();
mRecorder.SetAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.SetOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.SetAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mRecorder.SetOutputFile("/dev/null");
try
{
mRecorder.Prepare();
}
catch (Java.IO.IOException ioe)
{
Debug.WriteLine("IO exception");
}
catch (Java.Lang.SecurityException e)
{
Debug.WriteLine("Security exception");
}
try
{
mRecorder.Start();
}
catch (Java.Lang.SecurityException e)
{
Debug.WriteLine("Security exception");
}
}
}
}
Visual studio gives me errors on MediaRecorder.AudioSource.MIC, MediaRecorder.OutputFormat.THREE_GPP and MediaRecorder.AudioEncoder.AMR_NB
It says that these classes do not have definition for MIC, THREE_GPP and AMR_NB constants, even if they are in official android api documentation.
Do you have any ideas what might be error or other ways of taking microphone input in .net maui? Thank you for help.
according to the docs
AudioSource Mic
OutputFormat ThreeGpp
AudioEncoder AmrNb

Can't Subscribe to Nodes RosSharp C# Unity

I cannnot subscribe to any topics using RosSharp. I am working entirely locally-on the same machine. I am fairly certain I have the right uri with the right port and cannot get any communication. I am running ROS through Win-ROS: https://ros-win.visualstudio.com/_git/ros-win?path=%2Fdoc%2FSetup.md&version=GBmaster
On my local Windows host machine, I am running roscore and publishing a node with:
rostopic pub -r 10 /testtopic std_msgs/String "whatever".
I'm able to run a subscriber from the command prompt with rostopic echo /testtopic and receive the correct data back, but I cannot get this subscriber to work in Unity. I'm expecting SubscriptionHandler to at least be called. This is the code I'm trying to replicate: https://github.com/siemens/ros-sharp/blob/a45e847f96d7dd1a7859dd9595e05ef27b27b5c3/Libraries/RosBridgeClientTest/RosSocketTests.cs
Below is my code attached to a GameObject, any help would be appreciated. Thank you.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using RosSharp.RosBridgeClient;
using std_msgs = RosSharp.RosBridgeClient.Messages.Standard;
public class BasicROS : MonoBehaviour {
public string uri = "ws://18.40.26.172:11311";
private RosSocket rosSocket;
string subscriptionId = "";
void Start () {
rosSocket = new RosSocket(new
RosSharp.RosBridgeClient.Protocols.WebSocketNetProtocol(uri)); // 10.189.42.225:9090
Subscribe("/testtopic");
}
public void Subscribe(string id)
{
subscriptionId = rosSocket.Subscribe<std_msgs.String>(id, SubscriptionHandler);
StartCoroutine(WaitForKey());
}
private IEnumerator WaitForKey()
{
Debug.Log("Press any key to close...");
while (!Input.anyKeyDown)
{
yield return null;
}
Debug.Log("Closed");
// rosSocket.Close();
}
private void SubscriptionHandler(std_msgs.String message)
{
Debug.Log("Message received!");
Debug.Log(message.data);
}
}
At the time of this writing, ros-win doesn't support rosbridge, which is the ros-websocket bridge that rosSharp can communicate with. If you must use ros-win and use RosSharp to do websocket communication in unity, then you will need to wait or write your own port of rosbridge.
If you can replace ros-win with ros on WSL, then you can do the following:
Install the ros-websocket bridge suite. (Note: desktop-full does not include this, so be sure you actually get this package)
sudo apt-get install ros-<rosdistro>-rosbridge-suite
e.g.,
sudo apt-get install ros-melodic-rosbridge-suite
Run it with roslaunch rosbridge_server rosbridge_websocket.launch in order for web socket messages to reach the ros network.
Doing that will create a websocket listener on port 9090, so you need to change your uri to use port 9090.
Also, you may want to use localhost, i.e., uri = "ws://localhost:9090";, to avoid routing issues.

Make a USSD call in Xamarin Crossplatform app

I want to make a USSD call in a xamarin crossplatform app using C# and i have no idea where to start. All the examples i have seen is done in java. Is it possible to successfully dial a USSD code like *270# within my app without opening the dialer? If yes, please how? I'll be very grateful for any help
To do it with Xamarin forms you have to create a custom renderer for android :
Create an interface in your shared project :
public interface IUssdRenderer
{
void StartTransaction();
}
then in your android project :
using System;
using Android.Content;
using Android.OS;
using ussd.Renderers;
[assembly: Xamarin.Forms.Dependency(typeof(IUssdRenderer))]
namespace ussd.Droid.Renderers
{
public class UssdRenderer : IUssdRenderer
{
public Android.Net.Uri createUriFromString(string ussd)
{
String uri = "tel:";
foreach (char c in ussd.ToCharArray())
{
if (c == '#')
{
uri += Android.Net.Uri.Encode("#");
}
else
{
uri += c;
}
}
return Android.Net.Uri.Parse(uri);
}
public void StartTransaction()
{
var intent = new Intent(Intent.ActionCall, createUriFromString("*270#"));
Context ctx = Xamarin.Forms.Forms.Context;
ctx.StartActivity(intent);
}
}
}
You'll also have to register you interface, I'm using prism :
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.Register< IUssdRenderer, UssdRenderer>();
}
The last bit is to make sure you have Call permissions enabled :
Right click on Android Project > Options > Android application
make sure CallPhone is selected
You may use Xamarin.Essentials PhoneDialer, to make a call, note that since USSD contains '#' you need to URL-encode it. example:
string code = "*123#";
PhoneDialer.Open(HttpUtility.UrlEncode(code));
After collecting from left and right I finally found the solution to my question with CrossMessaging plugin.
The steps are as follow:
Create your project and give the name
Install from nuget Xam.Plugins.Messaging in your project
Add below line in Android project MainActivity's OnCreate method:
CrossMessaging.Current.Settings().Phone.AutoDial = true;
Add android.permission.CALL_PHONE to the manifest file.
Make calls as follow
try
{
var phonedialer = CrossMessaging.Current.PhoneDialer;
if (phonedialer.CanMakePhoneCall)
{
//Ussd call's
phonedialer.MakePhoneCall(HttpUtility.UrlEncode("#150#"));
//For normal calls
phonedialer.MakePhoneCall("9111111111")
}
}
catch (Exception exc)
{
await DisplayAlert("Error!!!!", exc.ToString(), "ok");
}

Load file downloaded iOS app created in Unity

I'm trying to load a json file downloaded and saved in the persistentDataPath of an iOS device. The download and save works great. However I think I have big issues to load the file. In fact when I try to compile the project in Xcode I have some errors messages.
First here is my C# code :
using UnityEngine;
using System.Collections;
using System.IO;
using System.Net;
using UnityEngine.UI;
public class ReadJson : MonoBehaviour
{
public Text City;
public Text Temperature;
public Image Weather;
public Text WeatherUrl;
[System.Serializable]
public class CityInfo
{
public string name;
}
[System.Serializable]
public class CurrentCondition
{
public string date;
public string hour;
public int tmp;
public int wnd_spd;
public int wnd_gust;
public string wnd_dir;
public double pressure;
public int humidity;
public string condition;
public string icon;
public string icon_big;
}
[System.Serializable]
public class RootObject
{
public CityInfo city_info;
public CurrentCondition current_condition;
}
void Start () {
WebClient client = new WebClient();
File.Delete(Path.Combine (Application.persistentDataPath, "myjson.json"));
client.DownloadFile ("http://www.myjsonurl", Path.Combine (Application.persistentDataPath, "myjson.json"));
TextAsset asset = Resources.Load (Path.Combine (Application.dataPath + "/Documents", "myjson")) as TextAsset;
RootObject m = JsonUtility.FromJson<RootObject> (asset.text);
City.text = m.city_info.name;
Temperature.text = (m.current_condition.tmp).ToString();
}
}
And now the xcode console :
2016-10-21 17:01:20.766001 json[1404:516674] [DYMTLInitPlatform] platform initialization successful
2016-10-21 17:01:20.929950 json[1404:516508] -> registered mono modules 0xb95f70
2016-10-21 17:01:21.356590 json[1404:516508] You've implemented -[<UIApplicationDelegate> application:didReceiveRemoteNotification:fetchCompletionHandler:], but you still need to add "remote-notification" to the list of your supported UIBackgroundModes in your Info.plist.
-> applicationDidFinishLaunching()
2016-10-21 17:01:21.452967 json[1404:516508] Metal GPU Frame Capture Enabled
2016-10-21 17:01:21.453369 json[1404:516508] Metal API Validation Enabled
-> applicationDidBecomeActive()
Init: screen size 750x1334
Initializing Metal device caps
Initialize engine version: 5.3.4f1 (fdbb5133b820)
UnloadTime: 1.705875 ms
Salut/var/mobile/Containers/Data/Application/51A2490E-94EB-4904-9F2E-112AD5632A98/Documents
(Filename: /Users/builduser/buildslave/unity/build/artifacts/generated/common/runtime/UnityEngineDebugBindings.gen.cpp Line: 37)
NullReferenceException: A null value was found where an object instance was required.
(Filename: currently not available on il2cpp Line: -1)
Setting up 1 worker threads for Enlighten.
Thread -> id: 19f17000 -> priority: 1
If someone has an idea. Thanks a lot in advance.
The problem with your code is on this line:
TextAsset asset = Resources.Load(Path.Combine(Application.dataPath + "/Documents", "myjson")) as TextAsset;
I don't think you understand how and when to use Resources.Load. If you want to use the Resources.Load function, you must create a special folder from the Editor. This folder should be at <ProjectDirectory>/Assets/Resources. You can only put/write stuff into this folder from the Editor. You can't do it after build on iOS. It becomes read only after you build it. This special folder can then be read with the Resources.Load function.
Replacing:
TextAsset asset = Resources.Load(Path.Combine(Application.dataPath + "/Documents", "myjson")) as TextAsset;
with
string text = File.ReadAllText(Path.Combine(Application.persistentDataPath, "myjson.json"));
RootObject m = JsonUtility.FromJson<RootObject>(text);
City.text = m.city_info.name;
Temperature.text = (m.current_condition.tmp).ToString();
Should solve your problem.
Another API that should not be using is WebClient. Unless you have a good reason to use that, you shouldn't. You should either use the WWW or UnityWebRequest(newer and recommended) API.
This is what your code should look like without WebClient:
void Start()
{
StartCoroutine(DownloadAndloadJson());
}
IEnumerator DownloadAndloadJson()
{
string url = "http://www.myjsonurl";
UnityWebRequest www = UnityWebRequest.Get(url);
yield return www.Send();
if (www.isError)
{
Debug.Log(www.error);
}
else
{
//Sucessfully downloaded the Json File
Debug.Log("Json: " + www.downloadHandler.text);
string jsonFile = www.downloadHandler.text;
//Delete old json file. Don't know why but this was in your original code
File.Delete(Path.Combine(Application.persistentDataPath, "myjson.json"));
//Save the downloaded data as File
File.WriteAllText(Path.Combine(Application.persistentDataPath, "myjson.json"), jsonFile);
//Load the downloaded data
string text = File.ReadAllText(Path.Combine(Application.persistentDataPath, "myjson.json"));
Debug.Log(text);
RootObject m = JsonUtility.FromJson<RootObject>(text);
City.text = m.city_info.name;
Temperature.text = (m.current_condition.tmp).ToString();
}
}
If you have problems please update to Unity 5.4. The UnityWebRequest API should be used for this and it was introduced in 5.3 but bugs were fixed in 5.4. You need using UnityEngine.Networking; to use UnityWebRequest.

Categories

Resources