| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "embedders/android/sound_service.h" | 5 #include "embedders/android/sound_service.h" |
| 6 | 6 |
| 7 #include "embedders/android/log.h" | 7 #include "embedders/android/log.h" |
| 8 #include "embedders/android/resource.h" | 8 #include "embedders/android/resource.h" |
| 9 | 9 |
| 10 SoundService::SoundService(android_app* application) | 10 SoundService::SoundService(android_app* application) |
| 11 : application_(application), | 11 : application_(application), |
| 12 engine_(NULL), | 12 engine_(NULL), |
| 13 engine_if_(NULL), | 13 engine_if_(NULL), |
| 14 output_mix_(NULL), | 14 output_mix_(NULL), |
| 15 background_player_(NULL), | 15 background_player_(NULL), |
| 16 background_player_if_(NULL), | 16 background_player_if_(NULL), |
| 17 background_player_seek_if_(NULL) { | 17 background_player_seek_if_(NULL), |
| 18 sample_player_(NULL), |
| 19 sample_player_if_(NULL), |
| 20 sample_player_queue_(NULL), |
| 21 samples_() { |
| 18 } | 22 } |
| 19 | 23 |
| 20 int32_t SoundService::Start() { | 24 int32_t SoundService::Start() { |
| 21 LOGI("Starting SoundService"); | 25 LOGI("Starting SoundService"); |
| 22 | 26 |
| 23 const SLInterfaceID k_engine_mix_IIDs[] = { SL_IID_ENGINE }; | 27 const SLInterfaceID k_engine_mix_IIDs[] = { SL_IID_ENGINE }; |
| 24 const SLboolean k_engine_mix_reqs[] = { SL_BOOLEAN_TRUE }; | 28 const SLboolean k_engine_mix_reqs[] = { SL_BOOLEAN_TRUE }; |
| 25 const SLInterfaceID k_output_mix_IIDs[] = {}; | 29 const SLInterfaceID k_output_mix_IIDs[] = {}; |
| 26 const SLboolean k_output_mix_reqs[] = {}; | 30 const SLboolean k_output_mix_reqs[] = {}; |
| 27 if (slCreateEngine(&engine_, 0, NULL, 1, k_engine_mix_IIDs, k_engine_mix_reqs) | 31 int32_t res = slCreateEngine(&engine_, 0, NULL, 1, |
| 28 == SL_RESULT_SUCCESS && | 32 k_engine_mix_IIDs, k_engine_mix_reqs); |
| 29 (*engine_)->Realize(engine_, SL_BOOLEAN_FALSE) == SL_RESULT_SUCCESS && | 33 if (res == SL_RESULT_SUCCESS) { |
| 30 (*engine_)->GetInterface(engine_, SL_IID_ENGINE, &engine_if_) == | 34 res = (*engine_)->Realize(engine_, SL_BOOLEAN_FALSE); |
| 31 SL_RESULT_SUCCESS && | 35 if (res == SL_RESULT_SUCCESS) { |
| 32 (*engine_if_)->CreateOutputMix(engine_if_, &output_mix_, 0, | 36 res = (*engine_)->GetInterface(engine_, SL_IID_ENGINE, &engine_if_); |
| 33 k_output_mix_IIDs, k_output_mix_reqs) == | 37 if (res == SL_RESULT_SUCCESS) { |
| 34 SL_RESULT_SUCCESS && | 38 res = (*engine_if_)->CreateOutputMix(engine_if_, &output_mix_, 0, |
| 35 (*output_mix_)->Realize(output_mix_, SL_BOOLEAN_FALSE) == | 39 k_output_mix_IIDs, k_output_mix_reqs); |
| 36 SL_RESULT_SUCCESS) { | 40 if (res == SL_RESULT_SUCCESS) { |
| 37 return 0; | 41 res = (*output_mix_)->Realize(output_mix_, SL_BOOLEAN_FALSE); |
| 42 if (res == SL_RESULT_SUCCESS) { |
| 43 if (StartSamplePlayer() == 0) { |
| 44 return 0; |
| 45 } |
| 46 } |
| 47 } |
| 48 } |
| 49 } |
| 38 } | 50 } |
| 39 LOGI("Failed to start SoundService"); | 51 LOGI("Failed to start SoundService"); |
| 40 Stop(); | 52 Stop(); |
| 41 return -1; | 53 return -1; |
| 42 } | 54 } |
| 43 | 55 |
| 44 void SoundService::Stop() { | 56 void SoundService::Stop() { |
| 45 StopBackground(); | 57 StopBackground(); |
| 46 if (output_mix_ != NULL) { | 58 if (output_mix_ != NULL) { |
| 47 (*output_mix_)->Destroy(output_mix_); | 59 (*output_mix_)->Destroy(output_mix_); |
| 48 output_mix_ = NULL; | 60 output_mix_ = NULL; |
| 49 } | 61 } |
| 50 if (engine_ != NULL) { | 62 if (engine_ != NULL) { |
| 51 (*engine_)->Destroy(engine_); | 63 (*engine_)->Destroy(engine_); |
| 52 engine_ = NULL; | 64 engine_ = NULL; |
| 53 engine_if_ = NULL; | 65 engine_if_ = NULL; |
| 54 } | 66 } |
| 67 if (sample_player_ != NULL) { |
| 68 (*sample_player_)->Destroy(sample_player_); |
| 69 sample_player_ = NULL; |
| 70 sample_player_if_ = NULL; |
| 71 sample_player_queue_ = NULL; |
| 72 } |
| 73 samples_.clear(); |
| 74 } |
| 75 |
| 76 int32_t SoundService::CreateAudioPlayer(SLEngineItf engine_if, |
| 77 const SLInterfaceID extra_if, |
| 78 SLDataSource data_source, |
| 79 SLDataSink data_sink, |
| 80 SLObjectItf& player_out, |
| 81 SLPlayItf& player_if_out) { |
| 82 const SLuint32 SoundPlayerIIDCount = 2; |
| 83 const SLInterfaceID SoundPlayerIIDs[] = { SL_IID_PLAY, extra_if }; |
| 84 const SLboolean SoundPlayerReqs[] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE }; |
| 85 int32_t res = (*engine_if)->CreateAudioPlayer(engine_if, |
| 86 &player_out, |
| 87 &data_source, |
| 88 &data_sink, |
| 89 SoundPlayerIIDCount, |
| 90 SoundPlayerIIDs, |
| 91 SoundPlayerReqs); |
| 92 |
| 93 if (res == SL_RESULT_SUCCESS) { |
| 94 res = (*player_out)->Realize(player_out, SL_BOOLEAN_FALSE); |
| 95 if (res == SL_RESULT_SUCCESS) { |
| 96 res = (*player_out)->GetInterface(sample_player_, |
| 97 SL_IID_PLAY, |
| 98 &player_if_out); |
| 99 if (res == SL_RESULT_SUCCESS) { |
| 100 return 0; |
| 101 } |
| 102 } |
| 103 } |
| 104 return -1; |
| 55 } | 105 } |
| 56 | 106 |
| 57 int32_t SoundService::PlayBackground(const char* path) { | 107 int32_t SoundService::PlayBackground(const char* path) { |
| 108 LOGI("Creating audio player"); |
| 109 |
| 58 Resource resource(application_, path); | 110 Resource resource(application_, path); |
| 59 if (resource.open() < 0) { | 111 int fd = resource.descriptor(); |
| 112 if (fd < 0) { |
| 60 LOGI("Could not open file %s", path); | 113 LOGI("Could not open file %s", path); |
| 61 return -1; | 114 return -1; |
| 62 } | 115 } |
| 63 LOGI("Saving FD data"); | |
| 64 SLDataLocator_AndroidFD data_locator_in; | |
| 65 data_locator_in.locatorType = SL_DATALOCATOR_ANDROIDFD; | |
| 66 data_locator_in.fd = resource.descriptor(); | |
| 67 data_locator_in.offset = resource.start(); | |
| 68 data_locator_in.length = resource.length(); | |
| 69 resource.close(); | |
| 70 | 116 |
| 71 LOGI("Init data format"); | 117 SLDataLocator_AndroidFD data_locator_in = { |
| 72 SLDataFormat_MIME data_format; | 118 SL_DATALOCATOR_ANDROIDFD, |
| 73 data_format.formatType = SL_DATAFORMAT_MIME; | 119 fd, |
| 74 data_format.mimeType = NULL; | 120 resource.start(), |
| 75 data_format.containerType = SL_CONTAINERTYPE_UNSPECIFIED; | 121 resource.length() |
| 122 }; |
| 123 SLDataFormat_MIME data_format = { |
| 124 SL_DATAFORMAT_MIME, |
| 125 NULL, |
| 126 SL_CONTAINERTYPE_UNSPECIFIED |
| 127 }; |
| 128 SLDataSource data_source = { &data_locator_in, &data_format }; |
| 76 | 129 |
| 77 LOGI("Init data source"); | 130 resource.Close(); |
| 78 SLDataSource data_source; | |
| 79 data_source.pLocator = &data_locator_in; | |
| 80 data_source.pFormat = &data_format; | |
| 81 | 131 |
| 82 LOGI("Init out locator"); | 132 SLDataLocator_OutputMix data_locator_out = |
| 83 SLDataLocator_OutputMix data_locator_out; | 133 { SL_DATALOCATOR_OUTPUTMIX, output_mix_ }; |
| 84 data_locator_out.locatorType = SL_DATALOCATOR_OUTPUTMIX; | 134 SLDataSink data_sink = { &data_locator_out, NULL }; |
| 85 data_locator_out.outputMix = output_mix_; | |
| 86 | 135 |
| 87 LOGI("Init data sink"); | 136 int32_t res = CreateAudioPlayer(engine_if_, |
| 88 SLDataSink data_sink; | 137 SL_IID_SEEK, |
| 89 data_sink.pLocator = &data_locator_out; | 138 data_source, |
| 90 data_sink.pFormat = NULL; | 139 data_sink, |
| 140 background_player_, |
| 141 background_player_if_); |
| 91 | 142 |
| 92 const SLInterfaceID k_background_player_IIDs[] = { SL_IID_PLAY, SL_IID_SEEK }; | 143 if (res != SL_RESULT_SUCCESS) { |
| 93 const SLboolean k_background_player_reqs[] = | |
| 94 { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE }; | |
| 95 | |
| 96 LOGI("Creating audio player"); | |
| 97 if ((*engine_if_)-> | |
| 98 CreateAudioPlayer(engine_if_, &background_player_, | |
| 99 &data_source, &data_sink, 2, | |
| 100 k_background_player_IIDs, | |
| 101 k_background_player_reqs) != SL_RESULT_SUCCESS) { | |
| 102 LOGE("Couldn't create audio player"); | 144 LOGE("Couldn't create audio player"); |
| 103 return -1; | 145 return -1; |
| 104 } | 146 } |
| 105 LOGI("Created audio player"); | 147 |
| 106 if ((*background_player_)-> | |
| 107 Realize(background_player_, SL_BOOLEAN_FALSE) != SL_RESULT_SUCCESS) { | |
| 108 LOGE("Couldn't realize audio player"); | |
| 109 return -1; | |
| 110 } | |
| 111 LOGI("Realized audio player"); | |
| 112 if ((*background_player_)-> | |
| 113 GetInterface(background_player_, SL_IID_PLAY, | |
| 114 &background_player_if_) != SL_RESULT_SUCCESS) { | |
| 115 LOGE("Couldn't get player interface"); | |
| 116 return -1; | |
| 117 } | |
| 118 LOGI("Got player interface"); | |
| 119 if ((*background_player_)-> | 148 if ((*background_player_)-> |
| 120 GetInterface(background_player_, SL_IID_SEEK, | 149 GetInterface(background_player_, SL_IID_SEEK, |
| 121 &background_player_seek_if_) != SL_RESULT_SUCCESS) { | 150 &background_player_seek_if_) != SL_RESULT_SUCCESS) { |
| 122 LOGE("Couldn't get seek interface"); | 151 LOGE("Couldn't get seek interface"); |
| 123 return -1; | 152 return -1; |
| 124 } | 153 } |
| 125 LOGI("Got seek interface"); | 154 LOGI("Got seek interface"); |
| 126 if ((*background_player_seek_if_)-> | 155 if ((*background_player_seek_if_)-> |
| 127 SetLoop(background_player_seek_if_, SL_BOOLEAN_TRUE, 0, | 156 SetLoop(background_player_seek_if_, SL_BOOLEAN_TRUE, 0, |
| 128 SL_TIME_UNKNOWN) != SL_RESULT_SUCCESS) { | 157 SL_TIME_UNKNOWN) != SL_RESULT_SUCCESS) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 148 (*background_player_if_)->SetPlayState(background_player_if_, | 177 (*background_player_if_)->SetPlayState(background_player_if_, |
| 149 SL_PLAYSTATE_PAUSED); | 178 SL_PLAYSTATE_PAUSED); |
| 150 | 179 |
| 151 (*background_player_)->Destroy(background_player_); | 180 (*background_player_)->Destroy(background_player_); |
| 152 background_player_ = NULL; | 181 background_player_ = NULL; |
| 153 background_player_if_ = NULL; | 182 background_player_if_ = NULL; |
| 154 background_player_seek_if_ = NULL; | 183 background_player_seek_if_ = NULL; |
| 155 } | 184 } |
| 156 } | 185 } |
| 157 } | 186 } |
| 187 |
| 188 int32_t SoundService::StartSamplePlayer() { |
| 189 SLDataLocator_AndroidSimpleBufferQueue data_locator_in = { |
| 190 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, |
| 191 1 |
| 192 }; |
| 193 |
| 194 SLDataFormat_PCM data_format= { |
| 195 SL_DATAFORMAT_PCM, |
| 196 1, |
| 197 SL_SAMPLINGRATE_44_1, |
| 198 SL_PCMSAMPLEFORMAT_FIXED_16, |
| 199 SL_PCMSAMPLEFORMAT_FIXED_16, |
| 200 SL_SPEAKER_FRONT_CENTER, |
| 201 SL_BYTEORDER_LITTLEENDIAN |
| 202 }; |
| 203 |
| 204 SLDataSource data_source = { &data_locator_in, &data_format }; |
| 205 |
| 206 SLDataLocator_OutputMix data_locator_out = |
| 207 { SL_DATALOCATOR_OUTPUTMIX, output_mix_ }; |
| 208 SLDataSink data_sink = { &data_locator_out, NULL }; |
| 209 |
| 210 int32_t res = CreateAudioPlayer(engine_if_, SL_IID_BUFFERQUEUE, |
| 211 data_source, |
| 212 data_sink, |
| 213 sample_player_, sample_player_if_); |
| 214 |
| 215 if (res == SL_RESULT_SUCCESS) { |
| 216 res = (*sample_player_)->GetInterface(sample_player_, |
| 217 SL_IID_BUFFERQUEUE, |
| 218 &sample_player_queue_); |
| 219 if (res == SL_RESULT_SUCCESS) { |
| 220 res = (*sample_player_if_)->SetPlayState(sample_player_if_, |
| 221 SL_PLAYSTATE_PLAYING); |
| 222 if (res == SL_RESULT_SUCCESS) { |
| 223 return 0; |
| 224 } |
| 225 } |
| 226 } |
| 227 LOGE("Error while starting sample player"); |
| 228 return -1; |
| 229 } |
| 230 |
| 231 Sample* SoundService::GetSample(const char* path) { |
| 232 for (samples_t::iterator sp = samples_.begin(); |
| 233 sp != samples_.end(); |
| 234 ++sp) { |
| 235 Sample* sample = (*sp); |
| 236 if (strcmp(sample->path(), path) == 0) { |
| 237 return sample; |
| 238 } |
| 239 } |
| 240 Sample* sample = new Sample(application_, path); |
| 241 if (sample->Load() != 0) { |
| 242 LOGI("Failed to load sample %s", path); |
| 243 delete sample; |
| 244 return NULL; |
| 245 } |
| 246 samples_.push_back(sample); |
| 247 return sample; |
| 248 } |
| 249 |
| 250 int32_t SoundService::PlaySample(const char* path) { |
| 251 SLuint32 state; |
| 252 (*sample_player_)->GetState(sample_player_, &state); |
| 253 if (state != SL_OBJECT_STATE_REALIZED) { |
| 254 LOGE("Sample player has not been realized"); |
| 255 } else { |
| 256 Sample* sample = GetSample(path); |
| 257 if (sample != NULL) { |
| 258 int16_t* buffer = static_cast<int16_t*>(sample->buffer_); |
| 259 off_t len = sample->length_; |
| 260 |
| 261 // Remove any current sample. |
| 262 int32_t res = (*sample_player_queue_)->Clear(sample_player_queue_); |
| 263 if (res == SL_RESULT_SUCCESS) { |
| 264 res = (*sample_player_queue_)->Enqueue(sample_player_queue_, |
| 265 buffer, len); |
| 266 if (res == SL_RESULT_SUCCESS) { |
| 267 return 0; |
| 268 } |
| 269 LOGE("Enqueueing sample failed"); |
| 270 } |
| 271 } |
| 272 } |
| 273 return -1; |
| 274 } |
| 275 |
| 276 |
| OLD | NEW |