Update Radio plugin, Media plugin
[src/app-framework-binder.git] / plugins / media / media-api.c
1 /*
2  * Copyright (C) 2016 "IoT.bzh"
3  * Author "Manuel Bachmann"
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #define _GNU_SOURCE
19 #include <json-c/json.h>
20
21 #include "media-api.h"
22 #include "media-rygel.h"
23
24 #include "afb-plugin.h"
25 #include "afb-req-itf.h"
26
27 json_object* _rygel_list (mediaCtxHandleT *);
28
29 /* ------ LOCAL HELPER FUNCTIONS --------- */
30
31 /* private client context creation ; default values */
32 static mediaCtxHandleT* initMediaCtx () {
33
34     mediaCtxHandleT *ctx;
35
36     ctx = malloc (sizeof(mediaCtxHandleT));
37     ctx->media_server = NULL;
38     ctx->index = 0;
39
40     return ctx;
41 }
42
43 /* ------ PUBLIC PLUGIN FUNCTIONS --------- */
44
45 static void init (struct afb_req request) {        /* AFB_SESSION_CHECK */
46
47     mediaCtxHandleT *ctx = (mediaCtxHandleT*) afb_req_context_get(request);
48     json_object *jresp;
49
50     /* create a private client context */
51     if (!ctx) {
52         ctx = initMediaCtx();
53         afb_req_context_set (request, ctx, free);
54     }
55
56     /* initialize server connection */
57     if (!ctx->media_server)
58       _rygel_init (ctx);
59
60     jresp = json_object_new_object ();
61     json_object_object_add (jresp, "init", json_object_new_string ("success"));
62     afb_req_success (request, jresp, "Media - Initialized");
63 }
64
65 static void list (struct afb_req request) {        /* AFB_SESSION_CHECK */
66
67     mediaCtxHandleT *ctx = (mediaCtxHandleT*) afb_req_context_get(request);
68     json_object *jresp;
69
70     jresp = _rygel_list (ctx);
71
72     if (!jresp) {
73       afb_req_fail (request, "failed", "no content found in media server");
74       return;
75     }
76
77     afb_req_success (request, jresp, "Media - Listed");
78 }
79
80 static void selecting (struct afb_req request) {   /* AFB_SESSION_CHECK */
81
82     mediaCtxHandleT *ctx = (mediaCtxHandleT*) afb_req_context_get(request);
83     const char *value = afb_req_value (request, "value");
84     json_object *jresp;
85     unsigned int index;
86     char index_str[5];
87
88     /* no "?value=" parameter : return current index */
89     if (!value) {
90         snprintf (index_str, sizeof(index_str), "%d", ctx->index);
91         jresp = json_object_new_object();
92         json_object_object_add (jresp, "index", json_object_new_string (index_str));
93     }
94
95     /* "?value=" parameter is negative */
96     else if (atoi(value) < 0) {
97         afb_req_fail (request, "failed", "chosen index cannot be negatuve");
98         return;
99     }
100
101     /* "?value=" parameter is positive */
102     else if (atoi(value) >= 0) {
103         index = (unsigned int) atoi(value);
104
105         if (!_rygel_select (ctx, index)) {
106           afb_req_fail (request, "failed", "chosen index superior to current media count");
107           return;
108         }
109
110         ctx->index = index;
111         jresp = json_object_new_object();
112         json_object_object_add (jresp, "index", json_object_new_string (value));
113     }
114     else
115         jresp = NULL;
116
117     afb_req_success (request, jresp, "Media - Listed");
118 }
119
120 static void play (struct afb_req request) {        /* AFB_SESSION_CHECK */
121
122     mediaCtxHandleT *ctx = (mediaCtxHandleT*) afb_req_context_get(request);
123     json_object *jresp;
124
125     if (!_rygel_do (ctx, PLAY, NULL)) {
126       afb_req_fail (request, "failed", "could not play chosen media");
127       return;
128     }
129
130     jresp = json_object_new_object ();
131     json_object_object_add (jresp, "play", json_object_new_string ("success"));
132     afb_req_success (request, jresp, "Media - Listed");
133 }
134
135 static void stop (struct afb_req request) {        /* AFB_SESSION_CHECK */
136
137     mediaCtxHandleT *ctx = (mediaCtxHandleT*) afb_req_context_get(request);
138     json_object *jresp;
139
140     if (!_rygel_do (ctx, STOP, NULL)) {
141       afb_req_fail (request, "failed", "could not stop chosen media");
142       return;
143     }
144
145     jresp = json_object_new_object ();
146     json_object_object_add (jresp, "stop", json_object_new_string ("success"));
147     afb_req_success (request, jresp, "Media - Stopped");
148 }
149
150 static void pausing (struct afb_req request) {     /* AFB_SESSION_CHECK */
151
152     mediaCtxHandleT *ctx = (mediaCtxHandleT*) afb_req_context_get(request);
153     json_object *jresp;
154
155     if (!_rygel_do (ctx, PAUSE, NULL)) {
156       afb_req_fail (request, "failed", "could not pause chosen media");
157       return;
158     }
159
160     jresp = json_object_new_object();
161     json_object_object_add (jresp, "pause", json_object_new_string ("success"));
162     afb_req_success (request, jresp, "Media - Paused");
163 }
164
165 static void seek (struct afb_req request) {        /* AFB_SESSION_CHECK */
166
167     mediaCtxHandleT *ctx = (mediaCtxHandleT*) afb_req_context_get(request);
168     const char *value = afb_req_value (request, "value");
169     json_object *jresp;
170
171     /* no "?value=" parameter : return error */
172     if (!value) {
173       afb_req_fail (request, "failed", "you must provide a time");
174       return;
175     }
176
177     if (!_rygel_do (ctx, SEEK, (char *)value)) {
178       afb_req_fail (request, "failed", "could not seek chosen media");
179       return;
180     }
181
182     jresp = json_object_new_object();
183     json_object_object_add (jresp, "seek", json_object_new_string ("success"));
184     afb_req_success (request, jresp, "Media - Sought");
185 }
186
187 #if 0
188 static void upload (AFB_request *request, AFB_PostItem *item) { /* AFB_SESSION_CHECK */
189
190     mediaCtxHandleT *ctx = (mediaCtxHandleT*) afb_req_context_get(request);
191     AFB_PostCtx *postFileCtx;
192     json_object *jresp;
193     char *path;
194
195     /* item is !NULL until transfer is complete */
196     if (item != NULL)
197       return getPostFile (request, item, "media");
198
199     /* target intermediary file path */
200     path = getPostPath (request);
201
202     if (!path)
203         fprintf (stderr, "Error encoutered during intermediary file transfer\n");
204
205     else if (!_rygel_upload (ctx, path)) {
206         request->errcode = MHD_HTTP_EXPECTATION_FAILED;
207         request->jresp = jsonNewMessage (AFB_FAIL, "Error when uploading file to media server... could not complete");
208     }
209
210     else {
211         request->errcode = MHD_HTTP_OK;
212         request->jresp = jsonNewMessage (AFB_SUCCESS, "upload=%s done", path);
213     }
214
215     /* finalizes file transfer */
216     return getPostFile (request, item, NULL);
217 }
218 #endif
219
220 static void ping (struct afb_req request) {         /* AFB_SESSION_NONE */
221     afb_req_success (request, NULL, "Media - Ping succeeded");
222 }
223
224
225 static const struct AFB_restapi pluginApis[]= {
226   {"init"   , AFB_SESSION_CHECK,  init       , "Media API - init"   },
227   {"list"   , AFB_SESSION_CHECK,  list       , "Media API - list"   },
228   {"select" , AFB_SESSION_CHECK,  selecting  , "Media API - select" },
229   {"play"   , AFB_SESSION_CHECK,  play       , "Media API - play"   },
230   {"stop"   , AFB_SESSION_CHECK,  stop       , "Media API - stop"   },
231   {"pause"  , AFB_SESSION_CHECK,  pausing    , "Media API - pause"  },
232   {"seek"   , AFB_SESSION_CHECK,  seek       , "Media API - seek"   },
233 //  {"upload" , AFB_SESSION_CHECK,  (AFB_apiCB)upload     , "Media API - upload" },
234   {"ping"   , AFB_SESSION_NONE,   ping       , "Media API - ping"   },
235   {NULL}
236 };
237
238 static const struct AFB_plugin pluginDesc = {
239     .type  = AFB_PLUGIN_JSON,
240     .info  = "Application Framework Binder - Media plugin",
241     .prefix  = "media",
242     .apis  = pluginApis
243 };
244
245 const struct AFB_plugin *pluginRegister (const struct AFB_interface *itf)
246 {
247         return &pluginDesc;
248 }