Skip to content

Commit

Permalink
When AudioShare is not installed, fall back to general pasteboard
Browse files Browse the repository at this point in the history
  • Loading branch information
lijon committed Jan 7, 2016
1 parent ff4e9fc commit 8bae81e
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 15 deletions.
3 changes: 3 additions & 0 deletions AudioShareSDK.h
Expand Up @@ -19,4 +19,7 @@ typedef void(^AudioShareImportBlock)(NSString *path);
- (BOOL) initiateSoundImport;
- (BOOL) checkPendingImport:(NSURL*)url withBlock:(AudioShareImportBlock)block;

// Convenience utility that returns filename extension for path if it's an audio or midi file
+ (NSString*)findFileType:(NSString*)path;

@end
97 changes: 82 additions & 15 deletions AudioShareSDK.m
Expand Up @@ -3,6 +3,7 @@

#import "AudioShareSDK.h"
#import <MobileCoreServices/UTCoreTypes.h>
#import <AudioToolbox/AudioToolbox.h>

#define BM_CLIPBOARD_CHUNK_SIZE (5 * 1024 * 1024)

Expand Down Expand Up @@ -32,18 +33,6 @@ - (NSString*)escapeString:(NSString*)string {
}

- (BOOL)addSoundFromData:(NSData*)data withName:(NSString*)name {
name = [self escapeString:name];
NSURL *asURL = [NSURL URLWithString:[NSString stringWithFormat:@"audiosharecmd://addFromPaste?%@",name]];
if(![[UIApplication sharedApplication] canOpenURL:asURL]) {
UIAlertView *a = [[UIAlertView alloc] initWithTitle:@"AudioShare"
message:@"AudioShare - audio document manager, version 2.1 or later is not installed on this device. You can get it on the App Store."
delegate:self
cancelButtonTitle:@"Cancel"
otherButtonTitles:@"Continue", nil];
[a show];

return NO;
}
UIPasteboard *board = [UIPasteboard generalPasteboard];
if (!data) {
UIAlertView *a = [[UIAlertView alloc] initWithTitle:@"Sorry"
Expand All @@ -67,6 +56,18 @@ - (BOOL)addSoundFromData:(NSData*)data withName:(NSString*)name {
[items addObject:dict];
}
board.items = items;

name = [self escapeString:name];
NSURL *asURL = [NSURL URLWithString:[NSString stringWithFormat:@"audiosharecmd://addFromPaste?%@",name]];
if(![[UIApplication sharedApplication] canOpenURL:asURL]) {
UIAlertView *a = [[UIAlertView alloc] initWithTitle:@"AudioShare"
message:@"Audio was copied to pasteboard and can now be pasted in other apps.\n\nInstall AudioShare for easy storage and management of all your soundfiles, and more copy/paste functionality. You can get it on the App Store."
delegate:self
cancelButtonTitle:@"Cancel"
otherButtonTitles:@"Continue", nil];
[a show];
return NO;
}
return [[UIApplication sharedApplication] openURL:asURL];
}

Expand Down Expand Up @@ -124,14 +125,22 @@ - (BOOL)initiateSoundImport {
}
NSURL *asURL = [NSURL URLWithString:[NSString stringWithFormat:@"audioshare.import://%@",callback]];
if(![[UIApplication sharedApplication] canOpenURL:asURL]) {
UIPasteboard *board = [UIPasteboard generalPasteboard];
NSArray *typeArray = @[(NSString *) kUTTypeAudio];
NSIndexSet *set = [board itemSetWithPasteboardTypes:typeArray];
BOOL hasAudio = [board containsPasteboardTypes:typeArray inItemSet:set];

UIAlertView *a = [[UIAlertView alloc] initWithTitle:@"AudioShare"
message:@"AudioShare - audio document manager, version 2.5 or later is not installed on this device. You can get it on the App Store."
message:[hasAudio?@"Audio was pasted from pasteboard.":@"No audio in pasteboard." stringByAppendingString:@"\n\nInstall AudioShare for easy storage and management of all your soundfiles, and more copy/paste functionality. You can get it on the App Store."]
delegate:self
cancelButtonTitle:@"Cancel"
otherButtonTitles:@"Continue", nil];
[a show];

return NO;

if(hasAudio)
asURL = [NSURL URLWithString:[callback stringByAppendingString:@"://PastedAudio"]];
else
return NO;
}

return [[UIApplication sharedApplication] openURL:asURL];
Expand All @@ -149,6 +158,7 @@ - (NSString*)writeSoundImport:(NSString*)filename {
if (!cnt)
return nil;
NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:filename];
[[NSFileManager defaultManager] removeItemAtPath:path error:nil];
if (![[NSFileManager defaultManager] createFileAtPath:path contents:nil attributes:nil])
return nil;
NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:path];
Expand All @@ -157,6 +167,16 @@ - (NSString*)writeSoundImport:(NSString*)filename {
for (NSUInteger i = 0; i < cnt; i++)
[handle writeData:[items objectAtIndex:i]];
[handle closeFile];

if(![[filename pathExtension] length]) {
NSString *ext = [AudioShare findFileType:path];
if(ext) {
NSString *newPath = [path stringByAppendingPathExtension:ext];
if([[NSFileManager defaultManager] moveItemAtPath:path toPath:newPath error:nil])
path = newPath;
}
}

return path;
}
return nil;
Expand Down Expand Up @@ -202,4 +222,51 @@ + (void)appDidLaunch {
}
}

+ (BOOL)fileIsMIDI:(NSString*)path {
const char *cpath = [path fileSystemRepresentation];
FILE *fp = fopen(cpath,"r");
if(fp) {
char buf[5];
fread(buf,1,4,fp);
fclose(fp);
buf[4]='\0';
if(strcmp(buf, "MThd")==0)
return YES;
}
return NO;
}

+ (NSString*)findFileType:(NSString*)path {
if([self fileIsMIDI:path])
return @"mid";
NSURL *audioFileURL = [NSURL fileURLWithPath:path];
AudioFileID af = NULL;
AudioFileOpenURL((__bridge CFURLRef)audioFileURL, kAudioFileReadPermission, 0, &af);
if(!af) return nil;
AudioFileTypeID typeID;
UInt32 size = sizeof(typeID);
AudioFileGetProperty(af, kAudioFilePropertyFileFormat, &size, &typeID);
AudioFileClose(af);
switch(typeID) {
case kAudioFileAIFFType: return @"aiff";
case kAudioFileAIFCType: return @"aifc";
case kAudioFileWAVEType: return @"wav";
case kAudioFileSoundDesigner2Type: return @"sd2";
case kAudioFileNextType: return @"nxt";
case kAudioFileMP3Type: return @"mp3";
case kAudioFileMP2Type: return @"mp2";
case kAudioFileMP1Type: return @"mp1";
case kAudioFileAC3Type: return @"ac3";
case kAudioFileAAC_ADTSType: return @"adts";
case kAudioFileMPEG4Type: return @"mp4";
case kAudioFileM4AType: return @"m4a";
case kAudioFileCAFType: return @"caf";
case kAudioFile3GPType: return @"3gp";
case kAudioFile3GP2Type: return @"3gp2";
case kAudioFileAMRType: return @"amr";
default:
return nil;
}
}

@end
4 changes: 4 additions & 0 deletions README.md
Expand Up @@ -59,6 +59,8 @@ These methods will check that a recent enough version of AudioShare is installed
present the user with the option to view the app on the App Store. If AudioShare was installed,
it will open AudioShare and import the audio, and return YES if successfull.

If AudioShare was not installed, it will just copy the audio to the general pasteboard.

Import from AudioShare
----------------------
Since AudioShare version 2.5, you can also easily import sound from AudioShare into your own app.
Expand Down Expand Up @@ -88,6 +90,8 @@ Since AudioShare version 2.5, you can also easily import sound from AudioShare i

This will launch AudioShare (if version 2.5 or later is installed), which will display an "Import into app: YourAppName" button. When the user taps this button in AudioShare, it will launch your application where the call to `checkPendingImport:withBlock:` will grab the imported soundfile.

If AudioShare was not installed, it will just paste audio from the general pasteboard, and then call your callback URL. The pasted audio will thus be handled in your `checkPendingImport` as usual. The filename will be "PastedAudio" with suitable path extension added depending on the file type.

Multithreading
--------------
The addSoundFrom* and initiateSoundImport methods should always be called from the main thread. If you need to call it from another thread, you must wrap the call in a block dispatched on the main thread. Example:
Expand Down

0 comments on commit 8bae81e

Please sign in to comment.