Roundware framework, updated for API v2 and re-built in Swift and made open source. See http://roundware.org for more information on configuring the server and other components.
Roundware is a flexible, distributed framework which collects, stores, organizes and re-presents audio content. Basically, it lets you collect audio from anyone with a smartphone or web access, upload it to a central repository along with its metadata and then filter it and play it back collectively in continuous audio streams.
This project consists of the Roundware framework (RWFramework) and an example app that implements the framework. Open the Example/RWFramework.xcworkspace
Xcode workspace to examine and run the project. The file structure follows from https://github.com/CocoaPods/pod-template.
The code is written in Swift 2.0 and currently requires Xcode 7.2 or later and iOS 9 or later.
You can look throughout the code for all methods marked public
to see what is available to your application. This document outlines some of the more common use cases. Be sure to read the comments on the methods you plan to use.
RWFramework is available through CocoaPods. To install
it, simply add the following line to your Podfile
:
pod "RWFramework"
Then install.
pod install
A RWFramework.plist
is required with minimum parameters defined. See the server setup documentation for more information.
You can try the example out like so:
pod try RWFramework
In order to demo any functionality in the simulator, you will need to set the location to Debug
> Location
> Apple
.
We use fastlane to load onto our device. Edit the fastlane configuration, add a devices.txt
and install ios-deploy. Plug in your device and then run this command to load the example onto your device the first time.
fastlane load first:true
Your application is responsible for configuring the AVAudioSession
for itself. You can see an example of this in the example app in AppDelegate.swift
.
Note, however, that RWFrameworkAudioRecorder.m
was provided and added to the project to facilitate a more advanced way of recording audio that would allow VoiceOver audio to be filtered out of the recorded audio. The useComplexRecordingMechanism
global flag is used to set whether this mechanism is used. If useComplexRecordingMechanism
is set to true note that certain aspects of the AVAudioSession
will be set internally in the framework. See setupAudioSession
in RWFrameworkAudioRecorder.m
for details.
In order to start using the framework, sometime after you've setup the AVAudioSession
you should start the framework running by setting yourself as the delegate
of the sharedInstance
and then calling the start()
method.
var rwf = RWFramework.sharedInstance
rwf.addDelegate(self)
rwf.start(letFrameworkRequestWhenInUseAuthorizationForLocation: false)
Note that setting a delegate is not required but your app will be next to useless without it. You can set multiple delegates and all will be called with whatever protocol methods they implement. This allows you to have a view controller only handle the methods it cares about. Be sure to call removeDelegate(object: AnyObject)
when an object no longer wants to be the delegate (or is deleted).
When you are completely done with the framework you should call rwf.end()
to give the framework a chance to cleanup anything it needs to cleanup.
If you want to change the project_id
after initialization, you can use setProjectId
.
Anytime after receiving the rwPostStreamsSuccess()
delegate method callback you can instruct the framework to play or pause the audio stream.
var rwf = RWFramework.sharedInstance
rwf.isPlaying ? rwf.stop() : rwf.play()
Other methods regarding audio playback include:
canPlay() -> Bool
play()
pause()
stop()
skip()
See RWFrameworkAudioPlayer.swift
The framework has a number of ways to automatically handle adding assets of various types to its internal queue to be uploaded. However, if your app needs more control you can always add them manually as well.
The key methods for recording, playing back and submitting an audio recording are as follows
Recording
canRecord() -> Bool
startRecording()
stopRecording()
isRecording() -> Bool
Resetting a recording (recording again)
hasRecording() -> Bool
deleteRecording()
Adding or removing a recording from the queue to upload
addRecording(description: String = "") -> String?
setRecordingDescription(string: String, description: String)
removeRecording(string: String)
Playing back a recording
startPlayback()
stopPlayback()
isPlayingBack() -> Bool
Note that the standard AVAudioRecorderDelegate
and AVAudioPlayerDelegate
callbacks are also passed thru to the delegate via rwAudioRecorderDidFinishRecording()
and rwAudioPlayerDidFinishPlaying()
for your convenience.
See RWFrameworkAudioRecorder.swift
Simply call doImage()
You can add an image manually by calling addImage(string: String, description: String = "") -> String?
passing the path to the image as the string. The return value is a key to be used when referencing this asset.
Also see the rwImagePickerControllerDidFinishPickingMedia
delegate protocol method
See RWFrameworkCamera.swift
Simply call doMovie()
You can add a movie manually by calling addMovie(string: String, description: String = "") -> String?
passing the path to the movie. The return value is a key to be used when referencing this asset.
Also see the rwImagePickerControllerDidFinishPickingMedia
delegate protocol method
See RWFrameworkCamera.swift
Simply call doPhotoLibrary()
You can add an image or movie manually by calling addImage(string: String)
or addMovie(string: String)
passing the path to the asset
See RWFrameworkCamera.swift
Simply call addText(string: String, description: String = "") -> String?
The return value is a key to be used when referencing this asset.
See RWFrameworkText.swift
To remove an asset, you must use the key returned from the add*
method or the rwImagePickerControllerDidFinishPickingMedia
delegate protocol method.
To remove an audio recording simply call removeRecording(string: String)
.
To remove a text asset simply call removeText(string: String)
passing the string returned from addText(string: String, description: String = "") -> String?
.
If you added an image or movie asset you can call the associated remove
method to remove the item. For example, if you called addImage(string: String, description: String = "") -> String?
or addMovie(string: String, description: String = "") -> String?
with the path of the assets, simply call removeImage(string: String)
or removeMovie(string: String)
to remove them, passing the key that was returned from the add*
call.
You can see how many assets are ready for upload by calling countMedia() -> Int
.
When you are ready to submit all the queued assets simply call uploadAllMedia()
There are times when uploads may fail. Errors are reported back to your application via the delegate protocol method. There are a number of methods designed to help your application manage these failures and allow the framework to try uploading again.
resetAllRetryCounts()
can be called at application startup to reset any failed uploads to try again.
countUploadFailedMedia() -> Int
will return the number of items that have currently failed to upload.
purgeUploadFailedMedia()
will delete any media that has failed to upload at least once.
Your applicatin can get all the tags and organize them according to UIGroups. Use the methods in the framework to get and set them accordingly.
See RWFrameworkTags.swift
and RWFrameworkUIGroups.swift
Tags can be submitted by calling submitTags()
. This will update the current stream (if playing) accordingly.
Tags can and should be uploaded with media content by passing their IDs joined as a string as an argument to uploadAllMedia()
.
See RWFrameworkTags.swift
Not many methods in RWFrameworkAPI.swift
are public as most of them are used internally but a few are available for application use.
To get a list of assets for a project or session you can call apiGetAssets(dict: [String:String], success:(data: NSData?) -> Void, failure:(error: NSError) -> Void)
. Note that the dict
is a dictionary of filters documented in the API documentation for the GET Assets endpoint. It can be nil.
To get the details of a specific asset you can call apiGetAssetsId(asset_id: String, success:(data: NSData?) -> Void, failure:(error: NSError) -> Void)
.
See RWFrameworkAPI.swift
You can vote on an asset by calling the apiPostAssetsIdVotes(asset_id: String, session_id: String, vote_type: String, value: NSNumber = 0, success:(data: NSData?) -> Void, failure:(error: NSError) -> Void)
method. See the documentation for valid vote_types and value parameter specifics.
You can get the votes for an asset by calling the apiGetAssetsIdVotes(asset_id: String, success:(data: NSData?) -> Void, failure:(error: NSError) -> Void)
method.
Your application can implement the RWFrameworkProtocol
in order to be kept in tune with the workings of the framework. Review RWFrameworkProtocol.swift
for all the methods you can implement and when they are called throughout the lifecycle of the framework.
NOTE: You can have any number of delegates receive these calls simply by adding and removing them using the addDelegate(object: AnyObject)
and removeDelegate(object: AnyObject)
calls.
NOTE: All of these methods will be called on the main thread.
NOTE: The example app shows how some of them are used in the ViewController.swift
file.
See RWFrameworkProtocol.swift
RWFramework
depends on SwiftyJSON
so you will need to run:
pod install
##Authors
- Joe Zobkiw, @zobskewed
- Christopher Reed, @seereadnow
RWFramework is available under the MIT license. See the LICENSE file for more info.