Isolated ALURE/ALUT source loading logic, avoided usage of deprecated alutLoadWAVFile()
[platform/core/api/sound-pool.git] / src / source.c
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 /**
18  * @file source.c
19  * @brief This file include implementation of protected API
20  * for the sound sources(OpenAL buffers) as part of SoundPool.
21  */
22
23 #include "internal/source.h"
24 #include "internal/stream.h"
25
26 #include <unistd.h>
27 #include <AL/alut.h>
28 #ifdef ENABLE_ALURE
29 #       include <AL/alure.h>
30 #endif
31
32 static sound_pool_error_e __sound_pool_add_source(sound_pool_t *pool, sound_source_t *src);
33 static sound_pool_error_e __sound_pool_remove_source(sound_pool_t *pool, sound_source_t *src);
34 static sound_pool_error_e __probe_file_access(const char *file, int amode);
35
36 static sound_pool_error_e __sound_pool_add_source(sound_pool_t *pool, sound_source_t *src)
37 {
38         SP_DEBUG_FENTER();
39         SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
40         SP_INST_CHECK(src, SOUND_POOL_ERROR_INVALID_PARAMETER);
41         SP_RETVM_IF(!pool->sources, SOUND_POOL_ERROR_INVALID_OPERATION, "Sound "
42                         "pool to add the source is corrupted: NULL sources hash table");
43         SP_RETVM_IF(!src->tag_name, SOUND_POOL_ERROR_INVALID_OPERATION,
44                         "Source to be added to sound pool is corrupted: NULL tag name");
45         SP_RETVM_IF(src->parent_pool != pool, SOUND_POOL_ERROR_INVALID_OPERATION,
46                         "Sound source can't be added to the pool different to the pool for"
47                         " which sound source was created");
48         SP_RETVM_IF(g_hash_table_contains(pool->sources, src->tag_name),
49                         SOUND_POOL_ERROR_INVALID_PARAMETER,
50                         "Tag already exists in sources hash table.");
51
52         SP_RETVM_IF(!g_hash_table_insert(pool->sources, src->tag_name, src),
53                         SOUND_POOL_ERROR_INVALID_OPERATION, "Error occurred when adding "
54                         "the source tagged [%s] to the sound pool", src->tag_name);
55
56         SP_DEBUG_FLEAVE();
57         return SOUND_POOL_ERROR_NONE;
58 }
59
60 static sound_pool_error_e __sound_pool_remove_source(sound_pool_t *pool, sound_source_t *src)
61 {
62         SP_DEBUG_FENTER();
63         SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
64         SP_INST_CHECK(pool->sources, SOUND_POOL_ERROR_INVALID_PARAMETER);
65         SP_INST_CHECK(src, SOUND_POOL_ERROR_INVALID_PARAMETER);
66
67         if (src->parent_pool == pool && src->tag_name) {
68                 if (!g_hash_table_steal(pool->sources, src->tag_name)) {
69                         SP_DEBUG("Tag [%s] doesn't exist in sources hash table",
70                                         src->tag_name);
71                         SP_DEBUG_FLEAVE();
72                         return SOUND_POOL_ERROR_NONE;
73                 }
74                 GHashTableIter iter;
75                 gpointer key, value;
76                 g_hash_table_iter_init(&iter, pool->streams);
77                 while (g_hash_table_iter_next(&iter, &key, &value)) {
78                         guint size_before = g_hash_table_size(pool->streams);
79                         sound_stream_t *stream = (sound_stream_t*)value;
80                         if (src == stream->parent_source)
81                                 _sound_stream_destroy((sound_stream_t*)value);
82                         guint size_after = g_hash_table_size(pool->streams);
83                         if (size_before != size_after)
84                                 g_hash_table_iter_init(&iter, pool->streams);
85                 }
86         } else {
87                         SP_DEBUG("Source wasn't removed from sound pool as it isn't known by "
88                                         "the pool for which operation is performed, or tag corrupted");
89         }
90
91         SP_DEBUG_FLEAVE();
92         return SOUND_POOL_ERROR_NONE;
93 }
94
95 /* file parameter should be not-NULL and not empty c-string */
96 static sound_pool_error_e __probe_file_access(const char *file, int amode)
97 {
98         SP_DEBUG_FENTER();
99         sound_pool_error_e ret = SOUND_POOL_ERROR_NONE;
100
101         if (-1 == access(file, amode)) {
102                 char errmsg[256];
103                 strerror_r(errno, errmsg, sizeof(errmsg));
104                 SP_ERROR("Couldn`t open file in [%i] mode, reason [%s].", amode, errmsg);
105                 if (EACCES == errno)
106                         ret = SOUND_POOL_ERROR_PERMISSION_DENIED;
107                 else if (ENOENT == errno)
108                         ret = SOUND_POOL_ERROR_NO_SUCH_FILE;
109                 else
110                         ret = SOUND_POOL_ERROR_INVALID_OPERATION;
111                 SP_DEBUG_FLEAVE();
112                 return ret;
113         }
114
115         SP_DEBUG_FLEAVE();
116         return ret;
117 }
118
119 sound_pool_error_e _sound_source_create(sound_pool_t *pool, const char *tag,
120                 sound_source_t **src)
121 {
122         SP_DEBUG_FENTER();
123         SP_RETVM_IF(!pool, SOUND_POOL_ERROR_INVALID_PARAMETER,
124                         "Can't create sound source in NULL sound pool");
125         SP_RETVM_IF(!tag, SOUND_POOL_ERROR_INVALID_PARAMETER,
126                         "Can't create sound source with NULL tag name");
127         SP_RETVM_IF(!src, SOUND_POOL_ERROR_INVALID_PARAMETER,
128                         "Can't create sound source. Source pointer is NULL");
129         SP_RETVM_IF(strnlen(tag, MAX_TAG_LEN + 1) == MAX_TAG_LEN + 1,
130                         SOUND_POOL_ERROR_INVALID_PARAMETER, "Can't create sound source "
131                         "with tag name longer than %u", MAX_TAG_LEN);
132         SP_RETVM_IF(!pool->sources, SOUND_POOL_ERROR_INVALID_OPERATION, "Sound "
133                         "pool to create source is corrupted: NULL sources hash table.");
134         SP_RETVM_IF(g_hash_table_contains(pool->sources, tag),
135                         SOUND_POOL_ERROR_INVALID_PARAMETER,
136                         "Tag already exists in sources hash table.");
137
138         SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
139                         SOUND_POOL_ERROR_INVALID_OPERATION,
140                         "Can't set current context.");
141
142         sound_source_t *_src = NULL;
143         SP_RETVM_IF(!(_src = g_try_malloc0(sizeof(*_src))),
144                         SOUND_POOL_ERROR_OUT_OF_MEMORY,
145                         "Memory alloc failure. Can't create sound _src");
146
147         sound_pool_error_e ret_destroy = SOUND_POOL_ERROR_NONE;
148         sound_pool_error_e ret = SOUND_POOL_ERROR_NONE;
149         alGenBuffers(1, &_src->al_buffer);
150         if (alGetError() != AL_NO_ERROR) {
151                 ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
152                 GOTO_FAIL("OpenAL error occurred when trying to generate Buffer id", cfail);
153         }
154
155         _src->parent_pool = pool;
156         _src->tag_name = NULL;
157         _src->tag_name = g_strndup(tag, MAX_TAG_LEN);
158
159         ret = __sound_pool_add_source(pool, _src);
160         if (ret != SOUND_POOL_ERROR_NONE)
161                 GOTO_FAIL("Error occurred when trying to add source to pool", cfail);
162
163         *src = _src;
164         SP_DEBUG_FLEAVE();
165         return ret;
166
167 cfail:
168         ret_destroy = _sound_source_destroy(_src);
169         SP_RETVM_IF(SOUND_POOL_ERROR_NONE != ret_destroy, ret_destroy,
170                         "Error occurred during removal of sound source[%s].", tag);
171         SP_DEBUG_FLEAVE();
172         return ret;
173 }
174
175 sound_pool_error_e _sound_source_destroy(sound_source_t *src)
176 {
177         SP_DEBUG_FENTER();
178         SP_RETVM_IF(!src, SOUND_POOL_ERROR_INVALID_PARAMETER,
179                         "Can't destroy NULL sound source");
180
181         /* If parent pool exists, then source has to be removed from the pool */
182         if (src->parent_pool && __sound_pool_remove_source(src->parent_pool, src)
183                         != SOUND_POOL_ERROR_NONE)
184                 SP_DEBUG("Source wasn't removed from sound pool.");
185
186         SP_DEBUG("Deleting OpenAL buffer with id [%u]", src->al_buffer);
187         alDeleteBuffers(1, &src->al_buffer);
188
189         SP_SAFE_GFREE(src->tag_name);
190         SP_SAFE_GFREE(src);
191
192         SP_DEBUG_FLEAVE();
193         return SOUND_POOL_ERROR_NONE;
194 }
195
196 sound_pool_error_e _sound_source_load_from_file(sound_source_t *src,
197                 const char *fname)
198 {
199         SP_DEBUG_FENTER();
200         SP_INST_CHECK(src, SOUND_POOL_ERROR_INVALID_PARAMETER);
201         SP_INST_CHECK(fname, SOUND_POOL_ERROR_INVALID_PARAMETER);
202         SP_INST_CHECK(src->parent_pool, SOUND_POOL_ERROR_INVALID_OPERATION);
203         SP_RETVM_IF(!alcMakeContextCurrent(src->parent_pool->al_context),
204                         SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current AL context.");
205
206         sound_pool_error_e ret = __probe_file_access(fname, R_OK);
207         SP_RETVM_IF(SOUND_POOL_ERROR_NONE != ret, ret,
208                         "Can't load source from [%s] file.", fname);
209
210         ALuint buffer_handle = AL_NONE;
211         src->al_buffer = AL_NONE;
212
213 #ifdef ENABLE_ALURE
214         buffer_handle = alureCreateBufferFromFile((const ALchar *)fname);
215         SP_RETVM_IF(buffer_handle == AL_NONE, SOUND_POOL_ERROR_INVALID_OPERATION,
216                         "Can't load audio file [%s]. Error message [%s]", fname,
217                         alureGetErrorString());
218 #else
219         alutInitWithoutContext(NULL, NULL);
220         buffer_handle = alutCreateBufferFromFile(fname);
221         ALenum error = alutGetError();
222         alutExit();
223         SP_RETVM_IF(error != ALUT_ERROR_NO_ERROR || buffer_handle == AL_NONE,
224                         SOUND_POOL_ERROR_INVALID_OPERATION, "Can't load audio file [%s]. "
225                         "Error message [%s]", fname, alutGetErrorString(error));
226 #endif
227
228         src->al_buffer = buffer_handle;
229         SP_DEBUG_FLEAVE();
230         return ret;
231 }
232
233 sound_pool_error_e _sound_pool_get_source_by_tag(sound_pool_t *pool,
234                 const char *tag, sound_source_t **src)
235 {
236         SP_DEBUG_FENTER();
237         SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
238         SP_INST_CHECK(tag, SOUND_POOL_ERROR_INVALID_PARAMETER);
239         SP_INST_CHECK(src, SOUND_POOL_ERROR_INVALID_PARAMETER);
240         SP_RETVM_IF(!pool->sources, SOUND_POOL_ERROR_INVALID_PARAMETER, "Corrupted "
241                         "sound pool. Sources hash table is NULL");
242
243         *src = (sound_source_t *)g_hash_table_lookup(pool->sources, tag);
244         SP_RETVM_IF(!(*src), SOUND_POOL_ERROR_KEY_NOT_AVAILABLE, "Tag doesn't "
245                         "exist in sources hash table");
246
247         SP_DEBUG_FLEAVE();
248         return SOUND_POOL_ERROR_NONE;
249 }