C # kullanarak bir akıştan ses çalın


99

Örneğin, verileri geçici olarak diske kaydetmeden bir WebRequest'ten döndürülen bir System.IO.Stream'den doğrudan ses (örneğin MP3) çalmanın bir yolu C # var mı ?


NAudio ile çözüm

NAudio 1.3 yardımıyla şunları yapmak mümkündür:

  1. Bir MP3 dosyasını URL'den MemoryStream'e yükleyin
  2. Tamamen yüklendikten sonra MP3 verilerini dalga verilerine dönüştürün
  3. NAudio'nun WaveOut sınıfını kullanarak wave verilerini oynatın

Yarım yüklü bir MP3 dosyasını bile çalabilmek güzel olurdu, ancak NAudio kitaplık tasarımı nedeniyle bu imkansız gibi görünüyor .

Ve bu işi yapacak olan işlev:

    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
Çalıştığını görmek güzel. Akış sırasında düzgün şekilde oynatılmasını sağlamak çok fazla iş olmaz. Ana sorun, Mp3FileReader'ın şu anda uzunluğu önceden bilmeyi beklemesidir. NAudio'nun bir sonraki sürümü için bir demo eklemeye bakacağım
Mark Heath

@Mark Heath, sorunu zaten çözdünüz mü ve demoyu mevcut NAudio sürümüne eklediniz mi yoksa hala iş hattınızda mı?
Martin

Korkarım henüz değil, ancak NAudio 1.3'te yapılan değişikliklerle birlikte çalışması için çok fazla ince ayar gerektirmeyecek.
Mark Heath

İşaret: Çalışması için NAudio'da değişiklik yapmam gerekiyor mu, çünkü NAudio1.3'ü yeni indirdim, ancak yukarıdaki kodu değiştirmeden kabul ediyor, ancak diğer yandan "ACM Dönüşümü mümkün değil" gibi bir şey söyleyen istisna atıyor.
Mubashar

Yanıtlar:


56

Düzenleme: Yanıt, NAudio'nun son sürümlerindeki değişiklikleri yansıtacak şekilde güncellendi

Yazdığım NAudio açık kaynak .NET ses kitaplığını kullanarak mümkün . Dönüştürmeyi yapmak için bilgisayarınızda bir ACM codec bileşeni arar. NAudio ile birlikte sağlanan Mp3FileReader şu anda kaynak akışı içinde yeniden konumlandırmayı beklemektedir (önden MP3 karelerinin bir dizinini oluşturur), bu nedenle ağ üzerinden akış için uygun değildir. Ancak, akış halindeki MP3'ü anında açmak için NAudio'daki MP3Frameve AcmMp3FrameDecompressorsınıflarını kullanmaya devam edebilirsiniz .

NAudio kullanarak bir MP3 akışının nasıl çalınacağını açıklayan blogumda bir makale yayınladım . Esasen, MP3 karelerini indiren, sıkıştırmalarını açan ve bunları bir BufferedWaveProvider. Daha sonra başka bir iş parçacığı BufferedWaveProvider, giriş olarak kullanılarak oynatılır.


3
NAudio Kitaplığı şimdi denilen bir örnek uygulama ile nakliye olduğunu Mp3StreamingDemo canlı akışa ağdan bir MP3 gerekir her şeyi birini sağlamalıdır.
Martin

Kitaplığınızı, bir android cihaza girişte canlı mikrofon / hat akışı sağlamak için kullanmak mümkün mü?
realtebo

10

SoundPlayer sınıfı yapabilirsiniz. Görünüşe göre tek yapmanız gereken, Stream özelliğini akışa ayarlamak ve ardından aramak Play.

düzenleme
MP3 dosyalarını çalabileceğini sanmıyorum; .wav ile sınırlı görünüyor. Çerçevede bir MP3 dosyasını doğrudan oynatabilecek herhangi bir şey olup olmadığından emin değilim. Bu konuda bulduğum her şey ya bir WMP kontrolü kullanmayı ya da DirectX ile etkileşim kurmayı içeriyor.


1
Yıllardır MP3 kodlama ve kod çözme yapan bir .NET kitaplığı bulmaya çalışıyorum, ancak var olduğunu düşünmüyorum.
MusiGenesis

NAudio işi sizin için yapmalı - en azından kod çözme için (ilk gönderiye bakın)
Martin

4
SoundPlayer'ın GC ile ilgili kötü sorunları var ve resmi Microsoft geçici çözümünü kullanmadığınız sürece rasgele çöp çalacak (Geçici Çözümleri tıklayın): connect.microsoft.com/VisualStudio/feedback/…
Roman Starkov

SoundPlayer + memoryStream tasarımda hata içeriyor. ilk ikinci veya üçüncü kez çaldığınızda, sesinizin ortasında garip bir gürültü ekler.
bh_earth0

Geçici çözüm bağlantısı artık çalışmıyor, ancak Wayback Machine'de: web.archive.org/web/20120722231139/http://connect.microsoft.com/…
Forestrf

5

Bass bunu yapabilir. Hafızadaki Bayt [] 'dan veya veriyi döndürdüğünüz dosya delegelerinden oynatın, böylece oynatmayı başlatmak için yeterli veriye sahip olur olmaz oynayabilirsiniz.


3

Konu başlangıç ​​kaynağını biraz değiştirdim, böylece artık tam olarak yüklenmemiş bir dosyayı oynatabilir. İşte burada (bunun sadece bir örnek olduğunu ve başlamak için bir nokta olduğunu unutmayın; burada bazı istisna ve hata işlemlerini yapmanız gerekir):

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

Kodunuzu test ettiniz mi? Öyleyse, NAudio'nun hangi sürümüyle çalıştı?
Martin

Ek olarak - kodunuz, iş parçacığı sorunlarına oldukça açık gibi görünüyor. Ne yaptığını bildiğinden emin misin?
Martin

1) Evet yaptım. 2) En son sürümle. 3) Bir önceki mesajımda belirttiğim gibi bu sadece bir kavram kanıtı.
ReVolly

"En son sürümü" nasıl tanımlıyorsunuz? Sürüm 1.3 mü yoksa revizyon 68454'teki kaynak mı?
Martin

@Martin Üzgünüm, uzun zamandır burada değildim. Kullandığım NAudio.dll 1.3.8 sürümüne sahip.
ReVolly

2

Soruyu burada yanıtlamak için Google'ın TTS API'siyle kullanıma izin vermek için soruda yayınlanan kaynağı değiştirdim :

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

Şununla çağırın:

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

Şununla sonlandır:

if (waiting)
    stop.Set();

ParameterizedThreadDelegateYukarıdaki kodda kullandığıma ve iş parçacığının ile başladığına dikkat edin playThread.Start(10000);. 10000, oynatılacak maksimum 10 saniyelik bir sesi temsil eder, bu nedenle yayınınızın oynatılması bundan daha uzun sürerse ince ayar yapılması gerekecektir. Bu gereklidir, çünkü NAudio'nun mevcut sürümü (v1.5.4.0), akışın ne zaman oynatılacağını belirlemede bir sorun yaşıyor gibi görünüyor. Daha sonraki bir sürümde düzeltilebilir veya bulmak için zaman ayırmadığım bir geçici çözüm olabilir.


1

NAudio, WaveOutXXXX API'sini sarar. Kaynağa bakmadım, ancak NAudio waveOutWrite () işlevini her aramada kayıttan yürütmeyi otomatik olarak durdurmayacak şekilde ortaya çıkarsa, o zaman gerçekten istediğiniz şeyi yapabilmeniz gerekir, bu da tüm verileri almadan önce ses akışı.

WaveOutWrite () işlevini kullanmak "ileride okumanızı" ve daha küçük ses parçalarını çıktı kuyruğuna atmanızı sağlar - Windows parçaları otomatik olarak sorunsuz bir şekilde oynatır. Kodunuzun sıkıştırılmış ses akışını alması ve onu anında küçük WAV ses parçalarına dönüştürmesi gerekir; bu bölüm gerçekten zor olurdu - şimdiye kadar gördüğüm tüm kitaplıklar ve bileşenler, bir seferde tüm bir dosyayı MP3'den WAV'a dönüştürüyor. Muhtemelen tek gerçekçi şansınız bunu MP3 yerine WMA kullanarak yapmaktır, çünkü multimedya SDK'nın etrafına basit C # sarmalayıcılar yazabilirsiniz.



1

Bir WebRequest onu denemedim, ama hem Windows Media Player ActiveX ve (gelen MediaElement WPF ) bileşenleri oynayan ve MP3 akışlarını tamponlayabilirler.

Bir SHOUTcast akışından gelen verileri oynatmak için kullanıyorum ve harika çalıştı. Ancak, önerdiğiniz senaryoda işe yarayıp yaramayacağından emin değilim.


0

FMOD'u her zaman bunun gibi şeyler için kullandım çünkü ticari olmayan kullanım için ücretsiz ve iyi çalışıyor.

Bununla birlikte, daha küçük (FMOD ~ 300k) ve açık kaynaklı bir şeye memnuniyetle geçebilirim. Tamamen yönetiliyorsa süper bonus puanlar, böylece onu .exe ile derleyebilir / birleştirebilirim ve diğer platformlara taşınabilirlik sağlamak için ekstra özen göstermem gerekmez ...

(FMOD de taşınabilirlik sağlar, ancak açıkça farklı platformlar için farklı ikili dosyalara ihtiyacınız olacaktır)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.