C#を使用してストリームからオーディオを再生する


99

たとえば、データを一時的にディスクに保存せずにWebRequestから返されたSystem.IO.Streamからオーディオ(たとえば、MP3)を直接再生する方法はありますか?


NAudioによるソリューション

NAudio 1.3を使用すると、次のことが可能になります。

  1. MP3ファイルをURLからMemoryStreamにロードします
  2. 完全に読み込まれた後にMP3データをWaveデータに変換する
  3. NAudioのWaveOutクラスを使用してWaveデータを再生する

半分ロードされたMP3ファイルを再生することさえできればいいのですが、これはNAudioライブラリの設計のために不可能のようです。

そして、これは仕事をする関数です:

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

4
うまくいったことを確認してください。ストリーミング中に適切に再生するのはそれほど大変な作業ではありません。主な問題は、Mp3FileReaderが現在、長さを事前に知っていることを期待していることです。NAudioの次のバージョンのデモを追加することを検討します
Mark Heath

@Mark Heathすでに問題を解決していて、現在のNAudioバージョンにデモを追加しましたか、それともまだパイプラインにありますか?
マーティン

恐れていませんが、NAudio 1.3で行われた変更により、NAudio 1.3を動作させるためにあまり手を加える必要はありません。
マークヒース

マーク:動作させるためにNAudioを変更する必要がありますか?NAudio1.3をダウンロードしたのですが、変更せずに上記のコードを受け入れていますが、一方で「ACM変換は不可能」のような例外をスローしています。
Mubashar 2011年

ちなみに私は以下をプレイしようとしています translate.google.com/translate_tts?q=I+love+techcrunch
Mubashar

回答:


56

編集:NAudioの最近のバージョンでの変更を反映するように回答を更新

私が書いたNAudioオープンソース.NETオーディオライブラリを使用することは可能です。PC上のACMコーデックを探して変換を行います。NAudioで提供されるMp3FileReaderは現在、ソースストリーム内で再配置できることを期待しているため(MP3フレームのインデックスを事前に作成します)、ネットワークを介したストリーミングには適していません。ただし、NAudio のMP3FrameおよびAcmMp3FrameDecompressorクラスを使用して、ストリーミングされたMP3をその場で解凍できます。

NAudioを使用してMP3ストリームを再生する方法を説明する記事をブログに投稿しました。基本的に、1つのスレッドでMP3フレームをダウンロードし、解凍してに保存しますBufferedWaveProvider。次に、別のスレッドがをBufferedWaveProvider入力として使用して再生します。


3
NAudioライブラリは今と呼ばれるサンプルアプリケーションで出荷されてMp3StreamingDemoライブストリームにネットワークからMP3を必要とするすべてのものを提供する必要があります。
マーティン

ライブラリを使用して、マイクデバイス/ラインをAndroidデバイスへの入力でライブストリーミングすることはできますか?
realtebo 2015年

10

SoundPlayerののクラスには、これを行うことができます。Streamプロパティをストリームに設定してを呼び出すだけでよいようPlayです。

編集
MP3ファイルを再生できるとは思いません。.wavに制限されているようです。フレームワークにMP3ファイルを直接再生できるものがあるかどうかはわかりません。それについて私が見つけるすべては、WMPコントロールの使用またはDirectXとの対話のいずれかを含みます。


1
私は何年もの間、MP3エンコードとデコードを行う.NETライブラリを見つけようとしてきましたが、それが存在するとは思いません。
MusiGenesis 2008年

NAudioがあなたのために仕事をします-少なくともデコード(最初の投稿を参照)
Martin

4
SoundPlayerにはGCに関する厄介な問題があり、公式のMicrosoftの回避策([回避策]をクリック)を使用しない限り、ランダムにゴミを再生します。connect.microsoft.com
Roman Starkov

SoundPlayer + memoryStreamには、設計によるバグがあります。1回、2回、または3回再生すると、オーディオの中央に奇妙なノイズが追加されます。
bh_earth0

回避策のリンクはもう動作しませんが、それはウェイバックマシン上にある:web.archive.org/web/20120722231139/http://connect.microsoft.com/...
Forestrf

5

低音はこれを行うことができます。メモリ内のByte []から再生するか、データを返すファイルデリゲートを介して再生します。これにより、再生を開始するのに十分なデータが揃ったらすぐに再生できます。


3

トピックのスターターソースを少し変更して、完全に読み込まれていないファイルを再生できるようにしました。ここにあります(これは単なるサンプルであり、開始点です。ここで例外とエラー処理を行う必要があります):

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で動作しましたか?
マーティン

さらに、あなたのコードは、スレッド化の問題でエラーが発生しやすいように見えます。あなたはあなたが何をしているのか知っていますか?
マーティン

1)はい、そうしました。2)最新バージョン。3)前のメッセージで述べたように、これは概念の証明にすぎません。
ReVolly、2011

「最新バージョン」をどのように定義しますか?バージョン1.3ですか、それともリビジョン68454のソースですか?
マーティン

@Martin申し訳ありませんが、長い間ここにいません。私が使用したNAudio.dllのバージョンは1.3.8です。
ReVolly、2011年

2

ここで質問に答えるために、GoogleのTTS APIでの使用を許可するために、質問に投稿されたソースを微調整しまし

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

で呼び出す:

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

次で終了:

if (waiting)
    stop.Set();

ParameterizedThreadDelegate上記のコードではを使用しており、スレッドはで始まっていplayThread.Start(10000);ます。10000は再生されるオーディオの最大10秒を表すので、ストリームの再生にそれよりも時間がかかる場合は微調整する必要があります。NAudioの現在のバージョン(v1.5.4.0)では、ストリームの再生がいつ終了したかを判断するのに問題があるようです。それは後のバージョンで修正されるかもしれません、あるいは私が見つけるのに時間をかけなかった回避策があるかもしれません。


1

NAudioはWaveOutXXXX APIをラップします。私はソースを確認していませんが、NAudioがwaveOutWrite()関数を公開して、呼び出しごとに自動的に再生を停止しない場合は、本当にやりたいことを実行できるはずです。すべてのデータを受信する前のオーディオストリーム。

waveOutWrite()関数を使用すると、「先読み」して、オーディオの小さなチャンクを出力キューにダンプできます。Windowsは自動的にチャンクをシームレスに再生します。コードは、圧縮されたオーディオストリームを取得して、オンザフライでWAVオーディオの小さなチャンクに変換する必要があります。この部分は本当に難しいでしょう-私が今まで見たすべてのライブラリとコンポーネントは、一度にファイル全体をMP3からWAVに変換します。マルチメディアSDKの周りに単純なC#ラッパーを記述できるので、おそらく唯一の現実的な可能性は、MP3の代わりにWMAを使用してこれを行うことです。



1

私はWebRequestからは試していませんが、Windows Media Player ActiveXとMediaElement(WPFから)コンポーネントと)コンポーネントは MP3ストリームの再生とバッファリングが可能です。

SHOUTcastストリームからのデータを再生するために使用しました。ただし、提案したシナリオで機能するかどうかはわかりません。


0

FMODは非商用目的で無料で機能するため、私は常にこのようなものにFMODを使用してきました。

そうは言っても、もっと小さく(FMODが〜300k)、オープンソースのものに喜んで切り替えます。それが完全に管理されていて、.exeでコンパイル/マージでき、他のプラットフォームへの移植性を確保するために特別な注意を払う必要がない場合、スーパーボーナスポイント...

(FMODも移植性がありますが、プラットフォームごとに異なるバイナリが必要になることは明らかです)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.