Повторение аудио в WatchKit (AVAudioPlayer?) - PullRequest
0 голосов
/ 18 ноября 2018

Я хочу зациклить локальный аудиофайл в приложении Apple Watch. В настоящее время я использую AVAudioPlayerNode и AVAudioEngine, которые работают хорошо, но я не могу понять, как зациклить звук.

Я заметил, что могу использовать AVAudioPlayer, который имеет удобный «numberOfLoops», но по какой-то причине AVAudioPlayer не работает на часах. Понятия не имею почему.

Вот мой текущий код для воспроизведения звука:

_audioPlayer = [[AVAudioPlayerNode alloc] init];
_audioEngine = [[AVAudioEngine alloc] init];
[_audioEngine attachNode:_audioPlayer];

AVAudioFormat *stereoFormat = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:44100 channels:2];
[_audioEngine connect:_audioPlayer to:_audioEngine.mainMixerNode format:stereoFormat];

if (!_audioEngine.isRunning) {
    NSError* error;
    [_audioEngine startAndReturnError:&error];
}

NSError *error;
NSBundle* appBundle = [NSBundle mainBundle];
NSURL *url = [NSURL fileURLWithPath:[appBundle pathForResource:@"FILE_NAME" ofType:@"mp3"]];
AVAudioFile *asset = [[AVAudioFile alloc] initForReading:url error:&error];

[_audioPlayer scheduleFile:asset atTime:nil completionHandler:nil];
[_audioPlayer play];

Вот код, который я пытался использовать для AVAudioPlayer, но не работает:

NSError *audioError;
AVAudioPlayer* player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"FILE_NAME" ofType:@"mp3"]] error:&audioError];
player.numberOfLoops = MAXFLOAT;
player.delegate = self;
[player play];

Я использую WatchKit 5.0 (+).

Ответы [ 2 ]

0 голосов
/ 20 ноября 2018

Вы можете зациклить свой AVAudioFile, рекурсивно запланировав его:

__block __weak void (^weakSheduleFile)(void);
void (^scheduleFile)(void);

weakSheduleFile = scheduleFile = ^{ [self->_audioPlayer scheduleFile:asset atTime:nil completionHandler:weakSheduleFile]; };

scheduleFile();

Я не уверен, будет ли это бесшовная петля. Если это не так, вы можете попробовать запланировать два файла:

scheduleFile();
scheduleFile();
0 голосов
/ 19 ноября 2018

Если ваш аудиофайл помещается в память, вы можете запланировать воспроизведение как AVAudioBuffer с опцией AVAudioPlayerNodeBufferLoops ( N.B. протестировано только на симуляторе!):

AVAudioFormat *outputFormat = [_audioPlayer outputFormatForBus:0];

__block AVAudioPCMBuffer *srcBuffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:asset.processingFormat frameCapacity:(AVAudioFrameCount)asset.length];

if (![asset readIntoBuffer:srcBuffer error:&error]) {
    NSLog(@"Read error: %@", error);
    abort();
}

AVAudioPCMBuffer *dstBuffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:outputFormat frameCapacity:(AVAudioFrameCount)asset.length];

AVAudioConverter *converter = [[AVAudioConverter alloc] initFromFormat:srcBuffer.format toFormat:dstBuffer.format];
AVAudioConverterOutputStatus status = [converter convertToBuffer:dstBuffer error:&error withInputFromBlock:^AVAudioBuffer * _Nullable(AVAudioPacketCount inNumberOfPackets, AVAudioConverterInputStatus * _Nonnull outStatus) {
    if (srcBuffer) {
        AVAudioBuffer *result = srcBuffer;
        srcBuffer = NULL;
        *outStatus = AVAudioConverterInputStatus_HaveData;
        return result;
    } else {
        *outStatus = AVAudioConverterInputStatus_EndOfStream;
        return NULL;
    }
}];

assert(status != AVAudioConverterOutputStatus_Error);

[_audioPlayer scheduleBuffer:dstBuffer atTime:nil options:AVAudioPlayerNodeBufferLoops completionHandler:nil];
[_audioPlayer play];
...