เล่นเสียงจากสตรีมโดยใช้ C #


99

มีวิธีใน C # ในการเล่นเสียง (เช่น MP3) จากSystem.IO หรือไม่สตรีมเช่นนั้นถูกดึงกลับมาจาก WebRequest โดยไม่บันทึกข้อมูลลงในดิสก์ชั่วคราวหรือไม่


โซลูชันด้วยNAudio

ด้วยความช่วยเหลือของNAudio 1.3 คุณสามารถ:

  1. โหลดไฟล์ MP3 จาก URL ลงใน MemoryStream
  2. แปลงข้อมูล MP3 เป็นข้อมูลคลื่นหลังจากโหลดเสร็จสมบูรณ์
  3. เล่นข้อมูลคลื่นโดยใช้คลาส WaveOutของ NAudio

คงจะดีไม่น้อยที่สามารถเล่นไฟล์ 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 เวอร์ชันปัจจุบันหรือยังอยู่ใน pipline ของคุณ?
Martin

ยังไม่ต้องกลัวแม้ว่าจะมีการเปลี่ยนแปลงใน NAudio 1.3 แต่ก็ไม่ต้องใช้การปรับแต่งมากเกินไปเพื่อให้มันทำงาน
Mark Heath

Mark: ฉันจำเป็นต้องแก้ไขใน NAudio เพื่อให้มันใช้งานได้หรือไม่เพราะฉันเพิ่งดาวน์โหลด NAudio1.3 แต่ยอมรับโค้ดด้านบนโดยไม่มีการเปลี่ยนแปลง แต่ในทางกลับกันมีข้อยกเว้นในการโยนข้อความเช่น "ไม่สามารถแปลง ACM ได้"
Mubashar

โดยวิธีที่ฉันพยายามเล่นต่อไปนี้translate.google.com/translate_tts?q=I+love+techcrunch
Mubashar

คำตอบ:


56

แก้ไข: อัปเดตคำตอบเพื่อให้สอดคล้องกับการเปลี่ยนแปลงใน NAudio เวอร์ชันล่าสุด

เป็นไปได้โดยใช้NAudioโอเพนซอร์สไลบรารีเสียง. NET ที่ฉันเขียน มองหาตัวแปลงสัญญาณ ACM บนพีซีของคุณเพื่อทำการแปลง Mp3FileReader ที่มาพร้อมกับ NAudio ในปัจจุบันคาดว่าจะสามารถเปลี่ยนตำแหน่งภายในสตรีมต้นทางได้ (สร้างดัชนีของเฟรม MP3 ไว้ด้านหน้า) ดังนั้นจึงไม่เหมาะสำหรับการสตรีมผ่านเครือข่าย อย่างไรก็ตามคุณยังสามารถใช้MP3FrameและAcmMp3FrameDecompressorคลาสใน NAudio เพื่อคลายการบีบอัดไฟล์ MP3 ที่สตรีมได้ทันที

ผมได้โพสต์บทความในบล็อกของฉันอธิบายวิธีการเล่นกลับกระแส MP3 ใช้ naudio โดยพื้นฐานแล้วคุณมีเธรดเดียวดาวน์โหลดเฟรม MP3 คลายการบีบอัดและจัดเก็บไว้ในไฟล์BufferedWaveProvider. จากนั้นเธรดอื่นจะเล่นโดยใช้BufferedWaveProviderเป็นอินพุต


3
naudioห้องสมุดอยู่ในขณะนี้การจัดส่งสินค้าที่มีตัวอย่างการประยุกต์เรียกMp3StreamingDemoซึ่งควรจะให้หนึ่งทุกอย่างจะต้องมีการสตรีมสดเพลง MP3 จากเครือข่าย
Martin

เป็นไปได้ไหมที่จะใช้ไลบรารีของคุณเพื่อสตรีมไมค์ / สายสัญญาณสดไปยังอุปกรณ์ Android
realtebo

10

SoundPlayerชั้นสามารถทำเช่นนี้ ดูเหมือนว่าสิ่งที่คุณต้องทำคือการกำหนดของสตรีมPlayคุณสมบัติการสตรีมโทรแล้ว

แก้ไข
ฉันไม่คิดว่ามันจะเล่นไฟล์ MP3 ได้ ดูเหมือนว่าจะ จำกัด เฉพาะ. wav ฉันไม่แน่ใจว่ามีอะไรในเฟรมเวิร์กที่สามารถเล่นไฟล์ MP3 ได้โดยตรง ทุกสิ่งที่ฉันพบเกี่ยวกับการใช้การควบคุม WMP หรือการโต้ตอบกับ DirectX


1
ฉันพยายามค้นหาไลบรารี. NET ที่เข้ารหัสและถอดรหัส MP3 มาหลายปีแล้ว แต่ฉันไม่คิดว่ามันมีอยู่จริง
MusiGenesis

NAudio ควรทำงานให้คุณ - อย่างน้อยก็สำหรับการถอดรหัส (ดูโพสต์แรก)
Martin

4
SoundPlayer มีปัญหาที่น่ารังเกียจกับ GC และจะสุ่มเล่นขยะเว้นแต่คุณจะใช้วิธีแก้ปัญหาอย่างเป็นทางการของ Microsoft (คลิกวิธีแก้ปัญหา): connect.microsoft.com/VisualStudio/feedback/…
Roman Starkov

SoundPlayer + memoryStream มีจุดบกพร่องโดยการออกแบบ เมื่อคุณเล่นวินาทีแรกหรือครั้งที่สามมันจะเพิ่มเสียงแปลก ๆ ขึ้นกลางเสียงของคุณ
bh_earth0

ลิงก์วิธีแก้ปัญหาไม่ทำงานอีกต่อไป แต่อยู่ใน Wayback Machine: 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 รุ่นใดที่ใช้งานได้
Martin

นอกจากนี้ - โค้ดของคุณดูเหมือนว่าจะมีข้อผิดพลาดค่อนข้างง่ายที่จะเกิดปัญหาเธรด แน่ใจหรือว่ารู้ว่ากำลังทำอะไร?
Martin

1) ใช่ฉันทำ 2) ด้วยเวอร์ชันล่าสุด 3) มันเป็นเพียงการพิสูจน์แนวคิดตามที่ฉันระบุไว้ในข้อความก่อนหน้านี้
ReVolly

คุณกำหนด "เวอร์ชันล่าสุด" ได้อย่างไร? เป็นเวอร์ชัน 1.3 หรือแหล่งที่มาในการแก้ไข 68454?
Martin

@Martin ขออภัยไม่ได้มาที่นี่นาน NAudio.dll ที่ฉันใช้มีเวอร์ชัน 1.3.8
ReVolly

2

ฉันได้ปรับแต่งแหล่งที่มาที่โพสต์ในคำถามเพื่ออนุญาตการใช้งานกับ TTS API ของ Google เพื่อตอบคำถามที่นี่ :

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);10,000 หมายถึงการเล่นเสียงสูงสุด 10 วินาทีดังนั้นจึงจำเป็นต้องปรับแต่งหากสตรีมของคุณใช้เวลาเล่นนานกว่านั้น นี่เป็นสิ่งที่จำเป็นเนื่องจาก NAudio เวอร์ชันปัจจุบัน (v1.5.4.0) ดูเหมือนจะมีปัญหาในการระบุว่าเมื่อใดที่สตรีมเล่นเสร็จแล้ว อาจได้รับการแก้ไขในเวอร์ชันที่ใหม่กว่าหรืออาจมีวิธีแก้ปัญหาที่ฉันไม่ได้ใช้เวลาค้นหา


1

NAudio รวม WaveOutXXXX API ฉันไม่ได้ดูแหล่งที่มา แต่ถ้า NAudio เปิดเผยฟังก์ชัน waveOutWrite () ในลักษณะที่ไม่หยุดเล่นโดยอัตโนมัติในแต่ละสายคุณควรจะสามารถทำสิ่งที่คุณต้องการได้ซึ่งก็คือการเริ่มเล่น สตรีมเสียงก่อนที่คุณจะได้รับข้อมูลทั้งหมด

การใช้ฟังก์ชัน waveOutWrite () ช่วยให้คุณ "อ่านไปข้างหน้า" และถ่ายโอนข้อมูลเสียงที่มีขนาดเล็กลงในคิวเอาต์พุต - Windows จะเล่นชิ้นส่วนโดยอัตโนมัติอย่างราบรื่น รหัสของคุณจะต้องรับสตรีมเสียงที่บีบอัดและแปลงเป็นเสียง WAV ขนาดเล็กได้ทันที ส่วนนี้จะยากมาก - ไลบรารีและส่วนประกอบทั้งหมดที่ฉันเคยเห็นทำการแปลง MP3-to-WAV ทั้งไฟล์พร้อมกัน โอกาสเดียวที่เป็นจริงของคุณคือการทำสิ่งนี้โดยใช้ WMA แทน MP3 เพราะคุณสามารถเขียน C # wrapper แบบธรรมดารอบ ๆ SDK มัลติมีเดียได้


1

ฉันห่อห้องสมุดถอดรหัส MP3 และทำให้มันสามารถใช้ได้สำหรับ.NETพัฒนาเป็นmpg123.net

รวมเป็นตัวอย่างในการแปลงไฟล์ MP3 เป็นPCMและอ่านแท็ID3


เยี่ยมมาก! ฉันหวังว่าจะได้ดูในสุดสัปดาห์นี้
Larry Smithmier

1

ฉันไม่ได้ลองใช้จาก WebRequest แต่ทั้งคอมโพเนนต์Windows Media Player ActiveXและ MediaElement (จากWPF ) สามารถเล่นและบัฟเฟอร์สตรีม MP3 ได้

ฉันใช้มันเพื่อเล่นข้อมูลที่มาจากสตรีมSHOUTcastและใช้งานได้ดี อย่างไรก็ตามฉันไม่แน่ใจว่าจะใช้ได้ในสถานการณ์ที่คุณเสนอหรือไม่


0

ฉันใช้ FMOD สำหรับสิ่งนี้มาโดยตลอดเพราะฟรีสำหรับการใช้งานที่ไม่ใช่เชิงพาณิชย์และทำงานได้ดี

ที่กล่าวว่าฉันยินดีที่จะเปลี่ยนไปใช้สิ่งที่เล็กกว่า (FMOD คือ ~ 300k) และโอเพ่นซอร์ส คะแนนโบนัสพิเศษหากมีการจัดการอย่างสมบูรณ์เพื่อให้ฉันสามารถรวบรวม / รวมเข้ากับ. exe ของฉันได้และไม่ต้องดูแลเป็นพิเศษในการพกพาไปยังแพลตฟอร์มอื่น ๆ ...

(FMOD พกพาได้เช่นกัน แต่คุณต้องการไบนารีที่แตกต่างกันสำหรับแพลตฟอร์มที่แตกต่างกัน)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.