2
votes

I'm trying to create a QuickLook plugin to play audio from within a package for that package's QuickLook preview, but my attempts only display the default QL preview - a larger file icon, file name, type, size and modification date.

I've successfully displayed a test string as kUTTPlainText with my XCode setup for the targeted UTI type, and verified that the CFDataRef passed to QLPreviewRequestSetDataRepresentation isn't NULL.

Here is the basic code I've got inside my GeneratePreviewForURL function:

NSURL *audioFilePath = @"the file path";
CFDataRef data = (__bridge CFDataRef)[NSData dataWithContentsOfURL:audioFilePath];
QLPreviewRequestSetDataRepresentation(preview, data, kUTTypeAudio, NULL);
return noErr;

Any ideas? Is playing audio from a QuickLook preview even possible?

2
I suspect you need to pass a more specific type to QLPreviewRequestSetDataRepresentation (not just kUTTypeAudio but something that identifies the audio format). Also make sure you're following the debugging steps in the programming guide so you can be sure it's not a plugin registration problem.rickster
From Apple's docs on QLPreviewRequestSetDataRepresentation: "The content data of the preview must be of a native Quick Look type. Currently supported UTIs for these types are: kUTTypeImage, kUTTypePDF, kUTTypeHTML, kUTTypeXML, kUTTypePlainText, kUTTypeRTF, kUTTypeMovie, and kUTTypeAudio."Benjineer
I've also verified my debugging setup as mentioned - can anyone verify that playing audio is possible? The docs seem to hint that it is, but provide no example.Benjineer
I've since tried displaying some HTML with an <audio> tag, still no luck - just shows a loading message indefinitely.Benjineer

2 Answers

0
votes

I'm basing this answer on my personal experience.

With Xcode 4.2 on OSX 10.6.8 it was possible to load an audio file inside a HTML-based QuickLook plugin simply using the <src> attribute of the <audio> tag:

OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options)
{
    @autoreleasepool {

        if (QLPreviewRequestIsCancelled(preview)) return noErr;

        NSMutableString *html=[[NSMutableString alloc] init];
        NSDictionary *props;

        props=@{
            (__bridge NSString *)kQLPreviewPropertyTextEncodingNameKey:@"UTF-8",
            (__bridge NSString *)kQLPreviewPropertyMIMETypeKey:@"text/html",
            };

        [html appendString:@"<html>"];
        [html appendString:@"<body>"];
        [html appendString:@"<audio src=\"/tmp/AudioFile.mp3\" type=\"audio/mpeg\" controls=\"true\" autoplay=\"true\" />"];
        [html appendString:@"</body>"];
        [html appendString:@"</html>"];

        QLPreviewRequestSetDataRepresentation(preview,(CFDataRef)[html dataUsingEncoding:NSUTF8StringEncoding],kUTTypeHTML,(CFDictionaryRef)props);
    }

    return noErr;
}

Now, with Xcode 5.1 on Mavericks, it seems that neither using the cid: scheme (I'll post an example below) does the job:

OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options)
{
    @autoreleasepool {

        if (QLPreviewRequestIsCancelled(preview)) return noErr;

        NSMutableString *html=[[NSMutableString alloc] init];
        NSDictionary *props;
        NSData *audioData=[NSData dataWithContentsOfFile:@"/tmp/AudioFile.mp3"];

        props=@{
            (__bridge NSString *)kQLPreviewPropertyTextEncodingNameKey:@"UTF-8",
            (__bridge NSString *)kQLPreviewPropertyMIMETypeKey:@"text/html",
            (__bridge NSString *)kQLPreviewPropertyAttachmentsKey:@{
                    @"AUDIO":@{
                            (__bridge NSString *)kQLPreviewPropertyMIMETypeKey:@"audio/mpeg",
                            (__bridge NSString *)kQLPreviewPropertyAttachmentDataKey: audioData,
                            },
                    },
            };

        [html appendString:@"<html>"];
        [html appendString:@"<body>"];
        [html appendString:@"<audio src=\"cid:AUDIO\" type=\"audio/mpeg\" controls=\"true\" autoplay=\"true\" />"];
        [html appendString:@"</body>"];
        [html appendString:@"</html>"];

        QLPreviewRequestSetDataRepresentation(preview,(CFDataRef)[html dataUsingEncoding:NSUTF8StringEncoding],kUTTypeHTML,(CFDictionaryRef)props);
    }

    return noErr;
}

I recon that you should report a bug to Apple for that!

0
votes

Some of the comments here refer to using audio in HTML-based Quicklook plugins (sorry, not enough reputation yet to add additional comments 🙄).

I recently had the same problem in a project I worked on where I needed to embed an audio file, but as noted by others, trying to use that data referenced as a 'CID:' object within the Quicklook plugin fails.

The solution I found was to embed the data as Base64 encoded within the HTML, like so:

<audio src="data:audio/wav;base64,{base64Data}">

with {base64Data} replaced with the actual Base64 data. Any NSData object can be converted to a Base64 string using:

[dataObject base64EncodedStringWithOptions:0]

Alternatively if you need to refer to that data more than once in your HTML code, you can create a Javascript URL object and use that instead:

let soundURL = new URL("data:audio/wav;base64,{base64Data}");
audioElement.src = soundURL;