1/*
2**
3** Copyright 2008, The Android Open Source Project
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#include <arpa/inet.h>
19#include <stdint.h>
20#include <sys/types.h>
21
22#include <binder/Parcel.h>
23
24#include <media/IMediaHTTPService.h>
25#include <media/IMediaPlayer.h>
26#include <media/IStreamSource.h>
27
28#include <gui/IGraphicBufferProducer.h>
29#include <utils/String8.h>
30
31namespace android {
32
33enum {
34    DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
35    SET_DATA_SOURCE_URL,
36    SET_DATA_SOURCE_FD,
37    SET_DATA_SOURCE_STREAM,
38    PREPARE_ASYNC,
39    START,
40    STOP,
41    IS_PLAYING,
42    PAUSE,
43    SEEK_TO,
44    GET_CURRENT_POSITION,
45    GET_DURATION,
46    RESET,
47    SET_AUDIO_STREAM_TYPE,
48    SET_LOOPING,
49    SET_VOLUME,
50    INVOKE,
51    SET_METADATA_FILTER,
52    GET_METADATA,
53    SET_AUX_EFFECT_SEND_LEVEL,
54    ATTACH_AUX_EFFECT,
55    SET_VIDEO_SURFACETEXTURE,
56    SET_PARAMETER,
57    GET_PARAMETER,
58    SET_RETRANSMIT_ENDPOINT,
59    GET_RETRANSMIT_ENDPOINT,
60    SET_NEXT_PLAYER,
61};
62
63class BpMediaPlayer: public BpInterface<IMediaPlayer>
64{
65public:
66    BpMediaPlayer(const sp<IBinder>& impl)
67        : BpInterface<IMediaPlayer>(impl)
68    {
69    }
70
71    // disconnect from media player service
72    void disconnect()
73    {
74        Parcel data, reply;
75        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
76        remote()->transact(DISCONNECT, data, &reply);
77    }
78
79    status_t setDataSource(
80            const sp<IMediaHTTPService> &httpService,
81            const char* url,
82            const KeyedVector<String8, String8>* headers)
83    {
84        Parcel data, reply;
85        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
86        data.writeInt32(httpService != NULL);
87        if (httpService != NULL) {
88            data.writeStrongBinder(httpService->asBinder());
89        }
90        data.writeCString(url);
91        if (headers == NULL) {
92            data.writeInt32(0);
93        } else {
94            // serialize the headers
95            data.writeInt32(headers->size());
96            for (size_t i = 0; i < headers->size(); ++i) {
97                data.writeString8(headers->keyAt(i));
98                data.writeString8(headers->valueAt(i));
99            }
100        }
101        remote()->transact(SET_DATA_SOURCE_URL, data, &reply);
102        return reply.readInt32();
103    }
104
105    status_t setDataSource(int fd, int64_t offset, int64_t length) {
106        Parcel data, reply;
107        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
108        data.writeFileDescriptor(fd);
109        data.writeInt64(offset);
110        data.writeInt64(length);
111        remote()->transact(SET_DATA_SOURCE_FD, data, &reply);
112        return reply.readInt32();
113    }
114
115    status_t setDataSource(const sp<IStreamSource> &source) {
116        Parcel data, reply;
117        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
118        data.writeStrongBinder(source->asBinder());
119        remote()->transact(SET_DATA_SOURCE_STREAM, data, &reply);
120        return reply.readInt32();
121    }
122
123    // pass the buffered IGraphicBufferProducer to the media player service
124    status_t setVideoSurfaceTexture(const sp<IGraphicBufferProducer>& bufferProducer)
125    {
126        Parcel data, reply;
127        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
128        sp<IBinder> b(bufferProducer->asBinder());
129        data.writeStrongBinder(b);
130        remote()->transact(SET_VIDEO_SURFACETEXTURE, data, &reply);
131        return reply.readInt32();
132    }
133
134    status_t prepareAsync()
135    {
136        Parcel data, reply;
137        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
138        remote()->transact(PREPARE_ASYNC, data, &reply);
139        return reply.readInt32();
140    }
141
142    status_t start()
143    {
144        Parcel data, reply;
145        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
146        remote()->transact(START, data, &reply);
147        return reply.readInt32();
148    }
149
150    status_t stop()
151    {
152        Parcel data, reply;
153        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
154        remote()->transact(STOP, data, &reply);
155        return reply.readInt32();
156    }
157
158    status_t isPlaying(bool* state)
159    {
160        Parcel data, reply;
161        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
162        remote()->transact(IS_PLAYING, data, &reply);
163        *state = reply.readInt32();
164        return reply.readInt32();
165    }
166
167    status_t pause()
168    {
169        Parcel data, reply;
170        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
171        remote()->transact(PAUSE, data, &reply);
172        return reply.readInt32();
173    }
174
175    status_t seekTo(int msec)
176    {
177        Parcel data, reply;
178        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
179        data.writeInt32(msec);
180        remote()->transact(SEEK_TO, data, &reply);
181        return reply.readInt32();
182    }
183
184    status_t getCurrentPosition(int* msec)
185    {
186        Parcel data, reply;
187        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
188        remote()->transact(GET_CURRENT_POSITION, data, &reply);
189        *msec = reply.readInt32();
190        return reply.readInt32();
191    }
192
193    status_t getDuration(int* msec)
194    {
195        Parcel data, reply;
196        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
197        remote()->transact(GET_DURATION, data, &reply);
198        *msec = reply.readInt32();
199        return reply.readInt32();
200    }
201
202    status_t reset()
203    {
204        Parcel data, reply;
205        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
206        remote()->transact(RESET, data, &reply);
207        return reply.readInt32();
208    }
209
210    status_t setAudioStreamType(audio_stream_type_t stream)
211    {
212        Parcel data, reply;
213        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
214        data.writeInt32((int32_t) stream);
215        remote()->transact(SET_AUDIO_STREAM_TYPE, data, &reply);
216        return reply.readInt32();
217    }
218
219    status_t setLooping(int loop)
220    {
221        Parcel data, reply;
222        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
223        data.writeInt32(loop);
224        remote()->transact(SET_LOOPING, data, &reply);
225        return reply.readInt32();
226    }
227
228    status_t setVolume(float leftVolume, float rightVolume)
229    {
230        Parcel data, reply;
231        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
232        data.writeFloat(leftVolume);
233        data.writeFloat(rightVolume);
234        remote()->transact(SET_VOLUME, data, &reply);
235        return reply.readInt32();
236    }
237
238    status_t invoke(const Parcel& request, Parcel *reply)
239    {
240        // Avoid doing any extra copy. The interface descriptor should
241        // have been set by MediaPlayer.java.
242        return remote()->transact(INVOKE, request, reply);
243    }
244
245    status_t setMetadataFilter(const Parcel& request)
246    {
247        Parcel reply;
248        // Avoid doing any extra copy of the request. The interface
249        // descriptor should have been set by MediaPlayer.java.
250        remote()->transact(SET_METADATA_FILTER, request, &reply);
251        return reply.readInt32();
252    }
253
254    status_t getMetadata(bool update_only, bool apply_filter, Parcel *reply)
255    {
256        Parcel request;
257        request.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
258        // TODO: Burning 2 ints for 2 boolean. Should probably use flags in an int here.
259        request.writeInt32(update_only);
260        request.writeInt32(apply_filter);
261        remote()->transact(GET_METADATA, request, reply);
262        return reply->readInt32();
263    }
264
265    status_t setAuxEffectSendLevel(float level)
266    {
267        Parcel data, reply;
268        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
269        data.writeFloat(level);
270        remote()->transact(SET_AUX_EFFECT_SEND_LEVEL, data, &reply);
271        return reply.readInt32();
272    }
273
274    status_t attachAuxEffect(int effectId)
275    {
276        Parcel data, reply;
277        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
278        data.writeInt32(effectId);
279        remote()->transact(ATTACH_AUX_EFFECT, data, &reply);
280        return reply.readInt32();
281    }
282
283    status_t setParameter(int key, const Parcel& request)
284    {
285        Parcel data, reply;
286        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
287        data.writeInt32(key);
288        if (request.dataSize() > 0) {
289            data.appendFrom(const_cast<Parcel *>(&request), 0, request.dataSize());
290        }
291        remote()->transact(SET_PARAMETER, data, &reply);
292        return reply.readInt32();
293    }
294
295    status_t getParameter(int key, Parcel *reply)
296    {
297        Parcel data;
298        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
299        data.writeInt32(key);
300        return remote()->transact(GET_PARAMETER, data, reply);
301    }
302
303    status_t setRetransmitEndpoint(const struct sockaddr_in* endpoint)
304    {
305        Parcel data, reply;
306        status_t err;
307
308        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
309        if (NULL != endpoint) {
310            data.writeInt32(sizeof(*endpoint));
311            data.write(endpoint, sizeof(*endpoint));
312        } else {
313            data.writeInt32(0);
314        }
315
316        err = remote()->transact(SET_RETRANSMIT_ENDPOINT, data, &reply);
317        if (OK != err) {
318            return err;
319        }
320        return reply.readInt32();
321    }
322
323    status_t setNextPlayer(const sp<IMediaPlayer>& player) {
324        Parcel data, reply;
325        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
326        sp<IBinder> b(player->asBinder());
327        data.writeStrongBinder(b);
328        remote()->transact(SET_NEXT_PLAYER, data, &reply);
329        return reply.readInt32();
330    }
331
332    status_t getRetransmitEndpoint(struct sockaddr_in* endpoint)
333    {
334        Parcel data, reply;
335        status_t err;
336
337        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
338        err = remote()->transact(GET_RETRANSMIT_ENDPOINT, data, &reply);
339
340        if ((OK != err) || (OK != (err = reply.readInt32()))) {
341            return err;
342        }
343
344        data.read(endpoint, sizeof(*endpoint));
345
346        return err;
347    }
348};
349
350IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");
351
352// ----------------------------------------------------------------------
353
354status_t BnMediaPlayer::onTransact(
355    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
356{
357    switch (code) {
358        case DISCONNECT: {
359            CHECK_INTERFACE(IMediaPlayer, data, reply);
360            disconnect();
361            return NO_ERROR;
362        } break;
363        case SET_DATA_SOURCE_URL: {
364            CHECK_INTERFACE(IMediaPlayer, data, reply);
365
366            sp<IMediaHTTPService> httpService;
367            if (data.readInt32()) {
368                httpService =
369                    interface_cast<IMediaHTTPService>(data.readStrongBinder());
370            }
371
372            const char* url = data.readCString();
373            KeyedVector<String8, String8> headers;
374            int32_t numHeaders = data.readInt32();
375            for (int i = 0; i < numHeaders; ++i) {
376                String8 key = data.readString8();
377                String8 value = data.readString8();
378                headers.add(key, value);
379            }
380            reply->writeInt32(setDataSource(
381                        httpService, url, numHeaders > 0 ? &headers : NULL));
382            return NO_ERROR;
383        } break;
384        case SET_DATA_SOURCE_FD: {
385            CHECK_INTERFACE(IMediaPlayer, data, reply);
386            int fd = data.readFileDescriptor();
387            int64_t offset = data.readInt64();
388            int64_t length = data.readInt64();
389            reply->writeInt32(setDataSource(fd, offset, length));
390            return NO_ERROR;
391        }
392        case SET_DATA_SOURCE_STREAM: {
393            CHECK_INTERFACE(IMediaPlayer, data, reply);
394            sp<IStreamSource> source =
395                interface_cast<IStreamSource>(data.readStrongBinder());
396            reply->writeInt32(setDataSource(source));
397            return NO_ERROR;
398        }
399        case SET_VIDEO_SURFACETEXTURE: {
400            CHECK_INTERFACE(IMediaPlayer, data, reply);
401            sp<IGraphicBufferProducer> bufferProducer =
402                    interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
403            reply->writeInt32(setVideoSurfaceTexture(bufferProducer));
404            return NO_ERROR;
405        } break;
406        case PREPARE_ASYNC: {
407            CHECK_INTERFACE(IMediaPlayer, data, reply);
408            reply->writeInt32(prepareAsync());
409            return NO_ERROR;
410        } break;
411        case START: {
412            CHECK_INTERFACE(IMediaPlayer, data, reply);
413            reply->writeInt32(start());
414            return NO_ERROR;
415        } break;
416        case STOP: {
417            CHECK_INTERFACE(IMediaPlayer, data, reply);
418            reply->writeInt32(stop());
419            return NO_ERROR;
420        } break;
421        case IS_PLAYING: {
422            CHECK_INTERFACE(IMediaPlayer, data, reply);
423            bool state;
424            status_t ret = isPlaying(&state);
425            reply->writeInt32(state);
426            reply->writeInt32(ret);
427            return NO_ERROR;
428        } break;
429        case PAUSE: {
430            CHECK_INTERFACE(IMediaPlayer, data, reply);
431            reply->writeInt32(pause());
432            return NO_ERROR;
433        } break;
434        case SEEK_TO: {
435            CHECK_INTERFACE(IMediaPlayer, data, reply);
436            reply->writeInt32(seekTo(data.readInt32()));
437            return NO_ERROR;
438        } break;
439        case GET_CURRENT_POSITION: {
440            CHECK_INTERFACE(IMediaPlayer, data, reply);
441            int msec;
442            status_t ret = getCurrentPosition(&msec);
443            reply->writeInt32(msec);
444            reply->writeInt32(ret);
445            return NO_ERROR;
446        } break;
447        case GET_DURATION: {
448            CHECK_INTERFACE(IMediaPlayer, data, reply);
449            int msec;
450            status_t ret = getDuration(&msec);
451            reply->writeInt32(msec);
452            reply->writeInt32(ret);
453            return NO_ERROR;
454        } break;
455        case RESET: {
456            CHECK_INTERFACE(IMediaPlayer, data, reply);
457            reply->writeInt32(reset());
458            return NO_ERROR;
459        } break;
460        case SET_AUDIO_STREAM_TYPE: {
461            CHECK_INTERFACE(IMediaPlayer, data, reply);
462            reply->writeInt32(setAudioStreamType((audio_stream_type_t) data.readInt32()));
463            return NO_ERROR;
464        } break;
465        case SET_LOOPING: {
466            CHECK_INTERFACE(IMediaPlayer, data, reply);
467            reply->writeInt32(setLooping(data.readInt32()));
468            return NO_ERROR;
469        } break;
470        case SET_VOLUME: {
471            CHECK_INTERFACE(IMediaPlayer, data, reply);
472            float leftVolume = data.readFloat();
473            float rightVolume = data.readFloat();
474            reply->writeInt32(setVolume(leftVolume, rightVolume));
475            return NO_ERROR;
476        } break;
477        case INVOKE: {
478            CHECK_INTERFACE(IMediaPlayer, data, reply);
479            status_t result = invoke(data, reply);
480            return result;
481        } break;
482        case SET_METADATA_FILTER: {
483            CHECK_INTERFACE(IMediaPlayer, data, reply);
484            reply->writeInt32(setMetadataFilter(data));
485            return NO_ERROR;
486        } break;
487        case GET_METADATA: {
488            CHECK_INTERFACE(IMediaPlayer, data, reply);
489            bool update_only = static_cast<bool>(data.readInt32());
490            bool apply_filter = static_cast<bool>(data.readInt32());
491            const status_t retcode = getMetadata(update_only, apply_filter, reply);
492            reply->setDataPosition(0);
493            reply->writeInt32(retcode);
494            reply->setDataPosition(0);
495            return NO_ERROR;
496        } break;
497        case SET_AUX_EFFECT_SEND_LEVEL: {
498            CHECK_INTERFACE(IMediaPlayer, data, reply);
499            reply->writeInt32(setAuxEffectSendLevel(data.readFloat()));
500            return NO_ERROR;
501        } break;
502        case ATTACH_AUX_EFFECT: {
503            CHECK_INTERFACE(IMediaPlayer, data, reply);
504            reply->writeInt32(attachAuxEffect(data.readInt32()));
505            return NO_ERROR;
506        } break;
507        case SET_PARAMETER: {
508            CHECK_INTERFACE(IMediaPlayer, data, reply);
509            int key = data.readInt32();
510
511            Parcel request;
512            if (data.dataAvail() > 0) {
513                request.appendFrom(
514                        const_cast<Parcel *>(&data), data.dataPosition(), data.dataAvail());
515            }
516            request.setDataPosition(0);
517            reply->writeInt32(setParameter(key, request));
518            return NO_ERROR;
519        } break;
520        case GET_PARAMETER: {
521            CHECK_INTERFACE(IMediaPlayer, data, reply);
522            return getParameter(data.readInt32(), reply);
523        } break;
524        case SET_RETRANSMIT_ENDPOINT: {
525            CHECK_INTERFACE(IMediaPlayer, data, reply);
526
527            struct sockaddr_in endpoint;
528            int amt = data.readInt32();
529            if (amt == sizeof(endpoint)) {
530                data.read(&endpoint, sizeof(struct sockaddr_in));
531                reply->writeInt32(setRetransmitEndpoint(&endpoint));
532            } else {
533                reply->writeInt32(setRetransmitEndpoint(NULL));
534            }
535
536            return NO_ERROR;
537        } break;
538        case GET_RETRANSMIT_ENDPOINT: {
539            CHECK_INTERFACE(IMediaPlayer, data, reply);
540
541            struct sockaddr_in endpoint;
542            status_t res = getRetransmitEndpoint(&endpoint);
543
544            reply->writeInt32(res);
545            reply->write(&endpoint, sizeof(endpoint));
546
547            return NO_ERROR;
548        } break;
549        case SET_NEXT_PLAYER: {
550            CHECK_INTERFACE(IMediaPlayer, data, reply);
551            reply->writeInt32(setNextPlayer(interface_cast<IMediaPlayer>(data.readStrongBinder())));
552
553            return NO_ERROR;
554        } break;
555        default:
556            return BBinder::onTransact(code, data, reply, flags);
557    }
558}
559
560// ----------------------------------------------------------------------------
561
562}; // namespace android
563