C #을 사용하여 스트림에서 오디오 재생


99

예를 들어 데이터를 디스크에 임시로 저장하지 않고 WebRequest 에서 재생 된 System.IO.Stream 에서 직접 오디오 (예 : MP3)를 C #에서 재생하는 방법이 있습니까?


NAudio 솔루션

NAudio 1.3 의 도움으로 다음이 가능합니다.

  1. URL에서 MemoryStream으로 MP3 파일로드
  2. MP3 데이터가 완전히로드 된 후 웨이브 데이터로 변환
  3. NAudio 의 WaveOut 클래스를 사용하여 웨이브 데이터 재생

절반 만로드 된 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 이미 문제를 해결하고 현재 NAudio 버전에 데모를 추가 했습니까? 아니면 여전히 pipline에 있습니까?
Martin

아직 두려워하지 않지만 NAudio 1.3에서 변경된 사항으로 작동하도록하기 위해 너무 많은 조정이 필요하지 않습니다.
Mark Heath

Mark : 작동하려면 NAudio에서 수정해야합니까? 방금 NAudio1.3을 다운로드했지만 변경없이 위의 코드를 수락하지만 다른 한편으로는 "ACM Conversion not possible"과 같은 예외가 발생합니다.
Mubashar 2011 년

그런데 나는 다음과 같은 재생하려고 translate.google.com/translate_tts?q=I+love+techcrunch
Mubashar

답변:


56

편집 : 최신 버전의 NAudio의 변경 사항을 반영하도록 답변이 업데이트되었습니다.

내가 작성한 NAudio 오픈 소스 .NET 오디오 라이브러리를 사용하는 것이 가능합니다 . 변환을 수행하기 위해 PC에서 ACM 코덱을 찾습니다. NAudio와 함께 제공되는 Mp3FileReader는 현재 소스 스트림 내에서 위치를 변경할 수있을 것으로 예상하므로 (MP3 프레임의 인덱스를 앞쪽에 구축) 네트워크를 통한 스트리밍에는 적합하지 않습니다. 그러나 NAudio 의 MP3FrameAcmMp3FrameDecompressor클래스를 사용하여 스트리밍 된 MP3의 압축을 즉석에서 풀 수 있습니다.

NAudio를 사용하여 MP3 스트림을 재생하는 방법을 설명 하는 기사를 블로그에 게시했습니다 . 기본적으로 MP3 프레임을 다운로드하고 압축을 풀고 BufferedWaveProvider. 그런 다음 다른 스레드는를 BufferedWaveProvider입력으로 사용하여 재생 합니다.


3
NAudio 도서관은 지금라는 예제 응용 프로그램과 함께 출하 Mp3StreamingDemo 라이브 스트림 네트워크에서 MP3을해야합니다 모든 것을 하나를 제공해야합니다.
Martin

라이브러리를 사용하여 Android 장치에 입력 된 마이크 / 라인을 라이브 스트리밍 할 수 있습니까?
realtebo

10

SoundPlayer의 클래스는이 작업을 수행 할 수 있습니다. 당신이해야 할 일은 Stream 속성을 스트림 으로 설정 한 다음 Play.

편집
나는 그것이 MP3 파일을 재생할 수 있다고 생각하지 않는다; .wav로 제한되는 것 같습니다. 프레임 워크에 MP3 파일을 직접 재생할 수있는 것이 있는지 확실하지 않습니다. 내가 찾은 모든 것은 WMP 컨트롤을 사용하거나 DirectX와 상호 작용하는 것과 관련이 있습니다.


1
나는 수년 동안 MP3 인코딩 및 디코딩을 수행하는 .NET 라이브러리를 찾으려고 노력해 왔지만 존재한다고 생각하지 않습니다.
MusiGenesis

NAudio는 당신을 위해 일을해야합니다-적어도 디코딩을 위해 (첫 번째 포스트 참조)
Martin

4
SoundPlayer는 GC에 심각한 문제가 있으며 공식 Microsoft 해결 방법을 사용하지 않는 한 무작위로 쓰레기를 재생합니다 (해결 방법 클릭) : connect.microsoft.com/VisualStudio/feedback/…
Roman Starkov 2009

SoundPlayer + memoryStream은 desing으로 버그가 있습니다. 처음 두 번째 또는 세 번째로 재생할 때 오디오 중간에 이상한 잡음이 추가됩니다.
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에서 작동 했습니까?
Martin

또한 코드가 스레딩 문제에 대해 오류가 발생하기 쉬운 것처럼 보입니다. 당신이하는 일을 알고 있습니까?
Martin

1) 네,했습니다. 2) 최신 버전. 3) 이전 메시지에서 언급했듯이 개념 증명 일뿐입니다.
ReVolly

"최신 버전"을 어떻게 정의합니까? 버전 1.3입니까 아니면 개정판 68454의 소스입니까?
Martin

@Martin 죄송합니다, 오랫동안 여기에 없었습니다. 내가 사용한 NAudio.dll의 버전은 1.3.8입니다.
ReVolly 2011 년

2

내가 질문에 대답하기 위해 구글의 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로 변환합니다. MP3 대신 WMA를 사용하여이 작업을 수행하는 것이 유일한 현실적인 기회 일 것입니다. 멀티미디어 SDK 주위에 간단한 C # 래퍼를 작성할 수 있기 때문입니다.



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.