Condividi tramite


Il presente articolo è stato tradotto automaticamente.

Touch-and-Go

Riproduzione di file audio in Windows Phone

Charles Petzold

Scaricare il codice di esempio

Charles PetzoldQuando ho letto che i miglioramenti in Windows Phone OS 7.1 incluso un modo per le applicazioni per riprodurre file di suono e la musica in sottofondo, ho pensato, "non abbiamo che già?"

Si scopre che sono stato corretto, ma solo un po'.È infatti possibile per un'applicazione di Windows Phone OS 7.0 per riprodurre un file di musica in sottofondo, ma solo in un caso molto speciale.In tutti gli altri casi, qualsiasi file musicale che riproduce l'applicazione Windows Phone OS 7.0 si fermerà quando l'applicazione viene spostata in background.Naturalmente, per la maggior parte delle applicazioni, questo comportamento è interamente appropriato e probabilmente esattamente quello che vuoi.

Ma si consideri un'applicazione che offre musica per il tuo cellulare a prescindere dalla biblioteca di musica normale del telefono.Per un'applicazione, è estremamente desiderabile per continuare a giocare mentre altre applicazioni occupano il primo piano o quando lo schermo è scaduta e passa a uno stato bloccato.E anche per quelli di noi che non hanno la necessità di scrivere un'applicazione, questa struttura offre un divertimento punto di ingresso nel ad esplorare il mondo nuovo "agenti di sfondo", introdotto nel Windows Phone OS 7.1.

Nel prossimo numero, vi mostrerò come scrivere un programma Windows Phone che riproduce file di musica in background.Ma per fornire un quadro più ampio di servizi audio su Windows Phone, voglio iniziare in questa colonna con i modi più standard per riprodurre file audio supportati in Windows Phone OS 7.0, come pure la versione 7.1.

MediaElement e le sue fonti

Il modo più comune per un programma di Silverlight per giocare una musica o file audio è con MediaElement.Nulla è più semplice: MediaElement deriva da FrameworkElement, in modo da potete metterlo nella struttura ad albero visuale di un file XAML e basta impostare la proprietà Source un URL:

<MediaElement Source="http://www.SomeWebSite.com/CoolSong.mp3" />

Quando viene caricato il file XAML, il file musicale automaticamente inizia a suonare. MediaElement supporta file MP3, WMA e WAV. Particolari sono documentati a msdn.microsoft.com/library/ff462087(VS.92).

In alternativa fare riferimento a un file su Internet, è possibile incorporare un file audio o la musica nel vostro file eseguibile dell'applicazione. Aggiungere il file al programma in Visual Studio e bandiera Build Action come contenuto o risorsa. (Contenuto è preferito e incorpora il file nell'eseguibile XAP; con la risorsa, il file è incorporato nella DLL per il programma.) Impostare la proprietà Source a un URL di riferimento al nome di file con un nome di cartella se applicabile:

<MediaElement Source="Music/LocalSong.wma" />

Anche se MediaElement può essere molto semplice, ci sono numerosi modi per renderlo più complicato.Un modo è per specificare il file audio in fase di esecuzione, come ho fatto nel programma MediaElementDemo, che fa parte del codice scaricabile per questo articolo.

In questo programma, MediaElement è ancora nella struttura ad albero visuale, ma non è impostata la proprietà Source e AutoPlay è impostata su False.Media­ElementDemo vi permette di riprodurre i tre movimenti il concerto per violino di Brahms.(I file sono da Internet Archive at archive.org/­BrahmsViolinConcerto/dettagli-Heifetz.È una performance 1939 con la violinista Jascha Heifetz e lo svolgimento di Serge Koussevitzky, inizialmente disponibile su dischi 78 giri di Victor). Tre elementi RadioButton hanno loro proprietà Tag impostare le fonti dei tre file di musica.Per il primo RadioButton, che è l'URL completo del file di musica sul sito Web di Internet Archive.Per il secondo movimento, ho scaricato il file di musica (denominato 02Ii.Adagio.mp3) al mio PC, creato una cartella denominata musica nel progetto in Visual Studio e ha aggiunto che il file nella cartella.La seconda RadioButton fa riferimento a tale file con il nome "Music/02Ii.Adagio.mp3." Quando uno di questi due pulsanti è selezionata, il gestore eventi ottiene la proprietà Tag e crea un oggetto Uri fuori di esso (specificando UriKind. Absolute per il riferimento Web e UriKind. relative per il contenuto) e che imposta la proprietà Source dell'oggetto MediaElement.

Il secondo movimento è un file di circa 4,5 MB, e ovviamente aumenta le dimensioni del file eseguibile di una massa considerevole.Aggiunta di file di queste dimensioni al vostro eseguibile non è raccomandato e fatto qui solo per dimostrazione!

Se l'applicazione deve file di quelle dimensioni, un compromesso possibile è disponibile: L'applicazione potrebbe scaricare il file una volta su Internet e salvarlo in archiviazione isolata.Ecco che cosa ho fatto per il terzo movimento del concerto per violino.Il terzo RadioButton (che viene assegnato un nome di "isoStoreRadio­pulsante") la cui proprietà IsEnabled inizialmente impostata su false.Figura 1 mostra il processo di download.Nel costruttore della pagina, se il file non è nell'archiviazione isolata, WebClient avvia un trasferimento di sfondo.Quando il trasferimento viene completato, il file viene salvato all'archiviazione isolata e RadioButton è abilitato.

Figura 1 download di un File Web all'archiviazione isolata

public MainPage()
{
  InitializeComponent();
  // ...
// Check if file is in Isolated Storage; otherwise start downloading it
  using (IsolatedStorageFile isoStore =
    IsolatedStorageFile.GetUserStoreForApplication())
  {
    if (isoStore.FileExists(isoStoreRadioButton.Tag as string))
    {
      isoStoreRadioButton.IsEnabled = true;
    }
    else
    {
      WebClient webClient = new WebClient();
      webClient.OpenReadCompleted += OnWebClientOpenReadCompleted;
      webClient.OpenReadAsync(new Uri("http://www.archive.org/....mp3"));
    }
  }
  // ...
}
// When the music file is downloaded, save it to Isolated Storage
void OnWebClientOpenReadCompleted(object sender, 
  OpenReadCompletedEventArgs args)
{
  if (!args.Cancelled && args.Error == null)
  {
    Stream inpStream = args.Result;
    byte[] buffer = new byte[inpStream.Length];
    inpStream.Read(buffer, 0, buffer.Length);
    using (IsolatedStorageFile isoStore =
      IsolatedStorageFile.GetUserStoreForApplication())
    {
      string isoPathName = isoStoreRadioButton.Tag as string;
      string isoDirName = Path.GetDirectoryName(isoPathName);
      if (!isoStore.DirectoryExists(isoDirName))
      {
        isoStore.CreateDirectory(isoDirName);
      }
      using (IsolatedStorageFileStream isoStream =
        isoStore.CreateFile(isoPathName))
      {
        isoStream.Write(buffer, 0, buffer.Length);
        isoStoreRadioButton.IsEnabled = true;
      }
    }
  }
}

In alcuni contesti su Windows Phone OS 7.1, è possibile definire un URI con il prefisso "isostore" per fare riferimento a un file nell'archiviazione isolata, ma questo non funziona per MediaElement. Fortunatamente, Media­elemento ha una proprietà SetSource che accetta un oggetto Stream. Figura 2mostra come il gestore Checked per gli elementi RadioButton gestisce queste differenze.

Figura 2 impostando la sorgente su MediaElement

void OnRadioButtonChecked(object sender, RoutedEventArgs args)
{
  RadioButton radioButton = sender as RadioButton;
  string uriString = radioButton.Tag as string;
  // Save index for tombstoning
  radioButtonIndex = radioButtonPanel.Children.IndexOf(radioButton);
  if (radioButton == isoStoreRadioButton)
  {
    // Call SetSource on MediaElement using Isolated Storage stream.
using (IsolatedStorageFile storage =
      IsolatedStorageFile.GetUserStoreForApplication())
    {
      using (Stream isoStream = storage.OpenFile(uriString, FileMode.Open))
      {
        mediaElement.SetSource(isoStream);
      }
    }
  }
  else
  {
    // Set Source property on MediaElement using URI
    Uri uri = new Uri(uriString, uriString.Contains(':')
      ?
UriKind.Absolute : UriKind.Relative);
    mediaElement.Source = uri;
  }
}

Trasporti e lapidi

Un altro modo si può fare più difficile MediaElement per te è con l'aggiunta di controlli per mettere in pausa e spostarsi all'inizio o alla fine del file. Ancora più divertente è un controllo Slider che consente di spostare in un determinato punto nel file, come illustrato nella Figura 3.

The MediaElementDemo Program
Nella figura 3 il programma MediaElementDemo

I quattro pulsanti di ApplicationBar vengono implementati molto semplicemente. Rispettivamente, essi impostare la proprietà Position di MediaElement a zero, chiamare il metodo Play di MediaElement, chiamare il metodo Pause e impostare la proprietà Position alla proprietà NaturalDuration.

La parte difficile è abilitazione e la disabilitazione i pulsanti. Per quel lavoro, viene gestito l'evento CurrentStateChanged di MediaElement. Quando si lavora fuori MediaElement logica, è utile prima di utilizzare debug. WriteLine in caso di gestore per avere un'idea di come la proprietà CurrentState cambia quando viene caricato un file di musica, tamponato, giocato, si fermò e si è conclusa.

Al telefono, tutti musica e file audio sono giocati attraverso un singolo pezzo di software e hardware denominata coda di Media di Zune. Se si utilizza l'applicazione standard + video musicali sul telefono cellulare per giocare una canzone o l'album dalla vostra collezione di musica, che la musica continuerà a giocare in background quando si lascia quell'applicazione e avviare altre applicazioni — e anche quando si avvia il programma di MediaElementDemo. Tuttavia, se si avvia uno dei movimenti del concerto per violino di Brahms riproduzione, si fermerà la musica di sottofondo. Ora MediaElementDemo è nel controllo.

Ma se MediaElementDemo lascia il primo piano — se dall'utente premendo il pulsante Start o lasciando il time out di schermo — il Brahms si fermerà, anche se il programma non è definitiva.

In una tale circostanza, che cosa vuoi accadere quando l'utente ritorna al programma? Se la risposta è "Niente", siete in buona fortuna! Ma se si desidera che la musica ad avviare nuovamente da dove si era interrotto, MediaElementDemo dimostra come questo può essere fatto. Nell'override suo OnNavigatedFrom, il programma salva l'indice del movimento attualmente giocando, lo stato (probabilmente giocando o pausa) e la posizione. In OnNavigatedTo, il programma di controlli RadioButton e imposta lo stato e la posizione nel gestore MediaOpened.

MediaLibrary e MediaPlayer

Ho detto che prima di Windows Phone OS 7.1, un impianto esisteva già a giocare alcuni file musicali sul telefono in background. Il fermo è che questi file di musica devono essere parte della libreria musicale del telefono cellulare. Il programma può giocare uno di queste canzoni, o si può giocare tutte le canzoni in un album o tutte le canzoni di un particolare artista o genere, o tutte le canzoni in una playlist.

Le classi per fare questo sono membri dello spazio dei nomi Microsoft.Xna.Framework.Media. Per utilizzare queste classi XNA in un progetto Silverlight per il telefono, è innanzitutto necessario aggiungere un riferimento alla libreria di Microsoft.Xna.Framework. Windows Phone OS 7.0, Visual Studio ti ha dato un avvertimento circa facendo questo. Tale avviso è andato con Windows Phone OS 7.1.

Qualsiasi programma di Silverlight che utilizza le classi XNA per riprodurre la musica deve includere una classe speciale che implementa IApplicationService e chiama FrameworkDispatcher.Update ogni 30 di un secondo. Si può dare quella classe qualsiasi nome che si desidera, ma verrà riferimento nel file app. xaml nella sezione ApplicationLifetimeObjects:

<local:XnaFrameworkDispatcherService />

Per riprodurre un brano dalla libreria musicale dell'utente, iniziare creando un'istanza della classe MusicLibrary. Proprietà denominate artisti, album, generi e playlist forniscono insiemi di oggetti di tipo artista, Album, genere e Playlist, e tutte queste classi includono una proprietà di canzoni di tipo SongCollection che è una raccolta di oggetti Song. (Queste collezioni sono sola lettura; l'applicazione non aggiunge nulla alla libreria musicale dell'utente o modificarlo in alcun modo.)

Per iniziare a suonare qualcosa, utilizzare i membri della classe MediaPlayer statica. Il metodo MediaPlayer.Play accetta un oggetto di canzone, un SongCollection o un SongCollection con un indice per indicare la canzone per iniziare.

Il programma di PlayRandomSong contiene un pulsante "Gioca Random Song", e quando colpite che, nel codice riportato di seguito viene eseguita:

void OnButtonClick(object sender, RoutedEventArgs args)
{
    MediaLibrary mediaLib = new MediaLibrary();
    AlbumCollection albums = mediaLib.Albums;
    Album album = albums[random.Next(albums.Count)];
    SongCollection songs = mediaLib.Songs;
    Song song = songs[random.Next(songs.Count)];
    MediaPlayer.Play(song);
}

Questo codice consente di estrarre un album casuale dalla tua collezione, una canzone casuale da quell'album e inizia la partita. (L'emulatore di Windows Phone contiene un album con alcuni file canzone molto piccolo, quindi questo programma viene eseguito sull'emulatore bene.)

Se si avvia una canzone giocando con PlayRandomSong, troverete che è possibile navigare lontano dal programma o anche terminare il programma e la canzone continuare a giocare. È esattamente come se hai giocato quella canzone dall'applicazione di video musicali + regolare del telefono — e se si avvia l'applicazione, vedrete la copertina dell'album e il titolo della canzone. Inoltre, se si preme il tasto di controllo del volume sul telefono, potrai vedere la canzone nella parte superiore dello schermo e accedere ai pulsanti di mettere in pausa o andare all'inizio o alla fine della canzone.

Appena come applicazione di musica + video del telefono sa quale canzone che hai giocato con MediaPlayer.Play, l'applicazione è in grado di determinare quale canzone applicazione + video musicali del telefono è attualmente in riproduzione. Questa informazione è disponibile tramite la proprietà coda di MediaPlayer, che fornisce un oggetto MediaQueue che indica la canzone attualmente in riproduzione e una raccolta di canzoni se sta giocando un album o playlist. Il programma PlayRandomSong utilizza un timer per controllare la proprietà ActiveSong della coda e visualizza informazioni su quella canzone. In alternativa, è possibile impostare gestori per l'evento ActiveSongChanged di MediaPlayer.

Creazione di oggetti Song

Il programma di PlayRandomSong ottiene un oggetto canzone da una delle proprietà o collezioni di MediaLibrary, ma la canzone ha anche una proprietà statica denominata FromUri che crea una proprietà canzone basata su un file non nella libreria musicale. Questo URI può fare riferimento a un file di musica su Internet, o che fa parte del file XAP del programma. (Può fare riferimento a file nell'archiviazione isolata.) È quindi possibile utilizzare MediaPlayer per giocare questo oggetto canzone. (È possibile creare oggetti di SongCollection).

Il programma di MediaPlayerDemo mostra come è fatto. Questo programma consentono di giocare il doppio Concerto di Brahms (un'altra registrazione 1939 da archive.org/details/BrahmsDoubleConcerto_339) con Heifetz nuovamente, Emanuel Feuermann al violoncello ed Eugene Ormandy conducendo. Perché non è possibile utilizzare MediaPlayer con archiviazione isolata, entrambi i primi e gli ultimi movimenti sono i riferimenti Web.

Un'altra differenza è che la proprietà Position di MediaElement è gettable e impostabile, mentre la proprietà PlayPosition di MediaPlayer è solo gettable. Di conseguenza, i due pulsanti di ApplicationBar che vanno all'inizio e alla fine della pista non sono applicabili. Inoltre, a quanto pare non è possibile per ottenere la durata di un oggetto canzone creato in questo modo, quindi il dispositivo di scorrimento è irrilevante pure. Ho anche rimosso tutta la logica di rimozione definitiva da questo programma perché non è possibile avviare una traccia in cui hai lasciato.

Perché MediaPlayer gioca un oggetto canzone ottenuto da libreria musicale del telefono in background, si potrebbe aspettare anche a giocare qualsiasi oggetto canzone sullo sfondo. Non lo fa. A questo proposito, MediaPlayer è proprio come MediaElement. La musica si ferma, non appena si navigare lontano dall'applicazione. Tuttavia, se è spostarsi lontano dal programma MediaPlayerDemo e non è definitivamente — che spesso accade con Windows Phone OS 7.1 — la musica è solo sospesa. Quando navigate all'applicazione, si capta dove si era interrotto.

Penso che quando gesso fino i Plus e minus, Silverlight MediaElement è un po' più avanti di XNA MediaPlayer, ma l'auto­matic ripresa della riproduzione è una caratteristica molto piacevole MediaPlayer.

Streaming e oltre

Formati MP3 e io ho discusso riproduzione di file audio e musica comuni in WMA. Windows Phone permette anche un programma generare suono in modo dinamico all'interno dell'applicazione. Nel contesto di Windows Phone di programmazione, questo è noto come "streaming". Ho dimostrato un approccio nel programma SpeakMemo nel mio articolo di febbraio 2011 UI Frontiers (msdn.microsoft.com/magazine/gg598930) utilizzando la classe XNA DyanamicSoundEffectInstance. È anche possibile utilizzare la classe MediaStreamSource in Silverlight per fare qualcosa di simile. Ecco come implementare la sintesi di musica elettronica sul telefono cellulare. Ancora una volta, tuttavia, queste sono solo utilizzabili da applicazioni di primo piano.

A partire dal Windows Phone OS 7.1, il concetto di un "agente di sfondo" è stata introdotta, e si può utilizzare questo per giocare o file musicali o lo streaming audio, mentre il programma è sospeso in background.

Nel prossimo numero, tratterò come questo è fatto.

Charles Petzold è un redattore lunga data di MSDN Magazine. Il suo sito Web è charlespetzold.com.

Grazie all'esperto tecnica seguente per la revisione di questo articolo: Mark Hopkins