1*d57664e9SAndroid Build Coastguard Worker /* 2*d57664e9SAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project 3*d57664e9SAndroid Build Coastguard Worker * 4*d57664e9SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*d57664e9SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*d57664e9SAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*d57664e9SAndroid Build Coastguard Worker * 8*d57664e9SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*d57664e9SAndroid Build Coastguard Worker * 10*d57664e9SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*d57664e9SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*d57664e9SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*d57664e9SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*d57664e9SAndroid Build Coastguard Worker * limitations under the License. 15*d57664e9SAndroid Build Coastguard Worker */ 16*d57664e9SAndroid Build Coastguard Worker 17*d57664e9SAndroid Build Coastguard Worker #pragma once 18*d57664e9SAndroid Build Coastguard Worker 19*d57664e9SAndroid Build Coastguard Worker #include <android-base/unique_fd.h> 20*d57664e9SAndroid Build Coastguard Worker #include <binder/MemoryBase.h> 21*d57664e9SAndroid Build Coastguard Worker #include <binder/MemoryHeapBase.h> 22*d57664e9SAndroid Build Coastguard Worker #include <system/audio.h> 23*d57664e9SAndroid Build Coastguard Worker 24*d57664e9SAndroid Build Coastguard Worker namespace android::soundpool { 25*d57664e9SAndroid Build Coastguard Worker 26*d57664e9SAndroid Build Coastguard Worker class SoundDecoder; 27*d57664e9SAndroid Build Coastguard Worker 28*d57664e9SAndroid Build Coastguard Worker /** 29*d57664e9SAndroid Build Coastguard Worker * Sound is a resource used by SoundPool, referenced by soundID. 30*d57664e9SAndroid Build Coastguard Worker * 31*d57664e9SAndroid Build Coastguard Worker * After loading, it is effectively const so no locking required. 32*d57664e9SAndroid Build Coastguard Worker * However, in order to guarantee that all the values have been 33*d57664e9SAndroid Build Coastguard Worker * written properly and read properly, we use the mState as an atomic synchronization 34*d57664e9SAndroid Build Coastguard Worker * point. So if getState() shows READY, then all the other getters may 35*d57664e9SAndroid Build Coastguard Worker * be safely read. 36*d57664e9SAndroid Build Coastguard Worker * 37*d57664e9SAndroid Build Coastguard Worker * Technical details: 38*d57664e9SAndroid Build Coastguard Worker * We access the mState atomic value through memory_order_seq_cst 39*d57664e9SAndroid Build Coastguard Worker * 40*d57664e9SAndroid Build Coastguard Worker * https://en.cppreference.com/w/cpp/atomic/memory_order 41*d57664e9SAndroid Build Coastguard Worker * 42*d57664e9SAndroid Build Coastguard Worker * which provides memory barriers. So if the last value written by the SoundDecoder 43*d57664e9SAndroid Build Coastguard Worker * is mState, then the compiler ensures no other prior writes by SoundDecoder will be 44*d57664e9SAndroid Build Coastguard Worker * reordered afterwards, and memory barrier is placed (as necessary) to ensure the 45*d57664e9SAndroid Build Coastguard Worker * cache is visible to other processors. 46*d57664e9SAndroid Build Coastguard Worker * 47*d57664e9SAndroid Build Coastguard Worker * Likewise, if the first value read by SoundPool is mState, 48*d57664e9SAndroid Build Coastguard Worker * the compiler ensures no reads for that thread will be reordered before mState is read, 49*d57664e9SAndroid Build Coastguard Worker * and a memory barrier is placed (as necessary) to ensure that the cache is properly 50*d57664e9SAndroid Build Coastguard Worker * updated with other processor's writes before reading. 51*d57664e9SAndroid Build Coastguard Worker * 52*d57664e9SAndroid Build Coastguard Worker * See https://developer.android.com/training/articles/smp for discussions about 53*d57664e9SAndroid Build Coastguard Worker * the variant load-acquire, store-release semantics. 54*d57664e9SAndroid Build Coastguard Worker */ 55*d57664e9SAndroid Build Coastguard Worker class Sound { 56*d57664e9SAndroid Build Coastguard Worker friend SoundDecoder; // calls doLoad(). 57*d57664e9SAndroid Build Coastguard Worker 58*d57664e9SAndroid Build Coastguard Worker public: 59*d57664e9SAndroid Build Coastguard Worker enum sound_state : int32_t { LOADING, READY, DECODE_ERROR }; 60*d57664e9SAndroid Build Coastguard Worker // A sound starts in the LOADING state and transitions only once 61*d57664e9SAndroid Build Coastguard Worker // to either READY or DECODE_ERROR when doLoad() is called. 62*d57664e9SAndroid Build Coastguard Worker 63*d57664e9SAndroid Build Coastguard Worker Sound(int soundID, int fd, int64_t offset, int64_t length); 64*d57664e9SAndroid Build Coastguard Worker ~Sound(); 65*d57664e9SAndroid Build Coastguard Worker getSoundID()66*d57664e9SAndroid Build Coastguard Worker int32_t getSoundID() const { return mSoundID; } getChannelCount()67*d57664e9SAndroid Build Coastguard Worker int32_t getChannelCount() const { return mChannelCount; } getSampleRate()68*d57664e9SAndroid Build Coastguard Worker uint32_t getSampleRate() const { return mSampleRate; } getFormat()69*d57664e9SAndroid Build Coastguard Worker audio_format_t getFormat() const { return mFormat; } getChannelMask()70*d57664e9SAndroid Build Coastguard Worker audio_channel_mask_t getChannelMask() const { return mChannelMask; } getSizeInBytes()71*d57664e9SAndroid Build Coastguard Worker size_t getSizeInBytes() const { return mSizeInBytes; } getState()72*d57664e9SAndroid Build Coastguard Worker sound_state getState() const { return mState; } getData()73*d57664e9SAndroid Build Coastguard Worker uint8_t* getData() const { return static_cast<uint8_t*>(mData->unsecurePointer()); } getIMemory()74*d57664e9SAndroid Build Coastguard Worker sp<IMemory> getIMemory() const { return mData; } 75*d57664e9SAndroid Build Coastguard Worker 76*d57664e9SAndroid Build Coastguard Worker private: 77*d57664e9SAndroid Build Coastguard Worker status_t doLoad(); // only SoundDecoder accesses this. 78*d57664e9SAndroid Build Coastguard Worker 79*d57664e9SAndroid Build Coastguard Worker size_t mSizeInBytes = 0; 80*d57664e9SAndroid Build Coastguard Worker const int32_t mSoundID; 81*d57664e9SAndroid Build Coastguard Worker uint32_t mSampleRate = 0; 82*d57664e9SAndroid Build Coastguard Worker std::atomic<sound_state> mState = LOADING; // used as synchronization point 83*d57664e9SAndroid Build Coastguard Worker int32_t mChannelCount = 0; 84*d57664e9SAndroid Build Coastguard Worker audio_format_t mFormat = AUDIO_FORMAT_INVALID; 85*d57664e9SAndroid Build Coastguard Worker audio_channel_mask_t mChannelMask = AUDIO_CHANNEL_NONE; 86*d57664e9SAndroid Build Coastguard Worker base::unique_fd mFd; // initialized in constructor, reset to -1 after loading 87*d57664e9SAndroid Build Coastguard Worker const int64_t mOffset; // int64_t to match java long, see off64_t 88*d57664e9SAndroid Build Coastguard Worker const int64_t mLength; // int64_t to match java long, see off64_t 89*d57664e9SAndroid Build Coastguard Worker sp<IMemory> mData; 90*d57664e9SAndroid Build Coastguard Worker sp<MemoryHeapBase> mHeap; 91*d57664e9SAndroid Build Coastguard Worker }; 92*d57664e9SAndroid Build Coastguard Worker 93*d57664e9SAndroid Build Coastguard Worker } // namespace android::soundpool 94