cordova-plugin-nativeaudio icon indicating copy to clipboard operation
cordova-plugin-nativeaudio copied to clipboard

Feature: Support cordova file system urls

Open wootwoot1234 opened this issue 11 years ago • 17 comments

Cordova has cleaned up it's file api and now makes it really easy to create/edit/move files. The problem is, I can't pass a 'file://' url to this plugin only relative paths. Would it be possible to add support for absolute paths or for 'file://" urls?

https://github.com/apache/cordova-plugin-file/blob/master/doc/index.md

Thanks

wootwoot1234 avatar Oct 07 '14 14:10 wootwoot1234

:+1: please

fidoboy avatar Nov 26 '14 05:11 fidoboy

@wootwoot1234 @fidoboy Have either of you found a solution or workaround to this?

Thanks.

gylippus avatar Dec 15 '14 12:12 gylippus

no :(

fidoboy avatar Dec 15 '14 12:12 fidoboy

@fidoboy turns out I may be onto something.

In the LowLatencyAudio.m file around line 52 is where it is looking for the file.

I have modified this based on some code I found at https://github.com/floatinghotpot/cordova-plugin-lowlatencyaudio/blob/master/src/ios/LowLatencyAudio.m and from the CDVFile.m file for finding files.

Basically I am checking for the file in two different places so that I can use local files in the www and ones that I have downloaded and am passing the full CDV File path (cordova.file.dataDirectory + ). This is for iOS only, but I presume there will be something similar for Android if it is needed there too.

NSNumber* existingReference = [audioMapping objectForKey: audioID];
        if (existingReference == nil)
        {
            NSString* basePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"www"];
            NSString* path = [NSString stringWithFormat:@"%@", assetPath];
            NSString* pathFromWWW = [NSString stringWithFormat:@"%@/%@", basePath, assetPath];

            NSURL *fileURL = [NSURL URLWithString:path];
            NSURL *resolvedFileURL = [fileURL URLByResolvingSymlinksInPath];
            path = [resolvedFileURL path];
            if ([[NSFileManager defaultManager] fileExistsAtPath : path])
            {
                NSLog(@"could find file at path: %@", path);
                LowLatencyAudioAsset* asset = [[LowLatencyAudioAsset alloc] initWithPath:path withVoices:voices];
                [audioMapping setObject:asset  forKey: audioID];

                pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString: CONTENT_LOAD_REQUESTED];
                [self.commandDelegate sendPluginResult:pluginResult callbackId:callbackID];
            }
            else if ([[NSFileManager defaultManager] fileExistsAtPath : pathFromWWW]) {
                NSLog(@"could find file at pathFromWWW: %@", pathFromWWW);
                LowLatencyAudioAsset* asset = [[LowLatencyAudioAsset alloc] initWithPath:pathFromWWW withVoices:voices];
                [audioMapping setObject:asset  forKey: audioID];

                pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString: CONTENT_LOAD_REQUESTED];
                [self.commandDelegate sendPluginResult:pluginResult callbackId:callbackID];
            }
            else
            {
                NSLog(@"could not file: %@", path);
                pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString: ERROR_NOT_FOUND];        
                [self.commandDelegate sendPluginResult:pluginResult callbackId:callbackID];
            }
        }
        else 
        {
            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString: WARN_EXISTING_REFERENCE];        
            [self.commandDelegate sendPluginResult:pluginResult callbackId:callbackID];
        }

gylippus avatar Dec 15 '14 14:12 gylippus

@fidoboy I just realized that I was using an even older version of this plugin so I believe it would actually be more like this for this project

            NSString* basePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"www"];
            NSString* path = [NSString stringWithFormat:@"%@", assetPath];
            NSString* pathFromWWW = [NSString stringWithFormat:@"%@/%@", basePath, assetPath];

            NSURL *fileURL = [NSURL URLWithString:path];
            NSURL *resolvedFileURL = [fileURL URLByResolvingSymlinksInPath];
            path = [resolvedFileURL path];

            if ([[NSFileManager defaultManager] fileExistsAtPath : path]) {
                NSLog(@"could find file at path: %@", path);
                LowLatencyAudioAsset* asset = [[LowLatencyAudioAsset alloc] initWithPath:path withVoices:voices withVolume:volume];
                [audioMapping setObject:asset  forKey: audioID];

                [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString: CONTENT_LOAD_REQUESTED] callbackId:callbackId];
            } else if ([[NSFileManager defaultManager] fileExistsAtPath : pathFromWWW]) {
                NSLog(@"could find file at pathFromWWW: %@", pathFromWWW);
                LowLatencyAudioAsset* asset = [[LowLatencyAudioAsset alloc] initWithPath:pathFromWWW withVoices:voices withVolume:volume];
                [audioMapping setObject:asset  forKey: audioID];

                [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString: CONTENT_LOAD_REQUESTED] callbackId:callbackId];
            } else {
                NSLog( @"audio file not found" );
                [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString: ERROR_NOT_FOUND] callbackId:callbackId];
            }

gylippus avatar Dec 15 '14 14:12 gylippus

Thanks gylippus your code is very useful, but it could be pretty cool to have the same on android.

fidoboy avatar Jan 15 '15 08:01 fidoboy

Hi @gylippus can you provide a working fork for this issue? I'm trying to integrate your posted code but struggling with errors like error: use of undeclared identifier 'voices' which is definitely a really simple case but I'm not Cocoa Dev so I just need to get it running :) Thx a lot if possible.

ddresch avatar Mar 13 '15 16:03 ddresch

@gylippus helps sometimes to ask and the answers follow by them self. Got it at least compiling now so no need to answer. Thanks!

ddresch avatar Mar 13 '15 16:03 ddresch

@ddresch glad to help :)

-Rubber Duck

gylippus avatar Mar 13 '15 16:03 gylippus

Are there any updates on this feature? I'm looking to play multiple audio tracks downloaded and saved in the app's Documents dir.

RShergold avatar Jul 28 '15 11:07 RShergold

Anyone implemented the fix for Android? I wish "file://" instead of appending "www/" to path was the implementation here

michaelkariv avatar Sep 10 '15 07:09 michaelkariv

Honestly, cordovas media plugin has a great function for both android and ios.

IOS for example:

// Maps a url for a resource path for playing
// "Naked" resource paths are assumed to be from the www folder as its base
- (NSURL*)urlForPlaying:(NSString*)resourcePath
{
    NSURL* resourceURL = nil;
    NSString* filePath = nil;

    // first try to find HTTP:// or Documents:// resources

    if ([resourcePath hasPrefix:HTTP_SCHEME_PREFIX] || [resourcePath hasPrefix:HTTPS_SCHEME_PREFIX]) {
        // if it is a http url, use it
        NSLog(@"Will use resource '%@' from the Internet.", resourcePath);
        resourceURL = [NSURL URLWithString:resourcePath];
    } else if ([resourcePath hasPrefix:DOCUMENTS_SCHEME_PREFIX]) {
        NSString* docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
        filePath = [resourcePath stringByReplacingOccurrencesOfString:DOCUMENTS_SCHEME_PREFIX withString:[NSString stringWithFormat:@"%@/", docsPath]];
        NSLog(@"Will use resource '%@' from the documents folder with path = %@", resourcePath, filePath);
    } else if ([resourcePath hasPrefix:CDVFILE_PREFIX]) {
        CDVFile *filePlugin = [self.commandDelegate getCommandInstance:@"File"];
        CDVFilesystemURL *url = [CDVFilesystemURL fileSystemURLWithString:resourcePath];
        filePath = [filePlugin filesystemPathForURL:url];
        if (filePath == nil) {
            resourceURL = [NSURL URLWithString:resourcePath];
        }
    } else {
        // attempt to find file path in www directory or LocalFileSystem.TEMPORARY directory
        filePath = [self.commandDelegate pathForResource:resourcePath];
        if (filePath == nil) {
            // see if this exists in the documents/temp directory from a previous recording
            NSString* testPath = [NSString stringWithFormat:@"%@/%@", [NSTemporaryDirectory()stringByStandardizingPath], resourcePath];
            if ([[NSFileManager defaultManager] fileExistsAtPath:testPath]) {
                // inefficient as existence will be checked again below but only way to determine if file exists from previous recording
                filePath = testPath;
                NSLog(@"Will attempt to use file resource from LocalFileSystem.TEMPORARY directory");
            } else {
                // attempt to use path provided
                filePath = resourcePath;
                NSLog(@"Will attempt to use file resource '%@'", filePath);
            }
        } else {
            NSLog(@"Found resource '%@' in the web folder.", filePath);
        }
    }
    // if the resourcePath resolved to a file path, check that file exists
    if (filePath != nil) {
        // create resourceURL
        resourceURL = [NSURL fileURLWithPath:filePath];
        // try to access file
        NSFileManager* fMgr = [NSFileManager defaultManager];
        if (![fMgr fileExistsAtPath:filePath]) {
            resourceURL = nil;
            NSLog(@"Unknown resource '%@'", resourcePath);
        }
    }

    return resourceURL;
}

pmwisdom avatar Sep 11 '15 19:09 pmwisdom

I am using cordovaMedia (via its angular wrapper ngCordova) and the problem is the delay. May be it is because there is no preload, like in NativeAudio.

michaelkariv avatar Sep 13 '15 13:09 michaelkariv

I have an easy solution for this for anyone interested. Use CDV urls and then just resolve them to a full path.

export const getFile = function(path) {
    return new Ember.RSVP.Promise( (resolve) => {
        window.resolveLocalFileSystemURL(path, function(entry) {
            resolve(entry);
        });
    });
};

then you can

let path = fileEntry.toURL();
// need a root level path
path = path.replace('file://', '');

then use my fork which eliminates the hardcoded www, so you can play files from anywhere on your device.

https://github.com/optikalefx/cordova-plugin-lowlatencyaudio/commit/7aaf6ce948a697d344efe0e186aa017cf6569bc4

optikalefx avatar Nov 05 '15 03:11 optikalefx

How has this not been resolved yet? It's pretty important not being restricted to the www/ folder.

sommerper avatar Apr 01 '16 09:04 sommerper

My fork has this resolved.

optikalefx avatar Apr 01 '16 13:04 optikalefx

simply...

path = path.replace('file://', '');

-- the above worked for ios, android needed a little more

in the folder plugin/cordova-plugin-nativeaudio/src/android

edit line 85 of NativeAudio.java from String fullPath = concat("www"+assetPath); to String fullPath = assetPath;

you will then need to remove the android platform and then re-add it for the plugin to update

cordova platforms rm android cordova platforms add android

RoryPicko avatar Jul 19 '16 11:07 RoryPicko