Xamarin IOS: unable to play mp3 from internet - c#

I read a lot of documentation regarding this problem, but I don't seen any answer.
I have a Xamarin form app that play mp3 sample music from the Groove music service.
On Android, everyhting workd fine.
On Ios, I'm not able to play the sound. I get the URL and it's not possible to ear anything (I was able to play a local mp3)
I see this problem occured also for people using SWIFT : How to play MP3 From URL in iOS
I also found several exemple on the Xamarin forum but no sound neither: https://forums.xamarin.com/discussion/19883/how-do-i-get-the-avplayer-to-play-an-mp3-from-a-remote-url
Here is the code I use:
public class AudioService : IAudio
{
protected string FileName = string.Empty;
protected AVPlayer Player;
public bool IsPlaying { get; private set; }
public void Init(string fileName)
{
//FileName = fileName;
string second = "http://progdownload.zune.net/145/119/034/170/audio.mp3?rid=0b80911a-ba3b-42ec-b17f-c242ba087024-s4-nl-BE-music-asset-location";
FileName = second;
QueueFile();
}
public async void PlayStream(string uri)
{
Init(uri);
System.Diagnostics.Debug.WriteLine("Enter in function");
Player.Play();
System.Diagnostics.Debug.WriteLine("Play sound");
System.Diagnostics.Debug.WriteLine(FileName);
IsPlaying = true;
System.Diagnostics.Debug.WriteLine(IsPlaying);
}
public void Pause()
{
IsPlaying = false;
Player.Pause();
}
public void Stop()
{
IsPlaying = false;
if (Player == null) return;
Player.Dispose();
Player = null;
}
public bool HasFile
{
get { return Player != null; }
}
private void QueueFile()
{
if (string.IsNullOrWhiteSpace(FileName))
{
throw new Exception("No file specified to play");
}
using (var url = NSUrl.FromString(FileName))
{
var test = AVAsset.FromUrl(url);
var playerItem = AVPlayerItem.FromAsset(test);
// if Player is null, we're creating a new instance and seeking to the spot required
// otherwise we simply resume from where we left off.
if (Player == null)
{
Player = AVPlayer.FromPlayerItem(playerItem);
if (Player == null)
{
// todo: what should we do if the file doesn't exist?
return;
}
}
}
}}
(IAudio just implements playstream and stop)
If you click on the url, your browser will be able to play music
http://progdownload.zune.net/145/119/034/170/audio.mp3?rid=0b80911a-ba3b-42ec-b17f-c242ba087024-s4-nl-BE-music-asset-location
Does any one was able to play mp3 from internet

The answer in the info.list file. You need to add this to your info.list:
<key>NSAppTransportSecurity</key><dict>
<key>NSAllowsArbitraryLoads</key>
<true/></dict>
I had the same issue and resolved it.

I've made some cleaning for your code :)
This is what we got, including the detecting the end of playing
public class AudioService
{
#region Members
protected AVPlayer Player;
#endregion
#region Properties
public bool IsPlaying { get; private set; }
public bool HasFile => Player != null;
public Action MediaEnded { get; set; }
#endregion
#region Public Methods
public void PlayStream(string uri)
{
try
{
if (Player != null)
Player.Dispose();
Player = null;
QueueFile(uri);
Player.Play();
IsPlaying = true;
}
catch (Exception ex)
{
IsPlaying = false;
Crashes.TrackError(ex);
}
}
public void Pause()
{
IsPlaying = false;
Player.Pause();
}
public void Stop()
{
IsPlaying = false;
if (Player == null)
return;
Player.Dispose();
Player = null;
}
public void QueueFile(string fileName)
{
if (string.IsNullOrWhiteSpace(fileName))
{
return;
}
using (var url = NSUrl.FromString(fileName))
{
var asset = AVAsset.FromUrl(url);
var playerItem = AVPlayerItem.FromAsset(asset);
if (Player == null)
{
Player = AVPlayer.FromPlayerItem(playerItem);
if (Player == null)
{
return;
}
else
{
NSNotificationCenter.DefaultCenter.AddObserver(AVPlayerItem.DidPlayToEndTimeNotification, OnPlayerDidFinishPlaying, NSObject.FromObject(playerItem));
}
}
}
}
#endregion
#region Private Methods
private void OnPlayerDidFinishPlaying(NSNotification notification)
{
IsPlaying = false;
MediaEnded?.Invoke();
}
#endregion

Related

Not working leaderboard Google Play Service

added a leaderboard to the Google Play Service. Resources are added, authorization is working, adding a record is working. But when use ShowLeaderboardUI() only shows the name of the highscore table, but there are no highscores. Help pls ;(
CODE Ads Init:
public class AdsInitialize : MonoBehaviour
{
public static AdsInitialize instance = null;
private string LEADER_BOARD = "******";
public Text _text;
private void Awake()
{
if (instance == null)
{
instance = this;
MobileAds.Initialize(initStatus => { });
PlayGamesPlatform.DebugLogEnabled = true;
PlayGamesPlatform.Activate();
Social.localUser.Authenticate(success =>
{
if (success)
{
_text.text = "Auth working";
}
else
{
_text.text = "Auth not working";
}
});
}
else if (instance != this)
{
Destroy(gameObject);
}
DontDestroyOnLoad(gameObject);
}
public void ShowLeaderBoard()
{
//Social.ShowLeaderboardUI();
PlayGamesPlatform.Instance.ShowLeaderboardUI(LEADER_BOARD);
}
}
Write highscores:
Social.ReportScore(_time, AdsInitialize.instance.LEADER_BOARD, (bool success) => {
if (success)
{
_text.text = "ReportScore working";
}
else
{
_text.text = "ReportScore not working";
}
});
Show leaderboard in menu (this method is hanging on button):
public void ShowLeaderBoard()
{
AdsInitialize.instance.ShowLeaderBoard();
}
You need update your Google Play Games at phone

unity c# - replay sounds overlapping

I have a code here which automatically plays a sound when target is found and stops when target is lost. What I'm doing is that I want to repeat the sound of the target currently found. The problem is when i click the replay button, the sound of the last target found, and the current target are both playing.
I coded this on the DefaultTrackableEventHandler script. Here's my code:
public AudioSource soundTarget;
public AudioClip clipTarget;
private AudioSource[] allAudioSources;
public Button Button;
void StopAllAudio()
{
allAudioSources = FindObjectsOfType(typeof(AudioSource)) as AudioSource[];
foreach (AudioSource audioS in allAudioSources)
{
audioS.Stop();
}
}
void playSound(string ss)
{
clipTarget = (AudioClip)Resources.Load(ss);
soundTarget.clip = clipTarget;
soundTarget.loop = false;
soundTarget.playOnAwake = false;
soundTarget.Play();
}
public void ReplayAudio()
{
soundTarget.PlayOneShot(clipTarget);
}
Under public virtual void OnTrackingFound()
public virtual void OnTrackingFound()
{
if (mTrackableBehaviour.TrackableName == "letterA")
{
playSound("sounds/airplane");
Button.onClick.AddListener(ReplayAudio);
}
if (mTrackableBehaviour.TrackableName == "letterB")
{
playSound("sounds/banana");
Button.onClick.AddListener(ReplayAudio);
}
//On trackingLost: StopAllAudio();
You need to call RemoveAllListeners on your button before adding another listener or they will stack everytime a target is found.
public virtual void OnTrackingFound()
{
Button.onClick.RemoveAllListeners();
if (mTrackableBehaviour.TrackableName == "letterA")
{
playSound("sounds/airplane");
Button.onClick.AddListener(ReplayAudio);
}
if (mTrackableBehaviour.TrackableName == "letterB")
{
playSound("sounds/banana");
Button.onClick.AddListener(ReplayAudio);
}
}

C# Xamarin speech recognition in the background [Android]

Is this possible to make an app what will recognize if I tell eg. "top" or "back" in the background and will start some actions when find if I tell that.
I tested speech recognition when click on button and it shows google voice recognition.
Can I do that without click on button, with recognition in real time in the background?
Yes it is very possible, if you are using google voice recognition on android, what you have to do to get rid of the clicking button is to make your own SpeechRecognizer class and inherit it.
Here is the code I use on my apps :
public class CustomRecognizer : Java.Lang.Object, IRecognitionListener, TextToSpeech.IOnInitListener
{
private SpeechRecognizer _speech;
private Intent _speechIntent;
public string Words;
public CustomRecognizer(Context _context)
{
this._context = _context;
Words = "";
_speech = SpeechRecognizer.CreateSpeechRecognizer(this._context);
_speech.SetRecognitionListener(this);
_speechIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech);
_speechIntent.PutExtra(RecognizerIntent.ExtraLanguageModel, RecognizerIntent.LanguageModelFreeForm);
_speechIntent.PutExtra(RecognizerIntent.ActionRecognizeSpeech, RecognizerIntent.ExtraPreferOffline);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputCompleteSilenceLengthMillis, 1000);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputPossiblyCompleteSilenceLengthMillis, 1000);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputMinimumLengthMillis, 1500);
}
void startover()
{
_speech.Destroy();
_speech = SpeechRecognizer.CreateSpeechRecognizer(this._context);
_speech.SetRecognitionListener(this);
_speechIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputCompleteSilenceLengthMillis, 1000);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputPossiblyCompleteSilenceLengthMillis, 1000);
_speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputMinimumLengthMillis, 1500);
StartListening();
}
public void StartListening()
{
_speech.StartListening(_speechIntent);
}
public void StopListening()
{
_speech.StopListening();
}
public void OnBeginningOfSpeech()
{
}
public void OnBufferReceived(byte[] buffer)
{
}
public void OnEndOfSpeech()
{
}
public void OnError([GeneratedEnum] SpeechRecognizerError error)
{
Words = error.ToString();
startover();
}
public void OnEvent(int eventType, Bundle #params)
{
}
public void OnPartialResults(Bundle partialResults)
{
}
public void OnReadyForSpeech(Bundle #params)
{
}
public void OnResults(Bundle results)
{
var matches = results.GetStringArrayList(SpeechRecognizer.ResultsRecognition);
if (matches == null)
Words = "Null";
else
if (matches.Count != 0)
Words = matches[0];
else
Words = "";
//do anything you want for the result
}
startover();
}
public void OnRmsChanged(float rmsdB)
{
}
public void OnInit([GeneratedEnum] OperationResult status)
{
if (status == OperationResult.Error)
txtspeech.SetLanguage(Java.Util.Locale.Default);
}}
To use it on your activity, just create the class and call StartListening()

Chartboost ads not showing in Unity 3D Game

I have a simple platformer game in which I'm using chartboost and unity ads t show ads and I it was working fine during the test mode but ever since I deployed to production and disabled the test mode in both chartboost and unity ads I noticed that my interstitial ads and videos don't load or show except once in a blue moon that too of a same game and then it start failing again.
I also noticed that my ads impression are quite low on the chartboost and Unity. Can you please tell me if I code for it correctly? I used the chartboost example an built my ad controller through it, oh and I'm using caching for ads and unless ad isn't cached already I won't show it.
Here's the code:
using UnityEngine;
using System.Collections;
using UnityEngine.Advertisements;
using ChartboostSDK;
using System;
public class AdsController : MonoBehaviour
{
public static AdsController instance;
// app id for unity apps
private const string _appId = "someID";
public bool canShowChartBoostInterstitial;
public bool canShowChartBoostVideo;
private void Awake()
{
MakeSingleton();
if (!canShowChartBoostInterstitial)
{
LoadChartBoostInterstitialAds();
}
if (!canShowChartBoostVideo)
{
LoadChartBoostVideoAds();
}
LoadUnityAds();
}
private void MakeSingleton()
{
if (instance != null)
{
Destroy(gameObject);
}
else
{
instance = this;
DontDestroyOnLoad(gameObject);
}
}
private void OnLevelWasLoaded()
{
if (Application.loadedLevelName == "LevelMenu")
{
if (GameController.instance.canShowAds)
{
if (canShowChartBoostInterstitial)
{
ShowChartBoostInterstitial();
}
else
{
LoadChartBoostInterstitialAds();
}
}
}
}
private void OnEnable()
{
Chartboost.didCompleteRewardedVideo += VideoCompleted;
Chartboost.didCacheInterstitial += DidCacheInterstitial;
Chartboost.didDismissInterstitial += DidDismissInterstitial;
Chartboost.didCloseInterstitial += DidCloseInterstitial;
Chartboost.didCacheRewardedVideo += DidCacheVideo;
Chartboost.didFailToLoadInterstitial += FailedToLoadInterstitial;
Chartboost.didFailToLoadRewardedVideo += FailedToLoadVideo;
}
private void OnDisable()
{
Chartboost.didCompleteRewardedVideo -= VideoCompleted;
Chartboost.didCacheInterstitial -= DidCacheInterstitial;
Chartboost.didDismissInterstitial -= DidDismissInterstitial;
Chartboost.didCloseInterstitial -= DidCloseInterstitial;
Chartboost.didCacheRewardedVideo -= DidCacheVideo;
Chartboost.didFailToLoadInterstitial -= FailedToLoadInterstitial;
Chartboost.didFailToLoadRewardedVideo -= FailedToLoadVideo;
}
public void VideoCompleted(CBLocation location, int reward)
{
canShowChartBoostVideo = false;
if (RewardController.instance != null)
{
RewardController.instance.VideoWatchedGiveUserAReward();
}
LoadChartBoostVideoAds();
}
public void DidCacheInterstitial(CBLocation location)
{
canShowChartBoostInterstitial = true;
}
public void DidDismissInterstitial(CBLocation location)
{
canShowChartBoostInterstitial = false;
LoadChartBoostVideoAds();
LoadChartBoostInterstitialAds();
}
public void DidCloseInterstitial(CBLocation location)
{
canShowChartBoostInterstitial = false;
LoadChartBoostVideoAds();
LoadChartBoostInterstitialAds();
}
public void DidCacheVideo(CBLocation location)
{
canShowChartBoostVideo = true;
}
private void FailedToLoadInterstitial(CBLocation location, CBImpressionError error)
{
canShowChartBoostInterstitial = false;
LoadChartBoostInterstitialAds();
}
private void FailedToLoadVideo(CBLocation location, CBImpressionError error)
{
canShowChartBoostVideo = false;
if (ShopMenuController.instance != null)
{
ShopMenuController.instance.FailedToLoadTheVideo();
}
LoadChartBoostVideoAds();
}
public void LoadChartBoostVideoAds()
{
Chartboost.cacheRewardedVideo(CBLocation.Default);
}
public void LoadChartBoostInterstitialAds()
{
Chartboost.cacheInterstitial(CBLocation.Default);
}
public void ShowChartBoostInterstitial()
{
if (canShowChartBoostInterstitial)
{
Chartboost.showInterstitial(CBLocation.Default);
}
else
{
LoadChartBoostInterstitialAds();
}
}
public void ShowChartBoostVideo()
{
if (canShowChartBoostVideo)
{
Chartboost.showRewardedVideo(CBLocation.Default);
}
else
{
LoadChartBoostVideoAds();
}
}
public void LoadUnityAds()
{
if (Advertisement.isSupported)
{
Advertisement.Initialize(_appId, false);
}
}
public void ShowUnityAds()
{
if (Advertisement.IsReady())
{
Advertisement.Show(null, new ShowOptions()
{
resultCallback = result =>
{
switch (result)
{
case ShowResult.Finished:
GameController.instance.RewardPlayerWithSomething();
LoadUnityAds();
break;
case ShowResult.Failed:
GameController.instance.VideoNotLoadedOrUserSkippedTheVideo("Failed to load the video. Please try again.");
LoadUnityAds();
break;
case ShowResult.Skipped:
GameController.instance.VideoNotLoadedOrUserSkippedTheVideo("Video skipped.");
LoadUnityAds();
break;
}
}
});
}
else
{
GameController.instance.VideoNotLoadedOrUserSkippedTheVideo("Failed to load the video. Please try again.");
LoadUnityAds();
}
}
}
Run cache after every time you show an interstitial.
like this :
Chartboost.showInterstitial(CBLocation.Default);
Chartboost.cacheInterstitial(CBLocation.Default);
That way you will replenish the cache every time you show an ad.
Remember to cache as soon as its initialized as well.

Why does PlaybackState remain at Playing after PlaybackStopped fires?

I'm a little new to using NAudio so I'm surely missing something important, hence this question.
Starting with example/demo code, I put together a class as simple as I could make it to play MP3 or WAV files:
public class AudioPlayer : IDisposable
{
WaveStream _waveStream; // sound data stream
WaveChannel32 _waveChannel32; // sound channel ??
IWavePlayer _iWavePlayer; // sound output driver
public bool IsPlaying
{
get { return _iWavePlayer != null
&& _iWavePlayer.PlaybackState
!= Wave.PlaybackState.Stopped; }
}
public PlaybackState PlaybackState
{
get { return _iWavePlayer.PlaybackState; }
}
public void LoadMp3(byte[] mp3Bytes)
{
Load(CreateInputStreamFromMp3Bytes(mp3Bytes));
}
public void LoadFile(string filename)
{
Load(CreateInputStream(filename));
}
void Load(WaveStream waveStream)
{
if (_iWavePlayer != null)
Dispose();
_iWavePlayer = new WaveOut();
_iWavePlayer.PlaybackStopped +=
new EventHandler(_iWavePlayer_PlaybackStopped);
_waveStream = waveStream;
_waveChannel32 = new WaveChannel32(_waveStream);
_waveChannel32.PadWithZeroes = false;
_iWavePlayer.Init(_waveChannel32);
}
void _iWavePlayer_PlaybackStopped(object sender, EventArgs e)
{
Stop();
}
static WaveStream CreateInputStreamFromMp3Bytes(byte[] mp3Bytes)
{
return new Mp3FileReader(new MemoryStream(mp3Bytes), false);
}
static WaveStream CreateInputStream(string fileName)
{
if (fileName.EndsWith(".wav"))
return new WaveFileReader(fileName);
else if (fileName.EndsWith(".mp3"))
return new Mp3FileReader(fileName);
else
throw new InvalidOperationException("Unsupported extension");
}
public void Play()
{
_iWavePlayer.Play();
}
public void Stop()
{
if (_iWavePlayer != null
&& _iWavePlayer.PlaybackState != PlaybackState.Stopped) {
_iWavePlayer.Stop();
_waveStream.Position = 0;
}
}
public void Dispose()
{
Stop();
if (_iWavePlayer != null) {
_iWavePlayer.Dispose();
_iWavePlayer = null;
}
if (_waveChannel32 != null) {
_waveChannel32.Dispose();
_waveChannel32 = null;
}
if (_waveStream != null) {
_waveStream.Dispose();
_waveStream = null;
}
}
}
I'm using the code in question to play MP3 files (not WAVs).
It works ok for the most part, which is pretty awesome considering that I'll be able to replace MediaElements in my project. The issue I'm having is that the PlaybackState stays at Playing rather than changing to Stopped once PlaybackStopped fires. To go around that, I subscribe to PlaybackStopped and call Stop() from there.
Is it normal that I have to call Stop() like that, or is there is something I am missing here?
Looks like a bug. If you look at NAudio code WaveOut will not change PlaybackState in RaisePlaybackStoppedEvent. But DirectSoundOut will change it to stopped. A little crazy.
Try this:
In the Load method change this line:
_iWavePlayer = new WaveOut();
by this:
_iWavePlayer = new WaveOut(WaveCallbackInfo.FunctionCallback());

Categories

Resources