Fix for internal bug.
[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
26 #include <pulse/mainloop.h>
27 #include <pulse/context.h>
28 #include <pulse/stream.h>
29 #include <pulse/error.h>
30
31 #include "soundsample_yswavfile.h"
32
33 //#include "app_log.h"
34 #include "ico_apf_log.h"
35 #include "soundsample.h"
36
37 #define ICO_PA_STREAM_PAUSE  (1)
38 #define ICO_PA_STREAM_RESUME (0)
39
40 extern "C"
41 {
42     int pulse_main(struct audio_config_t *audio_config, int filedes);
43 }
44
45 static int ExitFlg;
46 static int ReadFiledes;
47 #define REPEAT_FLG 1            /* ON:0 ,OFF:1 */
48
49 static YSRESULT YsPulseAudioWaitForConnectionEstablished(pa_context *
50                                                          paContext,
51                                                          pa_mainloop *
52                                                          paMainLoop,
53                                                          time_t timeOut)
54 {
55     time_t timeLimit = time(NULL) + timeOut;
56     while (timeLimit >= time(NULL)) {
57         pa_mainloop_iterate(paMainLoop, 0, NULL);
58         if (PA_CONTEXT_READY == pa_context_get_state(paContext)) {
59             return YSOK;
60         }
61     }
62     return YSERR;
63 }
64
65 static void event_input_callback(pa_mainloop_api *a, pa_io_event *e, int fd,
66                                  pa_io_event_flags_t f, void *userdata)
67 {
68
69     uim_debug("event_input_callback: Enter");
70
71     char buff[255];
72     memset(buff, 0x00, sizeof(buff));
73
74     /* From a pipe to reading */
75     read(ReadFiledes, buff, sizeof(buff));
76     uim_debug("buff :%s", buff);
77
78     switch (atoi(buff)) {
79     case STOP_REQ:
80         uim_debug("Stop directions reception");
81         ExitFlg = 1;
82         break;
83
84     case PAUSE_REQ:
85         uim_debug("Pause directions reception");
86
87         if (0 == pa_stream_is_corked((pa_stream *) userdata)) {
88             pa_stream_cork((pa_stream *) userdata, ICO_PA_STREAM_PAUSE, NULL,
89                            NULL);
90             uim_debug("pa_stream_cork(PAUSE)");
91             sleep(2);
92             uim_debug("sleep end");
93         }
94         else {
95             pa_stream_cork((pa_stream *) userdata, ICO_PA_STREAM_RESUME, NULL,
96                            NULL);
97             uim_debug("pa_stream_cork(RESUME)");
98             sleep(2);
99             uim_debug("sleep end");
100         }
101         break;
102
103     default:
104         uim_debug("Err Reception range outside");
105         break;
106     }
107
108     uim_debug("event_input_callback: Leave");
109 }
110
111 int pulse_main(struct audio_config_t *audio_config, int filedes)
112 {
113     char *server_ip = NULL;
114     char *device_name = NULL;
115     int volume_set = -1;
116     int volume_set2 = -1;
117     char *app_name = NULL;
118     char *stream_name = NULL;
119
120     pa_cvolume *cvolume = NULL;
121
122     char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
123     pa_channel_map cmap;
124
125     YsWavFile wavFile;
126
127     ReadFiledes = filedes;
128     ExitFlg = 0;
129
130     if (audio_config == NULL) {
131         uim_debug("Param Err");
132         return -1;
133     }
134
135     if (YSOK != wavFile.LoadWav(audio_config->wavfile_path)) {
136 //        fprintf(stderr, "Cannot open wave file.\n");
137         uim_debug("Cannot open wave file.");
138         return -1;
139     }
140
141     if (audio_config->volume1 != -1) {
142         cvolume = (pa_cvolume *) malloc(sizeof(pa_cvolume));
143     }
144     else {
145         cvolume = NULL;
146     }
147
148     server_ip = audio_config->server_ip;
149     device_name = audio_config->device_name;
150     volume_set = audio_config->volume1;
151     volume_set2 = audio_config->volume2;
152     app_name = audio_config->app_name;
153     stream_name = audio_config->stream_name;
154
155     uim_debug("Before Resampling:");
156     uim_debug("Bit per sample: %d", wavFile.BitPerSample());
157     uim_debug("Stereo: %d", wavFile.Stereo());
158     uim_debug("Playback Rate: %d", wavFile.PlayBackRate());
159     uim_debug("Signed: %d", wavFile.IsSigned());
160
161     wavFile.ConvertTo16Bit();
162     wavFile.ConvertToSigned();
163 //    wavFile.ConvertToStereo();
164     wavFile.Resample(44100);
165 //    wavFile.ConvertToMono();
166
167     uim_debug("After Resampling:");
168     uim_debug("Bit per sample: %d", wavFile.BitPerSample());
169     uim_debug("Stereo: %d", wavFile.Stereo());
170     uim_debug("Playback Rate: %d", wavFile.PlayBackRate());
171     uim_debug("Signed: %d", wavFile.IsSigned());
172
173     pa_mainloop *paMainLoop = pa_mainloop_new();
174     if (NULL == paMainLoop) {
175 //        fprintf(stderr,"Cannot create main loop.\n");
176         uim_debug("Cannot create main loop.");
177         return -1;
178     }
179     uim_debug("pa_mainloop_new()");
180
181     pa_context *paContext = pa_context_new(pa_mainloop_get_api(paMainLoop),
182                                            app_name);
183     if (NULL == paContext) {
184 //        fprintf(stderr,"Cannot create context.\n");
185         uim_debug("Cannot create context.");
186         return -1;
187     }
188     uim_debug("pa_context_new()");
189
190     // pa_context_set_state_callback(paContext,YsPulseAudioConnectionCallBack,NULL);
191     pa_context_connect(paContext, server_ip, (pa_context_flags_t) 0, NULL);
192     uim_debug("pa_context_connect()");
193
194     YsPulseAudioWaitForConnectionEstablished(paContext, paMainLoop, 5);
195
196     pa_sample_format_t format = PA_SAMPLE_U8;
197     switch (wavFile.BitPerSample()) {
198     case 8:
199         if (YSTRUE == wavFile.IsSigned()) {
200             wavFile.ConvertToUnsigned();
201         }
202         format = PA_SAMPLE_U8;
203         break;
204     case 16:
205         if (YSTRUE != wavFile.IsSigned()) {
206             wavFile.ConvertToSigned();
207         }
208         format = PA_SAMPLE_S16LE;
209         break;
210     }
211     const int rate = wavFile.PlayBackRate();
212     const int nChannel = (YSTRUE == wavFile.Stereo()? 2 : 1);
213
214     const pa_sample_spec ss = {
215         format,
216         rate,
217         nChannel
218     };
219
220     pa_channel_map_init_auto(&cmap, nChannel, PA_CHANNEL_MAP_ALSA);
221     uim_debug("pa_channel_map_init_auto()");
222     uim_debug("map: <%s>", pa_channel_map_snprint(cm, sizeof(cm), &cmap));
223
224     if (NULL != cvolume) {
225 //        int i = 0;
226         unsigned int i = 0;
227         for (i = 0; i < PA_CHANNELS_MAX; i++) {
228             if (1 == i) {
229                 if (-1 != volume_set2) {
230                     cvolume->values[i] = volume_set2;
231                 }
232             }
233             else {
234                 cvolume->values[i] = volume_set;
235             }
236             uim_debug("volume[%d]_%d", i, cvolume->values[i]);
237         }
238         cvolume->channels = nChannel;
239     }
240
241     unsigned int playBackPtr = 0;
242     YSBOOL checkForUnderflow = YSTRUE;
243 //    time_t t0 = time(NULL);
244     time_t prevT = time(NULL) - 1;
245
246     uim_debug("enter mainloop");
247     pa_stream *paStream;
248     int loopcnt;
249     static pa_io_event *stdio_event = NULL;
250     static pa_mainloop_api *mainloop_api = pa_mainloop_get_api(paMainLoop);
251
252     paStream = pa_stream_new(paContext, stream_name, &ss, &cmap);
253     if (NULL != paStream) {
254         uim_debug("Stream created!  Getting there!");
255     }
256     else {
257         uim_debug("Stream created : NG");
258         ExitFlg = 1;
259     }
260
261     uim_debug("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         uim_debug("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     uim_debug("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             uim_debug("TURN(%6d)_", loopcnt);
281
282             switch (pa_stream_get_state(paStream)) {
283             case PA_STREAM_UNCONNECTED:
284                 uim_debug("PA_STREAM_UNCONNECTED");
285                 break;
286             case PA_STREAM_CREATING:
287                 uim_debug("PA_STREAM_CREATING");
288                 break;
289             case PA_STREAM_READY:
290                 uim_debug("PA_STREAM_READY");
291                 break;
292             case PA_STREAM_FAILED:
293                 uim_debug("PA_STREAM_FAILED");
294                 break;
295             case PA_STREAM_TERMINATED:
296                 uim_debug("PA_STREAM_TERMINATED");
297                 break;
298             }
299         }
300
301         if (time(NULL) != prevT) {
302 /*          uim_debug("Ping..."); */
303             prevT = time(NULL);
304         }
305
306         if (PA_STREAM_READY == pa_stream_get_state(paStream)) {
307             const size_t writableSize = pa_stream_writable_size(paStream);
308             const size_t sizeRemain = wavFile.SizeInByte() - playBackPtr;
309             const size_t writeSize =
310                 (sizeRemain < writableSize ? sizeRemain : writableSize);
311
312             if (0 < writeSize) {
313                 pa_stream_write(paStream, wavFile.DataPointer() + playBackPtr,
314                                 writeSize, NULL, 0, PA_SEEK_RELATIVE);
315                 playBackPtr += writeSize;
316                 uim_debug("pa_stream_write()_%d", (int) writeSize);
317             }
318         }
319
320         if ((wavFile.SizeInByte() <= playBackPtr) &&
321             (0 <= pa_stream_get_underflow_index(paStream)) &&
322             (YSTRUE == checkForUnderflow)) {
323             uim_debug
324                 ("Underflow detected. (Probably the playback is done.)");
325             playBackPtr = 0;
326 #if REPEAT_FLG
327             break;
328 #endif
329         }
330         pa_mainloop_iterate(paMainLoop, 0, NULL);
331     }
332
333     uim_debug("STREAM is END.");
334
335     pa_stream_disconnect(paStream);
336     uim_debug("pa_stream_disconnect()");
337
338     pa_stream_unref(paStream);
339     uim_debug("pa_stream_unref()");
340 //  sleep(1);
341
342     uim_debug("leave mainloop");
343
344     if (NULL != cvolume) {
345         free(cvolume);
346     }
347
348     pa_context_disconnect(paContext);
349     uim_debug("pa_context_disconnect()");
350
351     pa_context_unref(paContext);
352     uim_debug("pa_context_unref()");
353
354     pa_mainloop_free(paMainLoop);
355     uim_debug("pa_mainloop_free()");
356
357     uim_debug("The End");
358
359     return 0;
360 }