FSAudioStream.h 16.9 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
/*
 * This file is part of the FreeStreamer project,
 * (C)Copyright 2011-2018 Matias Muhonen <mmu@iki.fi> 穆马帝
 * See the file ''LICENSE'' for using the code.
 *
 * https://github.com/muhku/FreeStreamer
 */

#import <Foundation/Foundation.h>
#import <CoreAudio/CoreAudioTypes.h>

/**
 * The major version of the current release.
 */
#define FREESTREAMER_VERSION_MAJOR          4

/**
 * The minor version of the current release.
 */
#define FREESTREAMER_VERSION_MINOR          0

/**
 * The reversion of the current release
 */
#define FREESTREAMER_VERSION_REVISION       0

/**
 * Follow this notification for the audio stream state changes.
 */
extern NSString* const FSAudioStreamStateChangeNotification;
extern NSString* const FSAudioStreamNotificationKey_State;

/**
 * Follow this notification for the audio stream errors.
 */
extern NSString* const FSAudioStreamErrorNotification;
extern NSString* const FSAudioStreamNotificationKey_Error;

/**
 * Follow this notification for the audio stream metadata.
 */
extern NSString* const FSAudioStreamMetaDataNotification;
extern NSString* const FSAudioStreamNotificationKey_MetaData;

/**
 * The audio stream state.
 */
typedef NS_ENUM(NSInteger, FSAudioStreamState) {
    /**
     * Retrieving URL.
     */
    kFsAudioStreamRetrievingURL,
    /**
     * Stopped.
     */
    kFsAudioStreamStopped,
    /**
     * Buffering.
     */
    kFsAudioStreamBuffering,
    /**
     * Playing.
     */
    kFsAudioStreamPlaying,
    /**
     * Paused.
     */
    kFsAudioStreamPaused,
    /**
     * Seeking.
     */
    kFsAudioStreamSeeking,
    /**
     * The stream has received all the data for a file.
     */
    kFSAudioStreamEndOfFile,
    /**
     * Failed.
     */
    kFsAudioStreamFailed,
    /**
     * Started retrying.
     */
    kFsAudioStreamRetryingStarted,
    /**
     * Retrying succeeded.
     */
    kFsAudioStreamRetryingSucceeded,
    /**
     * Retrying failed.
     */
    kFsAudioStreamRetryingFailed,
    /**
     * Playback completed.
     */
    kFsAudioStreamPlaybackCompleted,
    /**
     * Unknown state.
     */
    kFsAudioStreamUnknownState
};

/**
 * The audio stream errors.
 */
typedef NS_ENUM(NSInteger, FSAudioStreamError) {
    /**
     * No error.
     */
    kFsAudioStreamErrorNone = 0,
    /**
     * Error opening the stream.
     */
    kFsAudioStreamErrorOpen = 1,
    /**
     * Error parsing the stream.
     */
    kFsAudioStreamErrorStreamParse = 2,
    /**
     * Network error.
     */
    kFsAudioStreamErrorNetwork = 3,
    /**
     * Unsupported format.
     */
    kFsAudioStreamErrorUnsupportedFormat = 4,
    /**
     * Stream buffered too often.
     */
    kFsAudioStreamErrorStreamBouncing = 5,
    /**
     * Stream playback was terminated by the operating system.
     */
    kFsAudioStreamErrorTerminated = 6
};

@protocol FSPCMAudioStreamDelegate;
@class FSAudioStreamPrivate;

/**
 * The audio stream playback position.
 */
typedef struct {
    unsigned minute;
    unsigned second;
    
    /**
     * Playback time in seconds.
     */
    float playbackTimeInSeconds;
    
    /**
     * Position within the stream, where 0 is the beginning
     * and 1.0 is the end.
     */
    float position;
} FSStreamPosition;

/**
 * The audio stream seek byte offset.
 */
typedef struct {
    UInt64 start;
    UInt64 end;
    /**
     * Position within the stream, where 0 is the beginning
     * and 1.0 is the end.
     */
    float position;
} FSSeekByteOffset;

/**
 * Audio levels.
 */
typedef struct {
    Float32 averagePower;
    Float32 peakPower;
} FSLevelMeterState;

/**
 * The low-level stream configuration.
 */
@interface FSStreamConfiguration : NSObject {
}

/**
 * The number of buffers.
 */
@property (nonatomic,assign) unsigned bufferCount;
/**
 * The size of each buffer.
 */
@property (nonatomic,assign) unsigned bufferSize;
/**
 * The number of packet descriptions.
 */
@property (nonatomic,assign) unsigned maxPacketDescs;
/**
 * The HTTP connection buffer size.
 */
@property (nonatomic,assign) unsigned httpConnectionBufferSize;
/**
 * The output sample rate.
 */
@property (nonatomic,assign) double   outputSampleRate;
/**
 * The number of output channels.
 */
@property (nonatomic,assign) long     outputNumChannels;
/**
 * The interval within the stream may enter to the buffering state before it fails.
 */
@property (nonatomic,assign) int      bounceInterval;
/**
 * The number of times the stream may enter the buffering state before it fails.
 */
@property (nonatomic,assign) int      maxBounceCount;
/**
 * The stream must start within this seconds before it fails.
 */
@property (nonatomic,assign) int      startupWatchdogPeriod;
/**
 * Allow buffering of this many bytes before the cache is full.
 */
@property (nonatomic,assign) int      maxPrebufferedByteCount;
/**
 * Calculate prebuffer sizes dynamically using the stream bitrate in seconds instead of bytes.
 */
@property (nonatomic,assign) BOOL     usePrebufferSizeCalculationInSeconds;
/**
 * Calculate prebuffer sizes using the packet counts.
 */
@property (nonatomic,assign) BOOL     usePrebufferSizeCalculationInPackets;
/**
 * Require buffering of this many bytes before the playback can start for a continuous stream.
 */
@property (nonatomic,assign) float      requiredPrebufferSizeInSeconds;
/**
 * Require buffering of this many bytes before the playback can start for a continuous stream.
 */
@property (nonatomic,assign) int      requiredInitialPrebufferedByteCountForContinuousStream;
/**
 * Require buffering of this many bytes before the playback can start a non-continuous stream.
 */
@property (nonatomic,assign) int      requiredInitialPrebufferedByteCountForNonContinuousStream;
/**
 * Require buffering of this many packets before the playback can start.
 */
@property (nonatomic,assign) int      requiredInitialPrebufferedPacketCount;
/**
 * The HTTP user agent used for stream operations.
 */
@property (nonatomic,strong) NSString *userAgent;
/**
 * The directory used for caching the streamed files.
 */
@property (nonatomic,strong) NSString *cacheDirectory;
/**
 * The HTTP headers that are appended to the request when the streaming starts. Notice
 * that the headers override any headers previously set by FreeStreamer.
 */
@property (nonatomic,strong) NSDictionary *predefinedHttpHeaderValues;
/**
 * The property determining if caching the streams to the disk is enabled.
 */
@property (nonatomic,assign) BOOL cacheEnabled;
/**
 * The property determining if seeking from the audio packets stored in cache is enabled.
 * The benefit is that seeking is faster in the case the audio packets are already cached in memory.
 */
@property (nonatomic,assign) BOOL seekingFromCacheEnabled;
/**
 * The property determining if FreeStreamer should handle audio session automatically.
 * Leave it on if you don't want to handle the audio session by yourself.
 */
@property (nonatomic,assign) BOOL automaticAudioSessionHandlingEnabled;
/**
 * The property enables time and pitch conversion for the audio queue. Put it on
 * if you want to use the play rate setting.
 */
@property (nonatomic,assign) BOOL enableTimeAndPitchConversion;
/**
 * Requires the content type given by the server to match an audio content type.
 */
@property (nonatomic,assign) BOOL requireStrictContentTypeChecking;
/**
 * The maximum size of the disk cache in bytes.
 */
@property (nonatomic,assign) int maxDiskCacheSize;

@end

/**
 * Statistics on the stream state.
 */
@interface FSStreamStatistics : NSObject {
}

/**
 * Time when the statistics were gathered.
 */
@property (nonatomic,strong) NSDate *snapshotTime;
/**
 * Time in a pretty format.
 */
@property (nonatomic,readonly) NSString *snapshotTimeFormatted;
/**
 * Audio stream packet count.
 */
@property (nonatomic,assign) NSUInteger audioStreamPacketCount;
/**
 * Audio queue used buffers count.
 */
@property (nonatomic,assign) NSUInteger audioQueueUsedBufferCount;
/**
 * Audio stream PCM packet queue count.
 */
@property (nonatomic,assign) NSUInteger audioQueuePCMPacketQueueCount;

@end

NSString*             freeStreamerReleaseVersion(void);

/**
 * FSAudioStream is a class for streaming audio files from an URL.
 * It must be directly fed with an URL, which contains audio. That is,
 * playlists or other non-audio formats yield an error.
 *
 * To start playback, the stream must be either initialized with an URL
 * or the playback URL can be set with the url property. The playback
 * is started with the play method. It is possible to pause or stop
 * the stream with the respective methods.
 *
 * Non-continuous streams (audio streams with a known duration) can be
 * seeked with the seekToPosition method.
 *
 * Note that FSAudioStream is not designed to be thread-safe! That means
 * that using the streamer from multiple threads without syncronization
 * could cause problems. It is recommended to keep the streamer in the
 * main thread and call the streamer methods only from the main thread
 * (consider using performSelectorOnMainThread: if calls from multiple
 * threads are needed).
 */
@interface FSAudioStream : NSObject {
    FSAudioStreamPrivate *_private;
}

/**
 * Initializes the audio stream with an URL.
 *
 * @param url The URL from which the stream data is retrieved.
 */
- (id)initWithUrl:(NSURL *)url;

/**
 * Initializes the stream with a configuration.
 *
 * @param configuration The stream configuration.
 */
- (id)initWithConfiguration:(FSStreamConfiguration *)configuration;

/**
 * Starts preload the stream. If no preload URL is
 * defined, an error will occur.
 */
- (void)preload;

/**
 * Starts playing the stream. If no playback URL is
 * defined, an error will occur.
 */
- (void)play;

/**
 * Starts playing the stream from the given URL.
 *
 * @param url The URL from which the stream data is retrieved.
 */
- (void)playFromURL:(NSURL*)url;

/**
 * Starts playing the stream from the given offset.
 * The offset can be retrieved from the stream with the
 * currentSeekByteOffset property.
 *
 * @param offset The offset where to start playback from.
 */
- (void)playFromOffset:(FSSeekByteOffset)offset;

/**
 * Stops the stream playback.
 */
- (void)stop;

/**
 * If the stream is playing, the stream playback is paused upon calling pause.
 * Otherwise (the stream is paused), calling pause will continue the playback.
 */
- (void)pause;

/**
 * Rewinds the stream. Only possible for continuous streams.
 *
 * @param seconds Seconds to rewind the stream.
 */
- (void)rewind:(unsigned)seconds;

/**
 * Seeks the stream to a given position. Requires a non-continuous stream
 * (a stream with a known duration).
 *
 * @param position The stream position to seek to.
 */
- (void)seekToPosition:(FSStreamPosition)position;

/**
 * Sets the audio stream playback rate from 0.5 to 2.0.
 * Value 1.0 means the normal playback rate. Values below
 * 1.0 means a slower playback rate than usual and above
 * 1.0 a faster playback rate. Notice that using a faster
 * playback rate than 1.0 may mean that you have to increase
 * the buffer sizes for the stream still to play.
 *
 * The play rate has only effect if the stream is playing.
 *
 * @param playRate The playback rate.
 */
- (void)setPlayRate:(float)playRate;

/**
 * Returns the playback status: YES if the stream is playing, NO otherwise.
 */
- (BOOL)isPlaying;

/**
 * Cleans all cached data from the persistent storage.
 */
- (void)expungeCache;

/**
 * The stream URL.
 */
@property (nonatomic,assign) NSURL *url;
/**
 * Determines if strict content type checking  is required. If the audio stream
 * cannot determine that the stream is actually an audio stream, the stream
 * does not play. Disabling strict content type checking bypasses the
 * stream content type checks and tries to play the stream regardless
 * of the content type information given by the server.
 */
@property (nonatomic,assign) BOOL strictContentTypeChecking;
/**
 * Set an output file to store the stream contents to a file.
 */
@property (nonatomic,assign) NSURL *outputFile;
/**
 * Sets a default content type for the stream. Used if
 * the stream content type is not available.
 */
@property (nonatomic,assign) NSString *defaultContentType;
/**
 * The property has the content type of the stream, for instance audio/mpeg.
 */
@property (nonatomic,readonly) NSString *contentType;
/**
 * The property has the suggested file extension for the stream based on the stream content type.
 */
@property (nonatomic,readonly) NSString *suggestedFileExtension;
/**
 * Sets a default content length for the stream.  Used if
 * the stream content-length is not available.
 */
@property (nonatomic, assign) UInt64 defaultContentLength;
/**
 * The property has the content length of the stream (in bytes). The length is zero if
 * the stream is continuous.
 */
@property (nonatomic,readonly) UInt64 contentLength;
/**
 * The number of bytes of audio data. Notice that this may differ
 * from the number of bytes the server returns for the content length!
 * For instance audio file meta data is excluded from the count.
 * Effectively you can use this property for seeking calculations.
 */
@property (nonatomic,readonly) UInt64 audioDataByteCount;
/**
 * This property has the current playback position, if the stream is non-continuous.
 * The current playback position cannot be determined for continuous streams.
 */
@property (nonatomic,readonly) FSStreamPosition currentTimePlayed;
/**
 * This property has the duration of the stream, if the stream is non-continuous.
 * Continuous streams do not have a duration.
 */
@property (nonatomic,readonly) FSStreamPosition duration;
/**
 * This property has the current seek byte offset of the stream, if the stream is non-continuous.
 * Continuous streams do not have a seek byte offset.
 */
@property (nonatomic,readonly) FSSeekByteOffset currentSeekByteOffset;
/**
 * This property has the bit rate of the stream. The bit rate is initially 0,
 * before the stream has processed enough packets to calculate the bit rate.
 */
@property (nonatomic,readonly) float bitRate;
/**
 * The property is true if the stream is continuous (no known duration).
 */
@property (nonatomic,readonly) BOOL continuous;
/**
 * The property is true if the stream has been cached locally.
 */
@property (nonatomic,readonly) BOOL cached;
/**
 * This property has the number of bytes buffered for this stream.
 */
@property (nonatomic,readonly) size_t prebufferedByteCount;
/**
 * This property holds the current playback volume of the stream,
 * from 0.0 to 1.0.
 *
 * Note that the overall volume is still constrained by the volume
 * set by the user! So the actual volume cannot be higher
 * than the volume currently set by the user. For example, if
 * requesting a volume of 0.5, then the volume will be 50%
 * lower than the current playback volume set by the user.
 */
@property (nonatomic,assign) float volume;
/**
 * The current size of the disk cache.
 */
@property (nonatomic,readonly) unsigned long long totalCachedObjectsSize;
/**
 * The property determines the amount of times the stream has tried to retry the playback
 * in case of failure.
 */
@property (nonatomic,readonly) NSUInteger retryCount;
/**
 * Holds the maximum amount of playback retries that will be 
 * performed before entering kFsAudioStreamRetryingFailed state.
 * Default is 3.
 */
@property (nonatomic,assign) NSUInteger maxRetryCount;
/**
 * The property determines the current audio levels.
 */
@property (nonatomic,readonly) FSLevelMeterState levels;
/**
 * This property holds the current statistics for the stream state.
 */
@property (nonatomic,readonly) FSStreamStatistics *statistics;
/**
 * Called upon completion of the stream. Note that for continuous
 * streams this is never called.
 */
@property (copy) void (^onCompletion)(void);
/**
 * Called upon a state change.
 */
@property (copy) void (^onStateChange)(FSAudioStreamState state);
/**
 * Called upon a meta data is available.
 */
@property (copy) void (^onMetaDataAvailable)(NSDictionary *metadata);
/**
 * Called upon a failure.
 */
@property (copy) void (^onFailure)(FSAudioStreamError error, NSString *errorDescription);
/**
 * The property has the low-level stream configuration.
 */
@property (readonly) FSStreamConfiguration *configuration;
/**
 * Delegate.
 */
@property (nonatomic,unsafe_unretained) IBOutlet id<FSPCMAudioStreamDelegate> delegate;

@end

/**
 * To access the PCM audio data, use this delegate.
 */
@protocol FSPCMAudioStreamDelegate <NSObject>

@optional
/**
 * Called when there are PCM audio samples available. Do not do any blocking operations
 * when you receive the data. Instead, copy the data and process it so that the
 * main event loop doesn't block. Failing to do so may cause glitches to the audio playback.
 *
 * Notice that the delegate callback may occur from other than the main thread so make
 * sure your delegate code is thread safe.
 *
 * @param audioStream The audio stream the samples are from.
 * @param samples The samples as a buffer list.
 * @param frames The number of frames.
 * @param description Description of the data provided.
 */
- (void)audioStream:(FSAudioStream *)audioStream samplesAvailable:(AudioBufferList *)samples frames:(UInt32)frames description: (AudioStreamPacketDescription)description;
@end