¿Hay alguna forma en C # de reproducir audio (por ejemplo, MP3) directamente desde un System.IO.Stream que, por ejemplo, fue recuperado de un WebRequest sin guardar los datos temporalmente en el disco?
Solución con NAudio
Con la ayuda de NAudio 1.3 es posible:
- Cargue un archivo MP3 desde una URL en un MemoryStream
- Convierta datos MP3 en datos de ondas después de que se hayan cargado por completo
- La reproducción de los datos de onda utilizando NAudio clase WaveOut 's
Hubiera sido bueno poder incluso reproducir un archivo MP3 medio cargado, pero esto parece imposible debido al diseño de la biblioteca NAudio .
Y esta es la función que hará el trabajo:
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);
}
}
}
}
}
Respuestas:
Editar: respuesta actualizada para reflejar cambios en versiones recientes de NAudio
Es posible usar la biblioteca de audio .NET de código abierto NAudio que he escrito. Busca un códec ACM en su PC para realizar la conversión. El Mp3FileReader suministrado con NAudio actualmente espera poder reposicionarse dentro del flujo de origen (crea un índice de fotogramas MP3 al principio), por lo que no es apropiado para transmitir a través de la red. Sin embargo, aún puede usar las clases
MP3Frame
yAcmMp3FrameDecompressor
en NAudio para descomprimir MP3 transmitido sobre la marcha.He publicado un artículo en mi blog que explica cómo reproducir un flujo de MP3 con NAudio . Básicamente, tiene un hilo descargando marcos MP3, descomprimiéndolos y almacenándolos en un archivo
BufferedWaveProvider
. Luego, se reproduce otro hilo utilizandoBufferedWaveProvider
como entrada.fuente
La clase SoundPlayer puede hacer esto. Parece que todo lo que tienes que hacer es establecer su propiedad Stream en la secuencia y luego llamar
Play
.editar
Aunque no creo que pueda reproducir archivos MP3; parece limitado a .wav. No estoy seguro de si hay algo en el marco que pueda reproducir un archivo MP3 directamente. Todo lo que encuentro sobre eso implica usar un control WMP o interactuar con DirectX.
fuente
Bass puede hacer precisamente esto. Reproducir desde Byte [] en la memoria o mediante delegados de archivo donde devuelve los datos, de modo que pueda reproducir tan pronto como tenga suficientes datos para iniciar la reproducción.
fuente
Modifiqué ligeramente la fuente de inicio del tema, por lo que ahora puede reproducir un archivo que no está completamente cargado. Aquí está (tenga en cuenta que es solo una muestra y es un punto desde el que comenzar; debe hacer alguna excepción y manejo de errores aquí):
fuente
Modifiqué la fuente publicada en la pregunta para permitir el uso con la API de TTS de Google para responder la pregunta aquí :
Invocar con:
Terminar con:
Observe que estoy usando
ParameterizedThreadDelegate
en el código anterior y el hilo se inicia conplayThread.Start(10000);
. El 10000 representa un máximo de 10 segundos de audio que se reproducirán, por lo que será necesario modificarlo si la transmisión tarda más en reproducirse. Esto es necesario porque la versión actual de NAudio (v1.5.4.0) parece tener problemas para determinar cuándo termina la reproducción de la transmisión. Puede que se solucione en una versión posterior o tal vez haya una solución que no me tomé el tiempo de encontrar.fuente
NAudio envuelve la API WaveOutXXXX. No he mirado la fuente, pero si NAudio expone la función waveOutWrite () de una manera que no detiene automáticamente la reproducción en cada llamada, entonces debería poder hacer lo que realmente quiere, que es comenzar a reproducir el flujo de audio antes de recibir todos los datos.
El uso de la función waveOutWrite () le permite "leer con anticipación" y volcar trozos más pequeños de audio en la cola de salida; Windows reproducirá automáticamente los trozos sin problemas. Su código tendría que tomar el flujo de audio comprimido y convertirlo en pequeños fragmentos de audio WAV sobre la marcha; esta parte sería realmente difícil: todas las bibliotecas y componentes que he visto hacen conversión de MP3 a WAV un archivo completo a la vez. Probablemente su única oportunidad realista sea hacer esto usando WMA en lugar de MP3, porque puede escribir envoltorios simples de C # alrededor del SDK multimedia.
fuente
Envolví la biblioteca de decodificadores MP3 y la puse a disposición de los desarrolladores de .NET como mpg123.net .
Se incluyen las muestras para convertir archivos MP3 a PCM y leer etiquetas ID3 .
fuente
No lo he probado desde una WebRequest, pero tanto Windows Media Player ActiveX como MediaElement (de WPF componentes ) son capaces de reproducir y almacenar en búfer transmisiones MP3.
Lo uso para reproducir datos provenientes de una transmisión SHOUTcast y funcionó muy bien. Sin embargo, no estoy seguro de si funcionará en el escenario que propone.
fuente
Siempre he usado FMOD para cosas como esta porque es gratis para uso no comercial y funciona bien.
Dicho esto, con mucho gusto cambiaría a algo más pequeño (FMOD es ~ 300k) y de código abierto. Súper puntos de bonificación si está completamente administrado para que pueda compilarlo / fusionarlo con mi .exe y no tener que tener mucho cuidado para obtener portabilidad a otras plataformas ...
(FMOD también tiene portabilidad, pero obviamente necesitaría diferentes binarios para diferentes plataformas)
fuente