Xamarin Audio players not working in Galaxy S8 - c#

I am trying to get a shoutcast URL (.stream) to stream audio in a cross-platform application. I've started with the Android app first and I cannot get the audio playing on the test device Samsung Galaxy S8.
However, the audio players work fine within the Emulator. If it weren't for the test device I would've assumed everything was working.
I've tried using "the local MediaPlayer" and "Plugin.MediaManager": Both work in the Emulator but none on the device. I have enabled the permissions required in the manifest: ACCESS_NETWORK_STATE, INTERNET, MEDIA_CONTENT_CONTROLS, RECORD_AUDIO, WAKE_LOCK, READ_EXTERNAL_STORAGE
(using MediaManager plugin)
in MainActivy:
protected override void OnCreate(Bundle savedInstanceState)
{
.....
CrossMediaManager.Current.Init(this);
.....
}
public class StreamingService: IStreaming.IStreaming
{
bool IsPrepared = false;
public async void Play()
{
await CrossMediaManager.Current.Play("http://someUrl/stream");
}
public void Pause()
{
CrossMediaManager.Current.Pause();
}
public void Stop()
{
CrossMediaManager.Current.Stop();
IsPrepared = false;
}
public int getResponse()
{
if (CrossMediaManager.Current.IsPlaying())
return 1;
else
return 0;
}
}
If I look at the data usage for the app on the device it is set to 0kb after a few tries it goes up by the kb currently at 3.24kb data usage. It doesnt appear that the media player is trying to access the stream, or can even access the stream.

I found a nuget package: LibVLCSharp.Forms
in the Main application created a class:
using LibVLCSharp.Shared;
public class RadioStream
{
readonly LibVLC _libVLC;
readonly MediaPlayer _mp;
public RadioStream()
{
if (DesignMode.IsDesignModeEnabled) return;
Core.Initialize();
_libVLC = new LibVLC();
_mp = new MediaPlayer(_libVLC);
}
public void Init()
{
_mp.Media = new Media(_libVLC, "http://url/stream", FromType.FromLocation);
_mp.Media.AddOption(":no-video");
}
public void Play(bool play)
{
if (play)
_mp.Play();
else _mp.Pause();
}
public bool isPlaying()
{
if (_mp.IsPlaying == false)
return false;
else
return true;
}
}
And its working!
In a while loop I check the isPlaying() that allows me to set the status of the stream and display accordingly.
Its simple at the moment, and stops playing when the internet state changes. But the above is working for simple playback.

Related

Android 8 receive of stop receiving media buttons events

I have a service that listens to media buttons, but I only want to listen to those when my service is running since I have a button on the UI to start/stop the service.
How can I achieve the following two actions:
On MyService start-up, start receiving media button events to com.myApp/MyService.
On MyService end, stop receiving media button events in com.myApp/MyService.
The related logs are the following:
D MediaSessionService: Sending KeyEvent { action=ACTION_DOWN, keyCode=KEYCODE_HEADSETHOOK, scanCode=226, metaState=0, flags=0x8, repeatCount=0, eventTime=13258317, downTime=13258317, deviceId=4, source=0x101 } to com.myApp/MyService (userId=0)
Note:
I found out that I can start receiving media events after my app started to play audio. This is however not ideal, since I don't want to play audio in my app. (I am only using media events in order to trigger voice recognition)
After I played audio, my service is apparently the default media receiver. This means that when a media button is pressed, my service get instantiated, does nothing, and get destroyed. This is not an idea behavior for the end user since my app ends up 'stealing' these events that could potentially be handled by something else.
Overriding OnStartCommand() in my service does not help
Calling SetMediaButtonReceiver on the MediaSession does not help either
Using a BroadcastReceiver with the intent "android.intent.action.MEDIA_BUTTON" registered in the AudioManager does not work either
Relevant code (in C#, I am on Xamarin.Forms, but that should not have any impact on the way to achieve this)
public class MediaSessionCompatCallback : MediaSessionCompat.Callback
{
public Func<Intent, bool> MediaButtonEvent { get; set; }
public override bool OnMediaButtonEvent(Intent mediaButtonEvent) => MediaButtonEvent?.Invoke(mediaButtonEvent) ?? false;
}
[Service(Exported = true, Enabled = true)]
[IntentFilter(new[] { ServiceInterface })]
public class MediaBrowserService : MediaBrowserServiceCompat, AudioManager.IOnAudioFocusChangeListener
{
private MediaSessionCompat mediaSession;
private MediaSessionCompatCallback mediaSessionCallback;
private void CreateMediaSessionCallback()
{
mediaSessionCallback = new MediaSessionCompatCallback()
{
MediaButtonEvent = OnMediaButtonEvent
};
}
private void SetupMediaSession()
{
CreateMediaSessionCallback();
var stateBuilder = new PlaybackStateCompat.Builder().SetActions(PlaybackStateCompat.ActionPlay | PlaybackStateCompat.ActionPlayPause);
mediaSession = new MediaSessionCompat(this, nameof(MediaBrowserService));
mediaSession.SetFlags(MediaSessionCompat.FlagHandlesMediaButtons | MediaSessionCompat.FlagHandlesTransportControls);
mediaSession.SetPlaybackState(stateBuilder.Build());
mediaSession.SetCallback(mediaSessionCallback);
mediaSession.Active = true;
SessionToken = mediaSession.SessionToken;
}
private void BuildNotification() { [...] }
public override void OnCreate()
{
base.OnCreate();
SetupMediaSession();
StartForeground(135, BuildNotification());
ContextCompat.StartForegroundService(ApplicationContext, new Intent(ApplicationContext, Java.Lang.Class.FromType(typeof(MediaBrowserService))));
}
public override void OnDestroy()
{
base.OnDestroy();
if (mediaSession != null)
{
mediaSession.Active = false;
mediaSession.SetCallback(null);
mediaSession.Release();
mediaSession.Dispose();
mediaSession = null;
}
if (mediaSessionCallback != null)
{
mediaSessionCallback.Dispose();
mediaSessionCallback = null;
}
StopForeground(true);
StopSelf();
}
}

C# CSCore no sound from mp3 file

Using the CSCore library, I wrote the code for playing an mp3 file in the class BGM in a seperate file called BGM.cs and the method for playback is BGM.Play("file directory");, which is called in the Form. But somehow I can't manage to get any sound out of it. I've already checked volume, codec and output, and I can't think of anything else that might cause this problem.
This is the code of the class file:
public class BGM
{
public static void Play(string file)
{
using (IWaveSource soundSource = GetSoundSource(file))
{
using (ISoundOut soundOut = GetSoundOut())
{
soundOut.Initialize(soundSource);
soundOut.Volume = 0.8f;
soundOut.Play();
}
}
}
private static ISoundOut GetSoundOut()
{
if (WasapiOut.IsSupportedOnCurrentPlatform)
return new WasapiOut();
else
return new DirectSoundOut();
}
private static IWaveSource GetSoundSource(string file)
{
return CodecFactory.Instance.GetCodec(file);
}
There are actually a couple reasons why your mp3 isn't playing.
The first reason is you haven't specified a device for the sound to play on. The code below gets the first device that can render sound, but that won't always be correct if the user has multiple devices attached to their computer. You'll have to handle that appropriately. The device has to be set on the WasapiOut object.
The second reason is your use of using statements in your Play method. While it's always a good idea to clean up objects that implement IDisposable, you can't always do so immediately. In this case, soundOut.Play() is not a blocking method, which meant that control was exiting the method immediately, causing Dispose() to be called on soundOut and soundSource. This meant that the sound would effectively never be played (maybe it would start for a short moment, but not enough to really hear it). Essentially, you need to hold onto the references and only dispose of them once playback is complete.
Have a look at the AudioPlayerSample for an idea on how to implement a complete solution. My code should get you started.
void Main()
{
using(var player = new BGM(#"D:\Test.mp3"))
{
player.Play();
// TODO: Need to wait here in order for playback to complete
// Otherwise, you need to hold onto the player reference and dispose of it later
Console.ReadLine();
}
}
public class BGM : IDisposable
{
private bool _isDisposed = false;
private ISoundOut _soundOut;
private IWaveSource _soundSource;
public BGM(string file)
{
_soundSource = CodecFactory.Instance.GetCodec(file);
_soundOut = GetSoundOut();
_soundOut.Initialize(_soundSource);
}
public void Play()
{
if(_soundOut != null)
{
_soundOut.Volume = 0.8f;
_soundOut.Play();
}
}
public void Stop()
{
if(_soundOut != null)
{
_soundOut.Stop();
}
}
private static ISoundOut GetSoundOut()
{
if (WasapiOut.IsSupportedOnCurrentPlatform)
{
return new WasapiOut
{
Device = GetDevice()
};
}
return new DirectSoundOut();
}
private static IWaveSource GetSoundSource(string file)
{
return CodecFactory.Instance.GetCodec(file);
}
public static MMDevice GetDevice()
{
using(var mmdeviceEnumerator = new MMDeviceEnumerator())
{
using(var mmdeviceCollection = mmdeviceEnumerator.EnumAudioEndpoints(DataFlow.Render, DeviceState.Active))
{
// This uses the first device, but that isn't what you necessarily want
return mmdeviceCollection.First();
}
}
}
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
if (disposing)
{
if(_soundOut != null)
{
_soundOut.Dispose();
}
if(_soundSource != null)
{
_soundSource.Dispose();
}
}
_isDisposed = true;
}
}
public void Dispose()
{
Dispose(true);
}
}

How to play music from url in Xamarin.Forms?

I am gonna build Xamarin.Forms app which play music from url.
I used dependency service for each platform implementation.
[assembly: Dependency(typeof(AudioSerivce))]
namespace xxx.Droid
{
public class AudioSerivce : IAudio
{
int clicks = 0;
MediaPlayer player;
public AudioSerivce()
{
}
public bool Play_Pause (string url)
{
if (clicks == 0) {
this.player = new MediaPlayer();
this.player.SetDataSource(url);
this.player.SetAudioStreamType(Stream.Music);
this.player.PrepareAsync();
this.player.Prepared += (sender, args) =>
{
this.player.Start();
};
clicks++;
} else if (clicks % 2 != 0) {
this.player.Pause();
clicks++;
} else {
this.player.Start();
clicks++;
}
return true;
}
public bool Stop (bool val)
{
this.player.Stop();
clicks = 0;
return true;
}
}
}
and calling it
DependencyService.Get<IAudio>().Play_Pause("https://www.searchgurbani.com/audio/sggs/1.mp3");
If I check log, it seems everything is ok.
But I can't hear sound on android phone.
If anyone has some suggestion, please let me know.
Thanks
From:
https://forums.xamarin.com/discussion/64218/no-video-player-really
I suspect that there may be a problem related to an incompatibility between Octane Video player and Android Emulator, are you using a emulator/simulator?
Also another suggestion is to add this permissions:
INTERNET
WRITE_EXTERNAL_STORAGE
READ_EXTERNAL_STORAGE
To your Android app.
If that does not work try to use another url and compare if it working with other url's.

Android C#:Listening for Volume button presses in background service

I'm creating an Android App in C# Xamarin.
Is there a way to "listen" for volume up/down key presses when an App goes into "background" mode, i.e. when a user "locks" their phone?
I've created several Service objects and made them "resident" by issuing the command 'StartCommandResult.Sticky'.
Any sample C# Xamarin code would be much appreciated.
You do not need to create a background service, just start a another task to listen the volume control. If the application do not be killed the task will run on the background.
public class MainActivity : Activity
{
private int currentVolume;
public AudioManager mAudioManager;
private int maxVolume;
private bool isDestory;
Android.Media.MediaPlayer player;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
player = Android.Media.MediaPlayer.Create(this, Resource.Raw.SampleAudio);
SetContentView (Resource.Layout.Main);
mAudioManager = (AudioManager)GetSystemService(Context.AudioService);
maxVolume = mAudioManager.GetStreamMaxVolume(Stream.Music);
onVolumeChangeListener();
player.Start();
}
protected override void OnDestroy()
{
base.OnDestroy();
isDestory = true;
}
private Task voluemChangeTask;
public void onVolumeChangeListener()
{
currentVolume = mAudioManager.GetStreamVolume(Stream.Music);
voluemChangeTask = new Task(ChangeVolume);
voluemChangeTask.Start();
}
public void ChangeVolume()
{
while (!isDestory)
{
int count = 0;
try
{
Thread.Sleep(20);
}
catch (Exception e)
{
}
if (currentVolume < mAudioManager.GetStreamVolume(Stream.Music))
{
System.Console.WriteLine("volunm+");
count++;
currentVolume = mAudioManager.GetStreamVolume(Stream.Music);
mAudioManager.SetStreamVolume(Stream.Music, currentVolume, VolumeNotificationFlags.RemoveSoundAndVibrate);
}
if (currentVolume > mAudioManager.GetStreamVolume(Stream.Music))
{
System.Console.WriteLine("volunm-");
count++;
currentVolume = mAudioManager.GetStreamVolume(Stream.Music);
mAudioManager.SetStreamVolume(Stream.Music, currentVolume, VolumeNotificationFlags.RemoveSoundAndVibrate);
}
}
}
}
I have tested it in the real device with screen lock and got the log:

Audio Capture is not working as expected

In my Microsoft Surface application I'd like to use voice capture. So I followed the tutorial metioned here (http://opensebj.blogspot.com/2009/04/naudio-tutorial-5-recording-audio.html) and modified the NAudio.dll to be able to execute the following code:
class AudioRecording
{
private WaveMixerStream32 mixer;
public AudioRecording()
{
mixer = new WaveMixerStream32();
mixer.AutoStop = false;
}
public void start()
{
Console.WriteLine("Start recording");
mixer.StreamMixToDisk("Test.wav");
mixer.StartStreamingToDisk();
}
public void stop()
{
Console.WriteLine("Stop recording");
mixer.StopStreamingToDisk();
}
}
But this doesn't really capture the sound. I just create a file of 58 bytes, that is empty. What Am I doing wrong?
Problem is sovled here:
http://naudio.codeplex.com/Thread/View.aspx?ThreadId=239825

Categories