Question

Existe-t-il un moyen en C # de lire de l’audio (par exemple, MP3) directement à partir d’un System.IO.Stream qui, par exemple, a été renvoyé de WebRequest sans enregistrer temporairement les données sur le disque?

Solution avec NAudio

À l'aide de NAudio 1.3, il est possible de:

  1. Chargez un fichier MP3 depuis une URL dans un MemoryStream
  2. Convertissez les données MP3 en données wave après leur chargement complet
  3. Lisez les données de vagues en utilisant la classe WaveOut de NAudio

Cela aurait été bien de pouvoir même lire un fichier MP3 à moitié chargé, mais cela semble impossible en raison de la Conception de la bibliothèque NAudio .

Et voici 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);
                    }
                }
            }
        }
    }

Autres conseils

La classe SoundPlayer peut le faire. Il semble que tout ce que vous avez à faire est de définir sa propriété Stream sur le flux, puis appelez Play .

modifier
Je ne pense pas qu'il puisse lire les fichiers MP3; il semble limité à .wav. Je ne suis pas certain que rien dans le framework puisse lire directement un fichier MP3. Tout ce que je trouve à ce sujet implique d’utiliser un contrôle WMP ou d’interagir avec DirectX.

Bass peut le faire. Jouez depuis octet [] en mémoire ou dans un fichier délégué où vous restituez les données. Vous pourrez ainsi jouer dès que vous aurez assez de données pour démarrer la lecture.

J'ai légèrement modifié la source de départ du sujet afin qu'elle puisse maintenant lire un fichier non chargé. La voici (remarquez que ce n’est qu’un exemple et que c’est un point de départ; vous devez faire quelques exceptions et gérer les 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);
            }
        }
    }
}

NAudio enveloppe l’API WaveOutXXXX. Je n'ai pas regardé la source, mais si NAudio expose la fonction waveOutWrite () de manière à ne pas arrêter automatiquement la lecture à chaque appel, vous devriez être en mesure de faire ce que vous voulez vraiment, à savoir: flux audio avant d'avoir reçu toutes les données.

L’utilisation de la fonction waveOutWrite () vous permet de "lire à l’avance". et vider de plus petits morceaux d’audio dans la file d’attente de sortie - Windows lit automatiquement les morceaux de manière transparente. Votre code devrait extraire le flux audio compressé et le convertir en petits morceaux d’audio WAV à la volée; cette partie serait vraiment difficile - toutes les bibliothèques et tous les composants que j'ai vus font la conversion de MP3 à WAV un fichier entier à la fois. Votre seule chance réaliste est probablement de le faire en utilisant WMA au lieu de MP3, car vous pouvez écrire de simples wrappers C # autour du SDK multimédia.

J'ai modifié la source publiée dans la question pour permettre l'utilisation de 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;
            }
        }
    }
}

Invoquer avec:

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);

Terminez avec:

if (waiting)
    stop.Set();

Notez que j'utilise le ParameterizedThreadDelegate dans le code ci-dessus et que le fil de discussion est démarré avec playThread.Start (10000); . Le 10000 représente un maximum de 10 secondes d’audio à jouer. Il faudra donc le peaufiner si la lecture de votre flux dure plus longtemps. Cela est nécessaire car la version actuelle de NAudio (v1.5.4.0) semble rencontrer un problème pour déterminer quand la lecture du flux est terminée. Cela peut être corrigé dans une version ultérieure ou il existe peut-être une solution de contournement que je n’ai pas pris le temps de rechercher.

J'ai enveloppé la bibliothèque de décodage MP3 et je l'ai mise à la disposition des développeurs .NET en tant que < a href = "http://sourceforge.net/projects/mpg123net/" rel = "nofollow noreferrer"> mpg123.net .

Sont inclus les exemples permettant de convertir des fichiers MP3 en PCM et de lire balises ID3 .

J'ai toujours utilisé FMOD pour des choses comme celle-ci, car il est gratuit pour une utilisation non commerciale et fonctionne bien.

Cela dit, je passerais volontiers à quelque chose de plus petit (environ 300 000 FMOD) et de source ouverte. Des points super bonus si c'est entièrement géré pour que je puisse le compiler / le fusionner avec mon .exe sans avoir à prendre des précautions supplémentaires pour obtenir la portabilité sur d'autres plateformes ...

(Le FMOD assure également la portabilité, mais vous aurez évidemment besoin de différents fichiers binaires pour différentes plates-formes)

Je n'ai pas essayé depuis WebRequest, mais à la fois sur le Lecteur Windows Media < a href = "http://en.wikipedia.org/wiki/ActiveX" rel = "nofollow noreferrer"> ActiveX et MediaElement (extrait de WPF ) sont capables de lire et de mettre en tampon les flux MP3.

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top