1 /*
2  * Copyright (C) 2020 The Android Open Source Project
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 package com.android.server.musicrecognition;
18 
19 import android.annotation.NonNull;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.media.AudioFormat;
23 import android.media.musicrecognition.IMusicRecognitionAttributionTagCallback;
24 import android.media.musicrecognition.IMusicRecognitionService;
25 import android.media.musicrecognition.MusicRecognitionService;
26 import android.os.IBinder;
27 import android.os.ParcelFileDescriptor;
28 import android.os.RemoteException;
29 import android.text.format.DateUtils;
30 
31 import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
32 import com.android.server.musicrecognition.MusicRecognitionManagerPerUserService.MusicRecognitionServiceCallback;
33 
34 import java.util.concurrent.CompletableFuture;
35 
36 
37 /** Remote connection to an instance of {@link MusicRecognitionService}. */
38 public class RemoteMusicRecognitionService extends
39         AbstractMultiplePendingRequestsRemoteService<RemoteMusicRecognitionService,
40                 IMusicRecognitionService> {
41 
42     // Maximum time allotted for the remote service to return a result. Up to 24s of audio plus
43     // time to fingerprint and make rpcs.
44     private static final long TIMEOUT_IDLE_BIND_MILLIS = 40 * DateUtils.SECOND_IN_MILLIS;
45 
46     // Allows the remote service to send back a result.
47     private final MusicRecognitionServiceCallback
48             mServerCallback;
49 
RemoteMusicRecognitionService(Context context, ComponentName serviceName, int userId, MusicRecognitionManagerPerUserService perUserService, MusicRecognitionServiceCallback callback, boolean bindInstantServiceAllowed, boolean verbose)50     public RemoteMusicRecognitionService(Context context, ComponentName serviceName,
51             int userId, MusicRecognitionManagerPerUserService perUserService,
52             MusicRecognitionServiceCallback callback,
53             boolean bindInstantServiceAllowed, boolean verbose) {
54         super(context, MusicRecognitionService.ACTION_MUSIC_SEARCH_LOOKUP, serviceName, userId,
55                 perUserService,
56                 context.getMainThreadHandler(),
57                 // Prevents the service from having its permissions stripped while in background.
58                 Context.BIND_INCLUDE_CAPABILITIES | (bindInstantServiceAllowed
59                         ? Context.BIND_ALLOW_INSTANT : 0), verbose,
60                 /* initialCapacity= */ 1);
61         mServerCallback = callback;
62     }
63 
64     @NonNull
65     @Override
getServiceInterface(@onNull IBinder service)66     protected IMusicRecognitionService getServiceInterface(@NonNull IBinder service) {
67         return IMusicRecognitionService.Stub.asInterface(service);
68     }
69 
70     @Override
getTimeoutIdleBindMillis()71     protected long getTimeoutIdleBindMillis() {
72         return TIMEOUT_IDLE_BIND_MILLIS;
73     }
74 
getServerCallback()75     MusicRecognitionServiceCallback getServerCallback() {
76         return mServerCallback;
77     }
78 
79     /**
80      * Required, but empty since we don't need to notify the callback implementation of the request
81      * results.
82      */
83     interface Callbacks extends VultureCallback<RemoteMusicRecognitionService> {}
84 
85     /**
86      * Sends the given descriptor to the app's {@link MusicRecognitionService} to read the
87      * audio.
88      */
onAudioStreamStarted(@onNull ParcelFileDescriptor fd, @NonNull AudioFormat audioFormat)89     public void onAudioStreamStarted(@NonNull ParcelFileDescriptor fd,
90             @NonNull AudioFormat audioFormat) {
91         scheduleAsyncRequest(
92                 binder -> binder.onAudioStreamStarted(fd, audioFormat, mServerCallback));
93     }
94 
95 
96     /**
97      * Returns the name of the <attribution> tag defined in the remote service's manifest.
98      */
getAttributionTag()99     public CompletableFuture<String> getAttributionTag() {
100         CompletableFuture<String> attributionTagFuture = new CompletableFuture<String>();
101         scheduleAsyncRequest(
102                 binder -> binder.getAttributionTag(
103                     new IMusicRecognitionAttributionTagCallback.Stub() {
104                         @Override
105                         public void onAttributionTag(String tag) throws RemoteException {
106                             attributionTagFuture.complete(tag);
107                         }
108                     }));
109         return attributionTagFuture;
110     }
111 }
112