QuickLook Generator Audio

572 views Asked by At

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

There are 2 answers

3
user3559460 On

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
coderSeb On

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;