Lire l'audio d'un flux en utilisant C#

est-il un moyen en C# de lire l'audio (par exemple, MP3) directement à partir d'un système .IO.Stream que par exemple était de retour d'une WebRequest sans enregistrer les données temporairement sur le disque?


Solution with NAudio

avec l'aide de NAudio 1.3 il est possible de:

  1. chargez un fichier MP3 à partir D'une URL dans un MemoryStream
  2. Convertissez les données MP3 en données d'onde après qu'il a été complètement chargé
  3. "1519160920 de Lecture" à la vague de données à l'aide de NAudio 's WaveOut classe

il aurait été agréable de pouvoir même jouer un fichier MP3 à moitié chargé, mais cela semble impossible en raison de la NAudio conception de la bibliothèque.

et c'est la fonction qui fera le travail:

    public static void PlayMp3FromUrl(string url)
    {
        using (Stream ms = new MemoryStream())
        {
            using (Stream stream = WebRequest.Create(url)
                .GetResponse().GetResponseStream())
            {
                byte[] buffer = new byte[32768];
                int read;
                while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    ms.Write(buffer, 0, read);
                }
            }

            ms.Position = 0;
            using (WaveStream blockAlignedStream =
                new BlockAlignReductionStream(
                    WaveFormatConversionStream.CreatePcmStream(
                        new Mp3FileReader(ms))))
            {
                using (WaveOut waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback()))
                {
                    waveOut.Init(blockAlignedStream);
                    waveOut.Play();                        
                    while (waveOut.PlaybackState == PlaybackState.Playing )                        
                    {
                        System.Threading.Thread.Sleep(100);
                    }
                }
            }
        }
    }
87
demandé sur Martin 2008-10-09 00:19:23

9 réponses

Edit: Réponse mis à jour pour refléter les changements dans les versions récentes de NAudio

il est possible d'utiliser le NAudio open source.net bibliothèque audio j'ai écrit. Il cherche un codec ACM sur votre PC pour faire la conversion. Le Mp3FileReader fourni avec NAudio s'attend actuellement à pouvoir se repositionner dans le flux source (il construit un index de cadres MP3 à l'avant), de sorte qu'il n'est pas approprié pour le streaming sur réseau. Cependant, vous pouvez toujours utiliser les classes MP3Frame et AcmMp3FrameDecompressor dans NAudio pour décompresser MP3 streamé à la volée.

j'ai posté un article sur mon blog expliquant comment rejouer un flux MP3 en utilisant NAudio . Essentiellement, vous avez un fil de téléchargement des cadres MP3, les décompresser et les stocker dans un BufferedWaveProvider . Un autre thread joue alors en arrière en utilisant le BufferedWaveProvider comme une entrée.

47
répondu Mark Heath 2011-05-09 14:20:34

la classe SoundPlayer peut faire cela. Il semble que tout ce que vous avez à faire est de définir sa propriété Stream , puis appeler Play .

modifier

Je ne pense pas qu'il peut lire des fichiers MP3; il semble limitée .WAV. Je ne suis pas sûr s'il y a quelque chose dans le cadre qui peut lire un fichier MP3 directement. Tout ce que je trouve à ce sujet implique soit utiliser un contrôle WMP ou interagir avec DirectX.

8
répondu OwenP 2008-10-08 20:47:07

Bass peut faire juste cela. Lecture à partir de Byte[] en mémoire ou d'un délégué de fichier à travers où vous retournez les données, de sorte que vous pouvez lire dès que vous avez assez de données pour commencer la lecture..

5
répondu slugster 2017-01-24 00:15:03

j'ai légèrement modifié la source de démarrage de sujet, de sorte qu'il peut maintenant lire un fichier pas entièrement chargé. Le voici (notez qu'il ne s'agit que d'un échantillon et qu'il s'agit d'un point de départ; vous devez faire un peu de gestion des exceptions et des erreurs ici):

private Stream ms = new MemoryStream();
public void PlayMp3FromUrl(string url)
{
    new Thread(delegate(object o)
    {
        var response = WebRequest.Create(url).GetResponse();
        using (var stream = response.GetResponseStream())
        {
            byte[] buffer = new byte[65536]; // 64KB chunks
            int read;
            while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
            {
                var pos = ms.Position;
                ms.Position = ms.Length;
                ms.Write(buffer, 0, read);
                ms.Position = pos;
            }
        }
    }).Start();

    // Pre-buffering some data to allow NAudio to start playing
    while (ms.Length < 65536*10)
        Thread.Sleep(1000);

    ms.Position = 0;
    using (WaveStream blockAlignedStream = new BlockAlignReductionStream(WaveFormatConversionStream.CreatePcmStream(new Mp3FileReader(ms))))
    {
        using (WaveOut waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback()))
        {
            waveOut.Init(blockAlignedStream);
            waveOut.Play();
            while (waveOut.PlaybackState == PlaybackState.Playing)
            {
                System.Threading.Thread.Sleep(100);
            }
        }
    }
}
3
répondu ReVolly 2013-11-15 23:54:27

NAudio enveloppe L'API WaveOutXXXX. Je n'ai pas regardé la source, mais si NAudio expose la fonction waveOutWrite() d'une manière qui n'arrête pas automatiquement la lecture à chaque appel, alors vous devriez être capable de faire ce que vous voulez vraiment, qui est de commencer à lire le flux audio avant que vous ayez reçu toutes les données.

L'utilisation de la fonction waveOutWrite() vous permet de "lire à l'avance" et de jeter des morceaux plus petits de l'audio dans la file d'attente de sortie - Windows sera automatiquement jouer les morceaux de façon transparente. Votre code devrait prendre le flux audio comprimé et le convertir en petits morceaux d'audio WAV à la volée; cette partie serait vraiment difficile - toutes les bibliothèques et les composants que j'ai jamais vu faire la conversion MP3-à-WAV un dossier entier à la fois. Probablement votre seule chance réaliste est de faire cela en utilisant WMA au lieu de MP3, parce que vous pouvez écrire simple C# wrappers autour du SDK multimédia.

1
répondu MusiGenesis 2008-10-19 22:25:02

j'ai modifié la source affichée dans la question pour permettre l'utilisation avec L'API TTS de Google afin de répondre à la question ici :

bool waiting = false;
AutoResetEvent stop = new AutoResetEvent(false);
public void PlayMp3FromUrl(string url, int timeout)
{
    using (Stream ms = new MemoryStream())
    {
        using (Stream stream = WebRequest.Create(url)
            .GetResponse().GetResponseStream())
        {
            byte[] buffer = new byte[32768];
            int read;
            while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
            {
                ms.Write(buffer, 0, read);
            }
        }
        ms.Position = 0;
        using (WaveStream blockAlignedStream =
            new BlockAlignReductionStream(
                WaveFormatConversionStream.CreatePcmStream(
                    new Mp3FileReader(ms))))
        {
            using (WaveOut waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback()))
            {
                waveOut.Init(blockAlignedStream);
                waveOut.PlaybackStopped += (sender, e) =>
                {
                    waveOut.Stop();
                };
                waveOut.Play();
                waiting = true;
                stop.WaitOne(timeout);
                waiting = false;
            }
        }
    }
}

Invoke:

var playThread = new Thread(timeout => PlayMp3FromUrl("http://translate.google.com/translate_tts?q=" + HttpUtility.UrlEncode(relatedLabel.Text), (int)timeout));
playThread.IsBackground = true;
playThread.Start(10000);

se termine par:

if (waiting)
    stop.Set();

notez que j'utilise le ParameterizedThreadDelegate dans le code ci-dessus, et le thread est démarré avec playThread.Start(10000); . Les 10000 représente un maximum de 10 secondes d'audio à lire donc devra être modifié si votre flux prend plus de temps que ça à jouer. Ceci est nécessaire car la version actuelle de NAudio (v1.5.4.0) semble avoir un problème pour déterminer quand le flux est fini de jouer. Il peut être corrigé dans une version ultérieure ou il y a peut-être une solution que je n'ai pas pris le temps de trouver.

1
répondu M.Babcock 2017-05-23 10:31:02

j'ai enveloppé la bibliothèque de décodeur MP3 et l'ai rendu disponible pour .NET développeurs comme mpg123.net .

sont Inclus les échantillons pour convertir les fichiers MP3 en fichiers PCM , et lire ID3 balises.

1
répondu Daniel Mošmondor 2013-11-15 23:52:25

j'ai toujours utilisé le FMOD pour ce genre de choses parce qu'il est gratuit pour un usage non commercial et fonctionne bien.

cela dit, je changerais volontiers à quelque chose qui est plus petit (FMOD est ~300k) et open-source. Super points bonus s'il est entièrement géré de sorte que je peux compiler / fusionner avec mon .exe et ne pas avoir à prendre des précautions supplémentaires pour obtenir la portabilité vers d'autres plates-formes...

(le FMOD fait la portabilité aussi, mais vous auriez évidemment besoin de binaires différents pour différentes plates-formes)

0
répondu Roman Starkov 2009-11-07 09:16:25

Je ne l'ai pas essayé d'une WebRequest, mais les deux composants Windows Media Player ActiveX et le MediaElement (de WPF ) sont capables de jouer et de buffer les flux MP3.

Je l'utilise pour lire des données provenant d'un flux SHOUTcast et ça a bien fonctionné. Cependant, je ne suis pas sûr que cela fonctionnera dans le scénario que vous proposez.

0
répondu Ramiro Berrelleza 2013-11-16 12:29:17