Czy istnieje sposób w języku C #, aby odtwarzać dźwięk (na przykład MP3) bezpośrednio z System.IO.Stream, który na przykład został odtworzony z żądania WebRequest bez tymczasowego zapisywania danych na dysku?
Rozwiązanie z NAudio
Z pomocą NAudio 1.3 można:
- Załaduj plik MP3 z adresu URL do MemoryStream
- Konwertuj dane MP3 na dane Wave po całkowitym załadowaniu
- Odtwarzanie danych za pomocą fal NAudio klasę „s WaveOut
Byłoby miło móc odtworzyć nawet w połowie załadowany plik MP3, ale wydaje się to niemożliwe ze względu na projekt biblioteki NAudio .
I to jest funkcja, która wykona całą pracę:
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);
}
}
}
}
}
Odpowiedzi:
Edycja: zaktualizowano odpowiedź, aby odzwierciedlić zmiany w ostatnich wersjach NAudio
Jest to możliwe dzięki otwartej bibliotece audio .NET NAudio, którą napisałem. Szuka kodeka ACM na komputerze, aby przeprowadzić konwersję. Mp3FileReader dostarczony z NAudio oczekuje obecnie, że będzie w stanie zmienić położenie w strumieniu źródłowym (buduje indeks ramek MP3 z góry), więc nie jest odpowiedni do przesyłania strumieniowego przez sieć. Jednak nadal możesz używać klas
MP3Frame
iAcmMp3FrameDecompressor
w NAudio do dekompresji strumieniowo odtwarzanych plików MP3 w locie.Opublikowałem artykuł na swoim blogu wyjaśniający, jak odtwarzać strumień MP3 za pomocą NAudio . Zasadniczo masz jeden wątek, który pobiera ramki MP3, dekompresuje je i zapisuje w pliku
BufferedWaveProvider
. Następnie inny wątek jest odtwarzany, używającBufferedWaveProvider
jako wejścia.źródło
SoundPlayer klasa może to zrobić. Wygląda na to, że wszystko, co musisz zrobić, to ustawić jego właściwość Stream na strumień, a następnie wywołać
Play
.edytuj
Nie sądzę jednak, że może odtwarzać pliki MP3; wydaje się ograniczone do .wav. Nie jestem pewien, czy w ramach jest coś, co może bezpośrednio odtwarzać plik MP3. Wszystko, co o tym wiem, obejmuje użycie kontrolki WMP lub interakcję z DirectX.
źródło
Bas może to zrobić. Odtwarzaj z Byte [] w pamięci lub przez delegatów plików, w których zwracasz dane, dzięki czemu możesz odtwarzać, gdy tylko masz wystarczającą ilość danych, aby rozpocząć odtwarzanie.
źródło
Nieznacznie zmodyfikowałem źródło startera tematu, więc może teraz odtwarzać nie w pełni załadowany plik. Oto jest (zauważ, że to tylko przykład i jest to punkt, od którego należy zacząć; musisz tutaj zrobić wyjątek i obsługę błędów):
źródło
Poprawiłem źródło zamieszczone w pytaniu, aby umożliwić używanie z interfejsem Google TTS API, aby odpowiedzieć na pytanie tutaj :
Wywołaj za pomocą:
Zakończ za pomocą:
Zwróć uwagę, że używam
ParameterizedThreadDelegate
w powyższym kodzie, a wątek jest uruchamiany zplayThread.Start(10000);
. Wartość 10000 oznacza maksymalnie 10 sekund dźwięku do odtworzenia, więc będzie trzeba ją dostosować, jeśli odtwarzanie strumienia trwa dłużej. Jest to konieczne, ponieważ obecna wersja NAudio (v1.5.4.0) wydaje się mieć problem z określeniem, kiedy strumień jest zakończony. Może to zostać naprawione w późniejszej wersji lub może istnieje obejście, którego nie znalazłem w czasie.źródło
NAudio otacza API WaveOutXXXX. Nie patrzyłem na źródło, ale jeśli NAudio ujawnia funkcję waveOutWrite () w sposób, który nie zatrzymuje automatycznie odtwarzania przy każdym wywołaniu, powinieneś być w stanie zrobić to, co naprawdę chcesz, czyli rozpocząć odtwarzanie strumień audio, zanim otrzymałeś wszystkie dane.
Użycie funkcji waveOutWrite () umożliwia „czytanie z wyprzedzeniem” i zrzucanie mniejszych fragmentów dźwięku do kolejki wyjściowej - system Windows automatycznie bezproblemowo odtworzy fragmenty. Twój kod musiałby pobierać skompresowany strumień audio i konwertować go na małe fragmenty dźwięku WAV w locie; ta część byłaby naprawdę trudna - wszystkie biblioteki i komponenty, które kiedykolwiek widziałem, konwertują cały plik MP3 na WAV na raz. Prawdopodobnie jedyną realną szansą jest zrobienie tego za pomocą WMA zamiast MP3, ponieważ możesz pisać proste opakowania C # wokół multimedialnego SDK.
źródło
Zapakowałem bibliotekę dekodera MP3 i udostępniłem ją programistom .NET jako mpg123.net .
Dołączone są próbki do konwersji plików MP3 na PCM i odczytu tagów ID3 .
źródło
Nie próbowałem tego z WebRequest, ale zarówno składniki Windows Media Player ActiveX, jak i MediaElement (z WPF ) są w stanie odtwarzać i buforować strumienie MP3.
Używam go do odtwarzania danych pochodzących ze strumienia SHOUTcast i działało świetnie. Nie jestem jednak pewien, czy zadziała w proponowanym przez Ciebie scenariuszu.
źródło
Zawsze używałem FMOD do takich rzeczy, ponieważ jest darmowy do użytku niekomercyjnego i działa dobrze.
To powiedziawszy, chętnie przełączyłbym się na coś mniejszego (FMOD to ~ 300k) i open-source. Super dodatkowe punkty, jeśli jest w pełni zarządzany, dzięki czemu mogę go skompilować / połączyć z moim .exe i nie muszę zwracać większej uwagi, aby uzyskać przenośność na inne platformy ...
(FMOD też jest przenośny, ale oczywiście potrzebujesz różnych plików binarnych dla różnych platform)
źródło