diff --git a/build/config/ios/rules.gni b/build/config/ios/rules.gni index 8902da070..92e4b0b96 100644 --- a/build/config/ios/rules.gni +++ b/build/config/ios/rules.gni @@ -145,7 +145,12 @@ template("ios_app") { bin_gen_target_name = target_name + "_bin" executable(bin_gen_target_name) { - libs = [ "UIKit.framework", "QuartzCore.framework", "OpenGLES.framework" ] + libs = [ + "UIKit.framework", + "AVFoundation.framework", + "QuartzCore.framework", + "OpenGLES.framework" + ] deps = invoker.deps output_name = app_name } diff --git a/sky/services/media/BUILD.gn b/sky/services/media/BUILD.gn index 9cc1afd24..f149bc26a 100644 --- a/sky/services/media/BUILD.gn +++ b/sky/services/media/BUILD.gn @@ -5,13 +5,11 @@ import("//mojo/public/tools/bindings/mojom.gni") group("media") { - testonly = true - deps = [ ":interfaces", ] - if (is_android) { + if (is_android || is_ios) { deps += [ ":media_lib" ] } } @@ -40,4 +38,20 @@ if (is_android) { ":interfaces_java", ] } +} else if (is_ios) { + source_set("media_lib") { + sources = [ + "ios/media_player_impl.h", + "ios/media_player_impl.mm", + "ios/media_service_impl.h", + "ios/media_service_impl.mm", + ] + + deps = [ + ":interfaces", + "//base:base", + "//mojo/common", + "//mojo/public/cpp/application", + ] + } } diff --git a/sky/services/media/ios/media_player_impl.h b/sky/services/media/ios/media_player_impl.h new file mode 100644 index 000000000..04bd5129e --- /dev/null +++ b/sky/services/media/ios/media_player_impl.h @@ -0,0 +1,54 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SKY_SERVICES_MEDIA_IOS_MEDIA_PLAYER_IMPL_H_ +#define SKY_SERVICES_MEDIA_IOS_MEDIA_PLAYER_IMPL_H_ + +#include "base/macros.h" +#include "mojo/public/cpp/application/interface_factory.h" +#include "mojo/public/cpp/bindings/strong_binding.h" +#include "sky/services/media/media.mojom.h" + +#if __OBJC__ +@class AudioClient; +#else // __OBJC__ +class AudioClient; +#endif // __OBJC__ + +namespace sky { +namespace services { +namespace media { + +class MediaPlayerImpl : public ::media::MediaPlayer { + public: + explicit MediaPlayerImpl( + mojo::InterfaceRequest<::media::MediaPlayer> request); + ~MediaPlayerImpl() override; + + void Prepare(mojo::ScopedDataPipeConsumerHandle data_source, + const ::media::MediaPlayer::PrepareCallback& callback) override; + void Start() override; + void Pause() override; + void SeekTo(uint32_t msec) override; + + private: + mojo::StrongBinding<::media::MediaPlayer> binding_; + AudioClient* audio_client_; + + void reset(); + + DISALLOW_COPY_AND_ASSIGN(MediaPlayerImpl); +}; + +class MediaPlayerFactory : public mojo::InterfaceFactory<::media::MediaPlayer> { + public: + void Create(mojo::ApplicationConnection* connection, + mojo::InterfaceRequest<::media::MediaPlayer> request) override; +}; + +} // namespace media +} // namespace services +} // namespace sky + +#endif // SKY_SERVICES_MEDIA_IOS_MEDIA_PLAYER_IMPL_H_ diff --git a/sky/services/media/ios/media_player_impl.mm b/sky/services/media/ios/media_player_impl.mm new file mode 100644 index 000000000..e8e9a8066 --- /dev/null +++ b/sky/services/media/ios/media_player_impl.mm @@ -0,0 +1,134 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/files/file_path.h" +#include "mojo/common/data_pipe_utils.h" +#include "sky/services/media/ios/media_player_impl.h" + +#import +#import + +@interface AudioClient : NSObject + +- (instancetype)initWithPath:(NSString*)path; + +- (BOOL)play; +- (void)pause; +- (BOOL)seekTo:(NSTimeInterval)interval; + ++ (NSString*)temporaryFilePath; + +@end + +@implementation AudioClient { + AVAudioPlayer* _player; +} + +- (instancetype)initWithPath:(NSString*)path { + self = [super init]; + + if (self) { + NSError* error = nil; + _player = + [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:path] + error:&error]; + + if (error != nil) { + NSLog(@"Could not initialize audio client: %@", + error.localizedDescription); + [self release]; + return nil; + } + } + + return self; +} + +- (BOOL)play { + return [_player play]; +} + +- (void)pause { + [_player pause]; +} + +- (BOOL)seekTo:(NSTimeInterval)interval { + return [_player playAtTime:_player.deviceCurrentTime + interval]; +} + ++ (NSString*)temporaryFilePath { + char* path = reinterpret_cast(calloc(256, sizeof(char))); + + snprintf(path, 256, "%smedia.XXXXXX", NSTemporaryDirectory().UTF8String); + path = mktemp(path); + + if (path == NULL) { + free(path); + return NULL; + } + + NSString* pathString = [NSString stringWithUTF8String:path]; + free(path); + + return pathString; +} + +- (void)dealloc { + [_player release]; + + [super dealloc]; +} + +@end + +namespace sky { +namespace services { +namespace media { + +MediaPlayerImpl::MediaPlayerImpl( + mojo::InterfaceRequest<::media::MediaPlayer> request) + : binding_(this, request.Pass()), audio_client_(nullptr) {} + +MediaPlayerImpl::~MediaPlayerImpl() { + reset(); +} + +void MediaPlayerImpl::Prepare( + mojo::ScopedDataPipeConsumerHandle data_source, + const ::media::MediaPlayer::PrepareCallback& callback) { + reset(); + + NSString* filePath = [AudioClient temporaryFilePath]; + base::FilePath path(filePath.UTF8String); + mojo::common::BlockingCopyToFile(data_source.Pass(), path); + audio_client_ = [[AudioClient alloc] initWithPath:filePath]; + callback.Run(audio_client_ != nullptr); +} + +void MediaPlayerImpl::Start() { + [audio_client_ play]; +} + +void MediaPlayerImpl::Pause() { + [audio_client_ pause]; +} + +void MediaPlayerImpl::SeekTo(uint32_t msec) { + [audio_client_ seekTo:msec * 1e-3]; +} + +void MediaPlayerImpl::reset() { + [audio_client_ release]; + audio_client_ = nullptr; +} + +void MediaPlayerFactory::Create( + mojo::ApplicationConnection* connection, + mojo::InterfaceRequest<::media::MediaPlayer> request) { + new MediaPlayerImpl(request.Pass()); +} + +} // namespace media +} // namespace services +} // namespace sky diff --git a/sky/services/media/ios/media_service_impl.h b/sky/services/media/ios/media_service_impl.h new file mode 100644 index 000000000..7e23c213c --- /dev/null +++ b/sky/services/media/ios/media_service_impl.h @@ -0,0 +1,44 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SKY_SERVICES_MEDIA_IOS_MEDIA_SERVICE_IMPL_H_ +#define SKY_SERVICES_MEDIA_IOS_MEDIA_SERVICE_IMPL_H_ + +#include "base/macros.h" +#include "mojo/public/cpp/application/interface_factory.h" +#include "mojo/public/cpp/bindings/strong_binding.h" +#include "sky/services/media/media.mojom.h" +#include "sky/services/media/ios/media_player_impl.h" + +namespace sky { +namespace services { +namespace media { + +class MediaServiceImpl : public ::media::MediaService { + public: + MediaServiceImpl(mojo::InterfaceRequest<::media::MediaService> request); + ~MediaServiceImpl() override; + + void CreatePlayer( + mojo::InterfaceRequest<::media::MediaPlayer> player) override; + + private: + mojo::StrongBinding<::media::MediaService> binding_; + MediaPlayerFactory media_player_; + + DISALLOW_COPY_AND_ASSIGN(MediaServiceImpl); +}; + +class MediaServiceFactory + : public mojo::InterfaceFactory<::media::MediaService> { + public: + void Create(mojo::ApplicationConnection* connection, + mojo::InterfaceRequest<::media::MediaService> request) override; +}; + +} // namespace media +} // namespace services +} // namespace sky + +#endif // SKY_SERVICES_MEDIA_IOS_MEDIA_SERVICE_IMPL_H_ diff --git a/sky/services/media/ios/media_service_impl.mm b/sky/services/media/ios/media_service_impl.mm new file mode 100644 index 000000000..0b5f2e8b0 --- /dev/null +++ b/sky/services/media/ios/media_service_impl.mm @@ -0,0 +1,30 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "sky/services/media/ios/media_service_impl.h" + +namespace sky { +namespace services { +namespace media { + +MediaServiceImpl::MediaServiceImpl( + mojo::InterfaceRequest<::media::MediaService> request) + : binding_(this, request.Pass()) {} + +MediaServiceImpl::~MediaServiceImpl() {} + +void MediaServiceImpl::CreatePlayer( + mojo::InterfaceRequest<::media::MediaPlayer> player) { + media_player_.Create(nullptr, player.Pass()); +} + +void MediaServiceFactory::Create( + mojo::ApplicationConnection* connection, + mojo::InterfaceRequest<::media::MediaService> request) { + new MediaServiceImpl(request.Pass()); +} + +} // namespace media +} // namespace services +} // namespace sky diff --git a/sky/shell/BUILD.gn b/sky/shell/BUILD.gn index 2af15d17c..5939a85a3 100644 --- a/sky/shell/BUILD.gn +++ b/sky/shell/BUILD.gn @@ -212,6 +212,7 @@ if (is_android) { ":common", "//sky/services/ns_net", "//sky/services/keyboard", + "//sky/services/media", ] } diff --git a/sky/shell/mac/platform_service_provider_mac.cc b/sky/shell/mac/platform_service_provider_mac.cc index e6760ceba..1e096a661 100644 --- a/sky/shell/mac/platform_service_provider_mac.cc +++ b/sky/shell/mac/platform_service_provider_mac.cc @@ -14,6 +14,8 @@ #if TARGET_OS_IPHONE #include "sky/services/keyboard/ios/keyboard_service_impl.h" +#include "sky/services/media/ios/media_service_impl.h" +#include "sky/services/media/ios/media_player_impl.h" #endif #if !TARGET_OS_IPHONE @@ -39,6 +41,14 @@ class PlatformServiceProvider : public mojo::ServiceProvider { keyboard_.Create(nullptr, mojo::MakeRequest<::keyboard::KeyboardService>( client_handle.Pass())); } + if (service_name == ::media::MediaPlayer::Name_) { + media_player_.Create(nullptr, mojo::MakeRequest<::media::MediaPlayer>( + client_handle.Pass())); + } + if (service_name == ::media::MediaService::Name_) { + media_service_.Create(nullptr, mojo::MakeRequest<::media::MediaService>( + client_handle.Pass())); + } #endif #if !TARGET_OS_IPHONE if (service_name == TestHarness::Name_) { @@ -53,6 +63,8 @@ class PlatformServiceProvider : public mojo::ServiceProvider { mojo::NetworkServiceFactory network_; #if TARGET_OS_IPHONE sky::services::keyboard::KeyboardServiceFactory keyboard_; + sky::services::media::MediaPlayerFactory media_player_; + sky::services::media::MediaServiceFactory media_service_; #endif };