CFReadStream - начать в фоновом режиме - PullRequest
0 голосов
/ 23 января 2012

есть аудио приложение, которое передает файлы по сети, все работает отлично, но одно. Для автоматического воспроизведения следующей дорожки в фоновом режиме CFReadStream инициализируется (я вижу это в журнале) после вызова AudioQueueStop, но обратный вызов никогда не вызывается (edit: фактически вызывается один раз), пока приложение не выходит на передний план. Кусок кода для инициализации потока:

    //also tried main runloop just for test, no luck 
CFReadStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);

Дело в том, что приложение функционирует после остановки очереди, инициализируется поток, но обратный вызов вызывается только в том случае, если поток был инициализирован в режиме переднего плана. Вот фрагмент кода для обратного вызова:

    CFReadStreamSetClient(stream,
                      kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered,
                      MyReadStreamCallBack,
                      &context);

С другой стороны, обратный вызов вызывается, когда приложение находится в фоновом режиме, и следующая дорожка запускается не автоматически, а с делегатом приложения (с той же функцией).

Я не совсем понимаю разницу между этими тремя случаями, пожалуйста, помогите.

Редактировать.

OSStatus status = AudioFileStreamOpen(self, MyAudioListener ...

Вызывается обратный вызов MyAudioListener, а MyReadStreamCallBack вызывается только один раз .

Редактировать 2

обратный вызов ReadStream чаще всего не вызывается ни разу, один раз - максимум того, что я смог увидеть.

С другой стороны, и это приводит меня к неправильному пониманию того, что происходит, после предыдущий AudioQueue останавливается , а следующий трек - локальный файл , затем другой AudioQueue открывается , он читает файл с помощью AudioFileReadPackets, и мне не нужно пробуждать приложение из фона, чтобы начать воспроизведение следующей дорожки, так как оно воспроизводит в фоновом режиме.

Ответы [ 2 ]

1 голос
/ 23 января 2012

Аудио-очередь будет продолжать работать в фоновом режиме, учитывая подходящие фоновые режимы. Но после остановки кажется, что Audio Queue не запустится в фоновом режиме. Один обратный вызов, вероятно, состоит в простом заполнении буфера, поэтому очередь может начаться сразу после вывода на передний план.

Единственное решение, которое я нашел, - не останавливать предыдущую Аудио-очередь, когда она находится в фоновом режиме, а каким-то образом подавать новые аудиоданные в старую Аудио-очередь, оставшуюся работающей, без потери каких-либо обратных вызовов между ними.

0 голосов
/ 25 января 2012

Текущее решение состоит в том, чтобы добавить фоновое задание, чтобы дождаться данных, с которых начинается новая очередь (запуск очереди без данных дает ошибку -50, и я полагаю, что зависает декодер hw).

Допустим, в функции воспроизведения стримера есть функция openNetworkStream с чем-то вроде этого:

// ...whatever we need to be happy 


// start the background job
UIDevice* device = [UIDevice currentDevice];
BOOL isBackgroundSupported = NO;
if ([device respondsToSelector:@selector(isMultitaskingSupported)])
    isBackgroundSupported = device.multitaskingSupported;

if(isBackgroundSupported && waitForQueueToStartBackgroundTask == UIBackgroundTaskInvalid) {
    waitForQueueToStartbackgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        [[UIApplication sharedApplication] endBackgroundTask:waitForQueueToStartBackgroundTask];
        waitForQueueToStartBackgroundTask = UIBackgroundTaskInvalid;
    }];
}

// Open the stream
if (!CFReadStreamOpen(stream)) {

Вы должны были где-нибудь вызывать AudioQueueStart, для меня это была функция StreamEnqueueBuffer, используемая для передачи загруженных фрагментов данных, когда буферы готовы к воспроизведению или достигнут конец файла (AudioQueueEnqueueBuffer), эта функция также начальный стартер AudioQueue, поскольку нам нужно заполнить буферы для его запуска. Мое решение состояло в том, чтобы завершить инициализированное запущенное фоновое задание здесь, когда очередь запущена:

OSStatus StreamEnqueueBuffer(AudioNetworkStreamer* aStreamer)

// wahtever you need to be happy with a filled buffer

if (!aStreamer->didStart) {     // start the queue if it has not been started already
    aStreamer->isBuffering = NO;
    [aStreamer startQueue];

    UIDevice* device = [UIDevice currentDevice];
    BOOL isBackgroundSupported = NO;
    if ([device respondsToSelector:@selector(isMultitaskingSupported)])
        isBackgroundSupported = device.multitaskingSupported;

    if(isBackgroundSupported && aStreamer->waitForQueueToStartBackgroundTask == UIBackgroundTaskInvalid) {
        [[UIApplication sharedApplication] endBackgroundTask:aStreamer->waitForQueueToStartBackgroundTask];
        aStreamer->waitForQueueToStartBackgroundTask = UIBackgroundTaskInvalid;
    }
}

    // nandle mutexes, flags ...
...