Reproducir sonido con XNA en Windows Phone

En uno de mis anteriores post hablé de reproducir sonido en Windows Store y Windows Phone usando entre otros el MediaElement.

Ya lo comenté, pero por si acaso lo vuelvo a decir, en Windows Phone 8 hay problemas para reproducir dos sonidos a la vez con el MediaElement. No sé si con 8.1 se ha solucionado

Una opción con Windows Phone para solucionar este problema es usando XNA. Os recuerdo que XNA ya no funciona con Windows Store Apps. XNA es una tecnología que no tiene continuidad con Windows 8.

XNA también nos soluciona el problema de la reproducción de sonido muy continuado. Cuando se reproduce un mismo sonido muchas veces y hay solapación, la nueva reproducción corta la anterior.

Para reproducir sonido en XNA usaremos la libreria Microsoft.Xna.Framework.Media y Microsoft.Xna.Framework.Audio


using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Audio;

Declaramos una variable que sea el Stream del sonido y otra de tipo SoundEffect que lo reproduzca:


private Stream soundStream;
soundStream = Application.GetResourceStream(new Uri("Assets/Sounds/timeIsUp.wav", UriKind.Relative)).Stream;

private SoundEffect soundEffect;
soundEffect = SoundEffect.FromStream(soundStream);

Sólo queda reproducirlo


soundEffect.Play();

Simple verdad? 🙂

 

 

Anuncis

MediaElement y reproducir sonido en Windows Store y Windows Phone

Como ya dice el título, MediaElement es un control que nos permite reproducir sonido tanto en aplicaciones Windows Phone (MediaElement para Windows Phone) como en aplicaciones Windows Store (MediaElement para Windows Store). Con mi experiencia quiero contar algunas cosas respecto a este control.

Primero, en Windows Phone tiene algún que otro fallo, a veces no reproduce el sonido, sobretodo si la aplicación está trabajando duro, no sé, quizá cuando está cargando el archivo de audio.

Otro problema es si tenemos más de un MediaElement que quieren reproducir sonido declarados en XAML; en cuanto activamos el segundo el primero deja de reproducir. En este escenario debemos usar XNA Framework para reproducir el sonido.

También, la reproducción continua del mismo, por ejemplo un botón que al pulsar reproduce un sonido, si lo pulsamos muchas veces y de forma continua el sonido de la nueva pulsación corta la del anterior.

A favor debo decir que es la forma más fácil que tenemos de reproducir sonido en Windows Phone, con el permiso del control de comportamiento PlaySoundAction.

Segundo, en Windows Store es más estable. No he detectado en ningún momento que deje de reproducir sonido pase lo que pase.

Además, ya no tenemos el problema de que si hay más de un control MediaElement uno deja de hacer reproducir el otro. Es decir, en Windows Store podemos reproducir varios MediaElement a la vez.

Pero, SI continua el problema del botón que se pulsa repetitivamente y con mucha velocidad. El sonido que reproduce el boton corta el sonido de la pulsación anterior. Para arreglar tenemos dos opciones:

1) Des de código creas el control MediaElement para cada pulsación del botón y lo haces reproducir


storageFile = await installedLocation.GetFileAsync("Assets\\Sounds\\hahahaaa.wav");
sound = await storageFile.OpenReadAsync();
Sound = new MediaElement();
Sound.AutoPlay = true;
Sound.SetSource(sound, storageFile.ContentType);

Pros: Fácil e intuitivo

Contras: Este control no lanzará jamás ningún evento, por tanto la única opción es reproducir con el AutoPlay=true. Eso implica que no puedes controlar cuando se reproduce el sonido porque tienes el tiempo que tarda el archivo de audio a cargarse dentro del control MediaElement. Otro problema, es que produce bajadas de rendimiento aleatorios importantes donde deja el Thread UI ocupado durante media segundo más o menos, lo que hace que en algunos casos la interacción con tu aplicación sea un desastre.

2) Usar XAudio2 de DirectX

Consulta un buen ejemplo aquí: XAudio2 audio file playback sample

Pros: máximo rendimiento y reproducción perfecta

Contras: Programar con C++ (que si somos de .Net pues es un poco diferente) y trabajar con DirectX

Nota : Si eres un maestro en C++ y sabes de DirectX ya no tienes ningún contra. Así que adelante 🙂

Windows Phone y enlaces bidireccionales y pérdida de foco

En Windows Phone a los enlaces bidireccionales existe solo dos formas de actualizar la fuente: Default y Explicit

Aquí tienes la información del MSDN : UpdateSourceTrigger Enumeration

En realidad no hay ningún problema ya que el perder el foco ya funciona correctamente. Lo que pasa es que en Windows Phone la application bar no genera perdida de foco y en el caso de que estuvieses escribiendo en un textbox el cambio no se propaga a la fuente.

Así, se puede dar el caso siguiente:

Tienes una página donde se pide escribir un texto y en la application bar un botón que al pulsar usa este texto para consultar. Lo que el usuario hará será pulsar en textbox, luego le aparece el teclado del Windows Phone, escribe y luego pulsa directamente en el botón de la application bar.

El comando se ejecuta pero la propiedad enlazada al textbox no se actualiza porque no ha habido perdida de foco.

Así que lo que tenemos que hacer es provocar nosotros mismos que se actualice. Esto es lo que escribiremos en el método Click del botón de la application bar.

object focusObj = FocusManager.GetFocusedElement();
if (focusObj != null && focusObj is TextBox)
{
var binding = (focusObj as TextBox).GetBindingExpression(TextBox.TextProperty);
  binding.UpdateSource();
}

Más información:

TextBox Binding TwoWay Doesn’t Update Until Focus Lost WP7

Original solution : Non-string parameters between pages in Windows Phone

My last post was about an original solution using Dependency properties. This time another original solution passing non-string parameters between pages in Windows Phone.

In WPF or Windows Runtime (aka Windows Store apps) you can pass parameters between pages as objects and this means that you don’t have any problem to pass parameters. But, in Windows Phone only parameters as string is possible. For example:


NavigationService.Navigate(new Uri("yourpage.xaml?parameter1=value1&parameter2=value2,UriKind.Absolute));

As you can see, navigate in Windows Phone is like web pages. Only using Uri you can pass parameters, and this parameters need to be in string format.

Yes, this is a problem, because in some cases, we are using complex objects structures in a page and we would like to pass this same complex structure to another page.

A solution is to serialize the object with DataContract attribute. But, the problem is, no all object can be serialized and the Uri is length limited.

An original solution that I found on internet is using an extension for NavigationService and a static field to save the object to pass to another page. Look an example:


public static class NavigationExtensions {

private static object _navigationData = null;

public static void Navigate(this NavigationService service, string page, object data)

{

_navigationData = data;

service.Navigate(new Uri(page, UriKind.Relative));

}

public static object GetLastNavigationData(this NavigationService service)

{

object data = _navigationData;

_navigationData = null;

return data;

}

}

Simply clever, awesome.

Then, you can call on the source page


NavigationService.Navigate("mypage.xaml", myParameter);

And on the target page in the OnNavigatedTo


var myParameter = NavigationService.GetLastNavigationData();

Source:

How do I pass non-string parameters between pages in windows phone 8?

Solución original : Añadir un DependencyProperty propio a un control

IC210095

Trabajando con Windows Phone 8 y concretamente con el control de mapas y el Toolkit de Windows Phone, que por cierto ahora es distinto que con Windows Phone 7 y 7.5, me he encontrado con el problema de que al momento de colocar Pushpins de forma dinámica usando una lista la propiedad ItemsSource de MapItemsControl no es Bindable.

Ante este problema una solución es asignar la lista directamente por código y con eso acabamos. Solución rápida y simple.

Pero si buscamos ser coherentes con lo que es o son las aplicaciones WPF de separar lo que es la lógica de la interfaz de usuario (XAML) y que por eso existe el patrón MVVM esta solución no es pura 🙂

Encontré una solución original que no solo sirve en este caso sino que también en cualquier otro. Crear tu propio propiedad Bindable y asignarlo a cualquier control como si fuera nativo.

El enlace lo encontráis al final de este post pero yo os lo cuento un poco por encima.

Si creas una clase estática con un Dependency Property luego puedes usar esa propiedad (que también debes hacerla estática) en cualquier control WPF. El truco está en programar el método que se debe ejecutar cuando cambia la propiedad Dependecy Property.

Aquí tienes la sintaxis del MSDN:


public static DependencyProperty Register(
string name,
Type propertyType,
Type ownerType,
PropertyMetadata typeMetadata,
ValidateValueCallback validateValueCallback
)

De esta forma puedes conseguir leer las propiedades del control al cual te “hospedas” y asignar valores en código.


private static void OnPushPinPropertyChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
UIElement uie = (UIElement)d;
var pushpin = MapExtensions.GetChildren((Map)uie).OfType<MapItemsControl>().FirstOrDefault();
pushpin.ItemsSource = (IEnumerable)e.NewValue;
}

 

Aquí tenéis el ejemplo completo: MVVM Windows Phone 8 – adding a collection of pushpins to a map

Si teneis alguna duda me lo preguntáis.

Mouse events Grid Control

In this article is explained How to handle mouse event on entire Grid Control in WPF or Windows Store apps or Windows Phone apps.
It is really simple and I would not write anything about that in my blog if I had not had problems with this simple action in my Windows Phone project that I am working.
At the bottom of this article it says the gold rule:
In order for this to work you need to always set the Grid Background, either to transparent or to whatever you like, because if its null the event isn’t triggered…

And that’s true, remember to put a background on your Grid, by default could be set to null.

Actuar quan entra una trucada a les aplicacions amb Windows Phone

Aquí teniu un gràfic del model d’execució de Windows Phone.

model_exec_wp

Com podeu veure les aplicacions passen a estat Dormant quan no estan en primer pla. Posteriorment si el sistema determina que necessita més memòria els passa a un estat Tombstoned.

Aquests dos estats són completament recuperables. La diferencia entre un i l’altre és que el primer tot està a memòria i el segon no.

Una aplicació passa a segon pla quan premem el botó de Windows o quan l’aplicació crida un altra aplicació. O bé quan el sistema ho necessita. En tots els casos tal com veieu a la gràfica es crida OnNavigatedFrom.

En una trucada entrant no és així. En aquest cas no es considera que la App passi a segon pla. Mentre tu parles l’aplicació continua la seva execució. Això significa que no es crida el OnNaviogatedFrom i per tant no ens dóna cap tipus de pista que hi ha una trucada entrant.

Per sort, si tenim els events Obscured i Unobscured. Aquí teniu un link que us dóna molta información : How to handle phone calls and other interruptions in Windows Phone, tot i que he detectat un petit error en el codi font. Aquí poso corretgit:


App<span style="font-family: Consolas; font-size: small;"><span style="font-family: Consolas; font-size: small;">.RootFrame.Obscured += RootFrame_Obscured;</span></span>

App.RootFrame.Unobscured += RootFrame_Unobscured;

void RootFrame_Obscured(object sender, ObscuredEventArgs e)
{
oTimer.Stop();
txtStatus.Text = "Obscured event occurred";
}

void RootFrame_Unobscured(object sender, EventArgs e)
{

oTimer.Start();
txtStatus.Text = "Unobscured event occurred";
}