ExoPlayer লাইব্রেরির মূল বিষয় হল Player ইন্টারফেস। Player
মিডিয়া প্লেয়ারের ঐতিহ্যবাহী হাই-লেভেল ফাংশনালিটি প্রকাশ করে, যেমন মিডিয়া
বাফার করা, চালানো, পজ করা ও খোঁজার ক্ষমতা। ডিফল্ট প্রয়োগ ExoPlayer হল
যে ধরনের মিডিয়া চালানো হচ্ছে, সেটি কীভাবে ও কোথায় স্টোর করা আছে এবং কীভাবে সেটি
রেন্ডার করা হচ্ছে সেই সম্পর্কে কিছু অনুমান করার (এবং সেই জন্য কিছু বিধিনিষেধ আরোপ করার)
জন্য ডিজাইন করা হয়েছে। সরাসরি মিডিয়া লোড ও রেন্ডার করার পরিবর্তে,
ExoPlayer প্লেয়ার তৈরি হলে বা প্লেয়ারে নতুন মিডিয়া সোর্স পাস করা হলে,
ইনজেক্ট করা কম্পোনেন্টকে এই কাজগুলি করার দায়িত্ব দেওয়া হয়।
সব ExoPlayer প্রয়োগের ক্ষেত্রে সাধারণ কম্পোনেন্ট হল:
MediaSourceইনস্ট্যান্স যা চালানো হবে এমন মিডিয়াকে সংজ্ঞায়িত করে, মিডিয়া লোড করে এবং যেখান থেকে লোড করা মিডিয়া পড়া যায়। প্লেয়ারের মধ্যেMediaSource.Factory-এর মাধ্যমেMediaItemথেকে একটিMediaSourceইনস্ট্যান্স তৈরি করা হয়। এছাড়াও, এগুলি মিডিয়া সোর্স ভিত্তিক প্লেলিস্ট API ব্যবহার করে সরাসরি প্লেয়ারে পাস করা যেতে পারে।MediaSource.Factoryইনস্ট্যান্স যাMediaItem-কেMediaSource-এ কনভার্ট করে। প্লেয়ার তৈরি করার সময়MediaSource.Factoryইনজেক্ট করা হয়।Rendererইনস্ট্যান্স যা মিডিয়ার আলাদা আলাদা কম্পোনেন্ট রেন্ডার করে। প্লেয়ার তৈরি করার সময় এগুলি ইনজেক্ট করা হয়।TrackSelectorযাMediaSource-এর দেওয়া ট্র্যাক বেছে নেয় যাতে উপলভ্য প্রতিটিRendererব্যবহার করতে পারে। প্লেয়ার তৈরি হলে একটিTrackSelectorইনজেক্ট করা হয় ।LoadControlযা নিয়ন্ত্রণ করে কখনMediaSourceআরও মিডিয়া বাফার করবে এবং কতটা মিডিয়া বাফার করা হবে। প্লেয়ার তৈরি করার সময় একটিLoadControlইনজেক্ট করা হয়।LivePlaybackSpeedControlযা লাইভ প্লেব্যাকের সময় প্লেব্যাক স্পিড কন্ট্রোল করে যাতে প্লেয়ার কনফিগার করা লাইভ অফসেটের কাছাকাছি থাকতে পারে। প্লেয়ার তৈরি করার সময়LivePlaybackSpeedControlইনজেক্ট করা হয়।
প্লেয়ার ফাংশনের অংশ প্রয়োগ করে এমন কম্পোনেন্ট ইনজেক্ট করার ধারণাটি লাইব্রেরি জুড়ে উপস্থিত। কিছু কম্পোনেন্টের ডিফল্ট প্রয়োগ আরও ইনজেক্ট করা কম্পোনেন্টকে কাজ ডেলিগেট করে। এর ফলে অনেক সাব-কম্পোনেন্টকে আলাদা আলাদাভাবে এমন ইমপ্লিমেন্টেশনের মাধ্যমে পরিবর্তন করা যায় যা কাস্টম উপায়ে কনফিগার করা হয়।
প্লেয়ার কাস্টমাইজ করা
কম্পোনেন্ট ইনজেক্ট করার মাধ্যমে প্লেয়ার কাস্টমাইজ করার কিছু সাধারণ উদাহরণ নিচে বর্ণিত আছে।
নেটওয়ার্ক স্ট্যাক কনফিগার করা
ExoPlayer-এর ব্যবহার করা নেটওয়ার্ক স্ট্যাক কাস্টমাইজ করা সম্পর্কে আমাদের একটি পৃষ্ঠা আছে।
নেটওয়ার্ক থেকে লোড করা ডেটা ক্যাশে করা
সাময়িক অন-দ্য-ফ্লাই ক্যাশিং ও মিডিয়া ডাউনলোড করা সংক্রান্ত নির্দেশিকা দেখুন।
সার্ভারের সাথে ইন্টার্যাকশন কাস্টমাইজ করা
কিছু অ্যাপ HTTP অনুরোধ ও উত্তর ইন্টারসেপ্ট করতে চাইতে পারে। আপনি হয়ত কাস্টম অনুরোধ হেডার ইনজেক্ট করতে, সার্ভারের উত্তর হেডার পড়তে, অনুরোধের URI পরিবর্তন করতে ইত্যাদি চান। যেমন, মিডিয়া সেগমেন্টের অনুরোধ করার সময় আপনার অ্যাপ হয়ত হেডার হিসেবে টোকেন ইনজেক্ট করে নিজেকে যাচাই করিয়ে নিতে পারে।
নিম্নলিখিত উদাহরণে দেখানো হয়েছে যে কীভাবে DefaultMediaSourceFactory-এ কাস্টম DataSource.Factory ইনজেক্ট করে
এইসব আচরণ প্রয়োগ করা যায়:
Kotlin
val dataSourceFactory = DataSource.Factory { val dataSource = httpDataSourceFactory.createDataSource() // Set a custom authentication request header. dataSource.setRequestProperty("Header", "Value") dataSource } val player = ExoPlayer.Builder(context) .setMediaSourceFactory( DefaultMediaSourceFactory(context).setDataSourceFactory(dataSourceFactory) ) .build()
জাভা
DataSource.Factory dataSourceFactory = () -> { HttpDataSource dataSource = httpDataSourceFactory.createDataSource(); // Set a custom authentication request header. dataSource.setRequestProperty("Header", "Value"); return dataSource; }; ExoPlayer player = new ExoPlayer.Builder(context) .setMediaSourceFactory( new DefaultMediaSourceFactory(context).setDataSourceFactory(dataSourceFactory)) .build();
উপরের কোড স্নিপেটে, ইনজেক্ট করা HttpDataSource প্রতিটি HTTP অনুরোধে হেডার
"Header: Value" অন্তর্ভুক্ত করে। HTTP সোর্সের সাথে প্রতিটি
ইন্টার্যাকশনের জন্য এই আচরণ নির্ধারিত।
আরও গ্র্যানুলার পদ্ধতির জন্য, আপনি
ResolvingDataSource ব্যবহার করে জাস্ট-ইন-টাইম আচরণ ইনজেক্ট করতে পারেন। HTTP সোর্সের সাথে ইন্টার্যাক্ট করার ঠিক আগে কীভাবে
অনুরোধ হেডার ইনজেক্ট করতে হয় তা নিম্নলিখিত কোড স্নিপেট থেকে বোঝা যায়:
Kotlin
val dataSourceFactory: DataSource.Factory = ResolvingDataSource.Factory(httpDataSourceFactory) { dataSpec: DataSpec -> // Provide just-in-time request headers. dataSpec.withRequestHeaders(getCustomHeaders(dataSpec.uri)) }
জাভা
DataSource.Factory dataSourceFactory = new ResolvingDataSource.Factory( httpDataSourceFactory, // Provide just-in-time request headers. dataSpec -> dataSpec.withRequestHeaders(getCustomHeaders(dataSpec.uri)));
এছাড়াও, আপনি ResolvingDataSource ব্যবহার করে
URI-তে ঠিক সেই সময়েই পরিবর্তন করতে পারেন, যেমনটি নিম্নলিখিত স্নিপেটে দেখানো হয়েছে:
Kotlin
val dataSourceFactory: DataSource.Factory = ResolvingDataSource.Factory(httpDataSourceFactory) { dataSpec: DataSpec -> // Provide just-in-time URI resolution logic. dataSpec.withUri(resolveUri(dataSpec.uri)) }
জাভা
DataSource.Factory dataSourceFactory = new ResolvingDataSource.Factory( httpDataSourceFactory, // Provide just-in-time URI resolution logic. dataSpec -> dataSpec.withUri(resolveUri(dataSpec.uri)));
সমস্যা ম্যানেজ করার প্রসেস কাস্টমাইজ করা
কাস্টম LoadErrorHandlingPolicy প্রয়োগ করলে, ExoPlayer লোড সংক্রান্ত সমস্যার ক্ষেত্রে
কীভাবে প্রতিক্রিয়া জানাবে তা অ্যাপ কাস্টমাইজ করতে পারে। যেমন, কোনও অ্যাপ অনেকবার আবার চেষ্টা করার পরিবর্তে
দ্রুত ব্যর্থ হতে চাইতে পারে অথবা ব্যাক-অফ লজিক কাস্টমাইজ করতে চাইতে পারে যা
প্রতিবার আবার চেষ্টা করার মধ্যে প্লেয়ার কতক্ষণ অপেক্ষা করবে তা কন্ট্রোল করে। নিম্নলিখিত স্নিপেট
থেকে কীভাবে কাস্টম ব্যাক-অফ লজিক প্রয়োগ করতে হয় তা জানা যায়:
Kotlin
val loadErrorHandlingPolicy: LoadErrorHandlingPolicy = object : DefaultLoadErrorHandlingPolicy() { override fun getRetryDelayMsFor( loadErrorInfo: LoadErrorHandlingPolicy.LoadErrorInfo ): Long { // Implement custom back-off logic here. return 0 } } val player = ExoPlayer.Builder(context) .setMediaSourceFactory( DefaultMediaSourceFactory(context).setLoadErrorHandlingPolicy(loadErrorHandlingPolicy) ) .build()
জাভা
LoadErrorHandlingPolicy loadErrorHandlingPolicy = new DefaultLoadErrorHandlingPolicy() { @Override public long getRetryDelayMsFor(LoadErrorHandlingPolicy.LoadErrorInfo loadErrorInfo) { // Implement custom back-off logic here. return 0; } }; ExoPlayer player = new ExoPlayer.Builder(context) .setMediaSourceFactory( new DefaultMediaSourceFactory(context) .setLoadErrorHandlingPolicy(loadErrorHandlingPolicy)) .build();
LoadErrorInfo আর্গুমেন্টে লোড না হওয়া সংক্রান্ত আরও তথ্য থাকে।
এর ফলে, সমস্যার ধরন বা অনুরোধ ব্যর্থ হওয়ার ভিত্তিতে লজিক কাস্টমাইজ করা যায়।
এক্সট্র্যাক্টর ফ্ল্যাগ কাস্টমাইজ করা
প্রোগ্রেসিভ মিডিয়া থেকে কীভাবে আলাদা আলাদা ফর্ম্যাট এক্সট্র্যাক্ট করা হবে তা কাস্টমাইজ করতে এক্সট্র্যাক্টর ফ্ল্যাগ ব্যবহার করা যেতে পারে
। DefaultMediaSourceFactory-কে দেওয়া DefaultExtractorsFactory-এ সেগুলি সেট করা যেতে পারে।
নিচের উদাহরণে একটি ফ্ল্যাগ পাস করা হয়েছে
যা MP3 স্ট্রিমের জন্য ইন্ডেক্স-ভিত্তিক সিকিং চালু করে।
Kotlin
val extractorsFactory = DefaultExtractorsFactory().setMp3ExtractorFlags(Mp3Extractor.FLAG_ENABLE_INDEX_SEEKING) val player = ExoPlayer.Builder(context) .setMediaSourceFactory(DefaultMediaSourceFactory(context, extractorsFactory)) .build()
জাভা
DefaultExtractorsFactory extractorsFactory = new DefaultExtractorsFactory().setMp3ExtractorFlags(Mp3Extractor.FLAG_ENABLE_INDEX_SEEKING); ExoPlayer player = new ExoPlayer.Builder(context) .setMediaSourceFactory(new DefaultMediaSourceFactory(context, extractorsFactory)) .build();
কনস্ট্যান্ট বিটরেট সিকিং চালু করা
MP3, ADTS ও AMR স্ট্রিমের জন্য, আপনি FLAG_ENABLE_CONSTANT_BITRATE_SEEKING ফ্ল্যাগ সহ
ধ্রুবক বিটরেট অনুমান ব্যবহার করে আনুমানিক সিকিং চালু করতে পারবেন।
উপরে বর্ণিত individual
DefaultExtractorsFactory.setXyzExtractorFlags পদ্ধতি ব্যবহার করে আলাদা আলাদা এক্সট্র্যাক্টরের জন্য এইসব ফ্ল্যাগ সেট করা যেতে পারে। যেসব এক্সট্র্যাক্টর এটি কাজ করে সেগুলির জন্য
কনস্ট্যান্ট বিটরেট খোঁজা চালু করতে, DefaultExtractorsFactory.setConstantBitrateSeekingEnabled
ব্যবহার করুন।
Kotlin
val extractorsFactory = DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true)
জাভা
DefaultExtractorsFactory extractorsFactory = new DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true);
ExtractorsFactory-কে DefaultMediaSourceFactory-এর মাধ্যমে ইনজেক্ট করা যেতে পারে, যেমন
উপরে এক্সট্র্যাক্টর ফ্ল্যাগ কাস্টমাইজ করার জন্য বর্ণনা করা হয়েছে।
অ্যাসিঙ্ক্রোনাস বাফার কিউয়িং চালু করা
অ্যাসিঙ্ক্রোনাস বাফার কিউয়িং হল ExoPlayer-এর রেন্ডারিং
পাইপলাইনে একটি উন্নত ফিচার, যা MediaCodec ইনস্ট্যান্সকে অ্যাসিঙ্ক্রোনাস মোডে অপারেট করে এবং
ডেটা ডিকোডিং ও রেন্ডারিং শিডিউল করার জন্য অতিরিক্ত থ্রেড ব্যবহার করে। এটি চালু করলে
ড্রপ করা ফ্রেম ও অডিও আন্ডাররান কমানো যেতে পারে।
Android 12 (API লেভেল 31) ও তার পরবর্তী যেকোনও ভার্সনে চলা ডিভাইসে ডিফল্ট হিসেবে অ্যাসিঙ্ক্রোনাস বাফার কিউয়িং চালু থাকে এবং Android 6.0 (API লেভেল 23) থেকে শুরু করে ম্যানুয়ালি চালু করা যেতে পারে। নির্দিষ্ট ডিভাইসে এই ফিচার চালু করার কথা বিবেচনা করুন, যেখানে আপনি ড্রপ করা ফ্রেম বা অডিও আন্ডাররান লক্ষ্য করেছেন, বিশেষ করে DRM সুরক্ষিত বা হাই-ফ্রেম-রেট কন্টেন্ট চালানোর সময়।
সবচেয়ে সহজ ক্ষেত্রে, আপনাকে প্লেয়ারকে
নিচে উল্লেখ করা DefaultRenderersFactory ইনজেক্ট করতে হবে:
Kotlin
val renderersFactory = DefaultRenderersFactory(context).forceEnableMediaCodecAsynchronousQueueing() val exoPlayer = ExoPlayer.Builder(context, renderersFactory).build()
জাভা
DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(context).forceEnableMediaCodecAsynchronousQueueing(); ExoPlayer exoPlayer = new ExoPlayer.Builder(context, renderersFactory).build();
আপনি সরাসরি রেন্ডারার ইনস্ট্যানশিয়েট করলে, new DefaultMediaCodecAdapter.Factory(context).forceEnableAsynchronous()-কে
MediaCodecVideoRenderer এবং MediaCodecAudioRenderer কনস্ট্রাক্টরে পাস করুন।
ForwardingSimpleBasePlayer-এর মাধ্যমে অপারেশন কাস্টমাইজ করা
ForwardingSimpleBasePlayer-এর সাবক্লাসে র্যাপ করে আপনি Player-এর কিছু আচরণ কাস্টমাইজ করতে পারেন।
এই ক্লাস আপনাকে সরাসরি Player
মেথড প্রয়োগ করার পরিবর্তে নির্দিষ্ট 'অপারেশন' ইন্টারসেপ্ট
করতে দেয়। এটি নিশ্চিত করে যে play(), pause()
এবং setPlayWhenReady(boolean)-এর মতো আইটেম সামঞ্জস্যপূর্ণ আচরণ করবে। এছাড়াও, এটি নিশ্চিত করে যে সমস্ত স্টেট পরিবর্তন সঠিকভাবে
রেজিস্টার করা Player.Listener ইনস্ট্যান্সে প্রোপাগেট করা হয়েছে। বেশিরভাগ কাস্টমাইজেশন
ব্যবহারের ক্ষেত্রে, ForwardingSimpleBasePlayer-কে বেশি
ভুল-প্রবণ ForwardingPlayer-এর চেয়ে বেশি পছন্দ করা উচিত, কারণ এর মধ্যে এই ধারাবাহিকতা সংক্রান্ত গ্যারান্টি থাকে।
যেমন, প্লেব্যাক শুরু বা বন্ধ করা হলে কিছু কাস্টম লজিক যোগ করতে:
Kotlin
class PlayerWithCustomPlay(player: Player) : ForwardingSimpleBasePlayer(player) { override fun handleSetPlayWhenReady(playWhenReady: Boolean): ListenableFuture<*> { // Add custom logic return super.handleSetPlayWhenReady(playWhenReady) } }
জাভা
public static final class PlayerWithCustomPlay extends ForwardingSimpleBasePlayer { public PlayerWithCustomPlay(Player player) { super(player); } @Override protected ListenableFuture<?> handleSetPlayWhenReady(boolean playWhenReady) { // Add custom logic return super.handleSetPlayWhenReady(playWhenReady); } }
অথবা SEEK_TO_NEXT কমান্ড বন্ধ করতে (এবং নিশ্চিত করতে যে Player.seekToNext হল
নো-অপ):
Kotlin
class PlayerWithoutSeekToNext(player: Player) : ForwardingSimpleBasePlayer(player) { override fun getState(): State { val state = super.getState() return state .buildUpon() .setAvailableCommands( state.availableCommands.buildUpon().remove(COMMAND_SEEK_TO_NEXT).build() ) .build() } // We don't need to override handleSeek, because it is guaranteed not to be called for // COMMAND_SEEK_TO_NEXT since we've marked that command unavailable. }
জাভা
public static final class PlayerWithoutSeekToNext extends ForwardingSimpleBasePlayer { public PlayerWithoutSeekToNext(Player player) { super(player); } @Override protected State getState() { State state = super.getState(); return state .buildUpon() .setAvailableCommands( state.availableCommands.buildUpon().remove(COMMAND_SEEK_TO_NEXT).build()) .build(); } // We don't need to override handleSeek, because it is guaranteed not to be called for // COMMAND_SEEK_TO_NEXT since we've marked that command unavailable. }
MediaSource কাস্টমাইজেশন
উপরে দেওয়া উদাহরণে প্লেয়ারে পাস করা সব
MediaItem অবজেক্টের প্লেব্যাকের সময় ব্যবহার করার জন্য কাস্টমাইজ করা কম্পোনেন্ট ইনজেক্ট করা হয়। যেখানে ফাইন-গ্রেন কাস্টমাইজেশন
প্রয়োজন, সেখানে আলাদা আলাদা
MediaSource ইন্সট্যান্সে কাস্টমাইজ করা কম্পোনেন্ট ইনজেক্ট করাও সম্ভব, যা সরাসরি প্লেয়ারে পাস করা যেতে পারে। নিচে দেওয়া উদাহরণ
থেকে বোঝা যাবে যে কীভাবে ProgressiveMediaSource কাস্টমাইজ করে কাস্টম
DataSource.Factory, ExtractorsFactory ও LoadErrorHandlingPolicy ব্যবহার করা যায়:
Kotlin
val mediaSource = ProgressiveMediaSource.Factory(customDataSourceFactory, customExtractorsFactory) .setLoadErrorHandlingPolicy(customLoadErrorHandlingPolicy) .createMediaSource(MediaItem.fromUri(streamUri))
জাভা
ProgressiveMediaSource mediaSource = new ProgressiveMediaSource.Factory(customDataSourceFactory, customExtractorsFactory) .setLoadErrorHandlingPolicy(customLoadErrorHandlingPolicy) .createMediaSource(MediaItem.fromUri(streamUri));
কাস্টম কম্পোনেন্ট তৈরি করা
এই পৃষ্ঠার উপরে
তালিকাভুক্ত কম্পোনেন্টগুলির ডিফল্ট প্রয়োগ সাধারণ ব্যবহারের ক্ষেত্রে লাইব্রেরি প্রদান করে। ExoPlayer এইসব কম্পোনেন্ট ব্যবহার করতে পারে, কিন্তু
অপ্রচলিত আচরণ প্রয়োজন হলে কাস্টম প্রয়োগ পদ্ধতি ব্যবহার করার জন্য
তৈরি করা হতে পারে। কাস্টম প্রয়োগের কিছু ব্যবহারিক উদাহরণ হল:
Renderer– লাইব্রেরির দেওয়া ডিফল্ট ইমপ্লিমেন্টেশনে কাজ করে না এমন মিডিয়া টাইপ হ্যান্ডেল করার জন্য আপনাকে কাস্টমRendererইমপ্লিমেন্ট করতে হতে পারে।TrackSelector– কাস্টমTrackSelectorপ্রয়োগ করলে, কোনও অ্যাপ ডেভেলপার,MediaSource-এর মাধ্যমে এক্সপোজ করা ট্র্যাকগুলি উপলভ্যRenderer-এর প্রতিটি দ্বারা কনজাম্পশনের জন্য বেছে নেওয়ার পদ্ধতি পরিবর্তন করতে পারেন।LoadControl– কাস্টমLoadControlপ্রয়োগ করলে, কোনও অ্যাপের ডেভেলপার প্লেয়ারের বাফারিং নীতি পরিবর্তন করতে পারেন।Extractor– লাইব্রেরিতে বর্তমানে কাজ করে না এমন কন্টেনার ফর্ম্যাট ব্যবহার করতে হলে, কাস্টমExtractorক্লাস প্রয়োগ করার কথা বিবেচনা করুন।MediaSource– আপনি যদি কাস্টম উপায়ে রেন্ডারারকে ফিড করার জন্য মিডিয়া স্যাম্পেল পেতে চান অথবা কাস্টমMediaSourceকম্পোজিটিং বিহেভিয়ার প্রয়োগ করতে চান, তাহলে কাস্টমMediaSourceক্লাস প্রয়োগ করা উপযুক্ত হতে পারে।MediaSource.Factory– কাস্টমMediaSource.Factoryপ্রয়োগ করলে কোনও অ্যাপ্লিকেশনMediaItemথেকেMediaSourceতৈরি করার পদ্ধতি কাস্টমাইজ করতে পারে।DataSource– ExoPlayer-এর আপস্ট্রিম প্যাকেজে আগে থেকেই বিভিন্ন ব্যবহারের ক্ষেত্রেDataSourceপ্রয়োগ করার সুবিধা রয়েছে। আপনি হয়ত অন্য কোনও উপায়ে ডেটা লোড করার জন্য নিজেরDataSourceক্লাস প্রয়োগ করতে চাইবেন, যেমন কাস্টম HTTP স্ট্যাক ব্যবহার করে কাস্টম প্রোটোকল বা কাস্টম পারসিস্টেন্ট ক্যাশে থেকে।
কাস্টম কম্পোনেন্ট তৈরি করার সময়, আমরা নিম্নলিখিত বিষয়গুলি সাজেস্ট করি:
- কোনও কাস্টম কম্পোনেন্টকে যদি অ্যাপে ইভেন্ট রিপোর্ট করতে হয়, তাহলে আমরা সাজেস্ট করি যে
আপনি যেন তা বর্তমান ExoPlayer কম্পোনেন্টগুলির মতো একই মডেল ব্যবহার করে করেন।
যেমন,
EventDispatcherক্লাস ব্যবহার করা অথবা কম্পোনেন্টের কনস্ট্রাক্টরে লিসনারের সাথেHandlerপাস করা। - আমরা সাজেস্ট করি যে কাস্টম কম্পোনেন্ট যেন আগে থেকে থাকা ExoPlayer
কম্পোনেন্টের মতো একই মডেল ব্যবহার করে যাতে প্লেব্যাকের সময় অ্যাপের মাধ্যমে রিকনফিগার করা যায়। এটি করতে,
কাস্টম কম্পোনেন্টকে
PlayerMessage.Targetপ্রয়োগ করতে হবে এবংhandleMessageপদ্ধতিতে কনফিগারেশন সংক্রান্ত পরিবর্তন পেতে হবে। অ্যাপ্লিকেশন কোডকে ExoPlayer-এরcreateMessageমেথড কল করে, মেসেজ কনফিগার করে এবংPlayerMessage.sendব্যবহার করে কম্পোনেন্টে পাঠিয়ে কনফিগারেশন পরিবর্তন পাস করতে হবে। প্লেব্যাক থ্রেডে ডেলিভার করার জন্য মেসেজ পাঠানো নিশ্চিত করে যে সেগুলি প্লেয়ারে করা অন্য যেকোনও অপারেশনের সাথে ক্রম অনুসারে এক্সিকিউট করা হয়েছে।