58

This question seems to be asked few times over last few years but none has answer for that. I am trying to process PCM data from HLS and I have to use AVPlayer.

this post taps the local files https://chritto.wordpress.com/2013/01/07/processing-avplayers-audio-with-mtaudioprocessingtap/

and this tap work with remote files but not with .m3u8 hls files. http://venodesigns.net/2014/01/08/recording-live-audio-streams-on-ios/

I can play first two tracks in the playlist but it doesn't start the needed callbacks to get the pcm, when the file is local or remote(not stream) I can still get the pcm but it is the hls is not working and I need HLS working

here is my code

//avplayer tap try
- (void)viewDidLoad {
    [super viewDidLoad];

    NSURL*testUrl= [NSURL URLWithString:@"http://playlists.ihrhls.com/c5/1469/playlist.m3u8"];

    AVPlayerItem *item = [AVPlayerItem playerItemWithURL:testUrl];
    self.player = [AVPlayer playerWithPlayerItem:item];

    // Watch the status property - when this is good to go, we can access the
    // underlying AVAssetTrack we need.
    [item addObserver:self forKeyPath:@"status" options:0 context:nil];

}

-(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
    if(![keyPath isEqualToString:@"status"])
        return;

    AVPlayerItem *item = (AVPlayerItem *)object;
    if(item.status != AVPlayerItemStatusReadyToPlay)
        return;

    NSArray *tracks = [self.player.currentItem tracks];
    for(AVPlayerItemTrack *track in tracks) {
        if([track.assetTrack.mediaType isEqualToString:AVMediaTypeAudio]) {
            NSLog(@"GOT DAT FUCKER");
            [self beginRecordingAudioFromTrack:track.assetTrack];
            [self.player play];
        }
    }
}

- (void)beginRecordingAudioFromTrack:(AVAssetTrack *)audioTrack
{
    // Configure an MTAudioProcessingTap to handle things.
    MTAudioProcessingTapRef tap;
    MTAudioProcessingTapCallbacks callbacks;
    callbacks.version = kMTAudioProcessingTapCallbacksVersion_0;
    callbacks.clientInfo = (__bridge void *)(self);
    callbacks.init = init;
    callbacks.prepare = prepare;
    callbacks.process = process;
    callbacks.unprepare = unprepare;
    callbacks.finalize = finalize;

    OSStatus err = MTAudioProcessingTapCreate(
                                              kCFAllocatorDefault,
                                              &callbacks,
                                              kMTAudioProcessingTapCreationFlag_PostEffects,
                                              &tap
                                              );

    if(err) {
        NSLog(@"Unable to create the Audio Processing Tap %d", (int)err);
        return;
    }

    // Create an AudioMix and assign it to our currently playing "item", which
    // is just the stream itself.
    AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];
    AVMutableAudioMixInputParameters *inputParams = [AVMutableAudioMixInputParameters
                                                     audioMixInputParametersWithTrack:audioTrack];

    inputParams.audioTapProcessor = tap;
    audioMix.inputParameters = @[inputParams];
    self.player.currentItem.audioMix = audioMix;
}

void process(MTAudioProcessingTapRef tap, CMItemCount numberFrames,
             MTAudioProcessingTapFlags flags, AudioBufferList *bufferListInOut,
             CMItemCount *numberFramesOut, MTAudioProcessingTapFlags *flagsOut)
{
    OSStatus err = MTAudioProcessingTapGetSourceAudio(tap, numberFrames, bufferListInOut,
                                                      flagsOut, NULL, numberFramesOut);
    if (err) NSLog(@"Error from GetSourceAudio: %d", (int)err);

    NSLog(@"Process");

}

void init(MTAudioProcessingTapRef tap, void *clientInfo, void **tapStorageOut)
{
    NSLog(@"Initialising the Audio Tap Processor");
    *tapStorageOut = clientInfo;
}

void finalize(MTAudioProcessingTapRef tap)
{
    NSLog(@"Finalizing the Audio Tap Processor");
}

void prepare(MTAudioProcessingTapRef tap, CMItemCount maxFrames, const AudioStreamBasicDescription *processingFormat)
{
    NSLog(@"Preparing the Audio Tap Processor");
}

void unprepare(MTAudioProcessingTapRef tap)
{
    NSLog(@"Unpreparing the Audio Tap Processor");
}

void init is called void prepare and process has to be called as well.

how can I do this?

Mord Fustang
  • 1,523
  • 4
  • 40
  • 71
  • Did you have any success with this? I am struggling with the same problem. – danielbuechele Dec 29 '15 at 12:01
  • @danielbuechele unfortunately no luck, we had to approach the problem with a different angle, we proxied the connection so we could feed the `.m4a` files into our own codec to analyze the PCM, then feed the m4a chunks to a player. It was really hacky though. – Mord Fustang Jan 22 '16 at 15:35
  • Even though it isn't answered as well, I'd like to reference a question of mine from over 4 years ago which is related closely. There is someone saying he actually succeeded, but kept it secret, how he did it :( https://stackoverflow.com/questions/19403584/avplayer-hls-live-stream-level-meter-display-fft-data – Julian F. Weinert Dec 10 '17 at 22:45
  • As stated in the documentation `audioMix` doesn't work "with media served using HTTP Live Streaming" so this seems to be a dead end. – fruitcoder Dec 13 '20 at 12:30

2 Answers2

1

I would suggest you use FFMPEG library to process HLS streams. This is a little harder but gives more flexibility. I did HLS Player for Android a few years ago (used this project) I believe same applies to iOS.

Artem Moroz
  • 119
  • 1
  • 5
-4

I recommended to use Novocaine

Really fast audio in iOS and Mac OS X using Audio Units is hard, and will leave you scarred and bloody. What used to take days can now be done with just a few lines of code.

  • After some investigation, novocaine doesn't have an easy way to, for example, get the raw data from a remote m3u8 url, so it's definitely not an answer to the OP's question. – Nick White Oct 06 '15 at 20:36
  • 2
    Novocaine is not a solution to the asked question. As of my research into the subject there is no known method of extracting PCM samples used by AVPlayer when playing back HLS. – Anders Cedronius Nov 26 '15 at 22:43