В приложении, над которым я сейчас работаю, я хотел бы воспроизвести аудиопоток AAC.Например, это интернет-радио: http://stream.bauermedia.fi/iskelma/kem_64.aac. Я хотел бы использовать платформу NAudio, так как она уже используется в этом проекте.
Для начала я рассмотрел Mp3StreamingDemo в NAudioDemo.Я создал класс ADTSFrame, где я обработал заголовок кадра ADTS (https://wiki.multimedia.cx/index.php/ADTS).. Из заголовка кадра ADTS я получил следующую информацию: частоту дискретизации, количество каналов, длину кадра. Затем я создал отдельный класс ADTSWaveFormat с одним частным полем waveFormatTagи два свойства Channels и SampleRate. WafeFormatTag установлен в WaveFormatEncoding.MPEG_ADTS_AAC. Как я понял отсюда - https://docs.microsoft.com/en-us/windows/desktop/DirectShow/audio-subtypes, больше никакой информации не требуется. Однако, когда я хотел получить формат PCM, AcmInterop.acmFormatSuggest () вернулся.«NoDriver». Поэтому я застрял здесь, так как не понимаю, двигаюсь ли я в правильном направлении.
Затем я искал в Интернете и нашел информацию, что в NAudio есть класс StreamMediaFoundationReader. StreamMediaFoundationReaderхочет получить поток в своем конструкторе. Прежде всего этот поток преобразуется в ComStream, а затем в IMFByteStream. Когда ComStream преобразуется в IMFByteStream, выполняется операция Seek. Поэтому ConnectStreamЯ получаю из response.GetResponseStream () не подходит для передачи конструктору StreamMediaFoundationReader, так как он не доступен для поиска.Поэтому я решил использовать поток памяти.
До сих пор наиболее успешный код, который я написал, был:
WebResponse response = WebRequest.Create(InputPath).GetResponse();
using (Stream rs = response.GetResponseStream())
{
using (MemoryStream ms = new MemoryStream())
{
byte[] buffer = new byte[16384 * 4];
int read = rs.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, read);
using (var streamMfReader = new StreamMediaFoundationReader(rs))
using (WaveOut waveOut = new WaveOut())
{
waveOut.Init(streamMfReader);
waveOut.Play();
while (waveOut.PlaybackState == PlaybackState.Playing)
Thread.Sleep(100);
}
}
}
Как видите, этот код никуда не годится, так как он играет только длямомент.
Я также попробовал это:
MemoryStream memoryStream = new MemoryStream();
new Thread(delegate (object o)
{
WebResponse response = WebRequest.Create(InputPath).GetResponse();
using (Stream responseStream = response.GetResponseStream())
{
byte[] buffer = new byte[65536];
int read;
while ((read = responseStream.Read(buffer, 0, buffer.Length)) > 0)
{
long pos = memoryStream.Position;
memoryStream.Position = memoryStream.Length;
memoryStream.Write(buffer, 0, read);
memoryStream.Position = pos;
}
}
}).Start();
while (memoryStream.Length < 65536 * 10)
Thread.Sleep(1000);
memoryStream.Position = 0;
using (WaveStream streamMediaFoundationReader = new
StreamMediaFoundationReader(memoryStream))
{
using (WaveOut waveOut = new
WaveOut(WaveCallbackInfo.FunctionCallback()))
{
waveOut.Init(streamMediaFoundationReader);
waveOut.Play();
while (waveOut.PlaybackState == PlaybackState.Playing)
{
Thread.Sleep(100);
}
}
}
Но здесь я получаю ContextSwitchDeadlock, так как memoryStream используется в разных потоках.
В настоящее время у меня не так много работыопыт программирования.
Не могли бы вы дать мне совет, как можно воспроизводить аудиопоток с помощью NAudio?
Сегодня я также попытался отредактировать ReadFullyStream следующим образом:
public class ReadFullyStream : Stream
{
private readonly Stream sourceStream;
private long readPos;
private long seekPos;
private readonly byte[] readAheadBuffer;
private int readAheadLength;
private int readAheadOffset;
public ReadFullyStream(Stream sourceStream)
{
this.sourceStream = sourceStream;
readAheadBuffer = new byte[4096];
}
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return true; }
}
public override bool CanWrite
{
get { return true; }
}
public override void Flush()
{
throw new InvalidOperationException();
}
public override long Length
{
get { return readPos; }
}
public override long Position
{
get => seekPos;
set => seekPos = value;
}
public override int Read(byte[] buffer, int offset, int count)
{
int bytesRead = 0;
while (bytesRead < count)
{
int readAheadAvailableBytes = readAheadLength - readAheadOffset;
int bytesRequired = count - bytesRead;
if (readAheadAvailableBytes > 0)
{
int toCopy = Math.Min(readAheadAvailableBytes, bytesRequired);
Array.Copy(readAheadBuffer, readAheadOffset, buffer, offset + bytesRead, toCopy);
bytesRead += toCopy;
readAheadOffset += toCopy;
}
else
{
readAheadOffset = 0;
readAheadLength = sourceStream.Read(readAheadBuffer, 0, readAheadBuffer.Length);
//Debug.WriteLine(String.Format("Read {0} bytes (requested {1})", readAheadLength, readAheadBuffer.Length));
if (readAheadLength == 0)
{
break;
}
}
}
readPos += bytesRead;
Position = readPos;
return bytesRead;
}
public override long Seek(long offset, SeekOrigin origin)
{
Position = offset;
return Position;
}
public override void SetLength(long value)
{
throw new InvalidOperationException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new InvalidOperationException();
}
}
Мое намерение состояло в том, чтобы сделать ReadFullyStream доступным для поиска, но на самом деле я понимаю, что не понимаю чего-то важного.После внесения этих изменений в классе ReadFullyStream я попробовал следующее:
WebRequest request = WebRequest.Create(InputPath);
WebResponse response = request.GetResponse();
using (Stream responseStream = response.GetResponseStream())
{
ReadFullyStream readFullyStream = new ReadFullyStream(responseStream);
using (WaveStream streamMediaFoundationReader = new
StreamMediaFoundationReader(readFullyStream))
{
using (WaveOut waveOut = new WaveOut())
{
waveOut.Init(streamMediaFoundationReader);
waveOut.Play();
while (waveOut.PlaybackState == PlaybackState.Playing)
{
Thread.Sleep(100);
}
}
}
}
Теперь я получаю следующую ошибку в MediaFoundationApi CreateSourceReaderFromByteStream (IMFByteStream byteStream):
System.Runtime.InteropServices.COMException: «Катастрофический сбой (исключение из HRESULT: 0x8000FFFF (E_UNEXPECTED))».