У меня есть вопрос об использовании файла AVFoundation AVPlayer (вероятно, применим как к iOS, так и к macOS). Я пытаюсь воспроизвести аудио (несжатые wav) данные, которые поступают из канала, отличного от стандартного HTTP Live Streaming.AVPlayer загрузка AVAsset из файла, который добавляется одновременно внешним источником (для macOS и iOS)
Корпус:
Пакеты аудиоданных сжимаются в канале вместе с другими данными, с которыми приложение должно работать. Например, видео и аудио входят в один канал и разделяются заголовком.
После фильтрации я получаю аудиоданные и распаковываю их в WAV-формат (на данном этапе не содержит заголовков).
После того, как пакеты данных готовы (9600 байт для 24k, стерео 16-битный звук), они передаются экземпляру AVPlayer (AVAudioPlayer в соответствии с Apple не подходит для потоковой передачи звука).
Учитывая, что AVPlayer (элемент или объект) не загружается из памяти (нет initWithData: (NSData)) и требует URL-адреса HTTP Live Stream или URL-адреса файла, я создаю файл на диске (либо macOS, либо iOS) , добавьте WAV Headers и добавьте несжатые данные там.
Назад на AVPlayer, я создаю следующее:
AVURLAsset *audioAsset = [[AVURLAsset alloc] initWithURL:[NSURL fileURLWithPath:tempAudioFile] options:nil];
AVPlayerItem *audioItem = [[AVPlayerItem alloc] initWithAsset:audioAsset];
AVPlayer *audioPlayer = [[AVPlayer alloc] initWithPlayerItem:audioItem];
добавления KVOs, а затем попытаться начать воспроизведение:
[audioPlayer play];
Результатом является то, что звук играет в течение 1-2 секунд и затем останавливается (AVPlayerItemDidPlayToEndTimeNotification), а данные продолжают добавляться в файл. Поскольку все это в цикле, [воспроизведение аудиопользователя] запускается и приостанавливает (скорость == 0) несколько раз.
Вся концепция в упрощенном виде:
-(void)PlayAudioWithData:(NSData *data) //data in encoded format
{
NSData *decodedSound = [AudioDecoder DecodeData:data]; //decodes the data from the compressed format (Opus) to WAV
[Player CreateTemporaryFiles]; //This creates the temporary file by appending the header and waiting for input.
[Player SendDataToPlayer:decodedSound]; //this sends the decoded data to the Player to be stored to file. See below for appending.
Boolean prepared = [Player isPrepared]; //a check if AVPlayer, Item and Asset are initialized
if (!prepared)= [Player Prepare]; //creates the objects like above
Boolean playing = [Player isAudioPlaying]; //a check done on the AVPlayer if rate == 1
if (!playing) [Player startPlay]; //this is actually [audioPlayer play]; on AVPlayer Instance
}
-(void)SendDataToPlayer:(NSData *data)
{
//Two different methods here. First with NSFileHandle — not so sure about this though as it definitely locks the file.
//Initializations and deallocations happen elsewhere, just condensing code to give you an idea
NSFileHandle *audioFile = [NSFileHandle fileHandleForWritingAtPath:_tempAudioFile]; //happens else where
[audioFile seekToEndOfFile];
[audioFile writeData:data];
[audioFile closeFile]; //happens else where
//Second method is
NSOutputStream *audioFileStream = [NSOutputStream outputStreamWithURL:[NSURL fileURLWithPath:_tempStreamFile] append:YES];
[audioFileStream open];
[audioFileStream write:[data bytes] maxLength:data.length];
[audioFileStream close];
}
Оба NSFileHandle и NSOutputStream сделать полностью рабочие WAV файлы, сыгранные QuickTime, Itunes, VLC и т.д. Кроме того, если я обойти [Player SendDataToPlayer: decodedSound ] и иметь временный аудиофайл, предварительно загруженный стандартным WAV, он также воспроизводится нормально.
До сих пор есть две стороны: a) У меня есть аудиоданные, декомпрессированные и готовые к воспроизведению b) Я правильно сохраняю данные.
То, что я пытаюсь сделать, это send-write-read в строке. Это заставляет меня думать, что сохранение данных в файл, получение эксклюзивного доступа к файловому ресурсу и не позволяет AVPlayer продолжить воспроизведение.
Любой, кто имеет представление о том, как сохранить файл как NSFileHandle/NSOutputStream, так и AVPlayer?
Или еще лучше ... Есть ли AVPlayer initWithData? (hehe ...)
Любая помощь очень ценится! Спасибо заранее.
Два вопроса: 1) Вы загружаете данные из WAV файла в связке. Вы используете это только для источника данных, или я должен использовать wav-файл, в который я добавляю данные? (Примечание: у меня уже есть данные в памяти) и 2) Это происходит в цикле, так как новые данные поступают непрерывно. Мне нужно выделить AVPlayer или я должен где-то освободиться? – Pericles
1) Я использую wav-файл, чтобы иметь некоторые исходные данные. 2) У меня недостаточно информации, чтобы сказать, когда вы должны освободить свой «AVPlayer». Что касается файла, к которому вы добавляете - я не знаю, если это необходимо, но вы можете либо передать делегата загрузчика из файла, либо непосредственно из распакованных данных в памяти. Но 'playerWithWavData' может быть не лучшим образом. Я только дал этот пример, потому что это то, о чем вы просили. –