How to play audio in xamarin forms? - audio

I am trying to play an audio file which is stored locally. I am using Xam.Plugin.SimpleAudioPlayer for playing audio. For UWP and Android, added the files in the Assets folder with the Build Action set to Content and Android Asset respectively.
My Code:
private void PlayAudio()
{
try
{
var stream = GetStreamFromFile("audio.mp3");
var audio = Plugin.SimpleAudioPlayer.CrossSimpleAudioPlayer.Current;
audio.Load(stream);
audio.Play();
}
catch (Exception e)
{
Debug.WriteLine("exception:>>" + e);
}
}
Stream GetStreamFromFile(string filename)
{
var assembly = typeof(App).GetTypeInfo().Assembly;
var stream = assembly.GetManifestResourceStream("AudioPlay." + filename);
return stream;
}
But getting an exception in android and UWP, didn't check in IOS.
Android Exception:
[0:] exception:>>System.NullReferenceException: Object reference not set to an instance of an object.
at Plugin.SimpleAudioPlayer.SimpleAudioPlayerImplementation.Load (System.IO.Stream audioStream) [0x00050] in C:\dev\open\Xamarin-Plugins\SimpleAudioPlayer\SimpleAudioPlayer\Plugin.SimpleAudioPlayer.Android\SimpleAudioPlayerImplementation.cs:100
at AudioPlay.MainPage.PlayAudio () [0x00014] in F:\AudioPlay\AudioPlay\AudioPlay\MainPage.xaml.cs:63
I am using .mp3 file. Am I missing something in this implementation? Please help me to fix this issue?

You just need to directly put the mp3 file in share project . And call the method
var stream = GetStreamFromFile("xxx.mp3");
var audio = Plugin.SimpleAudioPlayer.CrossSimpleAudioPlayer.Current;
audio.Load(stream );
audio.Play();
Stream GetStreamFromFile(string filename)
{
var assembly = typeof(App).GetTypeInfo().Assembly;
var stream = assembly.GetManifestResourceStream("yourprojectname." + filename);
return stream;
}
Update
I check your demo , and if you want to play mp3 file in your project. You need to set the build action of the mp3 as Embedded resource
Right click the mp3 file -> Property

try this For xamarin.android
var u = Android.Net.Uri.Parse("filepath");
MediaPlayer _player = MediaPlayer.Create(this, u);
_player.Start();
or
use XamarinMediaManager plugin
https://github.com/martijn00/XamarinMediaManager

The accepted answer does not work when attempting to load a resource from a project that is not the main Xamarin Forms project.
The solution is to use Android.AssetManager.Open() to get a Stream (I'm sure iOS has something similar). You'll need to use DependencyService to access this outside the Android project.
The MP3 files would be put in the Assets folder of the Android project. The audio files need to have Build Action: "Android Asset", not "Embedded Resource" as above.
Example:
Android Project has Assets/Audio/click.mp3
AndroidProject/AndroidAssetManager.cs
[assembly: Dependency (typeof (AndroidAssetManager))]
namespace App.Droid
{
public interface IAssetManager
{
Stream LoadAsset(string assetName);
...
}
public class AndroidAssetManager : IAssetManager
{
private readonly AssetManager _assets;
public AndroidAssetManager(AssetManager assets)
{
_assets = assets;
}
public Stream LoadAsset(string assetName)
{
return _assets.Open(assetName);
}
...
}
}
Shared/AudioPlayer.cs:
class AudioPlayer : IAudioPlayer
{
private IAssetManager AssetManager => DependencyService.Get<IAssetManager>();
private ISimpleAudioPlayer _clickPlayer;
public AudioPlayer()
{
_clickPlayer = CrossSimpleAudioPlayer.CreateSimpleAudioPlayer();
_clickPlayer.Load(AssetManager.Load("Audio/click.mp3"));
}
public void PlayClick()
{
_clickPlayer.Play();
}
}

Related

Calling Azure IoT File Upload from Android KitKat is returning BAD_FORMAT

I am trying to upload a .png file to Azure IoT Hubs, but for some reason I am constantly getting BAD_FORMAT. I am using com.microsoft.azure.sdk.iot:iot-device-client:1.14.2 library as I need to using an android device that is quite old (KitKat version).
The code I am using:
public void btnFileUploadOnClick(View v) throws URISyntaxException, IOException
{
Log.i("IoT App","Uploading file to IoT Hub...");
EditText text = (EditText)findViewById(R.id.editTextFileName);
String fullFileName = text.getText().toString();
try
{
File directory = Environment.getExternalStorageDirectory();
File file = new File(directory, "payments.json");
InputStream inputStream = new FileInputStream(file);
long streamLength = file.length();
if(file.isDirectory())
{
throw new IllegalArgumentException(fullFileName + " is a directory, please provide a single file name, or use the FileUploadSample to upload directories.");
}
else
{
client.uploadToBlobAsync("payments", inputStream, streamLength, new FileUploadStatusCallBack(), null);
}
Log.i("IoT App","File upload started with success");
Log.i("IoT App","Waiting for file upload callback with the status...");
}
catch (Exception e)
{
Log.e("IoT App","Exception while sending event: " + e.getMessage());
}
}
protected class FileUploadStatusCallBack implements IotHubEventCallback
{
public void execute(IotHubStatusCode status, Object context)
{
Log.i("IoT App","IoT Hub responded to file upload operation with status " + status.name());
TextViewControl.log("IoT Hub responded to file upload operation with status " + status.name());
}
}
I have the file payments.json in the device (emulator).
Any help would be appreciated!
It seems I just needed to import a separate library for accessing blob storage. Had to add the following to my gradle script:
implementation 'com.microsoft.azure.android:azure-storage-android:2.0.0'

How to bundle sounds with Codename One?

I want to include sounds in my Codename One app for effects like clicking a button, transitions, etc. I prefer not to download them from URL, since they are very small and I want them to be played even when the device is not connected to the internet. It looks like I cannot include the source files in the theme. What should I do?
Put the sound file in the "src" folder inside your project folder and reference it like below:
private Media MEDIA = null;
public void playAudio(String fileName) {
try {
if (MEDIA == null) {
final InputStream is = Display.getInstance().getResourceAsStream(getClass(), "/" + fileName);
MEDIA = MediaManager.createMedia(is, "audio/mp3", new Runnable() {
#Override
public void run() {
MEDIA = null;
}
});
}
if (MEDIA != null && MEDIA.isPlaying() == false) {
MEDIA.setVolume(100);
MEDIA.play();
}
} catch (IOException ioe) {
}
}
...
playAudio("my_sound.mp3");

Downloads with JavaFX WebView

my web application offers a download. Javascript creats at the click the url (it depends on the user input) and the browser should open it, so that the page isn't reloaded.
For that, I think I have to alternatives:
// Alt1:
window.open(pathToFile);
// Alt2:
var downloadFrame = document.getElementById('downloads');
if (downloadFrame === null) {
downloadFrame = document.createElement('iframe');
downloadFrame.id = 'downloads';
downloadFrame.style.display = 'none';
document.body.appendChild(downloadFrame);
}
downloadFrame.src = pathToFile;
Both works under Firefox. Problem with open new window method: If the creation of the file at the server needs more time, the new empty tab will be closed late.
Problem with iframe: If there is an error at the server, no feedback is given.
I think at firefox the iframe is the better solution. But the web application must run with an JavaFX WebView, too. JavaFX haven't a download feature, I have to write it. One possible way is to listen on the location property:
final WebView webView = new WebView();
webView.getEngine().locationProperty().addListener(new ChangeListener<String>() {
#Override public void changed(ObservableValue<? extends String> observableValue, String oldLoc, String newLoc) {
if (newLoc.cotains("/download")) {
FileChooser chooser = new FileChooser();
chooser.setTitle("Save " + newLoc);
File saveFile = chooser.showSaveDialog(webView.getEngine().getScene().getWindow());
if (saveFile != null) {
BufferedInputStream is = null;
BufferedOutputStream os = null;
try {
is = new BufferedInputStream(new URL(newLoc).openStream());
os = new BufferedOutputStream(new FileOutputStream(saveFile));
while ((readBytes = is.read()) != -1) {
os.write(b);
}
} finally {
try { if (is != null) is.close(); } catch (IOException e) {}
try { if (os != null) os.close(); } catch (IOException e) {}
}
}
}
}
}
There are some problems:
The download start depends on a part of the url, because JafaFX supports no access to the http headers (that is bearable)
If the user starts the download with the same url two times, only the first download works (the change event only fires, if the url is new). I can crate unique urls (with #1, #2 and so on at the end). But this is ugly.
Only the "window.open(pathToFile);" method works. Loading an iframe don't fire the change location event of the website. That is expectable but I haven't found the right Listener.
Can someone help me to solve 2. or 3.?
Thank you!
PS: Sorry for my bad english.
edit:
For 2. I found a way. I don't know if it is a good one, if it is performant, if the new webview is deleted or is in the cache after download, ....
And the user don't get an feedback, when some a problem is raised:
webView.getEngine().setCreatePopupHandler(new Callback<PopupFeatures, WebEngine>() {
#Override public WebEngine call(PopupFeatures config) {
final WebView downloader = new WebView();
downloader.getEngine().locationProperty().addListener(/* The Listener from above */);
return downloader.getEngine();
}
}
I think you may just need to use copyURLtoFile to get the file...call that when the location changes or just call that using a registered java class. Something like this:
org.apache.commons.io.FileUtils.copyURLToFile(new URL(newLoc), new File(System.getProperty("user.home")+filename));
Using copyURLToFile the current page doesn't have to serve the file. I think registering the class is probably the easiest way to go... something like this:
PHP Code:
Download $filename
Java (in-line class in your javafx class/window... in this case my javafx window is inside of a jframe):
public class JavaApp {
JFrame cloudFrameREF;
JavaApp(JFrame cloudFrameREF)
{
this.cloudFrameREF = cloudFrameREF;
}
public void getfile(String filename) {
String newLoc = "http://your_web_site.com/send_file.php?filename=" + filename;
org.apache.commons.io.FileUtils.copyURLToFile(new URL(newLoc), new File(System.getProperty("user.home")+filename));
}
}
This part would go in the main javafx class:
Platform.runLater(new Runnable() {
#Override
public void run() {
browser2 = new WebView();
webEngine = browser2.getEngine();
appREF = new JavaApp(cloudFrame);
webEngine.getLoadWorker().stateProperty().addListener(
new ChangeListener<State>() {
#Override public void changed(ObservableValue ov, State oldState, State newState) {
if (newState == Worker.State.SUCCEEDED) {
JSObject win
= (JSObject) webEngine.executeScript("window");
// this next line registers the JavaApp class with the page... you can then call it from javascript using "app.method_name".
win.setMember("app", appREF);
}
}
});
You may not need the frame reference... I was hacking some of my own code to test this out and the ref was useful for other things...

Downloading Media File programmatically in Windows Phone 8

Our app is video/audio based app, and we have uploaded all the media on Windows Azure.
However it is required to facilitate user to download audio/video file on demand, so that they can play it locally.
So i need to download audio/video file programmatically and save it in IsolatedStorage.
We have Windows Azure Media File Access URLs for each audio/video. But I am stuck in 1st step of downloading media file.
I googled and came across this article, but for WebClient there is no function DownloadFileAsync that I can use.
However I tried its other function DownloadStringAsyn, and download media file is in string format but don't know how to convert it to audio(wma)/video(mp4) format. Please suggest me, how can I proceed? Is there other way to download media file?
Here is sample code that I used
private void ApplicationBarMenuItem_Click_1(object sender, EventArgs e)
{
WebClient mediaWC = new WebClient();
mediaWC.DownloadProgressChanged += new DownloadProgressChangedEventHandler(mediaWC_DownloadProgressChanged);
mediaWC.DownloadStringAsync(new Uri(link));
mediaWC.DownloadStringCompleted += new DownloadStringCompletedEventHandler(mediaWC_DownloadCompleted);
}
private void mediaWC_DownloadCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Cancelled)
MessageBox.Show("Downloading is cancelled");
else
{
MessageBox.Show("Downloaded");
}
}
private void mediaWC_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
statusbar.Text = status= e.ProgressPercentage.ToString();
}
For downloading binary data, use [WebClient.OpenReadAsync][1]. You can use it to download data other than string data.
var webClient = new WebClient();
webClient.OpenReadCompleted += OnOpenReadCompleted;
webClient.OpenReadAsync(new Uri("...", UriKind.Absolute));
private void OnOpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
}
Save this in your toolbox :)
public static Task<Stream> DownloadFile(Uri url)
{
var tcs = new TaskCompletionSource<Stream>();
var wc = new WebClient();
wc.OpenReadCompleted += (s, e) =>
{
if (e.Error != null) tcs.TrySetException(e.Error);
else if (e.Cancelled) tcs.TrySetCanceled();
else tcs.TrySetResult(e.Result);
};
wc.OpenReadAsync(url);
return tcs.Task;
}

How do I display a PDF using PdfSharp in ASP.Net MVC?

We're making an ASP.Net MVC app that needs to be able to generate a PDF and display it to the screen or save it somewhere easy for the user to access. We're using PdfSharp to generate the document. Once it's finished, how do we let the user save the document or open it up in a reader? I'm especially confused because the PDF is generated server-side but we want it to show up client-side.
Here is the MVC controller to create the report that we have written so far:
public class ReportController : ApiController
{
private static readonly string filename = "report.pdf";
[HttpGet]
public void GenerateReport()
{
ReportPdfInput input = new ReportPdfInput()
{
//Empty for now
};
var manager = new ReportPdfManagerFactory().GetReportPdfManager();
var documentRenderer = manager.GenerateReport(input);
documentRenderer.PdfDocument.Save(filename); //Returns a PdfDocumentRenderer
Process.Start(filename);
}
}
When this runs, I get an UnauthorizedAccessException at documentRenderer.PdfDocument.Save(filename); that says, Access to the path 'C:\Program Files (x86)\Common Files\Microsoft Shared\DevServer\10.0\report.pdf' is denied. I'm also not sure what will happen when the line Process.Start(filename); is executed.
This is the code in manager.GenerateReport(input):
public class ReportPdfManager : IReportPdfManager
{
public PdfDocumentRenderer GenerateReport(ReportPdfInput input)
{
var document = CreateDocument(input);
var renderer = new PdfDocumentRenderer(true, PdfSharp.Pdf.PdfFontEmbedding.Always);
renderer.Document = document;
renderer.RenderDocument();
return renderer;
}
private Document CreateDocument(ReportPdfInput input)
{
//Put content into the document
}
}
Using Yarx's suggestion and PDFsharp Team's tutorial, this is the code we ended up with:
Controller:
[HttpGet]
public ActionResult GenerateReport(ReportPdfInput input)
{
using (MemoryStream stream = new MemoryStream())
{
var manager = new ReportPdfManagerFactory().GetReportPdfManager();
var document = manager.GenerateReport(input);
document.Save(stream, false);
return File(stream.ToArray(), "application/pdf");
}
}
ReportPdfManager:
public PdfDocument GenerateReport(ReportPdfInput input)
{
var document = CreateDocument(input);
var renderer = new PdfDocumentRenderer(true,
PdfSharp.Pdf.PdfFontEmbedding.Always);
renderer.Document = document;
renderer.RenderDocument();
return renderer.PdfDocument;
}
private Document CreateDocument(ReportPdfInput input)
{
//Creates a Document and puts content into it
}
I'm not familar with PDF sharp but for MVC is mostly done via built in functionality. You need to get your pdf document represented as an array of bytes. Then you'd simply use MVC's File method to return it to the browser and let it handle the download. Are there any methods on their class to do that?
public class PdfDocumentController : Controller
{
public ActionResult GenerateReport(ReportPdfInput input)
{
//Get document as byte[]
byte[] documentData;
return File(documentData, "application/pdf");
}
}

Resources