使用 AQ 和音频文件流动态检测和流式传输 AAC

发布于 2024-10-21 20:59:57 字数 470 浏览 0 评论 0原文

我目前正在播放 MP3 和 AAC 广播电台。 我正在读取 ICY/HTTP 标头,当检测内容类型中的音频/aac 或音频/aacp 时,我提供 kAudioFileAAC_ADTSType 作为 AudioFileStreamOpen 的线索,否则我给它 kAudioFileMP3Type。

它工作得很好,问题是当电台正在播放 AAC,但不发送音频/aacp 作为 HTTP 标头中的内容类型时。当发生这种情况时,我通常使用 mp3 线索创建音频文件流(与 0 作为线索也没有什么不同),然后音频文件流的属性回调表明该流认为它正在读取 MP3,formatList 回调也永远不会发生,并且当这时音频队列的创建失败了。

有没有办法让 AudioFileStream 与 A​​AC 一起工作,而无需在其构造函数中传递 AAC 提示,或者是否有人对如何检测这些电台有任何其他想法,然后以某种方式在我的电台数据库中标记它们?我也不想在每次正常失败时尝试使用 AAC 作为提示创建新的音频文件流。

I am currently streaming MP3 and AAC radio stations.
I'm reading the ICY/HTTP headers, and when detecting audio/aac or audio/aacp in the content-type, i provide kAudioFileAAC_ADTSType as the clue for AudioFileStreamOpen, otherwise i give it kAudioFileMP3Type.

It works great, the problem is when the station is playing AAC, but doesn't send audio/aacp as content-type in the HTTP headers. When that happens, i create the audiofilestream normally with an mp3 clue (nothing is different with 0 as clue either), and then the property callbacks of the audiofilestream indicate that the stream thinks it's reading MP3, the formatList callback never happens either, and when the time comes the creation of the audio queue fails.

Is there a way to make AudioFileStream work with AAC without the AAC hint being passed in it's constructor, or does anyone has any other idea about how to detect those stations other then marking them somehow in my stations databases? I'd also rather not attempt to create a new audiofilestream with AAC as a hint each time i fail normally.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

口干舌燥 2024-10-28 20:59:57

我已经有一段时间没有查看这段代码了,但我认为它应该可以解决问题。

// the file stream parser is now ready to produce audio packets.
// get the stream format.
AudioFormatListItem afli = GetFirstPlayableAudioFormatForFile(inAudioFileStream);
AudioStreamBasicDescription asbd = afli.mASBD;
...
// create the audio queue
err = AudioQueueNewOutput(&asbd, MyAudioQueueOutputCallback, myData, NULL, NULL, 0, &myData->audioQueue);

GetFirstPlayableAudioFormatForFile 实现:

AudioFormatListItem GetFirstPlayableAudioFormatForFile(AudioFileStreamID inAudioFileStream)
{
    AudioFormatListItem *formatListPtr = NULL;
    AudioFormatListItem formatItem = {0};
    UInt32 propertySize;

    OSStatus status = noErr;

    if (NULL == inAudioFileStream) return formatItem;

    status = AudioFileStreamGetPropertyInfo(inAudioFileStream, kAudioFileStreamProperty_FormatList, &propertySize, NULL);
    if (noErr == status) {

        // allocate memory for the format list items
        formatListPtr = (AudioFormatListItem *)malloc(propertySize);
        if (NULL == formatListPtr) return formatItem;

        // get the list of Audio Format List Item's
        status = AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_FormatList, &propertySize, formatListPtr);
        if (noErr == status) {
            // print out some helpful information
            UInt32 numFormats = propertySize / sizeof(AudioFormatListItem);
            printf ("This file has a %d layered data format:\n", (int)numFormats);
            /*for (unsigned int i = 0; i < numFormats; ++i) {
                CAStreamBasicDescription(formatListPtr[i].mASBD).Print();
            }*/

            UInt32 itemIndex;
            UInt32 indexSize = sizeof(itemIndex);

            // get the index number of the first playable format -- this index number will be for
            // the highest quality layer the platform is capable of playing
            status = AudioFormatGetProperty(kAudioFormatProperty_FirstPlayableFormatFromList, propertySize,
                                            formatListPtr, &indexSize, &itemIndex);
            if (noErr == status) {
                printf ("Returning AudioFormatListItem at index %d.\n", (int)itemIndex);
                // copy the format item at index we want returned
                formatItem =  formatListPtr[itemIndex];
            }
        }

        free(formatListPtr);
    } else {
        AudioStreamBasicDescription asbd;
        UInt32 asbdSize = sizeof(asbd);
        /*status = */AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_DataFormat, &asbdSize, &asbd);
        //if (err) { errorDidOccur(myData, err, @"get kAudioFileStreamProperty_DataFormat"); return err; }

        formatItem.mASBD = asbd;
    }


    return formatItem;
}

I haven't looked at this code in a while, but I think it should do the trick.

// the file stream parser is now ready to produce audio packets.
// get the stream format.
AudioFormatListItem afli = GetFirstPlayableAudioFormatForFile(inAudioFileStream);
AudioStreamBasicDescription asbd = afli.mASBD;
...
// create the audio queue
err = AudioQueueNewOutput(&asbd, MyAudioQueueOutputCallback, myData, NULL, NULL, 0, &myData->audioQueue);

GetFirstPlayableAudioFormatForFile impl:

AudioFormatListItem GetFirstPlayableAudioFormatForFile(AudioFileStreamID inAudioFileStream)
{
    AudioFormatListItem *formatListPtr = NULL;
    AudioFormatListItem formatItem = {0};
    UInt32 propertySize;

    OSStatus status = noErr;

    if (NULL == inAudioFileStream) return formatItem;

    status = AudioFileStreamGetPropertyInfo(inAudioFileStream, kAudioFileStreamProperty_FormatList, &propertySize, NULL);
    if (noErr == status) {

        // allocate memory for the format list items
        formatListPtr = (AudioFormatListItem *)malloc(propertySize);
        if (NULL == formatListPtr) return formatItem;

        // get the list of Audio Format List Item's
        status = AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_FormatList, &propertySize, formatListPtr);
        if (noErr == status) {
            // print out some helpful information
            UInt32 numFormats = propertySize / sizeof(AudioFormatListItem);
            printf ("This file has a %d layered data format:\n", (int)numFormats);
            /*for (unsigned int i = 0; i < numFormats; ++i) {
                CAStreamBasicDescription(formatListPtr[i].mASBD).Print();
            }*/

            UInt32 itemIndex;
            UInt32 indexSize = sizeof(itemIndex);

            // get the index number of the first playable format -- this index number will be for
            // the highest quality layer the platform is capable of playing
            status = AudioFormatGetProperty(kAudioFormatProperty_FirstPlayableFormatFromList, propertySize,
                                            formatListPtr, &indexSize, &itemIndex);
            if (noErr == status) {
                printf ("Returning AudioFormatListItem at index %d.\n", (int)itemIndex);
                // copy the format item at index we want returned
                formatItem =  formatListPtr[itemIndex];
            }
        }

        free(formatListPtr);
    } else {
        AudioStreamBasicDescription asbd;
        UInt32 asbdSize = sizeof(asbd);
        /*status = */AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_DataFormat, &asbdSize, &asbd);
        //if (err) { errorDidOccur(myData, err, @"get kAudioFileStreamProperty_DataFormat"); return err; }

        formatItem.mASBD = asbd;
    }


    return formatItem;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文