1*c8dee2aaSAndroid Build Coastguard Worker/* 2*c8dee2aaSAndroid Build Coastguard Worker* Copyright 2020 Google Inc. 3*c8dee2aaSAndroid Build Coastguard Worker* 4*c8dee2aaSAndroid Build Coastguard Worker* Use of this source code is governed by a BSD-style license that can be 5*c8dee2aaSAndroid Build Coastguard Worker* found in the LICENSE file. 6*c8dee2aaSAndroid Build Coastguard Worker*/ 7*c8dee2aaSAndroid Build Coastguard Worker 8*c8dee2aaSAndroid Build Coastguard Worker#include "include/core/SkData.h" 9*c8dee2aaSAndroid Build Coastguard Worker#include "modules/audioplayer/SkAudioPlayer.h" 10*c8dee2aaSAndroid Build Coastguard Worker 11*c8dee2aaSAndroid Build Coastguard Worker#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) 12*c8dee2aaSAndroid Build Coastguard Worker 13*c8dee2aaSAndroid Build Coastguard Worker#ifdef SK_BUILD_FOR_MAC 14*c8dee2aaSAndroid Build Coastguard Worker#include <AVFoundation/AVFoundation.h> 15*c8dee2aaSAndroid Build Coastguard Worker#endif 16*c8dee2aaSAndroid Build Coastguard Worker 17*c8dee2aaSAndroid Build Coastguard Worker#ifdef SK_BUILD_FOR_IOS 18*c8dee2aaSAndroid Build Coastguard Worker// ??? 19*c8dee2aaSAndroid Build Coastguard Worker#endif 20*c8dee2aaSAndroid Build Coastguard Worker 21*c8dee2aaSAndroid Build Coastguard Workerclass SkAudioPlayer_Mac : public SkAudioPlayer { 22*c8dee2aaSAndroid Build Coastguard Workerpublic: 23*c8dee2aaSAndroid Build Coastguard Worker SkAudioPlayer_Mac(AVAudioPlayer* player, sk_sp<SkData> data) 24*c8dee2aaSAndroid Build Coastguard Worker : fPlayer(player) 25*c8dee2aaSAndroid Build Coastguard Worker , fData(std::move(data)) 26*c8dee2aaSAndroid Build Coastguard Worker { 27*c8dee2aaSAndroid Build Coastguard Worker fPlayer.enableRate = YES; 28*c8dee2aaSAndroid Build Coastguard Worker [fPlayer prepareToPlay]; 29*c8dee2aaSAndroid Build Coastguard Worker } 30*c8dee2aaSAndroid Build Coastguard Worker 31*c8dee2aaSAndroid Build Coastguard Worker ~SkAudioPlayer_Mac() override { 32*c8dee2aaSAndroid Build Coastguard Worker // [fPlayer release]; 33*c8dee2aaSAndroid Build Coastguard Worker } 34*c8dee2aaSAndroid Build Coastguard Worker 35*c8dee2aaSAndroid Build Coastguard Worker double onGetDuration() const override { return [fPlayer duration]; } 36*c8dee2aaSAndroid Build Coastguard Worker 37*c8dee2aaSAndroid Build Coastguard Worker double onGetTime() const override { return fPlayer.currentTime; } 38*c8dee2aaSAndroid Build Coastguard Worker 39*c8dee2aaSAndroid Build Coastguard Worker double onSetTime(double t) override { 40*c8dee2aaSAndroid Build Coastguard Worker bool wasPlaying = this->isPlaying(); 41*c8dee2aaSAndroid Build Coastguard Worker if (wasPlaying) { 42*c8dee2aaSAndroid Build Coastguard Worker [fPlayer pause]; 43*c8dee2aaSAndroid Build Coastguard Worker } 44*c8dee2aaSAndroid Build Coastguard Worker fPlayer.currentTime = t; 45*c8dee2aaSAndroid Build Coastguard Worker if (wasPlaying) { 46*c8dee2aaSAndroid Build Coastguard Worker [fPlayer play]; 47*c8dee2aaSAndroid Build Coastguard Worker } 48*c8dee2aaSAndroid Build Coastguard Worker return fPlayer.currentTime; 49*c8dee2aaSAndroid Build Coastguard Worker } 50*c8dee2aaSAndroid Build Coastguard Worker 51*c8dee2aaSAndroid Build Coastguard Worker 52*c8dee2aaSAndroid Build Coastguard Worker State onSetState(State state) override { 53*c8dee2aaSAndroid Build Coastguard Worker switch (state) { 54*c8dee2aaSAndroid Build Coastguard Worker case State::kPlaying: [fPlayer play]; break; 55*c8dee2aaSAndroid Build Coastguard Worker case State::kStopped: [fPlayer stop]; break; 56*c8dee2aaSAndroid Build Coastguard Worker case State::kPaused: [fPlayer pause]; break; 57*c8dee2aaSAndroid Build Coastguard Worker } 58*c8dee2aaSAndroid Build Coastguard Worker return state; 59*c8dee2aaSAndroid Build Coastguard Worker } 60*c8dee2aaSAndroid Build Coastguard Worker 61*c8dee2aaSAndroid Build Coastguard Worker float onSetRate(float r) override { fPlayer.rate = r; return r; } 62*c8dee2aaSAndroid Build Coastguard Worker 63*c8dee2aaSAndroid Build Coastguard Worker float onSetVolume(float v) override { fPlayer.volume = v; return v; } 64*c8dee2aaSAndroid Build Coastguard Worker 65*c8dee2aaSAndroid Build Coastguard Workerprivate: 66*c8dee2aaSAndroid Build Coastguard Worker AVAudioPlayer* fPlayer; 67*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> fData; // we hold this onbehalf of the player's NSData 68*c8dee2aaSAndroid Build Coastguard Worker}; 69*c8dee2aaSAndroid Build Coastguard Worker 70*c8dee2aaSAndroid Build Coastguard Workerstd::unique_ptr<SkAudioPlayer> SkAudioPlayer::Make(sk_sp<SkData> src) { 71*c8dee2aaSAndroid Build Coastguard Worker // The NSData does not own the actual buffer (src), but our subclass will 72*c8dee2aaSAndroid Build Coastguard Worker 73*c8dee2aaSAndroid Build Coastguard Worker NSData* data = [[NSData alloc] initWithBytesNoCopy:(void*)src->data() length:src->size()]; 74*c8dee2aaSAndroid Build Coastguard Worker AVAudioPlayer* player = [[AVAudioPlayer alloc] initWithData:data error:nil]; 75*c8dee2aaSAndroid Build Coastguard Worker [data release]; 76*c8dee2aaSAndroid Build Coastguard Worker 77*c8dee2aaSAndroid Build Coastguard Worker if (player) { 78*c8dee2aaSAndroid Build Coastguard Worker return std::unique_ptr<SkAudioPlayer>(new SkAudioPlayer_Mac(player, std::move(src))); 79*c8dee2aaSAndroid Build Coastguard Worker } 80*c8dee2aaSAndroid Build Coastguard Worker return nullptr; 81*c8dee2aaSAndroid Build Coastguard Worker} 82*c8dee2aaSAndroid Build Coastguard Worker 83*c8dee2aaSAndroid Build Coastguard Worker#endif 84