Pergunta

Existe uma maneira em C # para reproduzir áudio (por exemplo, MP3) direcly de um System.IO.Stream que, por exemplo, foi returend de um WebRequest sem salvar os dados temporariamente para o disco?


Solução com NAudio

Com a ajuda de NAudio 1.3 é possível:

  1. Coloque um arquivo MP3 a partir de uma URL em um MemoryStream
  2. dados converter MP3 em dados onda depois que foi completamente carregado
  3. reproduzir os dados de onda usando NAudio 's classe WaveOut

Ele teria sido bom para ser capaz de até mesmo jogar uma meia carregado arquivo MP3, mas este parece ser impossível devido à noreferrer NAudio projeto biblioteca.

E esta é a função que irá fazer o trabalho:

    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);
                    }
                }
            }
        }
    }
Foi útil?

Solução

Edit: Resposta atualizado para refletir mudanças em versões recentes do NAudio

É possível utilizar o href="http://www.codeplex.com/naudio" rel="noreferrer"> NAudio biblioteca .NET audio MP3Frame e AcmMp3FrameDecompressor em NAudio para descomprimir transmitido MP3 na mosca.

Tenho postado um artigo no meu blog explicando como reproduzir um fluxo de MP3 usando NAudio . Essencialmente, você tem um segmento de baixar quadros MP3, descomprimindo-los e armazená-los em um BufferedWaveProvider. Outro segmento em seguida, reproduz usando o BufferedWaveProvider como uma entrada.

Outras dicas

O SoundPlayer classe pode fazer isso. Parece que tudo que você tem a fazer é definir a sua Corrente propriedade para o fluxo, então Play chamada.

editar
Eu não acho que ele pode reproduzir arquivos MP3 embora; parece limitado a .wav. Eu não estou certo se há alguma coisa na estrutura que pode reproduzir um arquivo MP3 diretamente. Tudo o que eu encontrar sobre que envolve tanto usando um controle WMP ou interagindo com DirectX.

Baixo pode fazer exatamente isso. Reproduzir a partir de byte [] em memória ou através de delegados de arquivo onde você retornar os dados, de modo com que você pode jogar, assim que você tem dados suficientes para iniciar a reprodução ..

Eu ligeiramente modificada a fonte arranque tópico, por isso agora pode jogar um arquivo não-completamente-carregado. Aqui é (note, que é apenas uma amostra e é um ponto para começar a partir, você precisa fazer alguma exceção e manipulação aqui erro):

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 envolve a API WaveOutXXXX. Eu não olhei para a fonte, mas se NAudio expõe a função waveOutWrite () de uma forma que não pára automaticamente a reprodução em cada chamada, então você deve ser capaz de fazer o que você realmente quer, que é para começar a jogar o stream de áudio antes que você recebeu todos os dados.

Usando a função waveOutWrite () permite que você "leia mais à frente" e despejar pequenos pedaços de áudio na fila de saída - Windows irá reproduzir automaticamente os pedaços perfeitamente. Seu código teria que tomar o fluxo de áudio comprimido e convertê-lo em pequenos pedaços de áudio WAV em tempo real; esta parte seria muito difícil - todas as bibliotecas e componentes que já vi fazer a conversão MP3-to-WAV um arquivo inteiro de uma vez. Provavelmente a sua única chance realista é fazer isso usando WMA em vez de MP3, porque você pode escrever C # invólucros simples ao redor do SDK multimídia.

Eu tweaked a fonte postou a questão para permitir o uso com a API TTS do Google, a fim de responder à pergunta aqui :

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

Invoke com:

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

Terminar com:

if (waiting)
    stop.Set();

Observe que eu estou usando o ParameterizedThreadDelegate no código acima, e o fio é iniciado com playThread.Start(10000);. A 10000 representa um máximo de 10 segundos de áudio para ser jogado por isso terá de ser ajustado se o seu fluxo leva mais tempo do que para jogar. Isso é necessário porque a versão atual do NAudio (v1.5.4.0) parece ter um problema determinar quando o fluxo é feito de jogo. Ele pode ser corrigido em uma versão posterior, ou talvez haja uma solução alternativa que eu não tomar o tempo para encontrar.

Eu passei a biblioteca decodificador MP3 e tornou disponível para .NET desenvolvedores como < a href = "http://sourceforge.net/projects/mpg123net/" rel = "nofollow noreferrer"> mpg123.net .

Incluem-se as amostras para converter arquivos de MP3 para PCM , e ler noreferrer tags ID3 .

Eu sempre usei FMOD para coisas como isso porque é gratuito para uso não-comercial e funciona bem.

Dito isso, eu trocaria de bom grado a algo que é menor (FMOD é ~ 300k) e de código aberto. pontos de bônus Super se ele está totalmente gerenciado para que eu possa compilar / fundi-la com a minha .exe e não tem que tomar cuidado extra para obter portabilidade para outras plataformas ...

(FMOD faz portabilidade também, mas você precisa obviamente diferentes binários para diferentes plataformas)

Eu não tentei de um WebRequest, mas tanto o Windows Media Player < a href = "http://en.wikipedia.org/wiki/ActiveX" rel = "nofollow noreferrer"> ActiveX eo MediaElement (de WPF ) componentes noreferrer nofollow são capazes de reproduzir e colocar em buffer fluxos de MP3.

Eu usá-lo para reproduzir dados provenientes de um SHOUTcast fluxo e funcionou muito bem. No entanto, eu não tenho certeza se ele vai trabalhar no cenário que você propõe.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top