1 /* 2 * Copyright (C) 2022 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.pandora 18 19 import android.content.Context 20 import android.content.Intent 21 import android.media.* 22 import android.support.v4.media.session.PlaybackStateCompat.SHUFFLE_MODE_ALL 23 import android.support.v4.media.session.PlaybackStateCompat.SHUFFLE_MODE_GROUP 24 import android.support.v4.media.session.PlaybackStateCompat.SHUFFLE_MODE_NONE 25 import com.google.protobuf.Empty 26 import io.grpc.stub.StreamObserver 27 import java.io.Closeable 28 import kotlinx.coroutines.CoroutineScope 29 import kotlinx.coroutines.Dispatchers 30 import kotlinx.coroutines.cancel 31 import pandora.MediaPlayerGrpc.MediaPlayerImplBase 32 import pandora.MediaPlayerProto.* 33 import pandora.MediaPlayerProto.GetShuffleModeResponse 34 import pandora.MediaPlayerProto.SetShuffleModeRequest 35 import pandora.MediaPlayerProto.ShuffleMode 36 37 @kotlinx.coroutines.ExperimentalCoroutinesApi 38 class MediaPlayer(val context: Context) : MediaPlayerImplBase(), Closeable { 39 private val TAG = "PandoraMediaPlayer" 40 41 private val scope: CoroutineScope 42 43 init { 44 // Init the CoroutineScope 45 scope = CoroutineScope(Dispatchers.Default.limitedParallelism(1)) 46 if (!MediaPlayerBrowserService.isInitialized()) { 47 context.startService(Intent(context, MediaPlayerBrowserService::class.java)) 48 } 49 } 50 playnull51 override fun play(request: Empty, responseObserver: StreamObserver<Empty>) { 52 grpcUnary<Empty>(scope, responseObserver) { 53 MediaPlayerBrowserService.instance.play() 54 Empty.getDefaultInstance() 55 } 56 } 57 stopnull58 override fun stop(request: Empty, responseObserver: StreamObserver<Empty>) { 59 grpcUnary<Empty>(scope, responseObserver) { 60 MediaPlayerBrowserService.instance.stop() 61 Empty.getDefaultInstance() 62 } 63 } 64 pausenull65 override fun pause(request: Empty, responseObserver: StreamObserver<Empty>) { 66 grpcUnary<Empty>(scope, responseObserver) { 67 MediaPlayerBrowserService.instance.pause() 68 Empty.getDefaultInstance() 69 } 70 } 71 rewindnull72 override fun rewind(request: Empty, responseObserver: StreamObserver<Empty>) { 73 grpcUnary<Empty>(scope, responseObserver) { 74 MediaPlayerBrowserService.instance.rewind() 75 Empty.getDefaultInstance() 76 } 77 } 78 fastForwardnull79 override fun fastForward(request: Empty, responseObserver: StreamObserver<Empty>) { 80 grpcUnary<Empty>(scope, responseObserver) { 81 MediaPlayerBrowserService.instance.fastForward() 82 Empty.getDefaultInstance() 83 } 84 } 85 forwardnull86 override fun forward(request: Empty, responseObserver: StreamObserver<Empty>) { 87 grpcUnary<Empty>(scope, responseObserver) { 88 MediaPlayerBrowserService.instance.forward() 89 Empty.getDefaultInstance() 90 } 91 } 92 backwardnull93 override fun backward(request: Empty, responseObserver: StreamObserver<Empty>) { 94 grpcUnary<Empty>(scope, responseObserver) { 95 MediaPlayerBrowserService.instance.backward() 96 Empty.getDefaultInstance() 97 } 98 } 99 setLargeMetadatanull100 override fun setLargeMetadata(request: Empty, responseObserver: StreamObserver<Empty>) { 101 grpcUnary<Empty>(scope, responseObserver) { 102 MediaPlayerBrowserService.instance.setLargeMetadata() 103 Empty.getDefaultInstance() 104 } 105 } 106 updateQueuenull107 override fun updateQueue(request: Empty, responseObserver: StreamObserver<Empty>) { 108 grpcUnary<Empty>(scope, responseObserver) { 109 MediaPlayerBrowserService.instance.updateQueue() 110 Empty.getDefaultInstance() 111 } 112 } 113 getShuffleModenull114 override fun getShuffleMode( 115 request: Empty, 116 responseObserver: StreamObserver<GetShuffleModeResponse> 117 ) { 118 grpcUnary(scope, responseObserver) { 119 val mode: Int = MediaPlayerBrowserService.instance.getShuffleMode() 120 val shuffleMode = 121 when (mode) { 122 SHUFFLE_MODE_NONE -> ShuffleMode.NONE 123 SHUFFLE_MODE_ALL -> ShuffleMode.ALL 124 SHUFFLE_MODE_GROUP -> ShuffleMode.GROUP 125 else -> ShuffleMode.NONE 126 } 127 GetShuffleModeResponse.newBuilder().setMode(shuffleMode).build() 128 } 129 } 130 setShuffleModenull131 override fun setShuffleMode( 132 request: SetShuffleModeRequest, 133 responseObserver: StreamObserver<Empty> 134 ) { 135 grpcUnary(scope, responseObserver) { 136 when (request.mode!!) { 137 ShuffleMode.NONE -> 138 MediaPlayerBrowserService.instance.setShuffleMode(SHUFFLE_MODE_NONE) 139 ShuffleMode.ALL -> 140 MediaPlayerBrowserService.instance.setShuffleMode(SHUFFLE_MODE_ALL) 141 ShuffleMode.GROUP -> 142 MediaPlayerBrowserService.instance.setShuffleMode(SHUFFLE_MODE_GROUP) 143 else -> MediaPlayerBrowserService.instance.setShuffleMode(SHUFFLE_MODE_NONE) 144 } 145 Empty.getDefaultInstance() 146 } 147 } 148 startTestPlaybacknull149 override fun startTestPlayback(request: Empty, responseObserver: StreamObserver<Empty>) { 150 grpcUnary<Empty>(scope, responseObserver) { 151 MediaPlayerBrowserService.instance.startTestPlayback() 152 Empty.getDefaultInstance() 153 } 154 } 155 stopTestPlaybacknull156 override fun stopTestPlayback(request: Empty, responseObserver: StreamObserver<Empty>) { 157 grpcUnary<Empty>(scope, responseObserver) { 158 MediaPlayerBrowserService.instance.stopTestPlayback() 159 Empty.getDefaultInstance() 160 } 161 } 162 closenull163 override fun close() { 164 // Deinit the CoroutineScope 165 scope.cancel() 166 } 167 } 168