it-swarm.com.de

Abspielen von Audio aus einem Stream mit C #

Gibt es in C # eine Möglichkeit, Audio (z. B. MP3) direkt von einem System.IO.Stream abzuspielen, das beispielsweise von einer WebRequest zurückgesendet wurde, ohne die Daten vorübergehend auf der Festplatte zu speichern?


Lösung mit NAudio

Mit Hilfe von NAudio 1.3 ist es möglich:

  1. Laden Sie eine MP3-Datei von einer URL in einen MemoryStream
  2. Konvertieren Sie MP3-Daten nach dem vollständigen Laden in Wave-Daten
  3. Spielen Sie die Wave-Daten mit der WaveOut-Klasse von NAudio ab

Es wäre schön gewesen, eine halb geladene MP3-Datei abspielen zu können, aber dies scheint aufgrund des NAudio Bibliotheksdesigns unmöglich zu sein.

Und dies ist die Funktion, die die Arbeit erledigen wird:

    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);
                    }
                }
            }
        }
    }
94
Martin

Bearbeiten: Die Antwort wurde aktualisiert, um Änderungen in den letzten Versionen von NAudio widerzuspiegeln.

Es ist möglich, die NAudio Open Source .NET-Audiobibliothek zu verwenden, die ich geschrieben habe. Es wird nach einem ACM-Codec auf Ihrem PC gesucht, um die Konvertierung durchzuführen. Der mit NAudio gelieferte Mp3FileReader erwartet derzeit, dass er sich innerhalb des Quellstreams neu positionieren kann (er erstellt einen Index von MP3-Frames im Voraus), sodass er nicht für das Streaming über das Netzwerk geeignet ist. Sie können jedoch weiterhin das MP3Frame und AcmMp3FrameDecompressor Klassen in NAudio, um gestreamte MP3-Dateien im laufenden Betrieb zu dekomprimieren.

Ich habe in meinem Blog einen Artikel gepostet, der erklärt , wie man einen MP3-Stream mit NAudio abspielt . Im Grunde haben Sie einen Thread, der MP3-Frames herunterlädt, dekomprimiert und in einem BufferedWaveProvider speichert. Ein anderer Thread wird dann unter Verwendung von BufferedWaveProvider als Eingabe wiedergegeben.

50
Mark Heath

Die SoundPlayer Klasse kann dies tun. Alles, was Sie tun müssen, ist die Eigenschaft Stream auf den Stream zu setzen und dann Play aufzurufen.

edit
Ich glaube nicht, dass es MP3-Dateien abspielen kann. es scheint auf .wav beschränkt zu sein. Ich bin nicht sicher, ob irgendetwas im Framework eine MP3-Datei direkt abspielen kann. Alles, was ich dazu finde, beinhaltet entweder die Verwendung eines WMP-Steuerelements oder die Interaktion mit DirectX.

8
OwenP

Bass kann genau das. Spielen Sie von Byte [] im Speicher oder von einer Durchgangsdatei ab, an die Sie die Daten zurückgeben, damit Sie spielen können, sobald Sie über genügend Daten verfügen, um die Wiedergabe zu starten.

5
NoName

Ich habe die Topic-Starter-Quelle geringfügig geändert, sodass eine nicht vollständig geladene Datei abgespielt werden kann. Hier ist es (beachten Sie, dass es sich nur um ein Beispiel handelt und ein Ausgangspunkt ist. Hier müssen Sie einige Ausnahmen und Fehlerbehandlungen durchführen):

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
ReVolly

Ich habe die in der Frage angegebene Quelle optimiert, um die Verwendung mit der TTS-API von Google zu ermöglichen und die Frage zu beantworten hier :

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

Aufrufen mit:

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

Kündigen mit:

if (waiting)
    stop.Set();

Beachten Sie, dass ich das ParameterizedThreadDelegate im obigen Code verwende und der Thread mit playThread.Start(10000); gestartet wird. Der 10000 entspricht maximal 10 Sekunden für die Audiowiedergabe, sodass eine Optimierung erforderlich ist, wenn die Wiedergabe Ihres Streams länger dauert. Dies ist erforderlich, da die aktuelle Version von NAudio (v1.5.4.0) ein Problem damit zu haben scheint, festzustellen, wann die Wiedergabe des Streams abgeschlossen ist. Möglicherweise wird es in einer späteren Version behoben, oder es gibt eine Problemumgehung, für die ich mir nicht die Zeit genommen habe.

1
M.Babcock

Ich habe die MP3-Decoder-Bibliothek verpackt und für . NET Entwickler als mpg123.net verfügbar gemacht.

Enthalten sind die Beispiele zum Konvertieren von MP3-Dateien in PCM und zum Lesen von ID Tags.

1

NAudio umschließt die WaveOutXXXX-API. Ich habe mir die Quelle nicht angesehen, aber wenn NAudio die Funktion waveOutWrite () so verfügbar macht, dass die Wiedergabe bei jedem Aufruf nicht automatisch gestoppt wird, sollten Sie in der Lage sein, das zu tun, was Sie wirklich wollen, nämlich die Wiedergabe zu starten Audio-Stream, bevor Sie alle Daten erhalten haben.

Mit der waveOutWrite () -Funktion können Sie "vorauslesen" und kleinere Audiodateien in die Ausgabewarteschlange kopieren. Windows spielt die Audiodateien automatisch nahtlos ab. Ihr Code müsste den komprimierten Audiostream sofort in kleine WAV-Audiodateien konvertieren. Dieser Teil wäre wirklich schwierig - alle Bibliotheken und Komponenten, die ich je gesehen habe, konvertieren jeweils eine ganze Datei von MP3 zu WAV. Wahrscheinlich ist Ihre einzige realistische Chance, dies mit WMA anstelle von MP3 zu tun, da Sie einfache C # -Umhüllungen um das Multimedia-SDK schreiben können.

1
MusiGenesis

Ich habe es nicht mit einer WebRequest versucht, sondern mit dem Windows Media PlayerActiveX und dem MediaElement (von WPF ) Komponenten können MP3-Streams abspielen und puffern.

Ich benutze es, um Daten abzuspielen, die von einem SHOUTcast -Stream stammen, und es hat großartig funktioniert. Ich bin mir jedoch nicht sicher, ob es in dem von Ihnen vorgeschlagenen Szenario funktionieren wird.

0

Ich habe FMOD immer für solche Dinge verwendet, da es für nichtkommerzielle Zwecke kostenlos ist und gut funktioniert.

Trotzdem würde ich gerne auf etwas Kleineres (FMOD ist ~ 300k) und Open Source umsteigen. Super Bonuspunkte, wenn es vollständig verwaltet wird, so dass ich es mit meiner .exe kompilieren/zusammenführen kann und nicht besonders vorsichtig sein muss, um Portabilität auf andere Plattformen zu erreichen ...

(FMOD macht auch Portabilität, aber Sie würden offensichtlich verschiedene Binärdateien für verschiedene Plattformen benötigen)

0
Roman Starkov