2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 * @brief This file include implementation of protected API
20 * for the sound sources(OpenAL buffers) as part of SoundPool.
23 #include "internal/source.h"
24 #include "internal/stream.h"
25 #include "internal/stream_cb_manager.h"
33 static sound_pool_error_e __sound_pool_add_source(sound_pool_t *pool, sound_source_t *src);
34 static sound_pool_error_e __sound_pool_remove_source(sound_pool_t *pool, sound_source_t *src);
35 static sound_pool_error_e __probe_file_access(const char *file, int amode);
37 static sound_pool_error_e __sound_pool_add_source(sound_pool_t *pool, sound_source_t *src)
40 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
41 SP_INST_CHECK(src, SOUND_POOL_ERROR_INVALID_PARAMETER);
42 SP_RETVM_IF(!pool->sources, SOUND_POOL_ERROR_INVALID_OPERATION, "Sound "
43 "pool to add the source is corrupted: NULL sources hash table");
44 SP_RETVM_IF(!src->tag_name, SOUND_POOL_ERROR_INVALID_OPERATION,
45 "Source to be added to sound pool is corrupted: NULL tag name");
46 SP_RETVM_IF(src->parent_pool != pool, SOUND_POOL_ERROR_INVALID_OPERATION,
47 "Sound source can't be added to the pool different to the pool for"
48 " which sound source was created");
49 SP_RETVM_IF(g_hash_table_contains(pool->sources, src->tag_name),
50 SOUND_POOL_ERROR_INVALID_PARAMETER,
51 "Tag already exists in sources hash table.");
53 SP_RETVM_IF(!g_hash_table_insert(pool->sources, src->tag_name, src),
54 SOUND_POOL_ERROR_INVALID_OPERATION, "Error occurred when adding "
55 "the source tagged [%s] to the sound pool", src->tag_name);
58 return SOUND_POOL_ERROR_NONE;
61 static sound_pool_error_e __sound_pool_remove_source(sound_pool_t *pool, sound_source_t *src)
64 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
65 SP_INST_CHECK(pool->sources, SOUND_POOL_ERROR_INVALID_PARAMETER);
66 SP_INST_CHECK(src, SOUND_POOL_ERROR_INVALID_PARAMETER);
68 if (src->parent_pool == pool && src->tag_name) {
69 if (!g_hash_table_steal(pool->sources, src->tag_name)) {
70 SP_DEBUG("Tag [%s] doesn't exist in sources hash table",
73 return SOUND_POOL_ERROR_NONE;
77 g_hash_table_iter_init(&iter, pool->streams);
78 while (g_hash_table_iter_next(&iter, &key, &value)) {
79 guint size_before = g_hash_table_size(pool->streams);
80 sound_stream_t *stream = (sound_stream_t*)value;
81 if (src == stream->parent_source)
82 _sound_stream_stop(stream);
83 guint size_after = g_hash_table_size(pool->streams);
84 if (size_before != size_after)
85 g_hash_table_iter_init(&iter, pool->streams);
88 SP_DEBUG("Source wasn't removed from sound pool as it isn't known by "
89 "the pool for which operation is performed, or tag corrupted");
93 return SOUND_POOL_ERROR_NONE;
96 /* file parameter should be not-NULL and not empty c-string */
97 static sound_pool_error_e __probe_file_access(const char *file, int amode)
100 sound_pool_error_e ret = SOUND_POOL_ERROR_NONE;
102 if (-1 == access(file, amode)) {
105 ret = SOUND_POOL_ERROR_NOT_PERMITTED;
106 else if (ENOENT == errno)
107 ret = SOUND_POOL_ERROR_NO_SUCH_FILE;
109 ret = SOUND_POOL_ERROR_INVALID_OPERATION;
110 strerror_r(errno, errmsg, sizeof(errmsg));
111 SP_ERROR("Couldn`t open file in [%i] mode, reason [%s].", amode, errmsg);
121 sound_pool_error_e _sound_source_create(sound_pool_t *pool, const char *tag,
122 sound_source_t **src)
125 SP_RETVM_IF(!pool, SOUND_POOL_ERROR_INVALID_PARAMETER,
126 "Can't create sound source in NULL sound pool");
127 SP_RETVM_IF(!tag, SOUND_POOL_ERROR_INVALID_PARAMETER,
128 "Can't create sound source with NULL tag name");
129 SP_RETVM_IF(!src, SOUND_POOL_ERROR_INVALID_PARAMETER,
130 "Can't create sound source. Source pointer is NULL");
131 SP_RETVM_IF(strnlen(tag, MAX_TAG_LEN + 1) == MAX_TAG_LEN + 1,
132 SOUND_POOL_ERROR_INVALID_PARAMETER, "Can't create sound source "
133 "with tag name longer than %u", MAX_TAG_LEN);
134 SP_RETVM_IF(!pool->sources, SOUND_POOL_ERROR_INVALID_OPERATION, "Sound "
135 "pool to create source is corrupted: NULL sources hash table.");
136 SP_RETVM_IF(g_hash_table_contains(pool->sources, tag),
137 SOUND_POOL_ERROR_INVALID_PARAMETER,
138 "Tag already exists in sources hash table.");
140 SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
141 SOUND_POOL_ERROR_INVALID_OPERATION,
142 "Can't set current context.");
144 sound_source_t *_src = NULL;
145 SP_RETVM_IF(!(_src = g_try_malloc0(sizeof(*_src))),
146 SOUND_POOL_ERROR_OUT_OF_MEMORY,
147 "Memory alloc failure. Can't create sound _src");
149 sound_pool_error_e ret_destroy = SOUND_POOL_ERROR_NONE;
150 sound_pool_error_e ret = SOUND_POOL_ERROR_NONE;
151 alGenBuffers(1, &_src->al_buffer);
152 if (alGetError() != AL_NO_ERROR) {
153 ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
154 GOTO_FAIL("OpenAL error occurred when trying to generate Buffer id", cfail);
157 _src->parent_pool = pool;
158 _src->tag_name = NULL;
159 _src->tag_name = g_strndup(tag, MAX_TAG_LEN);
161 ret = __sound_pool_add_source(pool, _src);
162 if (ret != SOUND_POOL_ERROR_NONE)
163 GOTO_FAIL("Error occurred when trying to add source to pool", cfail);
170 ret_destroy = _sound_source_destroy(_src);
171 SP_RETVM_IF(SOUND_POOL_ERROR_NONE != ret_destroy, ret_destroy,
172 "Error occurred during removal of sound source[%s].", tag);
177 sound_pool_error_e _sound_source_destroy(sound_source_t *src)
180 SP_RETVM_IF(!src, SOUND_POOL_ERROR_INVALID_PARAMETER,
181 "Can't destroy NULL sound source");
183 SP_INST_CHECK(src->parent_pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
184 SP_INST_CHECK(src->parent_pool->cbmgr, SOUND_POOL_ERROR_INVALID_PARAMETER);
185 stream_cb_manager_t *cbmgr = (stream_cb_manager_t *)(src->parent_pool->cbmgr);
187 /* If parent pool exists, then source has to be removed from the pool */
188 if (src->parent_pool && __sound_pool_remove_source(src->parent_pool, src)
189 != SOUND_POOL_ERROR_NONE)
190 SP_DEBUG("Source wasn't removed from sound pool.");
192 SP_DEBUG("Deleting OpenAL buffer with id [%u]", src->al_buffer);
193 alDeleteBuffers(1, &src->al_buffer);
195 /* Wait for completing the isolator callback thread events */
196 _stream_cb_manager_process_pending_events(cbmgr);
198 SP_SAFE_GFREE(src->tag_name);
202 return SOUND_POOL_ERROR_NONE;
205 sound_pool_error_e _sound_source_load_from_file(sound_source_t *src,
209 SP_INST_CHECK(src, SOUND_POOL_ERROR_INVALID_PARAMETER);
210 SP_INST_CHECK(fname, SOUND_POOL_ERROR_INVALID_PARAMETER);
211 SP_INST_CHECK(src->parent_pool, SOUND_POOL_ERROR_INVALID_OPERATION);
212 SP_RETVM_IF(!alcMakeContextCurrent(src->parent_pool->al_context),
213 SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current AL context.");
215 sound_pool_error_e ret = __probe_file_access(fname, R_OK);
216 SP_RETVM_IF(SOUND_POOL_ERROR_NONE != ret, ret,
217 "Can't load source from [%s] file.", fname);
219 ALuint buffer_handle = AL_NONE;
220 src->al_buffer = AL_NONE;
223 buffer_handle = alureCreateBufferFromFile((const ALchar *)fname);
224 SP_RETVM_IF(buffer_handle == AL_NONE, SOUND_POOL_ERROR_INVALID_OPERATION,
225 "Can't load audio file [%s]. Error message [%s]", fname,
226 alureGetErrorString());
228 alutInitWithoutContext(NULL, NULL);
229 buffer_handle = alutCreateBufferFromFile(fname);
230 ALenum error = alutGetError();
232 SP_RETVM_IF(error != ALUT_ERROR_NO_ERROR || buffer_handle == AL_NONE,
233 SOUND_POOL_ERROR_INVALID_OPERATION, "Can't load audio file [%s]. "
234 "Error message [%s]", fname, alutGetErrorString(error));
237 src->al_buffer = buffer_handle;
242 sound_pool_error_e _sound_pool_get_source_by_tag(sound_pool_t *pool,
243 const char *tag, sound_source_t **src)
246 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
247 SP_INST_CHECK(tag, SOUND_POOL_ERROR_INVALID_PARAMETER);
248 SP_INST_CHECK(src, SOUND_POOL_ERROR_INVALID_PARAMETER);
249 SP_RETVM_IF(!pool->sources, SOUND_POOL_ERROR_INVALID_PARAMETER, "Corrupted "
250 "sound pool. Sources hash table is NULL");
252 *src = (sound_source_t *)g_hash_table_lookup(pool->sources, tag);
253 SP_RETVM_IF(!(*src), SOUND_POOL_ERROR_KEY_NOT_AVAILABLE, "Tag doesn't "
254 "exist in sources hash table");
257 return SOUND_POOL_ERROR_NONE;