Revise: add manifest file for SMACK label setting. Log output level correction.(perfo...
[profile/ivi/ico-uxf-homescreen-sample-apps.git] / ico-app-soundsample / src / soundsample_pulse_async_test.cpp
1 /*
2  * Copyright (c) 2013, TOYOTA MOTOR CORPORATION.
3  *
4  * This program is licensed under the terms and conditions of the 
5  * Apache License, version 2.0.  The full text of the Apache License is at
6  * http://www.apache.org/licenses/LICENSE-2.0
7  *
8  */
9 /**
10  * @brief   Sound Sample APP
11  *          Test use with which sound is sounded
12  *
13  * @date    Mar-04-2013
14  */
15
16 /**
17  *  TP using PulseAudio with wavfile
18  **/
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <time.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <pulse/mainloop.h>
26 #include <pulse/context.h>
27 #include <pulse/stream.h>
28 #include <pulse/error.h>
29 #include "soundsample_yswavfile.h"
30 //#include "ico_apf_log.h"
31 #include "soundsample.h"
32 #include "ico_log.h"
33
34 #define ICO_PA_STREAM_PAUSE  (1)
35 #define ICO_PA_STREAM_RESUME (0)
36
37 extern "C"
38 {
39     int pulse_main(struct audio_config_t *audio_config, int filedes);
40 }
41
42 static int ExitFlg;
43 static int ReadFiledes;
44
45 static YSRESULT YsPulseAudioWaitForConnectionEstablished(pa_context *
46                                                          paContext,
47                                                          pa_mainloop *
48                                                          paMainLoop,
49                                                          time_t timeOut)
50 {
51     time_t timeLimit = time(NULL) + timeOut;
52     while (timeLimit >= time(NULL)) {
53         pa_mainloop_iterate(paMainLoop, 0, NULL);
54         if (PA_CONTEXT_READY == pa_context_get_state(paContext)) {
55             return YSOK;
56         }
57     }
58     return YSERR;
59 }
60
61 static void event_input_callback(pa_mainloop_api *a, pa_io_event *e, int fd,
62                                  pa_io_event_flags_t f, void *userdata)
63 {
64
65     ICO_DBG("event_input_callback: Enter");
66
67     char buff[255];
68     memset(buff, 0x00, sizeof(buff));
69
70     /* From a pipe to reading */
71     read(ReadFiledes, buff, sizeof(buff));
72     ICO_DBG("buff :%s", buff);
73
74     switch (atoi(buff)) {
75     case STOP_REQ:
76         ICO_PRF("STOP_SOUND Stop directions reception");
77         ExitFlg = 1;
78         break;
79
80     case PAUSE_REQ:
81         ICO_DBG("Pause directions reception");
82
83         if (0 == pa_stream_is_corked((pa_stream *) userdata)) {
84             pa_stream_cork((pa_stream *) userdata, ICO_PA_STREAM_PAUSE, NULL,
85                            NULL);
86             ICO_PRF("STOP_SOUND pa_stream_cork(PAUSE)");
87         }
88         else {
89             pa_stream_cork((pa_stream *) userdata, ICO_PA_STREAM_RESUME, NULL,
90                            NULL);
91             ICO_PRF("START_SOUND pa_stream_cork(RESUME)");
92         }
93         break;
94
95     default:
96         ICO_DBG("Err Reception range outside");
97         break;
98     }
99
100     ICO_DBG("event_input_callback: Leave");
101 }
102
103 int pulse_main(struct audio_config_t *audio_config, int filedes)
104 {
105     char *server_ip = NULL;
106     char *device_name = NULL;
107     int volume_set = -1;
108     int volume_set2 = -1;
109     char *app_name = NULL;
110     char *stream_name = NULL;
111     char *repeat_flg = NULL;
112     char *media_role = NULL;
113     pa_cvolume *cvolume = NULL;
114
115     char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
116     pa_channel_map cmap;
117
118     YsWavFile wavFile;
119
120     ReadFiledes = filedes;
121     ExitFlg = 0;
122
123     if (audio_config == NULL) {
124         ICO_DBG("Param Err");
125         return -1;
126     }
127
128     if (YSOK != wavFile.LoadWav(audio_config->wavfile_path)) {
129         ICO_DBG("Cannot open wave file.");
130         return -1;
131     }
132
133     if (audio_config->volume1 != -1) {
134         cvolume = (pa_cvolume *) malloc(sizeof(pa_cvolume));
135     }
136     else {
137         cvolume = NULL;
138     }
139
140     server_ip = audio_config->server_ip;
141     device_name = audio_config->device_name;
142     volume_set = audio_config->volume1;
143     volume_set2 = audio_config->volume2;
144     app_name = audio_config->app_name;
145     stream_name = audio_config->stream_name;
146     repeat_flg = audio_config->repeat_flg;
147     media_role = audio_config->media_role;
148
149     ICO_DBG("Before Resampling:");
150     ICO_DBG("Bit per sample: %d", wavFile.BitPerSample());
151     ICO_DBG("Stereo: %d", wavFile.Stereo());
152     ICO_DBG("Playback Rate: %d", wavFile.PlayBackRate());
153     ICO_DBG("Signed: %d", wavFile.IsSigned());
154
155     wavFile.ConvertTo16Bit();
156     wavFile.ConvertToSigned();
157 //    wavFile.ConvertToStereo();
158     wavFile.Resample(44100);
159 //    wavFile.ConvertToMono();
160
161     ICO_DBG("After Resampling:");
162     ICO_DBG("Bit per sample: %d", wavFile.BitPerSample());
163     ICO_DBG("Stereo: %d", wavFile.Stereo());
164     ICO_DBG("Playback Rate: %d", wavFile.PlayBackRate());
165     ICO_DBG("Signed: %d", wavFile.IsSigned());
166
167     pa_mainloop *paMainLoop = pa_mainloop_new();
168     if (NULL == paMainLoop) {
169         ICO_DBG("Cannot create main loop.");
170         return -1;
171     }
172     ICO_DBG("pa_mainloop_new()");
173
174     pa_context *paContext = pa_context_new(pa_mainloop_get_api(paMainLoop),
175                                            app_name);
176     if (NULL == paContext) {
177         ICO_DBG("Cannot create context.");
178         return -1;
179     }
180     ICO_DBG("pa_context_new()");
181
182     // pa_context_set_state_callback(paContext,YsPulseAudioConnectionCallBack,NULL);
183     pa_context_connect(paContext, server_ip, (pa_context_flags_t) 0, NULL);
184     ICO_DBG("pa_context_connect()");
185
186     YsPulseAudioWaitForConnectionEstablished(paContext, paMainLoop, 5);
187
188     pa_sample_format_t format = PA_SAMPLE_U8;
189     switch (wavFile.BitPerSample()) {
190     case 8:
191         if (YSTRUE == wavFile.IsSigned()) {
192             wavFile.ConvertToUnsigned();
193         }
194         format = PA_SAMPLE_U8;
195         break;
196     case 16:
197         if (YSTRUE != wavFile.IsSigned()) {
198             wavFile.ConvertToSigned();
199         }
200         format = PA_SAMPLE_S16LE;
201         break;
202     }
203     const int rate = wavFile.PlayBackRate();
204     const int nChannel = (YSTRUE == wavFile.Stereo()? 2 : 1);
205
206     const pa_sample_spec ss = {
207         format,
208         rate,
209         nChannel
210     };
211
212     pa_channel_map_init_auto(&cmap, nChannel, PA_CHANNEL_MAP_ALSA);
213     ICO_DBG("pa_channel_map_init_auto()");
214     ICO_DBG("map: <%s>", pa_channel_map_snprint(cm, sizeof(cm), &cmap));
215
216     if (NULL != cvolume) {
217         unsigned int i = 0;
218         for (i = 0; i < PA_CHANNELS_MAX; i++) {
219             if (1 == i) {
220                 if (-1 != volume_set2) {
221                     cvolume->values[i] = volume_set2;
222                 }
223             }
224             else {
225                 cvolume->values[i] = volume_set;
226             }
227             ICO_DBG("volume[%d]_%d", i, cvolume->values[i]);
228         }
229         cvolume->channels = nChannel;
230     }
231
232     unsigned int playBackPtr = 0;
233     YSBOOL checkForUnderflow = YSTRUE;
234     time_t prevT = time(NULL) - 1;
235
236     ICO_DBG("enter mainloop");
237     pa_stream *paStream;
238     int loopcnt;
239     static pa_io_event *stdio_event = NULL;
240     static pa_mainloop_api *mainloop_api = pa_mainloop_get_api(paMainLoop);
241
242     pa_proplist *plist_p = pa_proplist_new();
243     if ((NULL != plist_p) && (NULL != media_role) && (0 != strcmp(media_role, "none"))) {
244         pa_proplist_sets(plist_p, PA_PROP_MEDIA_ROLE, media_role);
245         paStream = pa_stream_new_with_proplist(paContext, stream_name, &ss, &cmap , plist_p);
246         ICO_DBG("pa_stream_new_with_proplist : media role set [%s]", media_role);
247     }
248     else {
249         paStream = pa_stream_new(paContext, stream_name, &ss, &cmap);
250         ICO_DBG("pa_stream_new : media role unset");
251     }
252
253     if (NULL != paStream) {
254         ICO_DBG("Stream created!  Getting there!");
255     }
256     else {
257         ICO_DBG("Stream created : NG");
258         ExitFlg = 1;
259     }
260
261     ICO_DBG("pa_stream_new()");
262
263     if (!(stdio_event = mainloop_api->io_new(mainloop_api, ReadFiledes,
264                                              PA_IO_EVENT_INPUT,
265                                              event_input_callback,
266                                              paStream))) {
267         ICO_DBG("io_new() failed()");
268         ExitFlg = 1;
269     }
270
271     pa_stream_connect_playback(paStream, device_name, NULL,
272                                (pa_stream_flags_t) 0, cvolume, NULL);
273     ICO_DBG("pa_stream_connect_playback()");
274
275     int st = -1;
276     for (loopcnt = 0; ExitFlg != 1; loopcnt++) {
277         if (st != pa_stream_get_state(paStream)) {
278             st = pa_stream_get_state(paStream);
279
280             ICO_DBG("TURN(%6d)_", loopcnt);
281
282             switch (pa_stream_get_state(paStream)) {
283             case PA_STREAM_UNCONNECTED:
284                 ICO_DBG("PA_STREAM_UNCONNECTED");
285                 break;
286             case PA_STREAM_CREATING:
287                 ICO_DBG("PA_STREAM_CREATING");
288                 break;
289             case PA_STREAM_READY:
290                 ICO_DBG("PA_STREAM_READY");
291                 break;
292             case PA_STREAM_FAILED:
293                 ICO_DBG("PA_STREAM_FAILED");
294                 break;
295             case PA_STREAM_TERMINATED:
296                 ICO_DBG("PA_STREAM_TERMINATED");
297                 break;
298             }
299         }
300
301         if (time(NULL) != prevT) {
302             prevT = time(NULL);
303         }
304
305         if (PA_STREAM_READY == pa_stream_get_state(paStream)) {
306             const size_t writableSize = pa_stream_writable_size(paStream);
307             const size_t sizeRemain = wavFile.SizeInByte() - playBackPtr;
308             const size_t writeSize =
309                 (sizeRemain < writableSize ? sizeRemain : writableSize);
310
311             if (0 < writeSize) {
312                 pa_stream_write(paStream, wavFile.DataPointer() + playBackPtr,
313                                 writeSize, NULL, 0, PA_SEEK_RELATIVE);
314                 playBackPtr += writeSize;
315                 ICO_PRF("START_SOUND pa_stream_write()_%d", (int) writeSize);
316             }
317         }
318
319         if ((wavFile.SizeInByte() <= playBackPtr) &&
320             (0 <= pa_stream_get_underflow_index(paStream)) &&
321             (YSTRUE == checkForUnderflow)) {
322             ICO_DBG
323                 ("Underflow detected. (Probably the playback is done.)");
324             playBackPtr = 0;
325
326             if (0 != strcmp(repeat_flg, "ON")) {
327                 break;
328             }
329         }
330         pa_mainloop_iterate(paMainLoop, 0, NULL);
331         usleep(500);
332     }
333
334     ICO_DBG("STREAM is END.");
335
336     pa_stream_disconnect(paStream);
337     ICO_PRF("STOP_SOUND pa_stream_disconnect()");
338
339     pa_stream_unref(paStream);
340     ICO_DBG("pa_stream_unref()");
341
342     ICO_DBG("leave mainloop");
343
344     if (NULL != cvolume) {
345         free(cvolume);
346     }
347
348     pa_context_disconnect(paContext);
349     ICO_DBG("pa_context_disconnect()");
350
351     pa_context_unref(paContext);
352     ICO_DBG("pa_context_unref()");
353
354     pa_mainloop_free(paMainLoop);
355     ICO_DBG("pa_mainloop_free()");
356
357     ICO_DBG("The End");
358
359     return 0;
360 }